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 '')
-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
-rw-r--r--libcli/auth/credentials.c1222
-rw-r--r--libcli/auth/credentials.h70
-rw-r--r--libcli/auth/libcli_auth.h28
-rw-r--r--libcli/auth/msrpc_parse.c409
-rw-r--r--libcli/auth/msrpc_parse.h58
-rw-r--r--libcli/auth/netlogon_creds_cli.c4256
-rw-r--r--libcli/auth/netlogon_creds_cli.h236
-rw-r--r--libcli/auth/ntlm_check.c656
-rw-r--r--libcli/auth/ntlm_check.h87
-rw-r--r--libcli/auth/pam_errors.c143
-rw-r--r--libcli/auth/pam_errors.h33
-rw-r--r--libcli/auth/proto.h296
-rw-r--r--libcli/auth/schannel.h25
-rw-r--r--libcli/auth/schannel_proto.h31
-rw-r--r--libcli/auth/schannel_state.h54
-rw-r--r--libcli/auth/schannel_state_tdb.c646
-rw-r--r--libcli/auth/session.c247
-rw-r--r--libcli/auth/smbdes.c213
-rw-r--r--libcli/auth/smbencrypt.c1325
-rw-r--r--libcli/auth/spnego.h82
-rw-r--r--libcli/auth/spnego_parse.c446
-rw-r--r--libcli/auth/spnego_proto.h28
-rw-r--r--libcli/auth/tests/ntlm_check.c413
-rw-r--r--libcli/auth/tests/test_encode_decode.c162
-rw-r--r--libcli/auth/tests/test_gnutls.c524
-rw-r--r--libcli/auth/tests/test_rc4_passwd_buffer.c336
-rw-r--r--libcli/auth/tests/test_schannel.c305
-rw-r--r--libcli/auth/wscript_build100
-rw-r--r--libcli/cldap/cldap.c1209
-rw-r--r--libcli/cldap/cldap.h134
-rw-r--r--libcli/cldap/wscript_build10
-rw-r--r--libcli/dns/dns.c591
-rw-r--r--libcli/dns/dns.h64
-rw-r--r--libcli/dns/dns_lookup.c374
-rw-r--r--libcli/dns/dns_lookup.h48
-rw-r--r--libcli/dns/dns_lookuptest.c55
-rw-r--r--libcli/dns/libdns.h43
-rw-r--r--libcli/dns/resolvconf.c123
-rw-r--r--libcli/dns/resolvconf.h37
-rw-r--r--libcli/dns/resolvconftest.c82
-rw-r--r--libcli/dns/wscript_build21
-rw-r--r--libcli/drsuapi/drsuapi.h32
-rw-r--r--libcli/drsuapi/repl_decrypt.c391
-rw-r--r--libcli/drsuapi/tests/test_repl_decrypt.c522
-rw-r--r--libcli/drsuapi/wscript_build19
-rw-r--r--libcli/echo/echo.c209
-rw-r--r--libcli/echo/libecho.h56
-rw-r--r--libcli/echo/tests/echo.c97
-rw-r--r--libcli/echo/tests/wscript_build8
-rw-r--r--libcli/echo/wscript_build7
-rw-r--r--libcli/http/gensec/basic.c204
-rw-r--r--libcli/http/gensec/generic.c286
-rw-r--r--libcli/http/http.c882
-rw-r--r--libcli/http/http.h143
-rw-r--r--libcli/http/http_auth.c383
-rw-r--r--libcli/http/http_conn.c347
-rw-r--r--libcli/http/http_internal.h50
-rw-r--r--libcli/http/wscript_build21
-rw-r--r--libcli/ldap/ldap_errors.h68
-rw-r--r--libcli/ldap/ldap_message.c1673
-rw-r--r--libcli/ldap/ldap_message.h244
-rw-r--r--libcli/ldap/ldap_ndr.c95
-rw-r--r--libcli/ldap/ldap_ndr.h34
-rw-r--r--libcli/ldap/tests/data/10000-or.datbin0 -> 39875 bytes
-rw-r--r--libcli/ldap/tests/data/ldap-recursive.datbin0 -> 970 bytes
-rw-r--r--libcli/ldap/tests/data/ldap-starttls-response.datbin0 -> 38 bytes
-rw-r--r--libcli/ldap/tests/ldap_message_test.c345
-rw-r--r--libcli/ldap/wscript_build23
-rw-r--r--libcli/lsarpc/util_lsarpc.c359
-rw-r--r--libcli/lsarpc/util_lsarpc.h38
-rw-r--r--libcli/lsarpc/wscript_build5
-rw-r--r--libcli/named_pipe_auth/npa_tstream.c1406
-rw-r--r--libcli/named_pipe_auth/npa_tstream.h145
-rw-r--r--libcli/named_pipe_auth/tstream_u32_read.c159
-rw-r--r--libcli/named_pipe_auth/tstream_u32_read.h37
-rw-r--r--libcli/named_pipe_auth/wscript_build9
-rw-r--r--libcli/nbt/libnbt.h377
-rw-r--r--libcli/nbt/lmhosts.c243
-rw-r--r--libcli/nbt/man/nmblookup4.1.xml213
-rw-r--r--libcli/nbt/namequery.c234
-rw-r--r--libcli/nbt/namerefresh.c347
-rw-r--r--libcli/nbt/nameregister.c514
-rw-r--r--libcli/nbt/namerelease.c134
-rw-r--r--libcli/nbt/nbt_proto.h65
-rw-r--r--libcli/nbt/nbtname.c486
-rw-r--r--libcli/nbt/nbtsocket.c566
-rw-r--r--libcli/nbt/pynbt.c447
-rw-r--r--libcli/nbt/tools/nmblookup.c477
-rw-r--r--libcli/nbt/wscript_build32
-rw-r--r--libcli/netlogon/netlogon.c285
-rw-r--r--libcli/netlogon/netlogon.h41
-rw-r--r--libcli/netlogon/netlogon_proto.h28
-rw-r--r--libcli/netlogon/wscript_build6
-rw-r--r--libcli/registry/util_reg.c138
-rw-r--r--libcli/registry/util_reg.h32
-rw-r--r--libcli/registry/wscript_build5
-rw-r--r--libcli/samsync/decrypt.c209
-rw-r--r--libcli/samsync/samsync.h36
-rw-r--r--libcli/samsync/wscript_build8
-rw-r--r--libcli/security/access_check.c958
-rw-r--r--libcli/security/access_check.h100
-rw-r--r--libcli/security/claims-conversions.c1216
-rw-r--r--libcli/security/claims-conversions.h60
-rw-r--r--libcli/security/conditional_ace.c2550
-rw-r--r--libcli/security/conditional_ace.h97
-rw-r--r--libcli/security/create_descriptor.c666
-rw-r--r--libcli/security/display_sec.c274
-rw-r--r--libcli/security/display_sec.h34
-rw-r--r--libcli/security/dom_sid.c582
-rw-r--r--libcli/security/dom_sid.h155
-rw-r--r--libcli/security/object_tree.c127
-rw-r--r--libcli/security/privileges.c498
-rw-r--r--libcli/security/privileges.h116
-rw-r--r--libcli/security/privileges_private.h41
-rw-r--r--libcli/security/pysecurity.c96
-rw-r--r--libcli/security/sddl.c1341
-rw-r--r--libcli/security/sddl.h47
-rw-r--r--libcli/security/sddl_conditional_ace.c3476
-rw-r--r--libcli/security/secace.c204
-rw-r--r--libcli/security/secace.h40
-rw-r--r--libcli/security/secacl.c75
-rw-r--r--libcli/security/secacl.h33
-rw-r--r--libcli/security/secdesc.c623
-rw-r--r--libcli/security/secdesc.h96
-rw-r--r--libcli/security/security.h121
-rw-r--r--libcli/security/security_descriptor.c908
-rw-r--r--libcli/security/security_descriptor.h99
-rw-r--r--libcli/security/security_token.c228
-rw-r--r--libcli/security/security_token.h74
-rw-r--r--libcli/security/session.c74
-rw-r--r--libcli/security/session.h44
-rw-r--r--libcli/security/tests/data/conditional_aces.txt83
-rw-r--r--libcli/security/tests/data/conditional_aces.txt.json1
-rw-r--r--libcli/security/tests/data/conditional_aces_case_insensitive.txt1
-rw-r--r--libcli/security/tests/data/conditional_aces_should_fail.txt14
-rw-r--r--libcli/security/tests/data/conditional_aces_windows_only.txt14
-rwxr-xr-xlibcli/security/tests/data/export-sddl-fuzz-seeds-as-json49
-rwxr-xr-xlibcli/security/tests/data/extract-sddl-seeds72
-rw-r--r--libcli/security/tests/data/ndr_dumps/fileb5iJt4bin0 -> 118 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/fileb8cNVSbin0 -> 360 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/filebI7h5Hbin0 -> 112 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/filebNdBgtbin0 -> 344 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/filebOjK4Hbin0 -> 124 bytes
-rw-r--r--libcli/security/tests/data/ndr_dumps/filebzCPTHbin0 -> 480 bytes
-rw-r--r--libcli/security/tests/data/oversize-acls.json20
-rw-r--r--libcli/security/tests/data/registry-object-rights.json1
-rw-r--r--libcli/security/tests/data/short-conditional-and-resource-aces-successes.json.gzbin0 -> 17815 bytes
-rw-r--r--libcli/security/tests/data/short-conditional-and-resource-aces-tx-int.json.gzbin0 -> 2183 bytes
-rw-r--r--libcli/security/tests/data/short-ordinary-acls-v2.json.gzbin0 -> 7223 bytes
-rw-r--r--libcli/security/tests/data/short-ordinary-acls.json.gzbin0 -> 220742 bytes
-rw-r--r--libcli/security/tests/test_claim_conversion.c171
-rw-r--r--libcli/security/tests/test_run_conditional_ace.c730
-rw-r--r--libcli/security/tests/test_sddl_conditional_ace.c1003
-rw-r--r--libcli/security/tests/windows/canonical.txt19
-rw-r--r--libcli/security/tests/windows/conditional_aces.txt.json1
-rw-r--r--libcli/security/tests/windows/non_canonical.txt50
-rw-r--r--libcli/security/tests/windows/should_fail.txt47
-rw-r--r--libcli/security/tests/windows/windows-sddl-tests.c341
-rw-r--r--libcli/security/tests/windows/windows-sddl-tests.py181
-rw-r--r--libcli/security/tests/windows/windows_is_fussy.txt1
-rw-r--r--libcli/security/tests/windows/windows_is_less_fussy.txt23
-rw-r--r--libcli/security/tests/windows/windows_is_weird.txt10
-rw-r--r--libcli/security/util_sid.c1117
-rw-r--r--libcli/security/wscript_build64
-rw-r--r--libcli/smb/py_reparse_symlink.c198
-rw-r--r--libcli/smb/read_smb.c114
-rw-r--r--libcli/smb/read_smb.h33
-rw-r--r--libcli/smb/reparse.c567
-rw-r--r--libcli/smb/reparse.h77
-rw-r--r--libcli/smb/smb1cli_close.c188
-rw-r--r--libcli/smb/smb1cli_create.c296
-rw-r--r--libcli/smb/smb1cli_echo.c169
-rw-r--r--libcli/smb/smb1cli_read.c241
-rw-r--r--libcli/smb/smb1cli_session.c821
-rw-r--r--libcli/smb/smb1cli_trans.c908
-rw-r--r--libcli/smb/smb1cli_write.c284
-rw-r--r--libcli/smb/smb2_constants.h317
-rw-r--r--libcli/smb/smb2_create_blob.c227
-rw-r--r--libcli/smb/smb2_create_blob.h75
-rw-r--r--libcli/smb/smb2_create_ctx.h47
-rw-r--r--libcli/smb/smb2_lease.c102
-rw-r--r--libcli/smb/smb2_lease.h43
-rw-r--r--libcli/smb/smb2_lock.h32
-rw-r--r--libcli/smb/smb2_negotiate_context.c203
-rw-r--r--libcli/smb/smb2_negotiate_context.h92
-rw-r--r--libcli/smb/smb2_posix.c51
-rw-r--r--libcli/smb/smb2_posix.h36
-rw-r--r--libcli/smb/smb2_signing.c1110
-rw-r--r--libcli/smb/smb2_signing.h102
-rw-r--r--libcli/smb/smb2cli_close.c136
-rw-r--r--libcli/smb/smb2cli_create.c580
-rw-r--r--libcli/smb/smb2cli_echo.c122
-rw-r--r--libcli/smb/smb2cli_flush.c133
-rw-r--r--libcli/smb/smb2cli_ioctl.c519
-rw-r--r--libcli/smb/smb2cli_notify.c236
-rw-r--r--libcli/smb/smb2cli_query_directory.c210
-rw-r--r--libcli/smb/smb2cli_query_info.c266
-rw-r--r--libcli/smb/smb2cli_read.c218
-rw-r--r--libcli/smb/smb2cli_session.c350
-rw-r--r--libcli/smb/smb2cli_set_info.c183
-rw-r--r--libcli/smb/smb2cli_tcon.c461
-rw-r--r--libcli/smb/smb2cli_write.c183
-rw-r--r--libcli/smb/smbXcli_base.c7034
-rw-r--r--libcli/smb/smbXcli_base.h969
-rw-r--r--libcli/smb/smb_common.h34
-rw-r--r--libcli/smb/smb_constants.h649
-rw-r--r--libcli/smb/smb_seal.c220
-rw-r--r--libcli/smb/smb_seal.h37
-rw-r--r--libcli/smb/smb_signing.c552
-rw-r--r--libcli/smb/smb_signing.h58
-rw-r--r--libcli/smb/smb_unix_ext.h458
-rw-r--r--libcli/smb/smb_util.h57
-rw-r--r--libcli/smb/test_smb1cli_session.c216
-rw-r--r--libcli/smb/test_util_translate.c83
-rw-r--r--libcli/smb/tstream_smbXcli_np.c1399
-rw-r--r--libcli/smb/tstream_smbXcli_np.h75
-rw-r--r--libcli/smb/util.c716
-rw-r--r--libcli/smb/wscript86
-rw-r--r--libcli/smbreadline/smbreadline.c184
-rw-r--r--libcli/smbreadline/smbreadline.h30
-rw-r--r--libcli/smbreadline/wscript_build8
-rw-r--r--libcli/smbreadline/wscript_configure85
-rw-r--r--libcli/tstream_binding_handle/tstream_binding_handle.c341
-rw-r--r--libcli/tstream_binding_handle/tstream_binding_handle.h37
-rw-r--r--libcli/tstream_binding_handle/wscript_build5
-rw-r--r--libcli/util/doserr.c147
-rw-r--r--libcli/util/doserr.h176
-rw-r--r--libcli/util/errmap_unix.c297
-rw-r--r--libcli/util/error.h59
-rw-r--r--libcli/util/errormap.c1246
-rw-r--r--libcli/util/hresult_err_table.txt20520
-rw-r--r--libcli/util/nterr.c377
-rw-r--r--libcli/util/ntstatus.h199
-rw-r--r--libcli/util/ntstatus_err_table.txt12629
-rw-r--r--libcli/util/tstream.c205
-rw-r--r--libcli/util/tstream.h123
-rw-r--r--libcli/util/werror.h171
-rw-r--r--libcli/util/werror_err_table.txt18949
-rw-r--r--libcli/util/wscript_build58
-rw-r--r--libcli/wsp/test_wsp_parser.c402
-rw-r--r--libcli/wsp/wscript_build41
-rw-r--r--libcli/wsp/wsp_aqs.c877
-rw-r--r--libcli/wsp/wsp_aqs.h166
-rw-r--r--libcli/wsp/wsp_aqs_lexer.l152
-rw-r--r--libcli/wsp/wsp_aqs_parser.y422
-rw-r--r--libds/common/flag_mapping.c266
-rw-r--r--libds/common/flag_mapping.h36
-rw-r--r--libds/common/flags.h309
-rw-r--r--libds/common/roles.h82
-rw-r--r--libds/common/wscript_build7
-rw-r--r--libgpo/admx/GNOME_Settings.admx88
-rw-r--r--libgpo/admx/en-US/GNOME_Settings.adml110
-rwxr-xr-xlibgpo/admx/en-US/samba.adml4730
-rw-r--r--libgpo/admx/ru-RU/GNOME_Settings.adml110
-rw-r--r--libgpo/admx/ru-RU/samba.adml5403
-rwxr-xr-xlibgpo/admx/samba.admx2549
-rw-r--r--libgpo/admx/wscript_build8
-rw-r--r--libgpo/gpext/gpext.c882
-rw-r--r--libgpo/gpext/gpext.h109
-rw-r--r--libgpo/gpo.h254
-rw-r--r--libgpo/gpo_fetch.c124
-rw-r--r--libgpo/gpo_filesync.c245
-rw-r--r--libgpo/gpo_ini.c468
-rw-r--r--libgpo/gpo_ini.h53
-rw-r--r--libgpo/gpo_ldap.c956
-rw-r--r--libgpo/gpo_proto.h94
-rw-r--r--libgpo/gpo_reg.c1047
-rw-r--r--libgpo/gpo_sec.c196
-rw-r--r--libgpo/gpo_util.c672
-rw-r--r--libgpo/pygpo.c767
-rw-r--r--libgpo/wscript_build24
-rw-r--r--librpc/ABI/ndr-0.0.1.sigs245
-rw-r--r--librpc/ABI/ndr-0.0.2.sigs247
-rw-r--r--librpc/ABI/ndr-0.0.3.sigs251
-rw-r--r--librpc/ABI/ndr-0.0.4.sigs252
-rw-r--r--librpc/ABI/ndr-0.0.5.sigs255
-rw-r--r--librpc/ABI/ndr-0.0.6.sigs256
-rw-r--r--librpc/ABI/ndr-0.0.7.sigs257
-rw-r--r--librpc/ABI/ndr-0.0.8.sigs258
-rw-r--r--librpc/ABI/ndr-0.0.9.sigs259
-rw-r--r--librpc/ABI/ndr-0.1.0.sigs259
-rw-r--r--librpc/ABI/ndr-0.1.1.sigs262
-rw-r--r--librpc/ABI/ndr-0.1.2.sigs263
-rw-r--r--librpc/ABI/ndr-0.2.0.sigs264
-rw-r--r--librpc/ABI/ndr-0.2.1.sigs265
-rw-r--r--librpc/ABI/ndr-1.0.0.sigs263
-rw-r--r--librpc/ABI/ndr-1.0.1.sigs264
-rw-r--r--librpc/ABI/ndr-1.0.2.sigs265
-rw-r--r--librpc/ABI/ndr-2.0.0.sigs269
-rw-r--r--librpc/ABI/ndr-3.0.0.sigs269
-rw-r--r--librpc/ABI/ndr-3.0.1.sigs272
-rw-r--r--librpc/ABI/ndr-3.0.2.sigs273
-rw-r--r--librpc/ABI/ndr-4.0.0.sigs277
-rw-r--r--librpc/binding-strings.txt4
-rw-r--r--librpc/gen_ndr/README4
-rw-r--r--librpc/idl/IDL_LICENSE.txt85
-rw-r--r--librpc/idl/ODJ.idl268
-rw-r--r--librpc/idl/atsvc.idl119
-rw-r--r--librpc/idl/audiosrv.idl23
-rw-r--r--librpc/idl/auth.idl170
-rw-r--r--librpc/idl/backupkey.idl153
-rw-r--r--librpc/idl/bkupblobs.idl54
-rw-r--r--librpc/idl/browser.idl86
-rw-r--r--librpc/idl/cab.idl130
-rw-r--r--librpc/idl/claims.idl149
-rw-r--r--librpc/idl/clusapi.idl2962
-rw-r--r--librpc/idl/conditional_ace.idl458
-rw-r--r--librpc/idl/dbgidl.idl9
-rw-r--r--librpc/idl/dcerpc.idl662
-rw-r--r--librpc/idl/dcom.idl314
-rw-r--r--librpc/idl/dfs.idl419
-rw-r--r--librpc/idl/dfsblobs.idl115
-rw-r--r--librpc/idl/dns.idl282
-rw-r--r--librpc/idl/dnsp.idl293
-rw-r--r--librpc/idl/dnsserver.idl1529
-rw-r--r--librpc/idl/drsblobs.idl680
-rw-r--r--librpc/idl/drsuapi.idl1915
-rw-r--r--librpc/idl/dsbackup.idl34
-rw-r--r--librpc/idl/dssetup.idl101
-rw-r--r--librpc/idl/echo.idl127
-rw-r--r--librpc/idl/efs.idl108
-rw-r--r--librpc/idl/epmapper.idl328
-rw-r--r--librpc/idl/eventlog.idl324
-rw-r--r--librpc/idl/eventlog6.idl343
-rw-r--r--librpc/idl/file_id.idl14
-rw-r--r--librpc/idl/frsapi.idl128
-rw-r--r--librpc/idl/frsrpc.idl458
-rw-r--r--librpc/idl/frstrans.idl295
-rw-r--r--librpc/idl/fscc.idl47
-rw-r--r--librpc/idl/fsrvp.idl107
-rw-r--r--librpc/idl/fsrvp_state.idl36
-rw-r--r--librpc/idl/gkdi.idl125
-rw-r--r--librpc/idl/gmsa.idl44
-rw-r--r--librpc/idl/idl_types.h70
-rw-r--r--librpc/idl/idmap.idl53
-rw-r--r--librpc/idl/initshutdown.idl91
-rw-r--r--librpc/idl/ioctl.idl242
-rw-r--r--librpc/idl/keysvc.idl16
-rw-r--r--librpc/idl/krb5ccache.idl115
-rw-r--r--librpc/idl/krb5pac.idl264
-rw-r--r--librpc/idl/lsa.idl1669
-rw-r--r--librpc/idl/mdssvc.idl68
-rw-r--r--librpc/idl/messaging.idl206
-rw-r--r--librpc/idl/mgmt.idl75
-rw-r--r--librpc/idl/misc.idl149
-rw-r--r--librpc/idl/msgsvc.idl22
-rw-r--r--librpc/idl/named_pipe_auth.idl58
-rw-r--r--librpc/idl/nbt.idl689
-rw-r--r--librpc/idl/negoex.idl152
-rw-r--r--librpc/idl/netlogon.idl1888
-rw-r--r--librpc/idl/nfs4acl.idl51
-rw-r--r--librpc/idl/notify.idl94
-rw-r--r--librpc/idl/ntlmssp.idl307
-rw-r--r--librpc/idl/ntprinting.idl156
-rw-r--r--librpc/idl/ntsvcs.idl399
-rw-r--r--librpc/idl/orpc.idl230
-rw-r--r--librpc/idl/oxidresolver.idl96
-rw-r--r--librpc/idl/policyagent.idl13
-rw-r--r--librpc/idl/preg.idl44
-rw-r--r--librpc/idl/printcap.idl18
-rw-r--r--librpc/idl/quota.idl54
-rw-r--r--librpc/idl/rap.idl1076
-rw-r--r--librpc/idl/remact.idl46
-rw-r--r--librpc/idl/rot.idl44
-rw-r--r--librpc/idl/samr.idl1665
-rw-r--r--librpc/idl/scerpc.idl18
-rw-r--r--librpc/idl/schannel.idl113
-rw-r--r--librpc/idl/security.cnf1
-rw-r--r--librpc/idl/security.idl972
-rw-r--r--librpc/idl/server_id.idl36
-rw-r--r--librpc/idl/smb2_lease_struct.idl34
-rw-r--r--librpc/idl/smb3posix.idl36
-rw-r--r--librpc/idl/smb_acl.idl96
-rw-r--r--librpc/idl/spoolss.idl3566
-rw-r--r--librpc/idl/srvsvc.idl1569
-rw-r--r--librpc/idl/svcctl.idl1040
-rw-r--r--librpc/idl/trkwks.idl17
-rw-r--r--librpc/idl/unixinfo.idl56
-rw-r--r--librpc/idl/w32time.idl21
-rw-r--r--librpc/idl/winbind.idl323
-rw-r--r--librpc/idl/windows_event_ids.idl52
-rw-r--r--librpc/idl/winreg.cnf52
-rw-r--r--librpc/idl/winreg.idl459
-rw-r--r--librpc/idl/winspool.idl878
-rw-r--r--librpc/idl/winstation.idl13
-rw-r--r--librpc/idl/witness.idl153
-rw-r--r--librpc/idl/wkssvc.idl796
-rw-r--r--librpc/idl/wscript_build164
-rw-r--r--librpc/idl/wsp.idl1345
-rw-r--r--librpc/idl/wsp_data.idl313
-rw-r--r--librpc/idl/wzcsvc.idl31
-rw-r--r--librpc/idl/xattr.idl239
-rw-r--r--librpc/ndr.pc.in11
-rw-r--r--librpc/ndr/libndr.h918
-rw-r--r--librpc/ndr/ndr.c2040
-rw-r--r--librpc/ndr/ndr_ODJ.c65
-rw-r--r--librpc/ndr/ndr_ODJ.h22
-rw-r--r--librpc/ndr/ndr_auth.c44
-rw-r--r--librpc/ndr/ndr_auth.h32
-rw-r--r--librpc/ndr/ndr_backupkey.c222
-rw-r--r--librpc/ndr/ndr_backupkey.h23
-rw-r--r--librpc/ndr/ndr_basic.c1596
-rw-r--r--librpc/ndr/ndr_bkupblobs.c82
-rw-r--r--librpc/ndr/ndr_cab.c442
-rw-r--r--librpc/ndr/ndr_cab.h22
-rw-r--r--librpc/ndr/ndr_claims.c90
-rw-r--r--librpc/ndr/ndr_claims.h34
-rw-r--r--librpc/ndr/ndr_compression.c1092
-rw-r--r--librpc/ndr/ndr_compression.h60
-rw-r--r--librpc/ndr/ndr_dcerpc.c316
-rw-r--r--librpc/ndr/ndr_dcerpc.h29
-rw-r--r--librpc/ndr/ndr_dns.c327
-rw-r--r--librpc/ndr/ndr_dns.h40
-rw-r--r--librpc/ndr/ndr_dns_utils.c134
-rw-r--r--librpc/ndr/ndr_dns_utils.h6
-rw-r--r--librpc/ndr/ndr_dnsp.c263
-rw-r--r--librpc/ndr/ndr_dnsp.h33
-rw-r--r--librpc/ndr/ndr_dnsserver.c100
-rw-r--r--librpc/ndr/ndr_dnsserver.h25
-rw-r--r--librpc/ndr/ndr_drsblobs.c220
-rw-r--r--librpc/ndr/ndr_drsblobs.h23
-rw-r--r--librpc/ndr/ndr_drsuapi.c577
-rw-r--r--librpc/ndr/ndr_drsuapi.h34
-rw-r--r--librpc/ndr/ndr_frsrpc.c92
-rw-r--r--librpc/ndr/ndr_frsrpc.h34
-rw-r--r--librpc/ndr/ndr_ioctl.c40
-rw-r--r--librpc/ndr/ndr_krb5pac.c130
-rw-r--r--librpc/ndr/ndr_krb5pac.h25
-rw-r--r--librpc/ndr/ndr_misc.c77
-rw-r--r--librpc/ndr/ndr_nbt.c406
-rw-r--r--librpc/ndr/ndr_nbt.h42
-rw-r--r--librpc/ndr/ndr_negoex.c521
-rw-r--r--librpc/ndr/ndr_negoex.h37
-rw-r--r--librpc/ndr/ndr_netlogon.c65
-rw-r--r--librpc/ndr/ndr_netlogon.h28
-rw-r--r--librpc/ndr/ndr_ntlmssp.c195
-rw-r--r--librpc/ndr/ndr_ntlmssp.h35
-rw-r--r--librpc/ndr/ndr_ntprinting.c87
-rw-r--r--librpc/ndr/ndr_ntprinting.h27
-rw-r--r--librpc/ndr/ndr_orpc.c163
-rw-r--r--librpc/ndr/ndr_preg.c69
-rw-r--r--librpc/ndr/ndr_preg.h23
-rw-r--r--librpc/ndr/ndr_private.h32
-rw-r--r--librpc/ndr/ndr_rap.c28
-rw-r--r--librpc/ndr/ndr_rap.h22
-rw-r--r--librpc/ndr/ndr_schannel.c107
-rw-r--r--librpc/ndr/ndr_schannel.h25
-rw-r--r--librpc/ndr/ndr_sec_helper.c457
-rw-r--r--librpc/ndr/ndr_spoolss_buf.c1615
-rw-r--r--librpc/ndr/ndr_spoolss_buf.h84
-rw-r--r--librpc/ndr/ndr_string.c1109
-rw-r--r--librpc/ndr/ndr_svcctl.c52
-rw-r--r--librpc/ndr/ndr_svcctl.h24
-rw-r--r--librpc/ndr/ndr_table.c182
-rw-r--r--librpc/ndr/ndr_table.h37
-rw-r--r--librpc/ndr/ndr_witness.c110
-rw-r--r--librpc/ndr/ndr_witness.h23
-rw-r--r--librpc/ndr/ndr_wmi.h24
-rw-r--r--librpc/ndr/ndr_xattr.c148
-rw-r--r--librpc/ndr/ndr_xattr.h37
-rw-r--r--librpc/ndr/util.c36
-rw-r--r--librpc/ndr/uuid.c258
-rw-r--r--librpc/ndr_krb5pac.pc.in11
-rw-r--r--librpc/ndr_nbt.pc.in11
-rw-r--r--librpc/ndr_standard.pc.in11
-rw-r--r--librpc/rpc/binding.c1502
-rw-r--r--librpc/rpc/binding_handle.c568
-rw-r--r--librpc/rpc/dcerpc_error.c153
-rw-r--r--librpc/rpc/dcerpc_helper.c132
-rw-r--r--librpc/rpc/dcerpc_helper.h26
-rw-r--r--librpc/rpc/dcerpc_pkt_auth.c500
-rw-r--r--librpc/rpc/dcerpc_pkt_auth.h59
-rw-r--r--librpc/rpc/dcerpc_samr.h42
-rw-r--r--librpc/rpc/dcerpc_util.c1140
-rw-r--r--librpc/rpc/dcerpc_util.h85
-rw-r--r--librpc/rpc/dcesrv_auth.c703
-rw-r--r--librpc/rpc/dcesrv_core.c3369
-rw-r--r--librpc/rpc/dcesrv_core.h715
-rw-r--r--librpc/rpc/dcesrv_handles.c372
-rw-r--r--librpc/rpc/dcesrv_mgmt.c169
-rw-r--r--librpc/rpc/dcesrv_reply.c309
-rw-r--r--librpc/rpc/rpc_common.h412
-rw-r--r--librpc/rpc/server/netlogon/schannel_util.c570
-rw-r--r--librpc/rpc/server/netlogon/schannel_util.h54
-rwxr-xr-xlibrpc/tables.pl87
-rw-r--r--librpc/tests/test_ndr.c142
-rw-r--r--librpc/tests/test_ndr_dns_nbt.c236
-rw-r--r--librpc/tests/test_ndr_gmsa.c166
-rw-r--r--librpc/tests/test_ndr_macros.c136
-rw-r--r--librpc/tests/test_ndr_string.c542
-rw-r--r--librpc/tools/ndrdump.1.xml89
-rw-r--r--librpc/tools/ndrdump.c795
-rw-r--r--librpc/tools/wscript_build7
-rw-r--r--librpc/wscript_build804
-rw-r--r--librpc/wsp/README50
-rw-r--r--librpc/wsp/allprops-from-ms-wsp-spec.csv423
-rw-r--r--librpc/wsp/extra-props.csv63
-rw-r--r--librpc/wsp/wsp_helper.c40
-rw-r--r--librpc/wsp/wsp_helper.h28
-rw-r--r--librpc/wsp/wsp_util.c919
-rw-r--r--librpc/wsp/wsp_util.h89
1626 files changed, 527013 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')
diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
new file mode 100644
index 0000000..84838be
--- /dev/null
+++ b/libcli/auth/credentials.c
@@ -0,0 +1,1222 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ code to manipulate domain credentials
+
+ Copyright (C) Andrew Tridgell 1997-2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 "system/time.h"
+#include "libcli/auth/libcli_auth.h"
+#include "../libcli/security/dom_sid.h"
+#include "lib/util/util_str_escape.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge)
+{
+ /*
+ * If none of the first 5 bytes of the client challenge is unique, the
+ * server MUST fail session-key negotiation without further processing
+ * of the following steps.
+ */
+
+ if (challenge->data[1] == challenge->data[0] &&
+ challenge->data[2] == challenge->data[0] &&
+ challenge->data[3] == challenge->data[0] &&
+ challenge->data[4] == challenge->data[0])
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void netlogon_creds_random_challenge(struct netr_Credential *challenge)
+{
+ ZERO_STRUCTP(challenge);
+ while (!netlogon_creds_is_random_challenge(challenge)) {
+ generate_random_buffer(challenge->data, sizeof(challenge->data));
+ }
+}
+
+static NTSTATUS netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *in,
+ struct netr_Credential *out)
+{
+ NTSTATUS status;
+ int rc;
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ memcpy(out->data, in->data, sizeof(out->data));
+
+ status = netlogon_creds_aes_encrypt(creds,
+ out->data,
+ sizeof(out->data));
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ rc = des_crypt112(out->data, in->data, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ initialise the credentials state for old-style 64 bit session keys
+
+ this call is made after the netr_ServerReqChallenge call
+*/
+static NTSTATUS netlogon_creds_init_64bit(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password)
+{
+ uint32_t sum[2];
+ uint8_t sum2[8];
+ int rc;
+
+ sum[0] = IVAL(client_challenge->data, 0) + IVAL(server_challenge->data, 0);
+ sum[1] = IVAL(client_challenge->data, 4) + IVAL(server_challenge->data, 4);
+
+ SIVAL(sum2,0,sum[0]);
+ SIVAL(sum2,4,sum[1]);
+
+ ZERO_ARRAY(creds->session_key);
+
+ rc = des_crypt128(creds->session_key, sum2, machine_password->hash);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ initialise the credentials state for ADS-style 128 bit session keys
+
+ this call is made after the netr_ServerReqChallenge call
+*/
+static NTSTATUS netlogon_creds_init_128bit(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password)
+{
+ uint8_t zero[4] = {0};
+ uint8_t tmp[gnutls_hash_get_len(GNUTLS_DIG_MD5)];
+ gnutls_hash_hd_t hash_hnd = NULL;
+ int rc;
+
+ ZERO_ARRAY(creds->session_key);
+
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ rc = gnutls_hash(hash_hnd, zero, sizeof(zero));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ rc = gnutls_hash(hash_hnd, client_challenge->data, 8);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ rc = gnutls_hash(hash_hnd, server_challenge->data, 8);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ gnutls_hash_deinit(hash_hnd, tmp);
+
+ /* This doesn't require HMAC MD5 RFC2104 as the hash is only 16 bytes */
+ rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
+ machine_password->hash,
+ sizeof(machine_password->hash),
+ tmp,
+ sizeof(tmp),
+ creds->session_key);
+ ZERO_ARRAY(tmp);
+
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ initialise the credentials state for AES/HMAC-SHA256-style 128 bit session keys
+
+ this call is made after the netr_ServerReqChallenge call
+*/
+static NTSTATUS netlogon_creds_init_hmac_sha256(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password)
+{
+ gnutls_hmac_hd_t hmac_hnd = NULL;
+ uint8_t digest[gnutls_hmac_get_len(GNUTLS_MAC_SHA256)];
+ int rc;
+
+ ZERO_ARRAY(creds->session_key);
+
+ rc = gnutls_hmac_init(&hmac_hnd,
+ GNUTLS_MAC_SHA256,
+ machine_password->hash,
+ sizeof(machine_password->hash));
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ rc = gnutls_hmac(hmac_hnd,
+ client_challenge->data,
+ 8);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ rc = gnutls_hmac(hmac_hnd,
+ server_challenge->data,
+ 8);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ gnutls_hmac_deinit(hmac_hnd, digest);
+
+ memcpy(creds->session_key, digest, sizeof(creds->session_key));
+
+ ZERO_ARRAY(digest);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS netlogon_creds_first_step(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge)
+{
+ NTSTATUS status;
+
+ status = netlogon_creds_step_crypt(creds,
+ client_challenge,
+ &creds->client);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = netlogon_creds_step_crypt(creds,
+ server_challenge,
+ &creds->server);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ creds->seed = creds->client;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ step the credentials to the next element in the chain, updating the
+ current client and server credentials and the seed
+*/
+static NTSTATUS netlogon_creds_step(struct netlogon_creds_CredentialState *creds)
+{
+ struct netr_Credential time_cred;
+ NTSTATUS status;
+
+ DEBUG(5,("\tseed %08x:%08x\n",
+ IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4)));
+
+ SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence);
+ SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
+
+ DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
+
+ status = netlogon_creds_step_crypt(creds,
+ &time_cred,
+ &creds->client);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(5,("\tCLIENT %08x:%08x\n",
+ IVAL(creds->client.data, 0), IVAL(creds->client.data, 4)));
+
+ SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1);
+ SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4));
+
+ DEBUG(5,("\tseed+time+1 %08x:%08x\n",
+ IVAL(time_cred.data, 0), IVAL(time_cred.data, 4)));
+
+ status = netlogon_creds_step_crypt(creds, &time_cred, &creds->server);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DEBUG(5,("\tSERVER %08x:%08x\n",
+ IVAL(creds->server.data, 0), IVAL(creds->server.data, 4)));
+
+ creds->seed = time_cred;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ DES encrypt a 8 byte LMSessionKey buffer using the Netlogon session key
+*/
+NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds,
+ struct netr_LMSessionKey *key)
+{
+ int rc;
+ struct netr_LMSessionKey tmp;
+
+ rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ *key = tmp;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ DES decrypt a 8 byte LMSessionKey buffer using the Netlogon session key
+*/
+NTSTATUS netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds,
+ struct netr_LMSessionKey *key)
+{
+ int rc;
+ struct netr_LMSessionKey tmp;
+
+ rc = des_crypt56_gnutls(tmp.key, key->key, creds->session_key, SAMBA_GNUTLS_DECRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ *key = tmp;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ DES encrypt a 16 byte password buffer using the session key
+*/
+NTSTATUS netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds,
+ struct samr_Password *pass)
+{
+ struct samr_Password tmp;
+ int rc;
+
+ rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ *pass = tmp;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ DES decrypt a 16 byte password buffer using the session key
+*/
+NTSTATUS netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds,
+ struct samr_Password *pass)
+{
+ struct samr_Password tmp;
+ int rc;
+
+ rc = des_crypt112_16(tmp.hash, pass->hash, creds->session_key, SAMBA_GNUTLS_DECRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ *pass = tmp;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ ARCFOUR encrypt/decrypt a password buffer using the session key
+*/
+NTSTATUS netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len)
+{
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t session_key = {
+ .data = creds->session_key,
+ .size = sizeof(creds->session_key),
+ };
+ int rc;
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_ARCFOUR_128,
+ &session_key,
+ NULL);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+ rc = gnutls_cipher_encrypt(cipher_hnd,
+ data,
+ len);
+ gnutls_cipher_deinit(cipher_hnd);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ AES encrypt a password buffer using the session key
+*/
+NTSTATUS netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len)
+{
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t key = {
+ .data = creds->session_key,
+ .size = sizeof(creds->session_key),
+ };
+ uint32_t iv_size =
+ gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
+ uint8_t _iv[iv_size];
+ gnutls_datum_t iv = {
+ .data = _iv,
+ .size = iv_size,
+ };
+ int rc;
+
+ ZERO_ARRAY(_iv);
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_AES_128_CFB8,
+ &key,
+ &iv);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ rc = gnutls_cipher_encrypt(cipher_hnd, data, len);
+ gnutls_cipher_deinit(cipher_hnd);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ AES decrypt a password buffer using the session key
+*/
+NTSTATUS netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds, uint8_t *data, size_t len)
+{
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ gnutls_datum_t key = {
+ .data = creds->session_key,
+ .size = sizeof(creds->session_key),
+ };
+ uint32_t iv_size =
+ gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
+ uint8_t _iv[iv_size];
+ gnutls_datum_t iv = {
+ .data = _iv,
+ .size = iv_size,
+ };
+ int rc;
+
+ ZERO_ARRAY(_iv);
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_AES_128_CFB8,
+ &key,
+ &iv);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ rc = gnutls_cipher_decrypt(cipher_hnd, data, len);
+ gnutls_cipher_deinit(cipher_hnd);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_CRYPTO_SYSTEM_INVALID);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the client specific functions
+******************************************************************/
+
+/*
+ initialise the credentials chain and return the first client
+ credentials
+*/
+
+struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
+ const char *client_account,
+ const char *client_computer_name,
+ uint16_t secure_channel_type,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password,
+ struct netr_Credential *initial_credential,
+ uint32_t negotiate_flags)
+{
+ struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+ NTSTATUS status;
+
+ if (!creds) {
+ return NULL;
+ }
+
+ creds->sequence = time(NULL);
+ creds->negotiate_flags = negotiate_flags;
+ creds->secure_channel_type = secure_channel_type;
+
+ creds->computer_name = talloc_strdup(creds, client_computer_name);
+ if (!creds->computer_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+ creds->account_name = talloc_strdup(creds, client_account);
+ if (!creds->account_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
+ dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
+ dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
+
+ if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ status = netlogon_creds_init_hmac_sha256(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
+ status = netlogon_creds_init_128bit(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ } else {
+ status = netlogon_creds_init_64bit(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ }
+
+ status = netlogon_creds_first_step(creds,
+ client_challenge,
+ server_challenge);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ dump_data_pw("Session key", creds->session_key, 16);
+ dump_data_pw("Credential ", creds->client.data, 8);
+
+ *initial_credential = creds->client;
+ return creds;
+}
+
+/*
+ initialise the credentials structure with only a session key. The caller better know what they are doing!
+ */
+
+struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
+ const uint8_t session_key[16])
+{
+ struct netlogon_creds_CredentialState *creds;
+
+ creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+ if (!creds) {
+ return NULL;
+ }
+
+ memcpy(creds->session_key, session_key, 16);
+
+ return creds;
+}
+
+/*
+ step the credentials to the next element in the chain, updating the
+ current client and server credentials and the seed
+
+ produce the next authenticator in the sequence ready to send to
+ the server
+*/
+NTSTATUS
+netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
+ struct netr_Authenticator *next)
+{
+ uint32_t t32n = (uint32_t)time(NULL);
+ NTSTATUS status;
+
+ /*
+ * we always increment and ignore an overflow here
+ */
+ creds->sequence += 2;
+
+ if (t32n > creds->sequence) {
+ /*
+ * we may increment more
+ */
+ creds->sequence = t32n;
+ } else {
+ uint32_t d = creds->sequence - t32n;
+
+ if (d >= INT32_MAX) {
+ /*
+ * got an overflow of time_t vs. uint32_t
+ */
+ creds->sequence = t32n;
+ }
+ }
+
+ status = netlogon_creds_step(creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ next->cred = creds->client;
+ next->timestamp = creds->sequence;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ check that a credentials reply from a server is correct
+*/
+bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *received_credentials)
+{
+ if (!received_credentials ||
+ !mem_equal_const_time(received_credentials->data, creds->server.data, 8)) {
+ DEBUG(2,("credentials check failed\n"));
+ return false;
+ }
+ return true;
+}
+
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the server specific functions
+******************************************************************/
+
+/*
+ check that a credentials reply from a server is correct
+*/
+static bool netlogon_creds_server_check_internal(const struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *received_credentials)
+{
+ if (!mem_equal_const_time(received_credentials->data, creds->client.data, 8)) {
+ DEBUG(2,("credentials check failed\n"));
+ dump_data_pw("client creds", creds->client.data, 8);
+ dump_data_pw("calc creds", received_credentials->data, 8);
+ return false;
+ }
+ return true;
+}
+
+/*
+ initialise the credentials chain and return the first server
+ credentials
+*/
+struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
+ const char *client_account,
+ const char *client_computer_name,
+ uint16_t secure_channel_type,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password,
+ const struct netr_Credential *credentials_in,
+ struct netr_Credential *credentials_out,
+ uint32_t negotiate_flags)
+{
+
+ struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+ NTSTATUS status;
+ bool ok;
+
+ if (!creds) {
+ return NULL;
+ }
+
+ creds->negotiate_flags = negotiate_flags;
+ creds->secure_channel_type = secure_channel_type;
+
+ dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
+ dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
+ dump_data_pw("Machine Pass", machine_password->hash, sizeof(machine_password->hash));
+
+ ok = netlogon_creds_is_random_challenge(client_challenge);
+ if (!ok) {
+ DBG_WARNING("CVE-2020-1472(ZeroLogon): "
+ "non-random client challenge rejected for "
+ "client_account[%s] client_computer_name[%s]\n",
+ log_escape(mem_ctx, client_account),
+ log_escape(mem_ctx, client_computer_name));
+ dump_data(DBGLVL_WARNING,
+ client_challenge->data,
+ sizeof(client_challenge->data));
+ talloc_free(creds);
+ return NULL;
+ }
+
+ creds->computer_name = talloc_strdup(creds, client_computer_name);
+ if (!creds->computer_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+ creds->account_name = talloc_strdup(creds, client_account);
+ if (!creds->account_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ status = netlogon_creds_init_hmac_sha256(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ } else if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
+ status = netlogon_creds_init_128bit(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ } else {
+ status = netlogon_creds_init_64bit(creds,
+ client_challenge,
+ server_challenge,
+ machine_password);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+ }
+
+ status = netlogon_creds_first_step(creds,
+ client_challenge,
+ server_challenge);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ dump_data_pw("Session key", creds->session_key, 16);
+ dump_data_pw("Client Credential ", creds->client.data, 8);
+ dump_data_pw("Server Credential ", creds->server.data, 8);
+
+ dump_data_pw("Credentials in", credentials_in->data, sizeof(credentials_in->data));
+
+ /* And before we leak information about the machine account
+ * password, check that they got the first go right */
+ if (!netlogon_creds_server_check_internal(creds, credentials_in)) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ *credentials_out = creds->server;
+
+ dump_data_pw("Credentials out", credentials_out->data, sizeof(credentials_out->data));
+
+ return creds;
+}
+
+NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator)
+{
+ NTSTATUS status;
+
+ if (!received_authenticator || !return_authenticator) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!creds) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ creds->sequence = received_authenticator->timestamp;
+ status = netlogon_creds_step(creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ ZERO_STRUCTP(return_authenticator);
+ return status;
+ }
+
+ if (netlogon_creds_server_check_internal(creds, &received_authenticator->cred)) {
+ return_authenticator->cred = creds->server;
+ return_authenticator->timestamp = 0;
+ return NT_STATUS_OK;
+ } else {
+ ZERO_STRUCTP(return_authenticator);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+}
+
+static NTSTATUS netlogon_creds_crypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation,
+ bool do_encrypt)
+{
+ struct netr_SamBaseInfo *base = NULL;
+ NTSTATUS status;
+
+ if (validation == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (validation_level) {
+ case 2:
+ if (validation->sam2) {
+ base = &validation->sam2->base;
+ }
+ break;
+ case 3:
+ if (validation->sam3) {
+ base = &validation->sam3->base;
+ }
+ break;
+ case 6:
+ if (validation->sam6) {
+ base = &validation->sam6->base;
+ }
+ break;
+ default:
+ /* If we can't find it, we can't very well decrypt it */
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ if (!base) {
+ return NT_STATUS_INVALID_INFO_CLASS;
+ }
+
+ /* find and decrypt the session keys, return in parameters above */
+ if (validation_level == 6) {
+ /* they aren't encrypted! */
+ } else if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
+ if (!all_zero(base->key.key, sizeof(base->key.key))) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(
+ creds,
+ base->key.key,
+ sizeof(base->key.key));
+ } else {
+ status = netlogon_creds_aes_decrypt(
+ creds,
+ base->key.key,
+ sizeof(base->key.key));
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (!all_zero(base->LMSessKey.key,
+ sizeof(base->LMSessKey.key))) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(
+ creds,
+ base->LMSessKey.key,
+ sizeof(base->LMSessKey.key));
+ } else {
+ status = netlogon_creds_aes_decrypt(
+ creds,
+ base->LMSessKey.key,
+ sizeof(base->LMSessKey.key));
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
+ if (!all_zero(base->key.key, sizeof(base->key.key))) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ base->key.key,
+ sizeof(base->key.key));
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (!all_zero(base->LMSessKey.key,
+ sizeof(base->LMSessKey.key))) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ base->LMSessKey.key,
+ sizeof(base->LMSessKey.key));
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ } else {
+ /* Don't crypt an all-zero key, it would give away the NETLOGON pipe session key */
+ if (!all_zero(base->LMSessKey.key,
+ sizeof(base->LMSessKey.key))) {
+ if (do_encrypt) {
+ status = netlogon_creds_des_encrypt_LMKey(creds,
+ &base->LMSessKey);
+ } else {
+ status = netlogon_creds_des_decrypt_LMKey(creds,
+ &base->LMSessKey);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation)
+{
+ return netlogon_creds_crypt_samlogon_validation(creds,
+ validation_level,
+ validation,
+ false);
+}
+
+NTSTATUS netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation)
+{
+ return netlogon_creds_crypt_samlogon_validation(creds,
+ validation_level,
+ validation,
+ true);
+}
+
+static NTSTATUS netlogon_creds_crypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon,
+ bool do_encrypt)
+{
+ NTSTATUS status;
+
+ if (logon == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (level) {
+ case NetlogonInteractiveInformation:
+ case NetlogonInteractiveTransitiveInformation:
+ case NetlogonServiceInformation:
+ case NetlogonServiceTransitiveInformation:
+ if (logon->password == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ uint8_t *h;
+
+ h = logon->password->lmpassword.hash;
+ if (!all_zero(h, 16)) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(
+ creds,
+ h,
+ 16);
+ } else {
+ status = netlogon_creds_aes_decrypt(
+ creds,
+ h,
+ 16);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ h = logon->password->ntpassword.hash;
+ if (!all_zero(h, 16)) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(creds,
+ h,
+ 16);
+ } else {
+ status = netlogon_creds_aes_decrypt(creds,
+ h,
+ 16);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ uint8_t *h;
+
+ h = logon->password->lmpassword.hash;
+ if (!all_zero(h, 16)) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ h,
+ 16);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ h = logon->password->ntpassword.hash;
+ if (!all_zero(h, 16)) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ h,
+ 16);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ } else {
+ struct samr_Password *p;
+
+ p = &logon->password->lmpassword;
+ if (!all_zero(p->hash, 16)) {
+ if (do_encrypt) {
+ status = netlogon_creds_des_encrypt(creds, p);
+ } else {
+ status = netlogon_creds_des_decrypt(creds, p);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ p = &logon->password->ntpassword;
+ if (!all_zero(p->hash, 16)) {
+ if (do_encrypt) {
+ status = netlogon_creds_des_encrypt(creds, p);
+ } else {
+ status = netlogon_creds_des_decrypt(creds, p);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ }
+ break;
+
+ case NetlogonNetworkInformation:
+ case NetlogonNetworkTransitiveInformation:
+ break;
+
+ case NetlogonGenericInformation:
+ if (logon->generic == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ if (do_encrypt) {
+ status = netlogon_creds_aes_encrypt(
+ creds,
+ logon->generic->data,
+ logon->generic->length);
+ } else {
+ status = netlogon_creds_aes_decrypt(
+ creds,
+ logon->generic->data,
+ logon->generic->length);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+ status = netlogon_creds_arcfour_crypt(creds,
+ logon->generic->data,
+ logon->generic->length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ /* Using DES to verify kerberos tickets makes no sense */
+ }
+ break;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon)
+{
+ return netlogon_creds_crypt_samlogon_logon(creds, level, logon, false);
+}
+
+NTSTATUS netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon)
+{
+ return netlogon_creds_crypt_samlogon_logon(creds, level, logon, true);
+}
+
+union netr_LogonLevel *netlogon_creds_shallow_copy_logon(TALLOC_CTX *mem_ctx,
+ enum netr_LogonInfoClass level,
+ const union netr_LogonLevel *in)
+{
+ union netr_LogonLevel *out;
+
+ if (in == NULL) {
+ return NULL;
+ }
+
+ out = talloc(mem_ctx, union netr_LogonLevel);
+ if (out == NULL) {
+ return NULL;
+ }
+
+ *out = *in;
+
+ switch (level) {
+ case NetlogonInteractiveInformation:
+ case NetlogonInteractiveTransitiveInformation:
+ case NetlogonServiceInformation:
+ case NetlogonServiceTransitiveInformation:
+ if (in->password == NULL) {
+ return out;
+ }
+
+ out->password = talloc(out, struct netr_PasswordInfo);
+ if (out->password == NULL) {
+ talloc_free(out);
+ return NULL;
+ }
+ *out->password = *in->password;
+
+ return out;
+
+ case NetlogonNetworkInformation:
+ case NetlogonNetworkTransitiveInformation:
+ break;
+
+ case NetlogonGenericInformation:
+ if (in->generic == NULL) {
+ return out;
+ }
+
+ out->generic = talloc(out, struct netr_GenericInfo);
+ if (out->generic == NULL) {
+ talloc_free(out);
+ return NULL;
+ }
+ *out->generic = *in->generic;
+
+ if (in->generic->data == NULL) {
+ return out;
+ }
+
+ if (in->generic->length == 0) {
+ return out;
+ }
+
+ out->generic->data = talloc_memdup(out->generic,
+ in->generic->data,
+ in->generic->length);
+ if (out->generic->data == NULL) {
+ talloc_free(out);
+ return NULL;
+ }
+
+ return out;
+ }
+
+ return out;
+}
+
+/*
+ copy a netlogon_creds_CredentialState struct
+*/
+
+struct netlogon_creds_CredentialState *netlogon_creds_copy(
+ TALLOC_CTX *mem_ctx,
+ const struct netlogon_creds_CredentialState *creds_in)
+{
+ struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+
+ if (!creds) {
+ return NULL;
+ }
+
+ creds->sequence = creds_in->sequence;
+ creds->negotiate_flags = creds_in->negotiate_flags;
+ creds->secure_channel_type = creds_in->secure_channel_type;
+
+ creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
+ if (!creds->computer_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+ creds->account_name = talloc_strdup(creds, creds_in->account_name);
+ if (!creds->account_name) {
+ talloc_free(creds);
+ return NULL;
+ }
+
+ if (creds_in->sid) {
+ creds->sid = dom_sid_dup(creds, creds_in->sid);
+ if (!creds->sid) {
+ talloc_free(creds);
+ return NULL;
+ }
+ }
+
+ memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
+ memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
+ memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
+ memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
+
+ return creds;
+}
diff --git a/libcli/auth/credentials.h b/libcli/auth/credentials.h
new file mode 100644
index 0000000..7b8fac6
--- /dev/null
+++ b/libcli/auth/credentials.h
@@ -0,0 +1,70 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ code to manipulate domain credentials
+
+ 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 "librpc/gen_ndr/netlogon.h"
+
+/* The 7 here seems to be required to get Win2k not to downgrade us
+ to NT4. Actually, anything other than 1ff would seem to do... */
+#define NETLOGON_NEG_AUTH2_FLAGS 0x000701ff
+/*
+ (NETLOGON_NEG_ACCOUNT_LOCKOUT |
+ NETLOGON_NEG_PERSISTENT_SAMREPL |
+ NETLOGON_NEG_ARCFOUR |
+ NETLOGON_NEG_PROMOTION_COUNT |
+ NETLOGON_NEG_CHANGELOG_BDC |
+ NETLOGON_NEG_FULL_SYNC_REPL |
+ NETLOGON_NEG_MULTIPLE_SIDS |
+ NETLOGON_NEG_REDO |
+ NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL |
+ NETLOGON_NEG_DNS_DOMAIN_TRUSTS |
+ NETLOGON_NEG_PASSWORD_SET2 |
+ NETLOGON_NEG_GETDOMAININFO)
+*/
+#define NETLOGON_NEG_DOMAIN_TRUST_ACCOUNT 0x2010b000
+
+/* these are the flags that ADS clients use */
+/*
+ (NETLOGON_NEG_ACCOUNT_LOCKOUT |
+ NETLOGON_NEG_PERSISTENT_SAMREPL |
+ NETLOGON_NEG_ARCFOUR |
+ NETLOGON_NEG_PROMOTION_COUNT |
+ NETLOGON_NEG_CHANGELOG_BDC |
+ NETLOGON_NEG_FULL_SYNC_REPL |
+ NETLOGON_NEG_MULTIPLE_SIDS |
+ NETLOGON_NEG_REDO |
+ NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL |
+ NETLOGON_NEG_SEND_PASSWORD_INFO_PDC |
+ NETLOGON_NEG_GENERIC_PASSTHROUGH |
+ NETLOGON_NEG_CONCURRENT_RPC |
+ NETLOGON_NEG_AVOID_ACCOUNT_DB_REPL |
+ NETLOGON_NEG_AVOID_SECURITYAUTH_DB_REPL |
+ NETLOGON_NEG_128BIT |
+ NETLOGON_NEG_TRANSITIVE_TRUSTS |
+ NETLOGON_NEG_DNS_DOMAIN_TRUSTS |
+ NETLOGON_NEG_PASSWORD_SET2 |
+ NETLOGON_NEG_GETDOMAININFO |
+ NETLOGON_NEG_CROSS_FOREST_TRUSTS |
+ NETLOGON_NEG_AUTHENTICATED_RPC_LSASS |
+ NETLOGON_NEG_SCHANNEL)
+*/
+
+#define NETLOGON_NEG_AUTH2_ADS_FLAGS (0x200fbffb | NETLOGON_NEG_ARCFOUR | NETLOGON_NEG_128BIT | NETLOGON_NEG_SCHANNEL)
+
diff --git a/libcli/auth/libcli_auth.h b/libcli/auth/libcli_auth.h
new file mode 100644
index 0000000..c5c7a7b
--- /dev/null
+++ b/libcli/auth/libcli_auth.h
@@ -0,0 +1,28 @@
+/*
+ samba -- 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/>.
+*/
+#ifndef __LIBCLI_AUTH_H__
+#define __LIBCLI_AUTH_H__
+
+#include "librpc/gen_ndr/netlogon.h"
+#include "librpc/gen_ndr/wkssvc.h"
+#include "librpc/gen_ndr/schannel.h"
+#include "libcli/auth/credentials.h"
+#include "libcli/auth/ntlm_check.h"
+#include "libcli/auth/proto.h"
+#include "libcli/auth/msrpc_parse.h"
+
+#endif /* __LIBCLI_AUTH_H__ */
diff --git a/libcli/auth/msrpc_parse.c b/libcli/auth/msrpc_parse.c
new file mode 100644
index 0000000..8326261
--- /dev/null
+++ b/libcli/auth/msrpc_parse.c
@@ -0,0 +1,409 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+ Copyright (C) Andrew Bartlett 2002-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 "libcli/auth/msrpc_parse.h"
+
+/*
+ this is a tiny msrpc packet generator. I am only using this to
+ avoid tying this code to a particular variant of our rpc code. This
+ generator is not general enough for all our rpc needs, its just
+ enough for the spnego/ntlmssp code
+
+ format specifiers are:
+
+ U = unicode string (input is unix string)
+ a = address (input is char *unix_string)
+ (1 byte type, 1 byte length, unicode/ASCII string, all inline)
+ A = ASCII string (input is unix string)
+ B = data blob (pointer + length)
+ b = data blob in header (pointer + length)
+ D
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+NTSTATUS msrpc_gen(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i, j;
+ bool ret;
+ va_list ap;
+ char *s;
+ uint8_t *b;
+ int head_size=0, data_size=0;
+ int head_ofs, data_ofs;
+ int *intargs;
+ size_t n;
+
+ DATA_BLOB *pointers;
+
+ pointers = talloc_array(mem_ctx, DATA_BLOB, strlen(format));
+ if (!pointers) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ intargs = talloc_array(pointers, int, strlen(format));
+ if (!intargs) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* first scan the format to work out the header and body size */
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ ret = push_ucs2_talloc(
+ pointers,
+ (smb_ucs2_t **)(void *)&pointers[i].data,
+ s, &n);
+ if (!ret) {
+ va_end(ap);
+ return map_nt_error_from_unix_common(errno);
+ }
+ pointers[i].length = n;
+ pointers[i].length -= 2;
+ data_size += pointers[i].length;
+ break;
+ case 'A':
+ s = va_arg(ap, char *);
+ head_size += 8;
+ ret = push_ascii_talloc(
+ pointers, (char **)(void *)&pointers[i].data,
+ s, &n);
+ if (!ret) {
+ va_end(ap);
+ return map_nt_error_from_unix_common(errno);
+ }
+ pointers[i].length = n;
+ pointers[i].length -= 1;
+ data_size += pointers[i].length;
+ break;
+ case 'a':
+ j = va_arg(ap, int);
+ intargs[i] = j;
+ s = va_arg(ap, char *);
+ ret = push_ucs2_talloc(
+ pointers,
+ (smb_ucs2_t **)(void *)&pointers[i].data,
+ s, &n);
+ if (!ret) {
+ va_end(ap);
+ return map_nt_error_from_unix_common(errno);
+ }
+ pointers[i].length = n;
+ pointers[i].length -= 2;
+ data_size += pointers[i].length + 4;
+ break;
+ case 'B':
+ b = va_arg(ap, uint8_t *);
+ head_size += 8;
+ pointers[i].data = b;
+ pointers[i].length = va_arg(ap, int);
+ data_size += pointers[i].length;
+ break;
+ case 'b':
+ b = va_arg(ap, uint8_t *);
+ pointers[i].data = b;
+ pointers[i].length = va_arg(ap, int);
+ head_size += pointers[i].length;
+ break;
+ case 'd':
+ j = va_arg(ap, int);
+ intargs[i] = j;
+ head_size += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+ pointers[i].data = (uint8_t *)s;
+ pointers[i].length = strlen(s)+1;
+ head_size += pointers[i].length;
+ break;
+ default:
+ va_end(ap);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ va_end(ap);
+
+ if (head_size + data_size == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* allocate the space, then scan the format again to fill in the values */
+ *blob = data_blob_talloc(mem_ctx, NULL, head_size + data_size);
+ if (!blob->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ head_ofs = 0;
+ data_ofs = head_size;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ case 'A':
+ case 'B':
+ n = pointers[i].length;
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+ SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+ if (pointers[i].data && n) /* don't follow null pointers... */
+ memcpy(blob->data+data_ofs, pointers[i].data, n);
+ data_ofs += n;
+ break;
+ case 'a':
+ j = intargs[i];
+ SSVAL(blob->data, data_ofs, j); data_ofs += 2;
+
+ n = pointers[i].length;
+ SSVAL(blob->data, data_ofs, n); data_ofs += 2;
+ memcpy(blob->data+data_ofs, pointers[i].data, n);
+ data_ofs += n;
+ break;
+ case 'd':
+ j = intargs[i];
+ SIVAL(blob->data, head_ofs, j);
+ head_ofs += 4;
+ break;
+ case 'b':
+ n = pointers[i].length;
+ if (pointers[i].data && n) {
+ /* don't follow null pointers... */
+ memcpy(blob->data + head_ofs, pointers[i].data, n);
+ }
+ head_ofs += n;
+ break;
+ case 'C':
+ n = pointers[i].length;
+ memcpy(blob->data + head_ofs, pointers[i].data, n);
+ head_ofs += n;
+ break;
+ default:
+ va_end(ap);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ va_end(ap);
+
+ talloc_free(pointers);
+
+ return NT_STATUS_OK;
+}
+
+
+/* a helpful macro to avoid running over the end of our blob */
+#define NEED_DATA(amount) \
+if ((head_ofs + amount) > blob->length) { \
+ va_end(ap); \
+ return false; \
+}
+
+/**
+ this is a tiny msrpc packet parser. This the the partner of msrpc_gen
+
+ format specifiers are:
+
+ U = unicode string (output is unix string)
+ A = ascii string
+ B = data blob
+ b = data blob in header
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+
+bool msrpc_parse(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ const char *format, ...)
+{
+ int i;
+ va_list ap;
+ char **ps, *s;
+ DATA_BLOB *b;
+ size_t head_ofs = 0;
+ uint16_t len1, len2;
+ uint32_t ptr;
+ uint32_t *v;
+ bool ret = true;
+
+ va_start(ap, format);
+ for (i=0; format[i]; i++) {
+ switch (format[i]) {
+ case 'U':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ ps = va_arg(ap, char **);
+ if (len1 == 0 && len2 == 0) {
+ *ps = talloc_strdup(mem_ctx, "");
+ if (*ps == NULL) {
+ ret = false;
+ goto cleanup;
+ }
+ } else {
+ /* make sure its in the right format - be strict */
+ if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
+ ret = false;
+ goto cleanup;
+ }
+ if (len1 & 1) {
+ /* if odd length and unicode */
+ ret = false;
+ goto cleanup;
+ }
+ if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
+ blob->data + ptr < blob->data) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (0 < len1) {
+ size_t pull_len;
+ if (!convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
+ blob->data + ptr, len1,
+ ps, &pull_len)) {
+ ret = false;
+ goto cleanup;
+ }
+ } else {
+ *ps = talloc_strdup(mem_ctx, "");
+ if (*ps == NULL) {
+ ret = false;
+ goto cleanup;
+ }
+ }
+ }
+ break;
+ case 'A':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ ps = (char **)va_arg(ap, char **);
+ /* make sure its in the right format - be strict */
+ if (len1 == 0 && len2 == 0) {
+ *ps = talloc_strdup(mem_ctx, "");
+ if (*ps == NULL) {
+ ret = false;
+ goto cleanup;
+ }
+ } else {
+ if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
+ blob->data + ptr < blob->data) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (0 < len1) {
+ size_t pull_len;
+
+ if (!convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX,
+ blob->data + ptr, len1,
+ ps, &pull_len)) {
+ ret = false;
+ goto cleanup;
+ }
+ } else {
+ *ps = talloc_strdup(mem_ctx, "");
+ if (*ps == NULL) {
+ ret = false;
+ goto cleanup;
+ }
+ }
+ }
+ break;
+ case 'B':
+ NEED_DATA(8);
+ len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
+ ptr = IVAL(blob->data, head_ofs); head_ofs += 4;
+
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ if (len1 == 0 && len2 == 0) {
+ *b = data_blob_talloc(mem_ctx, NULL, 0);
+ } else {
+ /* make sure its in the right format - be strict */
+ if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (blob->data + ptr < (uint8_t *)(uintptr_t)ptr ||
+ blob->data + ptr < blob->data) {
+ ret = false;
+ goto cleanup;
+ }
+
+ *b = data_blob_talloc(mem_ctx, blob->data + ptr, len1);
+ }
+ break;
+ case 'b':
+ b = (DATA_BLOB *)va_arg(ap, void *);
+ len1 = va_arg(ap, unsigned int);
+ /* make sure its in the right format - be strict */
+ NEED_DATA(len1);
+ if (blob->data + head_ofs < (uint8_t *)head_ofs ||
+ blob->data + head_ofs < blob->data) {
+ ret = false;
+ goto cleanup;
+ }
+
+ *b = data_blob_talloc(mem_ctx, blob->data + head_ofs, len1);
+ head_ofs += len1;
+ break;
+ case 'd':
+ v = va_arg(ap, uint32_t *);
+ NEED_DATA(4);
+ *v = IVAL(blob->data, head_ofs); head_ofs += 4;
+ break;
+ case 'C':
+ s = va_arg(ap, char *);
+
+ if (blob->data + head_ofs < (uint8_t *)head_ofs ||
+ blob->data + head_ofs < blob->data ||
+ (head_ofs + (strlen(s) + 1)) > blob->length) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (memcmp(blob->data + head_ofs, s, strlen(s)+1) != 0) {
+ ret = false;
+ goto cleanup;
+ }
+ head_ofs += (strlen(s) + 1);
+
+ break;
+ }
+ }
+
+cleanup:
+ va_end(ap);
+ return ret;
+}
diff --git a/libcli/auth/msrpc_parse.h b/libcli/auth/msrpc_parse.h
new file mode 100644
index 0000000..717dec9
--- /dev/null
+++ b/libcli/auth/msrpc_parse.h
@@ -0,0 +1,58 @@
+/*
+ Unix SMB/CIFS implementation.
+ simple kerberos5/SPNEGO routines
+ Copyright (C) Andrew Tridgell 2001
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
+ Copyright (C) Andrew Bartlett 2002-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 _LIBCLI_AUTH_MSRPC_PARSE_H__
+#define _LIBCLI_AUTH_MSRPC_PARSE_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+
+/* The following definitions come from libcli/auth/msrpc_parse.c */
+
+NTSTATUS msrpc_gen(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ const char *format, ...);
+
+/**
+ this is a tiny msrpc packet parser. This the the partner of msrpc_gen
+
+ format specifiers are:
+
+ U = unicode string (output is unix string)
+ A = ascii string
+ B = data blob
+ b = data blob in header
+ d = word (4 bytes)
+ C = constant ascii string
+ */
+bool msrpc_parse(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ const char *format, ...);
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif
+
diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
new file mode 100644
index 0000000..118c81f
--- /dev/null
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -0,0 +1,4256 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ module to store/fetch session keys for the schannel client
+
+ Copyright (C) Stefan Metzmacher 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/dbwrap/dbwrap.h"
+#include "lib/dbwrap/dbwrap_rbt.h"
+#include "lib/util/util_tdb.h"
+#include "libcli/security/security.h"
+#include "../lib/param/param.h"
+#include "../libcli/auth/schannel.h"
+#include "../librpc/gen_ndr/ndr_schannel.h"
+#include "../librpc/gen_ndr/ndr_netlogon_c.h"
+#include "../librpc/gen_ndr/ndr_netlogon.h"
+#include "../librpc/gen_ndr/server_id.h"
+#include "netlogon_creds_cli.h"
+#include "source3/include/messages.h"
+#include "source3/include/g_lock.h"
+#include "libds/common/roles.h"
+#include "lib/crypto/md4.h"
+#include "auth/credentials/credentials.h"
+#include "lib/param/loadparm.h"
+
+struct netlogon_creds_cli_locked_state;
+
+struct netlogon_creds_cli_context {
+ struct {
+ const char *computer;
+ const char *account;
+ uint32_t proposed_flags;
+ uint32_t required_flags;
+ enum netr_SchannelType type;
+ enum dcerpc_AuthLevel auth_level;
+ } client;
+
+ struct {
+ const char *computer;
+ const char *netbios_domain;
+ const char *dns_domain;
+ uint32_t cached_flags;
+ bool try_validation6;
+ bool try_logon_ex;
+ bool try_logon_with;
+ } server;
+
+ struct {
+ const char *key_name;
+ TDB_DATA key_data;
+ struct db_context *ctx;
+ struct g_lock_ctx *g_ctx;
+ struct netlogon_creds_cli_locked_state *locked_state;
+ enum netlogon_creds_cli_lck_type lock;
+ } db;
+};
+
+struct netlogon_creds_cli_locked_state {
+ struct netlogon_creds_cli_context *context;
+ bool is_glocked;
+ struct netlogon_creds_CredentialState *creds;
+};
+
+static int netlogon_creds_cli_locked_state_destructor(
+ struct netlogon_creds_cli_locked_state *state)
+{
+ struct netlogon_creds_cli_context *context = state->context;
+
+ if (context == NULL) {
+ return 0;
+ }
+
+ if (context->db.locked_state == state) {
+ context->db.locked_state = NULL;
+ }
+
+ if (state->is_glocked) {
+ g_lock_unlock(context->db.g_ctx,
+ string_term_tdb_data(context->db.key_name));
+ }
+
+ return 0;
+}
+
+static NTSTATUS netlogon_creds_cli_context_common(
+ const char *client_computer,
+ const char *client_account,
+ enum netr_SchannelType type,
+ enum dcerpc_AuthLevel auth_level,
+ uint32_t proposed_flags,
+ uint32_t required_flags,
+ const char *server_computer,
+ const char *server_netbios_domain,
+ const char *server_dns_domain,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_context **_context)
+{
+ struct netlogon_creds_cli_context *context = NULL;
+ char *_key_name = NULL;
+ size_t server_netbios_name_len;
+ char *p = NULL;
+
+ *_context = NULL;
+
+ context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
+ if (context == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->client.computer = talloc_strdup(context, client_computer);
+ if (context->client.computer == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->client.account = talloc_strdup(context, client_account);
+ if (context->client.account == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->client.proposed_flags = proposed_flags;
+ context->client.required_flags = required_flags;
+ context->client.type = type;
+ context->client.auth_level = auth_level;
+
+ context->server.computer = talloc_strdup(context, server_computer);
+ if (context->server.computer == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
+ if (context->server.netbios_domain == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->server.dns_domain = talloc_strdup(context, server_dns_domain);
+ if (context->server.dns_domain == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * TODO:
+ * Force the callers to provide a unique
+ * value for server_computer and use this directly.
+ *
+ * For now we have to deal with
+ * "HOSTNAME" vs. "hostname.example.com".
+ */
+
+ p = strchr(server_computer, '.');
+ if (p != NULL) {
+ server_netbios_name_len = p-server_computer;
+ } else {
+ server_netbios_name_len = strlen(server_computer);
+ }
+
+ _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
+ client_computer,
+ client_account,
+ (int)server_netbios_name_len,
+ server_computer,
+ server_netbios_domain);
+ if (_key_name == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->db.key_name = talloc_strdup_upper(context, _key_name);
+ TALLOC_FREE(_key_name);
+ if (context->db.key_name == NULL) {
+ TALLOC_FREE(context);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->db.key_data = string_term_tdb_data(context->db.key_name);
+
+ *_context = context;
+ return NT_STATUS_OK;
+}
+
+static struct db_context *netlogon_creds_cli_global_db;
+
+NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx,
+ struct db_context **db)
+{
+ netlogon_creds_cli_warn_options(lp_ctx);
+
+ if (netlogon_creds_cli_global_db != NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ netlogon_creds_cli_global_db = talloc_move(NULL, db);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
+{
+ char *fname;
+ struct db_context *global_db;
+ int hash_size, tdb_flags;
+
+ netlogon_creds_cli_warn_options(lp_ctx);
+
+ if (netlogon_creds_cli_global_db != NULL) {
+ return NT_STATUS_OK;
+ }
+
+ fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
+ if (fname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
+ tdb_flags = lpcfg_tdb_flags(
+ lp_ctx,
+ TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
+
+ global_db = dbwrap_local_open(
+ NULL,
+ fname,
+ hash_size,
+ tdb_flags,
+ O_RDWR|O_CREAT,
+ 0600,
+ DBWRAP_LOCK_ORDER_2,
+ DBWRAP_FLAG_NONE);
+ if (global_db == NULL) {
+ DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
+ fname, strerror(errno)));
+ talloc_free(fname);
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(fname);
+
+ netlogon_creds_cli_global_db = global_db;
+ return NT_STATUS_OK;
+}
+
+void netlogon_creds_cli_close_global_db(void)
+{
+ TALLOC_FREE(netlogon_creds_cli_global_db);
+}
+
+void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx)
+{
+ bool global_reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
+ bool global_require_strong_key = lpcfg_require_strong_key(lp_ctx);
+ int global_client_schannel = lpcfg_client_schannel(lp_ctx);
+ bool global_seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
+ int global_kerberos_enctypes = lpcfg_kerberos_encryption_types(lp_ctx);
+ static bool warned_global_reject_md5_servers = false;
+ static bool warned_global_require_strong_key = false;
+ static bool warned_global_client_schannel = false;
+ static bool warned_global_seal_secure_channel = false;
+ static bool warned_global_kerberos_encryption_types = false;
+ static int warned_global_pid = 0;
+ int current_pid = tevent_cached_getpid();
+
+ if (warned_global_pid != current_pid) {
+ warned_global_reject_md5_servers = false;
+ warned_global_require_strong_key = false;
+ warned_global_client_schannel = false;
+ warned_global_seal_secure_channel = false;
+ warned_global_kerberos_encryption_types = false;
+ warned_global_pid = current_pid;
+ }
+
+ if (!global_reject_md5_servers && !warned_global_reject_md5_servers) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'reject md5 servers = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_reject_md5_servers = true;
+ }
+
+ if (!global_require_strong_key && !warned_global_require_strong_key) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'require strong key = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_require_strong_key = true;
+ }
+
+ if (global_client_schannel != true && !warned_global_client_schannel) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'client schannel = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_client_schannel = true;
+ }
+
+ if (!global_seal_secure_channel && !warned_global_seal_secure_channel) {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-38023 (and others): "
+ "Please configure 'winbind sealed pipes = yes' (the default), "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
+ warned_global_seal_secure_channel = true;
+ }
+
+ if (global_kerberos_enctypes == KERBEROS_ETYPES_LEGACY &&
+ !warned_global_kerberos_encryption_types)
+ {
+ /*
+ * We want admins to notice their misconfiguration!
+ */
+ DBG_ERR("CVE-2022-37966: "
+ "Please void 'kerberos encryption types = legacy', "
+ "See https://bugzilla.samba.org/show_bug.cgi?id=15237\n");
+ warned_global_kerberos_encryption_types = true;
+ }
+}
+
+NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
+ struct messaging_context *msg_ctx,
+ const char *client_account,
+ enum netr_SchannelType type,
+ const char *server_computer,
+ const char *server_netbios_domain,
+ const char *server_dns_domain,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_context **_context)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ struct netlogon_creds_cli_context *context = NULL;
+ const char *client_computer;
+ uint32_t proposed_flags;
+ uint32_t required_flags = 0;
+ bool reject_md5_servers = true;
+ bool require_strong_key = true;
+ int require_sign_or_seal = true;
+ bool seal_secure_channel = true;
+ enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
+ bool neutralize_nt4_emulation = false;
+
+ *_context = NULL;
+
+ if (msg_ctx == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ client_computer = lpcfg_netbios_name(lp_ctx);
+ if (strlen(client_computer) > 15) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ /*
+ * allow overwrite per domain
+ * reject md5 servers:<netbios_domain>
+ */
+ reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
+ reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
+ "reject md5 servers",
+ server_netbios_domain,
+ reject_md5_servers);
+
+ /*
+ * allow overwrite per domain
+ * require strong key:<netbios_domain>
+ */
+ require_strong_key = lpcfg_require_strong_key(lp_ctx);
+ require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
+ "require strong key",
+ server_netbios_domain,
+ require_strong_key);
+
+ /*
+ * allow overwrite per domain
+ * client schannel:<netbios_domain>
+ */
+ require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
+ require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
+ "client schannel",
+ server_netbios_domain,
+ require_sign_or_seal);
+
+ /*
+ * allow overwrite per domain
+ * winbind sealed pipes:<netbios_domain>
+ */
+ seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
+ seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
+ "winbind sealed pipes",
+ server_netbios_domain,
+ seal_secure_channel);
+
+ /*
+ * allow overwrite per domain
+ * neutralize nt4 emulation:<netbios_domain>
+ */
+ neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
+ neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
+ "neutralize nt4 emulation",
+ server_netbios_domain,
+ neutralize_nt4_emulation);
+
+ proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
+ proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
+
+ switch (type) {
+ case SEC_CHAN_WKSTA:
+ if (lpcfg_security(lp_ctx) == SEC_ADS) {
+ /*
+ * AD domains should be secure
+ */
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ require_sign_or_seal = true;
+ require_strong_key = true;
+ }
+ break;
+
+ case SEC_CHAN_DOMAIN:
+ break;
+
+ case SEC_CHAN_DNS_DOMAIN:
+ /*
+ * AD domains should be secure
+ */
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ require_sign_or_seal = true;
+ require_strong_key = true;
+ neutralize_nt4_emulation = true;
+ break;
+
+ case SEC_CHAN_BDC:
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ require_sign_or_seal = true;
+ require_strong_key = true;
+ break;
+
+ case SEC_CHAN_RODC:
+ required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ require_sign_or_seal = true;
+ require_strong_key = true;
+ neutralize_nt4_emulation = true;
+ break;
+
+ default:
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (neutralize_nt4_emulation) {
+ proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
+ }
+
+ if (require_sign_or_seal) {
+ required_flags |= NETLOGON_NEG_ARCFOUR;
+ required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
+ } else {
+ proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
+ }
+
+ if (reject_md5_servers) {
+ required_flags |= NETLOGON_NEG_ARCFOUR;
+ required_flags |= NETLOGON_NEG_PASSWORD_SET2;
+ required_flags |= NETLOGON_NEG_SUPPORTS_AES;
+ required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
+ }
+
+ if (require_strong_key) {
+ required_flags |= NETLOGON_NEG_ARCFOUR;
+ required_flags |= NETLOGON_NEG_STRONG_KEYS;
+ required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
+ }
+
+ /*
+ * If weak crypto is disabled, do not announce that we support RC4 and
+ * require AES.
+ */
+ if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
+ required_flags &= ~NETLOGON_NEG_ARCFOUR;
+ required_flags |= NETLOGON_NEG_SUPPORTS_AES;
+ proposed_flags &= ~NETLOGON_NEG_ARCFOUR;
+ proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
+ }
+
+ proposed_flags |= required_flags;
+
+ if (seal_secure_channel) {
+ auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ } else {
+ auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ }
+
+ status = netlogon_creds_cli_context_common(client_computer,
+ client_account,
+ type,
+ auth_level,
+ proposed_flags,
+ required_flags,
+ server_computer,
+ server_netbios_domain,
+ "",
+ mem_ctx,
+ &context);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
+ if (context->db.g_ctx == NULL) {
+ TALLOC_FREE(context);
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = netlogon_creds_cli_open_global_db(lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(context);
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ context->db.ctx = netlogon_creds_cli_global_db;
+ *_context = context;
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_bind_cli_credentials(
+ struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
+ struct cli_credentials **pcli_creds)
+{
+ struct cli_credentials *cli_creds;
+ struct netlogon_creds_CredentialState *ncreds;
+ NTSTATUS status;
+
+ cli_creds = cli_credentials_init(mem_ctx);
+ if (cli_creds == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_credentials_set_secure_channel_type(cli_creds,
+ context->client.type);
+ cli_credentials_set_username(cli_creds, context->client.account,
+ CRED_SPECIFIED);
+ cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
+ CRED_SPECIFIED);
+ cli_credentials_set_realm(cli_creds, context->server.dns_domain,
+ CRED_SPECIFIED);
+
+ status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(cli_creds);
+ return status;
+ }
+ cli_credentials_set_netlogon_creds(cli_creds, ncreds);
+
+ *pcli_creds = cli_creds;
+ return NT_STATUS_OK;
+}
+
+char *netlogon_creds_cli_debug_string(
+ const struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx)
+{
+ return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
+ context->db.key_name);
+}
+
+enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
+ struct netlogon_creds_cli_context *context)
+{
+ return context->client.auth_level;
+}
+
+static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags,
+ uint32_t proposed_flags,
+ uint32_t required_flags)
+{
+ uint32_t req_flags = required_flags;
+ uint32_t tmp_flags;
+
+ req_flags = required_flags;
+ if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_AES) &&
+ (proposed_flags & NETLOGON_NEG_SUPPORTS_AES))
+ {
+ req_flags &= ~NETLOGON_NEG_ARCFOUR|NETLOGON_NEG_STRONG_KEYS;
+ }
+
+ tmp_flags = negotiated_flags;
+ tmp_flags &= req_flags;
+ if (tmp_flags != req_flags) {
+ return true;
+ }
+
+ return false;
+}
+
+struct netlogon_creds_cli_fetch_state {
+ TALLOC_CTX *mem_ctx;
+ struct netlogon_creds_CredentialState *creds;
+ uint32_t proposed_flags;
+ uint32_t required_flags;
+ NTSTATUS status;
+};
+
+static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
+ void *private_data)
+{
+ struct netlogon_creds_cli_fetch_state *state =
+ (struct netlogon_creds_cli_fetch_state *)private_data;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ bool downgraded;
+
+ state->creds = talloc_zero(state->mem_ctx,
+ struct netlogon_creds_CredentialState);
+ if (state->creds == NULL) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return;
+ }
+
+ blob.data = data.dptr;
+ blob.length = data.dsize;
+
+ ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
+ (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(state->creds);
+ state->status = ndr_map_error2ntstatus(ndr_err);
+ return;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
+ }
+
+ downgraded = netlogon_creds_cli_downgraded(
+ state->creds->negotiate_flags,
+ state->proposed_flags,
+ state->required_flags);
+ if (downgraded) {
+ TALLOC_FREE(state->creds);
+ state->status = NT_STATUS_DOWNGRADE_DETECTED;
+ return;
+ }
+
+ state->status = NT_STATUS_OK;
+}
+
+static NTSTATUS netlogon_creds_cli_get_internal(
+ struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
+
+NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **_creds)
+{
+ NTSTATUS status;
+ struct netlogon_creds_CredentialState *creds;
+
+ *_creds = NULL;
+
+ status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * mark it as invalid for step operations.
+ */
+ creds->sequence = 0;
+ creds->seed = (struct netr_Credential) {{0}};
+ creds->client = (struct netr_Credential) {{0}};
+ creds->server = (struct netr_Credential) {{0}};
+
+ *_creds = creds;
+ return NT_STATUS_OK;
+}
+
+bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
+ const struct netlogon_creds_CredentialState *creds1)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct netlogon_creds_CredentialState *creds2;
+ DATA_BLOB blob1;
+ DATA_BLOB blob2;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ bool equal;
+
+ status = netlogon_creds_cli_get(context, frame, &creds2);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return false;
+ }
+
+ equal = data_blob_equal_const_time(&blob1, &blob2);
+
+ TALLOC_FREE(frame);
+
+ return equal;
+}
+
+static NTSTATUS netlogon_creds_cli_store_internal(
+ struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds)
+{
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ TDB_DATA data;
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, creds, creds,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ return status;
+ }
+
+ data.dptr = blob.data;
+ data.dsize = blob.length;
+
+ status = dbwrap_store(context->db.ctx,
+ context->db.key_data,
+ data, TDB_REPLACE);
+ TALLOC_FREE(data.dptr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds)
+{
+ NTSTATUS status;
+
+ if (context->db.locked_state == NULL) {
+ /*
+ * this was not the result of netlogon_creds_cli_lock*()
+ */
+ return NT_STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ if (context->db.locked_state->creds != creds) {
+ /*
+ * this was not the result of netlogon_creds_cli_lock*()
+ */
+ return NT_STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ status = netlogon_creds_cli_store_internal(context, creds);
+ return status;
+}
+
+static NTSTATUS netlogon_creds_cli_delete_internal(
+ struct netlogon_creds_cli_context *context)
+{
+ NTSTATUS status;
+ status = dbwrap_delete(context->db.ctx, context->db.key_data);
+ return status;
+}
+
+NTSTATUS netlogon_creds_cli_delete_lck(
+ struct netlogon_creds_cli_context *context)
+{
+ NTSTATUS status;
+
+ if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+ return NT_STATUS_NOT_LOCKED;
+ }
+
+ status = netlogon_creds_cli_delete_internal(context);
+ return status;
+}
+
+NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds)
+{
+ NTSTATUS status;
+
+ if (context->db.locked_state == NULL) {
+ /*
+ * this was not the result of netlogon_creds_cli_lock*()
+ */
+ return NT_STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ if (context->db.locked_state->creds != creds) {
+ /*
+ * this was not the result of netlogon_creds_cli_lock*()
+ */
+ return NT_STATUS_INVALID_PAGE_PROTECTION;
+ }
+
+ status = netlogon_creds_cli_delete_internal(context);
+ return status;
+}
+
+struct netlogon_creds_cli_lock_state {
+ struct netlogon_creds_cli_locked_state *locked_state;
+ struct netlogon_creds_CredentialState *creds;
+};
+
+static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_lock_state *state;
+ struct netlogon_creds_cli_locked_state *locked_state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_lock_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (context->db.locked_state != NULL) {
+ tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
+ return tevent_req_post(req, ev);
+ }
+
+ locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
+ if (tevent_req_nomem(locked_state, req)) {
+ return tevent_req_post(req, ev);
+ }
+ talloc_set_destructor(locked_state,
+ netlogon_creds_cli_locked_state_destructor);
+ locked_state->context = context;
+
+ context->db.locked_state = locked_state;
+ state->locked_state = locked_state;
+
+ if (context->db.g_ctx == NULL) {
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_get_internal(
+ context, state, &state->creds);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+ }
+
+ subreq = g_lock_lock_send(state, ev,
+ context->db.g_ctx,
+ string_term_tdb_data(context->db.key_name),
+ G_LOCK_WRITE,
+ NULL, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_lock_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_lock_state);
+ NTSTATUS status;
+
+ status = g_lock_lock_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ state->locked_state->is_glocked = true;
+
+ status = netlogon_creds_cli_get_internal(state->locked_state->context,
+ state, &state->creds);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS netlogon_creds_cli_get_internal(
+ struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
+{
+ struct netlogon_creds_cli_fetch_state fstate = {
+ .status = NT_STATUS_INTERNAL_ERROR,
+ .proposed_flags = context->client.proposed_flags,
+ .required_flags = context->client.required_flags,
+ };
+ NTSTATUS status;
+
+ fstate.mem_ctx = mem_ctx;
+ status = dbwrap_parse_record(context->db.ctx,
+ context->db.key_data,
+ netlogon_creds_cli_fetch_parser,
+ &fstate);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (!NT_STATUS_IS_OK(fstate.status)) {
+ return fstate.status;
+ }
+
+ if (context->server.cached_flags == fstate.creds->negotiate_flags) {
+ *pcreds = fstate.creds;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * It is really important to try SamLogonEx here,
+ * because multiple processes can talk to the same
+ * domain controller, without using the credential
+ * chain.
+ *
+ * With a normal SamLogon call, we must keep the
+ * credentials chain updated and intact between all
+ * users of the machine account (which would imply
+ * cross-node communication for every NTLM logon).
+ *
+ * The credentials chain is not per NETLOGON pipe
+ * connection, but globally on the server/client pair
+ * by computer name.
+ *
+ * It's also important to use NetlogonValidationSamInfo4 (6),
+ * because it relies on the rpc transport encryption
+ * and avoids using the global netlogon schannel
+ * session key to en/decrypt secret information
+ * like the user_session_key for network logons.
+ *
+ * [MS-APDS] 3.1.5.2 NTLM Network Logon
+ * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
+ * NETLOGON_NEG_AUTHENTICATED_RPC set together
+ * are the indication that the server supports
+ * NetlogonValidationSamInfo4 (6). And it must only
+ * be used if "SealSecureChannel" is used.
+ *
+ * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
+ * check is done in netlogon_creds_cli_LogonSamLogon*().
+ */
+
+ context->server.cached_flags = fstate.creds->negotiate_flags;
+ context->server.try_validation6 = true;
+ context->server.try_logon_ex = true;
+ context->server.try_logon_with = true;
+
+ if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+ context->server.try_validation6 = false;
+ context->server.try_logon_ex = false;
+ }
+ if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
+ context->server.try_validation6 = false;
+ }
+
+ *pcreds = fstate.creds;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **creds)
+{
+ struct netlogon_creds_cli_lock_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_lock_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ talloc_steal(state->creds, state->locked_state);
+ state->locked_state->creds = state->creds;
+ *creds = talloc_move(mem_ctx, &state->creds);
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **creds)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_lock_send(frame, ev, context);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_lck {
+ struct netlogon_creds_cli_context *context;
+};
+
+struct netlogon_creds_cli_lck_state {
+ struct netlogon_creds_cli_lck *lck;
+ enum netlogon_creds_cli_lck_type type;
+};
+
+static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
+static int netlogon_creds_cli_lck_destructor(
+ struct netlogon_creds_cli_lck *lck);
+
+struct tevent_req *netlogon_creds_cli_lck_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ enum netlogon_creds_cli_lck_type type)
+{
+ struct tevent_req *req, *subreq;
+ struct netlogon_creds_cli_lck_state *state;
+ enum g_lock_type gtype;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_lck_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
+ DBG_DEBUG("context already locked\n");
+ tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
+ return tevent_req_post(req, ev);
+ }
+
+ switch (type) {
+ case NETLOGON_CREDS_CLI_LCK_SHARED:
+ gtype = G_LOCK_READ;
+ break;
+ case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
+ gtype = G_LOCK_WRITE;
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->lck = talloc(state, struct netlogon_creds_cli_lck);
+ if (tevent_req_nomem(state->lck, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->lck->context = context;
+ state->type = type;
+
+ subreq = g_lock_lock_send(state, ev,
+ context->db.g_ctx,
+ string_term_tdb_data(context->db.key_name),
+ gtype,
+ NULL, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct netlogon_creds_cli_lck_state *state = tevent_req_data(
+ req, struct netlogon_creds_cli_lck_state);
+ NTSTATUS status;
+
+ status = g_lock_lock_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->lck->context->db.lock = state->type;
+ talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
+
+ tevent_req_done(req);
+}
+
+static int netlogon_creds_cli_lck_destructor(
+ struct netlogon_creds_cli_lck *lck)
+{
+ struct netlogon_creds_cli_context *ctx = lck->context;
+ NTSTATUS status;
+
+ status = g_lock_unlock(ctx->db.g_ctx,
+ string_term_tdb_data(ctx->db.key_name));
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
+ smb_panic("g_lock_unlock failed");
+ }
+ ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
+ return 0;
+}
+
+NTSTATUS netlogon_creds_cli_lck_recv(
+ struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_lck **lck)
+{
+ struct netlogon_creds_cli_lck_state *state = tevent_req_data(
+ req, struct netlogon_creds_cli_lck_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ *lck = talloc_move(mem_ctx, &state->lck);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_lck(
+ struct netlogon_creds_cli_context *context,
+ enum netlogon_creds_cli_lck_type type,
+ TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_lck_send(frame, ev, context, type);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_auth_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+ uint8_t num_nt_hashes;
+ uint8_t idx_nt_hashes;
+ const struct samr_Password * const *nt_hashes;
+ const struct samr_Password *used_nt_hash;
+ char *srv_name_slash;
+ uint32_t current_flags;
+ struct netr_Credential client_challenge;
+ struct netr_Credential server_challenge;
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Credential client_credential;
+ struct netr_Credential server_credential;
+ uint32_t rid;
+ bool try_auth3;
+ bool try_auth2;
+ bool require_auth2;
+};
+
+static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
+
+struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint8_t num_nt_hashes,
+ const struct samr_Password * const *nt_hashes)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_auth_state *state;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_auth_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+ if (num_nt_hashes < 1) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ if (num_nt_hashes > 4) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ state->num_nt_hashes = num_nt_hashes;
+ state->idx_nt_hashes = 0;
+ state->nt_hashes = nt_hashes;
+
+ if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+ tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
+ return tevent_req_post(req, ev);
+ }
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->try_auth3 = true;
+ state->try_auth2 = true;
+
+ if (context->client.required_flags != 0) {
+ state->require_auth2 = true;
+ }
+
+ state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
+ state->current_flags = context->client.proposed_flags;
+
+ status = dbwrap_purge(state->context->db.ctx,
+ state->context->db.key_data);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ netlogon_creds_cli_auth_challenge_start(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
+{
+ struct netlogon_creds_cli_auth_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_auth_state);
+ struct tevent_req *subreq;
+
+ TALLOC_FREE(state->creds);
+
+ netlogon_creds_random_challenge(&state->client_challenge);
+
+ subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ &state->client_challenge,
+ &state->server_challenge);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_auth_challenge_done,
+ req);
+}
+
+static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_auth_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_auth_state);
+ NTSTATUS status;
+ NTSTATUS result;
+
+ status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ if (tevent_req_nterror(req, result)) {
+ return;
+ }
+
+ if (!state->try_auth3 && !state->try_auth2) {
+ state->current_flags = 0;
+ }
+
+ /* Calculate the session key and client credentials */
+
+ state->creds = netlogon_creds_client_init(state,
+ state->context->client.account,
+ state->context->client.computer,
+ state->context->client.type,
+ &state->client_challenge,
+ &state->server_challenge,
+ state->used_nt_hash,
+ &state->client_credential,
+ state->current_flags);
+ if (tevent_req_nomem(state->creds, req)) {
+ return;
+ }
+
+ if (state->try_auth3) {
+ subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.account,
+ state->context->client.type,
+ state->context->client.computer,
+ &state->client_credential,
+ &state->server_credential,
+ &state->creds->negotiate_flags,
+ &state->rid);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ } else if (state->try_auth2) {
+ state->rid = 0;
+
+ subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.account,
+ state->context->client.type,
+ state->context->client.computer,
+ &state->client_credential,
+ &state->server_credential,
+ &state->creds->negotiate_flags);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ } else {
+ state->rid = 0;
+
+ subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.account,
+ state->context->client.type,
+ state->context->client.computer,
+ &state->client_credential,
+ &state->server_credential);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ }
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_auth_srvauth_done,
+ req);
+}
+
+static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_auth_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_auth_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ TDB_DATA data;
+ bool downgraded;
+
+ if (state->try_auth3) {
+ status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ state->try_auth3 = false;
+ netlogon_creds_cli_auth_challenge_start(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ } else if (state->try_auth2) {
+ status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ state->try_auth2 = false;
+ if (state->require_auth2) {
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ return;
+ }
+ netlogon_creds_cli_auth_challenge_start(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ } else {
+ status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(result) &&
+ !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
+ {
+ tevent_req_nterror(req, result);
+ return;
+ }
+
+ downgraded = netlogon_creds_cli_downgraded(
+ state->creds->negotiate_flags,
+ state->context->client.proposed_flags,
+ state->context->client.required_flags);
+ if (downgraded) {
+ if (NT_STATUS_IS_OK(result)) {
+ tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
+ return;
+ }
+ tevent_req_nterror(req, result);
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
+ uint32_t tmp_flags = state->context->client.proposed_flags;
+ if ((state->current_flags == tmp_flags) &&
+ (state->creds->negotiate_flags != tmp_flags))
+ {
+ /*
+ * lets retry with the negotiated flags
+ */
+ state->current_flags = state->creds->negotiate_flags;
+ netlogon_creds_cli_auth_challenge_start(req);
+ return;
+ }
+
+ state->idx_nt_hashes += 1;
+ if (state->idx_nt_hashes >= state->num_nt_hashes) {
+ /*
+ * we already retried, giving up...
+ */
+ tevent_req_nterror(req, result);
+ return;
+ }
+
+ /*
+ * lets retry with the old nt hash.
+ */
+ state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
+ state->current_flags = state->context->client.proposed_flags;
+ netlogon_creds_cli_auth_challenge_start(req);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(state->creds,
+ &state->server_credential);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ data.dptr = blob.data;
+ data.dsize = blob.length;
+
+ status = dbwrap_store(state->context->db.ctx,
+ state->context->db.key_data,
+ data, TDB_REPLACE);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
+ uint8_t *idx_nt_hashes)
+{
+ struct netlogon_creds_cli_auth_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_auth_state);
+ NTSTATUS status;
+
+ *idx_nt_hashes = 0;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *idx_nt_hashes = state->idx_nt_hashes;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint8_t num_nt_hashes,
+ const struct samr_Password * const *nt_hashes,
+ uint8_t *idx_nt_hashes)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ *idx_nt_hashes = 0;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_auth_send(frame, ev, context, b,
+ num_nt_hashes, nt_hashes);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_check_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+
+ union netr_Capabilities caps;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_check_state *state;
+ struct tevent_req *subreq;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_check_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+ tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
+ return tevent_req_post(req, ev);
+ }
+
+ status = netlogon_creds_cli_get_internal(context, state,
+ &state->creds);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &auth_type, &auth_level);
+
+ if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ switch (auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ status = netlogon_creds_client_authenticator(state->creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ &state->req_auth,
+ &state->rep_auth,
+ 1,
+ &state->caps);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_check_caps,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_check_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_check_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete_lck(state->context);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_check_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_check_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ /*
+ * Note that the negotiated flags are already checked
+ * for our required flags after the ServerAuthenticate3/2 call.
+ */
+ uint32_t negotiated = state->creds->negotiate_flags;
+
+ if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
+ /*
+ * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
+ * already, we expect this to work!
+ */
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
+ /*
+ * If we have negotiated NETLOGON_NEG_STRONG_KEYS
+ * we expect this to work at least as far as the
+ * NOT_SUPPORTED error handled below!
+ *
+ * NT 4.0 and Old Samba servers are not
+ * allowed without "require strong key = no"
+ */
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ /*
+ * If we not require NETLOGON_NEG_SUPPORTS_AES or
+ * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
+ * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
+ *
+ * This is needed against NT 4.0 and old Samba servers.
+ *
+ * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
+ * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
+ * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
+ * with the next request as the sequence number processing
+ * gets out of sync.
+ */
+ netlogon_creds_cli_check_cleanup(req, status);
+ tevent_req_done(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
+ /*
+ * Note that the negotiated flags are already checked
+ * for our required flags after the ServerAuthenticate3/2 call.
+ */
+ uint32_t negotiated = state->creds->negotiate_flags;
+
+ if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
+ /*
+ * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
+ * already, we expect this to work!
+ */
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ /*
+ * This is ok, the server does not support
+ * NETLOGON_NEG_SUPPORTS_AES.
+ *
+ * netr_LogonGetCapabilities() was
+ * netr_LogonDummyRoutine1() before
+ * NETLOGON_NEG_SUPPORTS_AES was invented.
+ */
+ netlogon_creds_cli_check_cleanup(req, result);
+ tevent_req_done(req);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_check_cleanup(req, result);
+ return;
+ }
+
+ if (state->caps.server_capabilities != state->creds->negotiate_flags) {
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ /*
+ * This is the key check that makes this check secure. If we
+ * get OK here (rather than NOT_SUPPORTED), then the server
+ * did support AES. If the server only proposed STRONG_KEYS
+ * and not AES, then it should have failed with
+ * NOT_IMPLEMENTED. We always send AES as a client, so the
+ * server should always have returned it.
+ */
+ if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_check_cleanup(req, status);
+ return;
+ }
+
+ status = netlogon_creds_cli_store_internal(state->context,
+ state->creds);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
+ union netr_Capabilities *capabilities)
+{
+ struct netlogon_creds_cli_check_state *state = tevent_req_data(
+ req, struct netlogon_creds_cli_check_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_check_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (capabilities != NULL) {
+ *capabilities = state->caps;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ union netr_Capabilities *capabilities)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_check_send(frame, ev, context, b);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_check_recv(req, capabilities);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_ServerPasswordSet_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+ uint32_t old_timeout;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ struct samr_CryptPassword samr_crypt_password;
+ struct netr_CryptPassword netr_crypt_password;
+ struct samr_Password samr_password;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const DATA_BLOB *new_password,
+ const uint32_t *new_version)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_ServerPasswordSet_state *state;
+ struct tevent_req *subreq;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_ServerPasswordSet_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ if (new_password->length < 14) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * netr_ServerPasswordSet
+ */
+ mdfour(state->samr_password.hash, new_password->data, new_password->length);
+
+ /*
+ * netr_ServerPasswordSet2
+ */
+ ok = set_pw_in_buffer(state->samr_crypt_password.data,
+ new_password);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (new_version != NULL) {
+ struct NL_PASSWORD_VERSION version;
+ uint32_t len = IVAL(state->samr_crypt_password.data, 512);
+ uint32_t ofs = 512 - len;
+ uint8_t *p;
+
+ if (len > 500) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ ofs -= 12;
+
+ version.ReservedField = 0;
+ version.PasswordVersionNumber = *new_version;
+ version.PasswordVersionPresent =
+ NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
+
+ p = state->samr_crypt_password.data + ofs;
+ SIVAL(p, 0, version.ReservedField);
+ SIVAL(p, 4, version.PasswordVersionNumber);
+ SIVAL(p, 8, version.PasswordVersionPresent);
+ }
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_ServerPasswordSet_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_ServerPasswordSet_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerPasswordSet_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ dcerpc_binding_handle_set_timeout(state->binding_handle,
+ state->old_timeout);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_ServerPasswordSet_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerPasswordSet_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ state->old_timeout = dcerpc_binding_handle_set_timeout(
+ state->binding_handle, 600000);
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
+
+ if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ status = netlogon_creds_aes_encrypt(&state->tmp_creds,
+ state->samr_crypt_password.data,
+ 516);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
+ state->samr_crypt_password.data,
+ 516);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ }
+
+ memcpy(state->netr_crypt_password.data,
+ state->samr_crypt_password.data, 512);
+ state->netr_crypt_password.length =
+ IVAL(state->samr_crypt_password.data, 512);
+
+ subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.account_name,
+ state->tmp_creds.secure_channel_type,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ &state->netr_crypt_password);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = netlogon_creds_des_encrypt(&state->tmp_creds,
+ &state->samr_password);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+
+ subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.account_name,
+ state->tmp_creds.secure_channel_type,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ &state->samr_password);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_ServerPasswordSet_done,
+ req);
+}
+
+static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_ServerPasswordSet_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerPasswordSet_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
+ status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
+ return;
+ }
+
+ dcerpc_binding_handle_set_timeout(state->binding_handle,
+ state->old_timeout);
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_ServerPasswordSet(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const DATA_BLOB *new_password,
+ const uint32_t *new_version)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
+ new_password,
+ new_version);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_ServerPasswordSet_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_LogonSamLogon_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+
+ enum netr_LogonInfoClass logon_level;
+ const union netr_LogonLevel *const_logon;
+ union netr_LogonLevel *logon;
+ uint32_t flags;
+
+ uint16_t validation_level;
+ union netr_Validation *validation;
+ uint8_t authoritative;
+
+ /*
+ * do we need encryption at the application layer?
+ */
+ bool user_encrypt;
+ bool try_logon_ex;
+ bool try_validation6;
+
+ /*
+ * the read only credentials before we started the operation
+ * used for netr_LogonSamLogonEx() if required (validation_level = 3).
+ */
+ struct netlogon_creds_CredentialState *ro_creds;
+
+ /*
+ * The (locked) credentials used for the credential chain
+ * used for netr_LogonSamLogonWithFlags() or
+ * netr_LogonSamLogonWith().
+ */
+ struct netlogon_creds_CredentialState *lk_creds;
+
+ /*
+ * While we have locked the global credentials (lk_creds above)
+ * we operate an a temporary copy, because a server
+ * may not support netr_LogonSamLogonWithFlags() and
+ * didn't process our netr_Authenticator, so we need to
+ * restart from lk_creds.
+ */
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
+static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+
+struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ enum netr_LogonInfoClass logon_level,
+ const union netr_LogonLevel *logon,
+ uint32_t flags)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_LogonSamLogon_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->logon_level = logon_level;
+ state->const_logon = logon;
+ state->flags = flags;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ switch (logon_level) {
+ case NetlogonInteractiveInformation:
+ case NetlogonInteractiveTransitiveInformation:
+ case NetlogonServiceInformation:
+ case NetlogonServiceTransitiveInformation:
+ case NetlogonGenericInformation:
+ state->user_encrypt = true;
+ break;
+
+ case NetlogonNetworkInformation:
+ case NetlogonNetworkTransitiveInformation:
+ break;
+ }
+
+ state->validation = talloc_zero(state, union netr_Validation);
+ if (tevent_req_nomem(state->validation, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+ return req;
+}
+
+static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_LogonSamLogon_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+
+ if (state->lk_creds == NULL) {
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ /*
+ * This is a hack to recover from a bug in old
+ * Samba servers, when LogonSamLogonEx() fails:
+ *
+ * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
+ *
+ * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
+ *
+ * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
+ * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
+ * If the sign/seal check fails.
+ *
+ * In that case we need to cleanup the netlogon session.
+ *
+ * It's the job of the caller to disconnect the current
+ * connection, if netlogon_creds_cli_LogonSamLogon()
+ * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
+ */
+ if (!state->context->server.try_logon_with) {
+ status = NT_STATUS_NETWORK_ACCESS_DENIED;
+ }
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->lk_creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->lk_creds);
+ TALLOC_FREE(state->lk_creds);
+}
+
+static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
+{
+ struct netlogon_creds_cli_LogonSamLogon_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+ struct tevent_req *subreq;
+ NTSTATUS status;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ TALLOC_FREE(state->ro_creds);
+ TALLOC_FREE(state->logon);
+ ZERO_STRUCTP(state->validation);
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &auth_type, &auth_level);
+
+ state->try_logon_ex = state->context->server.try_logon_ex;
+ state->try_validation6 = state->context->server.try_validation6;
+
+ if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
+ state->try_logon_ex = false;
+ }
+
+ if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+ state->try_validation6 = false;
+ }
+
+ if (state->try_logon_ex) {
+ if (state->try_validation6) {
+ state->validation_level = 6;
+ } else {
+ state->validation_level = 3;
+ state->user_encrypt = true;
+ }
+
+ state->logon = netlogon_creds_shallow_copy_logon(state,
+ state->logon_level,
+ state->const_logon);
+ if (tevent_req_nomem(state->logon, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ if (state->user_encrypt) {
+ status = netlogon_creds_cli_get(state->context,
+ state,
+ &state->ro_creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
+ state->logon_level,
+ state->logon);
+ if (!NT_STATUS_IS_OK(status)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ }
+
+ subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ state->logon_level,
+ state->logon,
+ state->validation_level,
+ state->validation,
+ &state->authoritative,
+ &state->flags);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonSamLogon_done,
+ req);
+ return;
+ }
+
+ if (state->lk_creds == NULL) {
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonSamLogon_done,
+ req);
+ return;
+ }
+
+ state->tmp_creds = *state->lk_creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ state->logon = netlogon_creds_shallow_copy_logon(state,
+ state->logon_level,
+ state->const_logon);
+ if (tevent_req_nomem(state->logon, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
+ state->logon_level,
+ state->logon);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ state->validation_level = 3;
+
+ if (state->context->server.try_logon_with) {
+ subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ &state->req_auth,
+ &state->rep_auth,
+ state->logon_level,
+ state->logon,
+ state->validation_level,
+ state->validation,
+ &state->authoritative,
+ &state->flags);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ } else {
+ state->flags = 0;
+
+ subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->context->client.computer,
+ &state->req_auth,
+ &state->rep_auth,
+ state->logon_level,
+ state->logon,
+ state->validation_level,
+ state->validation,
+ &state->authoritative);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonSamLogon_done,
+ req);
+}
+
+static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_LogonSamLogon_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ if (state->try_logon_ex) {
+ status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
+ state->validation,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ state->context->server.try_validation6 = false;
+ state->context->server.try_logon_ex = false;
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ if ((state->validation_level == 6) &&
+ (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
+ {
+ state->context->server.try_validation6 = false;
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
+ return;
+ }
+
+ if (state->ro_creds == NULL) {
+ tevent_req_done(req);
+ return;
+ }
+
+ ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
+ if (!ok) {
+ /*
+ * We got a race, lets retry with on authenticator
+ * protection.
+ *
+ * netlogon_creds_cli_LogonSamLogon_start()
+ * will TALLOC_FREE(state->ro_creds);
+ */
+ state->try_logon_ex = false;
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+
+ status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
+ state->validation_level,
+ state->validation);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+ }
+
+ if (state->lk_creds == NULL) {
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->lk_creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+
+ if (state->context->server.try_logon_with) {
+ status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
+ state->validation,
+ &result);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
+ state->context->server.try_logon_with = false;
+ netlogon_creds_cli_LogonSamLogon_start(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = dcerpc_netr_LogonSamLogon_recv(subreq,
+ state->validation,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ *state->lk_creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->lk_creds);
+ TALLOC_FREE(state->lk_creds);
+
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
+ return;
+ }
+
+ status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
+ state->validation_level,
+ state->validation);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *validation_level,
+ union netr_Validation **validation,
+ uint8_t *authoritative,
+ uint32_t *flags)
+{
+ struct netlogon_creds_cli_LogonSamLogon_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonSamLogon_state);
+ NTSTATUS status;
+
+ /* authoritative is also returned on error */
+ *authoritative = state->authoritative;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ *validation_level = state->validation_level;
+ *validation = talloc_move(mem_ctx, &state->validation);
+ *flags = state->flags;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_LogonSamLogon(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ enum netr_LogonInfoClass logon_level,
+ const union netr_LogonLevel *logon,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *validation_level,
+ union netr_Validation **validation,
+ uint8_t *authoritative,
+ uint32_t *flags)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
+ logon_level, logon,
+ *flags);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
+ validation_level,
+ validation,
+ authoritative,
+ flags);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ const char *site_name;
+ uint32_t dns_ttl;
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const char *site_name,
+ uint32_t dns_ttl,
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->site_name = site_name;
+ state->dns_ttl = dns_ttl;
+ state->dns_names = dns_names;
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ state->site_name,
+ state->dns_ttl,
+ state->dns_names);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
+ req);
+}
+
+static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ /*
+ * We use state->dns_names as the memory context, as this is
+ * the only in/out variable and it has been overwritten by the
+ * out parameter from the server.
+ *
+ * We need to preserve the return value until the caller can use it.
+ */
+ status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
+ &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ return;
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const char *site_name,
+ uint32_t dns_ttl,
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
+ site_name,
+ dns_ttl,
+ dns_names);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_ServerGetTrustInfo_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ struct samr_Password new_owf_password;
+ struct samr_Password old_owf_password;
+ struct netr_TrustInfo *trust_info;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_ServerGetTrustInfo_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.account_name,
+ state->tmp_creds.secure_channel_type,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ &state->new_owf_password,
+ &state->old_owf_password,
+ &state->trust_info);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_ServerGetTrustInfo_done,
+ req);
+}
+
+static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ const struct samr_Password zero = {};
+ bool cmp;
+ bool ok;
+
+ /*
+ * We use state->dns_names as the memory context, as this is
+ * the only in/out variable and it has been overwritten by the
+ * out parameter from the server.
+ *
+ * We need to preserve the return value until the caller can use it.
+ */
+ status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+
+ cmp = mem_equal_const_time(state->new_owf_password.hash,
+ zero.hash, sizeof(zero.hash));
+ if (!cmp) {
+ status = netlogon_creds_des_decrypt(&state->tmp_creds,
+ &state->new_owf_password);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+ }
+ cmp = mem_equal_const_time(state->old_owf_password.hash,
+ zero.hash, sizeof(zero.hash));
+ if (!cmp) {
+ status = netlogon_creds_des_decrypt(&state->tmp_creds,
+ &state->old_owf_password);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct samr_Password *new_owf_password,
+ struct samr_Password *old_owf_password,
+ struct netr_TrustInfo **trust_info)
+{
+ struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_ServerGetTrustInfo_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (new_owf_password != NULL) {
+ *new_owf_password = state->new_owf_password;
+ }
+ if (old_owf_password != NULL) {
+ *old_owf_password = state->old_owf_password;
+ }
+ if (trust_info != NULL) {
+ *trust_info = talloc_move(mem_ctx, &state->trust_info);
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct samr_Password *new_owf_password,
+ struct samr_Password *old_owf_password,
+ struct netr_TrustInfo **trust_info)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
+ mem_ctx,
+ new_owf_password,
+ old_owf_password,
+ trust_info);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_GetForestTrustInformation_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ uint32_t flags;
+ struct lsa_ForestTrustInformation *forest_trust_info;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->flags = 0;
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_GetForestTrustInformation_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ state->flags,
+ &state->forest_trust_info);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_GetForestTrustInformation_done,
+ req);
+}
+
+static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ /*
+ * We use state->dns_names as the memory context, as this is
+ * the only in/out variable and it has been overwritten by the
+ * out parameter from the server.
+ *
+ * We need to preserve the return value until the caller can use it.
+ */
+ status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ return;
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_ForestTrustInformation **forest_trust_info)
+{
+ struct netlogon_creds_cli_GetForestTrustInformation_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_GetForestTrustInformation_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_ForestTrustInformation **forest_trust_info)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
+ mem_ctx,
+ forest_trust_info);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+struct netlogon_creds_cli_SendToSam_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ DATA_BLOB opaque;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ struct netr_SendToSamBase *message)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_SendToSam_state *state;
+ struct tevent_req *subreq;
+ enum ndr_err_code ndr_err;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_SendToSam_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
+ (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_SendToSam_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_SendToSam_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_SendToSam_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+ TALLOC_FREE(state->creds);
+}
+
+static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_SendToSam_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_SendToSam_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+ status = netlogon_creds_aes_encrypt(&state->tmp_creds,
+ state->opaque.data,
+ state->opaque.length);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+ } else {
+ status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
+ state->opaque.data,
+ state->opaque.length);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+ }
+
+ subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ state->opaque.data,
+ state->opaque.length);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_SendToSam_done,
+ req);
+}
+
+static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_SendToSam_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_SendToSam_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ TALLOC_FREE(state->creds);
+
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ return;
+ }
+
+ /*
+ * Creds must be stored before we send back application errors
+ * e.g. NT_STATUS_NOT_IMPLEMENTED
+ */
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, result);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_SendToSam_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ struct netr_SendToSamBase *message)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_SendToSam_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct netlogon_creds_cli_LogonGetDomainInfo_state {
+ struct tevent_context *ev;
+ struct netlogon_creds_cli_context *context;
+ struct dcerpc_binding_handle *binding_handle;
+
+ char *srv_name_slash;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ uint32_t level;
+ union netr_WorkstationInfo *query;
+ union netr_DomainInfo *info;
+
+ struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_CredentialState tmp_creds;
+ struct netr_Authenticator req_auth;
+ struct netr_Authenticator rep_auth;
+};
+
+static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
+ NTSTATUS status);
+static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
+
+struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint32_t level,
+ union netr_WorkstationInfo *query)
+{
+ struct tevent_req *req;
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->context = context;
+ state->binding_handle = b;
+
+ state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
+ context->server.computer);
+ if (tevent_req_nomem(state->srv_name_slash, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->level = level;
+ state->query = query;
+ state->info = talloc_zero(state, union netr_DomainInfo);
+ if (tevent_req_nomem(state->info, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ dcerpc_binding_handle_auth_info(state->binding_handle,
+ &state->auth_type,
+ &state->auth_level);
+
+ subreq = netlogon_creds_cli_lock_send(state, state->ev,
+ state->context);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonGetDomainInfo_locked,
+ req);
+
+ return req;
+}
+
+static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
+ NTSTATUS status)
+{
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+
+ if (state->creds == NULL) {
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ TALLOC_FREE(state->creds);
+ return;
+ }
+
+ netlogon_creds_cli_delete(state->context, state->creds);
+}
+
+static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
+
+static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+ NTSTATUS status;
+
+ status = netlogon_creds_cli_lock_recv(subreq, state,
+ &state->creds);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ switch (state->auth_level) {
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ } else {
+ uint32_t tmp = state->creds->negotiate_flags;
+
+ if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
+ /*
+ * if DCERPC_AUTH_TYPE_SCHANNEL is supported
+ * it should be used, which means
+ * we had a chance to verify no downgrade
+ * happened.
+ *
+ * This relies on netlogon_creds_cli_check*
+ * being called before, as first request after
+ * the DCERPC bind.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return;
+ }
+ }
+
+ /*
+ * we defer all callbacks in order to cleanup
+ * the database record.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ state->tmp_creds = *state->creds;
+ status = netlogon_creds_client_authenticator(&state->tmp_creds,
+ &state->req_auth);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ ZERO_STRUCT(state->rep_auth);
+
+ subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
+ state->binding_handle,
+ state->srv_name_slash,
+ state->tmp_creds.computer_name,
+ &state->req_auth,
+ &state->rep_auth,
+ state->level,
+ state->query,
+ state->info);
+ if (tevent_req_nomem(subreq, req)) {
+ status = NT_STATUS_NO_MEMORY;
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_set_callback(subreq,
+ netlogon_creds_cli_LogonGetDomainInfo_done,
+ req);
+}
+
+static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+ NTSTATUS status;
+ NTSTATUS result;
+ bool ok;
+
+ /*
+ * We use state->dns_names as the memory context, as this is
+ * the only in/out variable and it has been overwritten by the
+ * out parameter from the server.
+ *
+ * We need to preserve the return value until the caller can use it.
+ */
+ status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ return;
+ }
+
+ ok = netlogon_creds_client_check(&state->tmp_creds,
+ &state->rep_auth.cred);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ tevent_req_nterror(req, status);
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ return;
+ }
+
+ if (tevent_req_nterror(req, result)) {
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
+ return;
+ }
+
+ *state->creds = state->tmp_creds;
+ status = netlogon_creds_cli_store(state->context,
+ state->creds);
+ if (tevent_req_nterror(req, status)) {
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ union netr_DomainInfo **info)
+{
+ struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
+ tevent_req_data(req,
+ struct netlogon_creds_cli_LogonGetDomainInfo_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
+ tevent_req_received(req);
+ return status;
+ }
+
+ *info = talloc_move(mem_ctx, &state->info);
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ union netr_WorkstationInfo *query,
+ union netr_DomainInfo **info)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
+ level, query);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
+ mem_ctx,
+ info);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
new file mode 100644
index 0000000..600242e
--- /dev/null
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -0,0 +1,236 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ module to store/fetch session keys for the schannel client
+
+ Copyright (C) Stefan Metzmacher 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 NETLOGON_CREDS_CLI_H
+#define NETLOGON_CREDS_CLI_H
+
+#include "librpc/gen_ndr/dcerpc.h"
+#include "librpc/gen_ndr/schannel.h"
+
+struct netlogon_creds_cli_context;
+struct cli_credentials;
+struct messaging_context;
+struct dcerpc_binding_handle;
+struct db_context;
+
+NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx, struct db_context **db);
+NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx);
+void netlogon_creds_cli_close_global_db(void);
+
+void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx);
+
+NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
+ struct messaging_context *msg_ctx,
+ const char *client_account,
+ enum netr_SchannelType type,
+ const char *server_computer,
+ const char *server_netbios_domain,
+ const char *server_dns_domain,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_context **_context);
+NTSTATUS netlogon_creds_bind_cli_credentials(
+ struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
+ struct cli_credentials **pcli_creds);
+
+char *netlogon_creds_cli_debug_string(
+ const struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx);
+
+enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
+ struct netlogon_creds_cli_context *context);
+
+NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **_creds);
+bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
+ const struct netlogon_creds_CredentialState *creds1);
+
+NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds);
+NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
+ struct netlogon_creds_CredentialState *creds);
+NTSTATUS netlogon_creds_cli_delete_lck(
+ struct netlogon_creds_cli_context *context);
+
+struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context);
+NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **creds);
+NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState **creds);
+
+struct netlogon_creds_cli_lck;
+
+enum netlogon_creds_cli_lck_type {
+ NETLOGON_CREDS_CLI_LCK_NONE,
+ NETLOGON_CREDS_CLI_LCK_SHARED,
+ NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+};
+
+struct tevent_req *netlogon_creds_cli_lck_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ enum netlogon_creds_cli_lck_type type);
+NTSTATUS netlogon_creds_cli_lck_recv(
+ struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_cli_lck **lck);
+NTSTATUS netlogon_creds_cli_lck(
+ struct netlogon_creds_cli_context *context,
+ enum netlogon_creds_cli_lck_type type,
+ TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck);
+
+struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint8_t num_nt_hashes,
+ const struct samr_Password * const *nt_hashes);
+NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
+ uint8_t *idx_nt_hashes);
+NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint8_t num_nt_hashes,
+ const struct samr_Password * const *nt_hashes,
+ uint8_t *idx_nt_hashes);
+
+struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b);
+NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
+ union netr_Capabilities *capabilities);
+NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ union netr_Capabilities *capabilities);
+
+struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const DATA_BLOB *new_password,
+ const uint32_t *new_version);
+NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_ServerPasswordSet(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const DATA_BLOB *new_password,
+ const uint32_t *new_version);
+
+struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ enum netr_LogonInfoClass logon_level,
+ const union netr_LogonLevel *logon,
+ uint32_t flags);
+NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *validation_level,
+ union netr_Validation **validation,
+ uint8_t *authoritative,
+ uint32_t *flags);
+NTSTATUS netlogon_creds_cli_LogonSamLogon(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ enum netr_LogonInfoClass logon_level,
+ const union netr_LogonLevel *logon,
+ TALLOC_CTX *mem_ctx,
+ uint16_t *validation_level,
+ union netr_Validation **validation,
+ uint8_t *authoritative,
+ uint32_t *flags);
+struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const char *site_name,
+ uint32_t dns_ttl,
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names);
+NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ const char *site_name,
+ uint32_t dns_ttl,
+ struct NL_DNS_NAME_INFO_ARRAY *dns_names);
+
+struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b);
+NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct samr_Password *new_owf_password,
+ struct samr_Password *old_owf_password,
+ struct netr_TrustInfo **trust_info);
+NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct samr_Password *new_owf_password,
+ struct samr_Password *old_owf_password,
+ struct netr_TrustInfo **trust_info);
+
+struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b);
+NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_ForestTrustInformation **forest_trust_info);
+NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ struct lsa_ForestTrustInformation **forest_trust_info);
+
+struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ struct netr_SendToSamBase *message);
+NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_SendToSam(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ struct netr_SendToSamBase *message);
+
+struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ uint32_t level,
+ union netr_WorkstationInfo *query);
+NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ union netr_DomainInfo **info);
+NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
+ struct netlogon_creds_cli_context *context,
+ struct dcerpc_binding_handle *b,
+ TALLOC_CTX *mem_ctx,
+ uint32_t level,
+ union netr_WorkstationInfo *query,
+ union netr_DomainInfo **info);
+
+#endif /* NETLOGON_CREDS_CLI_H */
diff --git a/libcli/auth/ntlm_check.c b/libcli/auth/ntlm_check.c
new file mode 100644
index 0000000..a238870
--- /dev/null
+++ b/libcli/auth/ntlm_check.c
@@ -0,0 +1,656 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2004
+ Copyright (C) Gerald Carter 2003
+ Copyright (C) Luke Kenneth Casson Leighton 1996-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 "includes.h"
+#include "lib/crypto/md4.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "libcli/auth/libcli_auth.h"
+
+/****************************************************************************
+ Core of smb password checking routine.
+****************************************************************************/
+
+static bool smb_pwd_check_ntlmv1(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *nt_response,
+ const uint8_t *part_passwd,
+ const DATA_BLOB *sec_blob,
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uint8_t p24[24];
+ int rc;
+ bool ok;
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false ! */
+ return false;
+ }
+
+ if (sec_blob->length != 8) {
+ DBG_ERR("incorrect challenge size (%zu)\n", sec_blob->length);
+ return false;
+ }
+
+ if (nt_response->length != 24) {
+ DBG_ERR("incorrect password length (%zu)\n",
+ nt_response->length);
+ return false;
+ }
+
+ rc = SMBOWFencrypt(part_passwd, sec_blob->data, p24);
+ if (rc != 0) {
+ return false;
+ }
+
+#if DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |\n"));
+ dump_data(100, part_passwd, 16);
+ DEBUGADD(100,("Password from client was |\n"));
+ dump_data(100, nt_response->data, nt_response->length);
+ DEBUGADD(100,("Given challenge was |\n"));
+ dump_data(100, sec_blob->data, sec_blob->length);
+ DEBUGADD(100,("Value from encryption was |\n"));
+ dump_data(100, p24, 24);
+#endif
+ ok = mem_equal_const_time(p24, nt_response->data, 24);
+ if (!ok) {
+ return false;
+ }
+ if (user_sess_key != NULL) {
+ *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16);
+ if (user_sess_key->data == NULL) {
+ DBG_ERR("data_blob_talloc failed\n");
+ return false;
+ }
+ SMBsesskeygen_ntv1(part_passwd, user_sess_key->data);
+ }
+ return true;
+}
+
+/****************************************************************************
+ Core of smb password checking routine. (NTLMv2, LMv2)
+ Note: The same code works with both NTLMv2 and LMv2.
+****************************************************************************/
+
+static bool smb_pwd_check_ntlmv2(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *ntv2_response,
+ const uint8_t *part_passwd,
+ const DATA_BLOB *sec_blob,
+ const char *user, const char *domain,
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uint8_t kr[16];
+ uint8_t value_from_encryption[16];
+ DATA_BLOB client_key_data;
+ NTSTATUS status;
+ bool ok;
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false */
+ return false;
+ }
+
+ if (sec_blob->length != 8) {
+ DBG_ERR("incorrect challenge size (%zu)\n", sec_blob->length);
+ return false;
+ }
+
+ if (ntv2_response->length < 24) {
+ /* We MUST have more than 16 bytes, or the stuff below will go
+ crazy. No known implementation sends less than the 24 bytes
+ for LMv2, let alone NTLMv2. */
+ DBG_ERR("incorrect password length (%zu)\n",
+ ntv2_response->length);
+ return false;
+ }
+
+ client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16);
+ /*
+ todo: should we be checking this for anything? We can't for LMv2,
+ but for NTLMv2 it is meant to contain the current time etc.
+ */
+
+ if (!ntv2_owf_gen(part_passwd, user, domain, kr)) {
+ return false;
+ }
+
+ status = SMBOWFencrypt_ntv2(kr,
+ sec_blob,
+ &client_key_data,
+ value_from_encryption);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+#if DEBUG_PASSWORD
+ DEBUG(100,("Part password (P16) was |\n"));
+ dump_data(100, part_passwd, 16);
+ DEBUGADD(100,("Password from client was |\n"));
+ dump_data(100, ntv2_response->data, ntv2_response->length);
+ DEBUGADD(100,("Variable data from client was |\n"));
+ dump_data(100, client_key_data.data, client_key_data.length);
+ DEBUGADD(100,("Given challenge was |\n"));
+ dump_data(100, sec_blob->data, sec_blob->length);
+ DEBUGADD(100,("Value from encryption was |\n"));
+ dump_data(100, value_from_encryption, 16);
+#endif
+ data_blob_clear_free(&client_key_data);
+
+ ok = mem_equal_const_time(value_from_encryption, ntv2_response->data, 16);
+ if (!ok) {
+ return false;
+ }
+ if (user_sess_key != NULL) {
+ *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16);
+ if (user_sess_key->data == NULL) {
+ DBG_ERR("data_blob_talloc failed\n");
+ return false;
+ }
+
+ status = SMBsesskeygen_ntv2(
+ kr, value_from_encryption, user_sess_key->data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/****************************************************************************
+ Core of smb password checking routine. (NTLMv2, LMv2)
+ Note: The same code works with both NTLMv2 and LMv2.
+****************************************************************************/
+
+static bool smb_sess_key_ntlmv2(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *ntv2_response,
+ const uint8_t *part_passwd,
+ const DATA_BLOB *sec_blob,
+ const char *user, const char *domain,
+ DATA_BLOB *user_sess_key)
+{
+ /* Finish the encryption of part_passwd. */
+ uint8_t kr[16];
+ uint8_t value_from_encryption[16];
+ DATA_BLOB client_key_data;
+ NTSTATUS status;
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false */
+ return false;
+ }
+
+ if (sec_blob->length != 8) {
+ DBG_ERR("incorrect challenge size (%zu)\n", sec_blob->length);
+ return false;
+ }
+
+ if (ntv2_response->length < 24) {
+ /* We MUST have more than 16 bytes, or the stuff below will go
+ crazy. No known implementation sends less than the 24 bytes
+ for LMv2, let alone NTLMv2. */
+ DBG_ERR("incorrect password length (%zu)\n",
+ ntv2_response->length);
+ return false;
+ }
+
+ client_key_data = data_blob_talloc(mem_ctx, ntv2_response->data+16, ntv2_response->length-16);
+
+ if (!ntv2_owf_gen(part_passwd, user, domain, kr)) {
+ return false;
+ }
+
+ status = SMBOWFencrypt_ntv2(kr,
+ sec_blob,
+ &client_key_data,
+ value_from_encryption);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ *user_sess_key = data_blob_talloc(mem_ctx, NULL, 16);
+ if (user_sess_key->data == NULL) {
+ DBG_ERR("data_blob_talloc failed\n");
+ return false;
+ }
+ status = SMBsesskeygen_ntv2(kr,
+ value_from_encryption,
+ user_sess_key->data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Compare password hashes against those from the SAM
+ *
+ * @param mem_ctx talloc context
+ * @param client_lanman LANMAN password hash, as supplied by the client
+ * @param client_nt NT (MD4) password hash, as supplied by the client
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param stored_lanman LANMAN password hash, as stored on the SAM
+ * @param stored_nt NT (MD4) password hash, as stored on the SAM
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx,
+ bool lanman_auth,
+ enum ntlm_auth_level ntlm_auth,
+ const struct samr_Password *client_lanman,
+ const struct samr_Password *client_nt,
+ const char *username,
+ const struct samr_Password *stored_lanman,
+ const struct samr_Password *stored_nt)
+{
+ if (ntlm_auth == NTLM_AUTH_DISABLED) {
+ DBG_WARNING("hash_password_check: NTLM authentication not "
+ "permitted by configuration.\n");
+ return NT_STATUS_NTLM_BLOCKED;
+ }
+
+ if (stored_nt == NULL) {
+ DEBUG(3,("hash_password_check: NO NT password stored for user %s.\n",
+ username));
+ }
+
+ if (client_nt && stored_nt) {
+ if (mem_equal_const_time(client_nt->hash, stored_nt->hash, sizeof(stored_nt->hash))) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("hash_password_check: Interactive logon: NT password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ } else if (client_lanman && stored_lanman) {
+ if (!lanman_auth) {
+ DEBUG(3,("hash_password_check: Interactive logon: only LANMAN password supplied for user %s, and LM passwords are disabled!\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ if (strchr_m(username, '@')) {
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ if (mem_equal_const_time(client_lanman->hash, stored_lanman->hash, sizeof(stored_lanman->hash))) {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("hash_password_check: Interactive logon: LANMAN password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ }
+ if (strchr_m(username, '@')) {
+ return NT_STATUS_NOT_FOUND;
+ }
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
+/**
+ * Check a challenge-response password against the value of the NT or
+ * LM password hash.
+ *
+ * @param mem_ctx talloc context
+ * @param challenge 8-byte challenge. If all zero, forces plaintext comparison
+ * @param nt_response 'unicode' NT response to the challenge, or unicode password
+ * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param stored_lanman LANMAN ASCII password from our passdb or similar
+ * @param stored_nt MD4 unicode password from our passdb or similar
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx,
+ bool lanman_auth,
+ enum ntlm_auth_level ntlm_auth,
+ uint32_t logon_parameters,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ const char *username,
+ const char *client_username,
+ const char *client_domain,
+ const struct samr_Password *stored_lanman,
+ const struct samr_Password *stored_nt,
+ DATA_BLOB *user_sess_key,
+ DATA_BLOB *lm_sess_key)
+{
+ DATA_BLOB tmp_sess_key;
+ const char *upper_client_domain = NULL;
+
+ if (ntlm_auth == NTLM_AUTH_DISABLED) {
+ DBG_WARNING("ntlm_password_check: NTLM authentication not "
+ "permitted by configuration.\n");
+ return NT_STATUS_NTLM_BLOCKED;
+ }
+
+ if (client_domain != NULL) {
+ upper_client_domain = talloc_strdup_upper(mem_ctx, client_domain);
+ if (upper_client_domain == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (stored_nt == NULL) {
+ DEBUG(3,("ntlm_password_check: NO NT password stored for user %s.\n",
+ username));
+ }
+
+ *lm_sess_key = data_blob(NULL, 0);
+ *user_sess_key = data_blob(NULL, 0);
+
+ /* Check for cleartext netlogon. Used by Exchange 5.5. */
+ if ((logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_ALLOWED)
+ && challenge->length == 8
+ && (all_zero(challenge->data, challenge->length))) {
+ struct samr_Password client_nt;
+ struct samr_Password client_lm;
+ char *unix_pw = NULL;
+ bool lm_ok;
+ size_t converted_size = 0;
+
+ DEBUG(4,("ntlm_password_check: checking plaintext passwords for user %s\n",
+ username));
+ mdfour(client_nt.hash, nt_response->data, nt_response->length);
+
+ if (lm_response->length &&
+ (convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX,
+ lm_response->data, lm_response->length,
+ &unix_pw, &converted_size))) {
+ if (E_deshash(unix_pw, client_lm.hash)) {
+ lm_ok = true;
+ } else {
+ lm_ok = false;
+ }
+ } else {
+ lm_ok = false;
+ }
+ return hash_password_check(mem_ctx,
+ lanman_auth,
+ ntlm_auth,
+ lm_ok ? &client_lm : NULL,
+ nt_response->length ? &client_nt : NULL,
+ username,
+ stored_lanman, stored_nt);
+ }
+
+ if (nt_response->length != 0 && nt_response->length < 24) {
+ DBG_NOTICE("invalid NT password length (%zu) for user %s\n",
+ nt_response->length,
+ username);
+ }
+
+ if (nt_response->length > 24 && stored_nt) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it
+ */
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with domain [%s]\n",
+ client_domain ? client_domain : "<NULL>"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ client_domain,
+ user_sess_key)) {
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password with uppercased version of domain [%s]\n",
+ upper_client_domain ? upper_client_domain : "<NULL>"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ upper_client_domain,
+ user_sess_key)) {
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking NTLMv2 password without a domain\n"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ "",
+ user_sess_key)) {
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NTLMv2 password check failed\n"));
+ }
+ } else if (nt_response->length == 24 && stored_nt) {
+ if (ntlm_auth == NTLM_AUTH_ON
+ || (ntlm_auth == NTLM_AUTH_MSCHAPv2_NTLMV2_ONLY && (logon_parameters & MSV1_0_ALLOW_MSVCHAPV2))) {
+ /* We have the NT MD4 hash challenge available - see if we can
+ use it (ie. does it exist in the smbpasswd file).
+ */
+ DEBUG(4,("ntlm_password_check: Checking NT MD4 password\n"));
+ if (smb_pwd_check_ntlmv1(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ user_sess_key)) {
+ /* The LM session key for this response is not very secure,
+ so use it only if we otherwise allow LM authentication */
+
+ if (lanman_auth && stored_lanman) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("ntlm_password_check: NT MD4 password check failed for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+ } else {
+ DEBUG(2,("ntlm_password_check: NTLMv1 passwords NOT PERMITTED for user %s\n",
+ username));
+ /* no return, because we might pick up LMv2 in the LM field */
+ }
+ }
+
+ if (lm_response->length == 0) {
+ DEBUG(3,("ntlm_password_check: NEITHER LanMan nor NT password supplied for user %s\n",
+ username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (lm_response->length < 24) {
+ DBG_NOTICE("invalid LanMan password length (%zu) for "
+ "user %s\n",
+ nt_response->length, username);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ if (!lanman_auth) {
+ DEBUG(3,("ntlm_password_check: Lanman passwords NOT PERMITTED for user %s\n",
+ username));
+ } else if (!stored_lanman) {
+ DEBUG(3,("ntlm_password_check: NO LanMan password set for user %s (and no NT password supplied)\n",
+ username));
+ } else if (strchr_m(username, '@')) {
+ DEBUG(3,("ntlm_password_check: NO LanMan password allowed for username@realm logins (user: %s)\n",
+ username));
+ } else {
+ DEBUG(4,("ntlm_password_check: Checking LM password\n"));
+ if (smb_pwd_check_ntlmv1(mem_ctx,
+ lm_response,
+ stored_lanman->hash, challenge,
+ NULL)) {
+ /* The session key for this response is still very odd.
+ It not very secure, so use it only if we otherwise
+ allow LM authentication */
+
+ if (lanman_auth && stored_lanman) {
+ uint8_t first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, stored_lanman->hash, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16);
+ *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8);
+ }
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (!stored_nt) {
+ DEBUG(4,("ntlm_password_check: LM password check failed for user, no NT password %s\n",username));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes.
+ - related to Win9X, legacy NAS pass-though authentication
+ */
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password with domain %s\n",
+ client_domain ? client_domain : "<NULL>"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ lm_response,
+ stored_nt->hash, challenge,
+ client_username,
+ client_domain,
+ &tmp_sess_key)) {
+ if (nt_response->length > 24) {
+ /* If NTLMv2 authentication has preceded us
+ * (even if it failed), then use the session
+ * key from that. See the RPC-SAMLOGON
+ * torture test */
+ smb_sess_key_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ client_domain,
+ user_sess_key);
+ } else {
+ /* Otherwise, use the LMv2 session key */
+ *user_sess_key = tmp_sess_key;
+ }
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password with upper-cased version of domain %s\n",
+ upper_client_domain ? upper_client_domain : "<NULL>"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ lm_response,
+ stored_nt->hash, challenge,
+ client_username,
+ upper_client_domain,
+ &tmp_sess_key)) {
+ if (nt_response->length > 24) {
+ /* If NTLMv2 authentication has preceded us
+ * (even if it failed), then use the session
+ * key from that. See the RPC-SAMLOGON
+ * torture test */
+ smb_sess_key_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ upper_client_domain,
+ user_sess_key);
+ } else {
+ /* Otherwise, use the LMv2 session key */
+ *user_sess_key = tmp_sess_key;
+ }
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(4,("ntlm_password_check: Checking LMv2 password without a domain\n"));
+ if (smb_pwd_check_ntlmv2(mem_ctx,
+ lm_response,
+ stored_nt->hash, challenge,
+ client_username,
+ "",
+ &tmp_sess_key)) {
+ if (nt_response->length > 24) {
+ /* If NTLMv2 authentication has preceded us
+ * (even if it failed), then use the session
+ * key from that. See the RPC-SAMLOGON
+ * torture test */
+ smb_sess_key_ntlmv2(mem_ctx,
+ nt_response,
+ stored_nt->hash, challenge,
+ client_username,
+ "",
+ user_sess_key);
+ } else {
+ /* Otherwise, use the LMv2 session key */
+ *user_sess_key = tmp_sess_key;
+ }
+ if (user_sess_key->length) {
+ *lm_sess_key = data_blob_talloc(mem_ctx, user_sess_key->data, MIN(8, user_sess_key->length));
+ }
+ return NT_STATUS_OK;
+ }
+
+ /* Apparently NT accepts NT responses in the LM field
+ - I think this is related to Win9X pass-though authentication
+ */
+ DEBUG(4,("ntlm_password_check: Checking NT MD4 password in LM field\n"));
+ if (ntlm_auth == NTLM_AUTH_ON) {
+ if (smb_pwd_check_ntlmv1(mem_ctx,
+ lm_response,
+ stored_nt->hash, challenge,
+ NULL)) {
+ /* The session key for this response is still very odd.
+ It not very secure, so use it only if we otherwise
+ allow LM authentication */
+
+ if (lanman_auth && stored_lanman) {
+ uint8_t first_8_lm_hash[16];
+ memcpy(first_8_lm_hash, stored_lanman->hash, 8);
+ memset(first_8_lm_hash + 8, '\0', 8);
+ *user_sess_key = data_blob_talloc(mem_ctx, first_8_lm_hash, 16);
+ *lm_sess_key = data_blob_talloc(mem_ctx, stored_lanman->hash, 8);
+ }
+ return NT_STATUS_OK;
+ }
+ DEBUG(3,("ntlm_password_check: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",username));
+ } else {
+ DEBUG(3,("ntlm_password_check: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",username));
+ }
+
+ /* Try and match error codes */
+ if (strchr_m(username, '@')) {
+ return NT_STATUS_NOT_FOUND;
+ }
+ return NT_STATUS_WRONG_PASSWORD;
+}
+
diff --git a/libcli/auth/ntlm_check.h b/libcli/auth/ntlm_check.h
new file mode 100644
index 0000000..3fcd1f4
--- /dev/null
+++ b/libcli/auth/ntlm_check.h
@@ -0,0 +1,87 @@
+/*
+ Unix SMB/CIFS implementation.
+ Password and authentication handling
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2004
+ Copyright (C) Gerald Carter 2003
+ Copyright (C) Luke Kenneth Casson Leighton 1996-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 __LIBCLI_AUTH_NTLM_CHECK_H__
+#define __LIBCLI_AUTH_NTLM_CHECK_H__
+
+/* mangled names options */
+enum ntlm_auth_level {NTLM_AUTH_DISABLED, NTLM_AUTH_ON,
+ NTLM_AUTH_NTLMV2_ONLY,
+ NTLM_AUTH_MSCHAPv2_NTLMV2_ONLY};
+
+struct samr_Password;
+
+/**
+ * Compare password hashes against those from the SAM
+ *
+ * @param mem_ctx talloc context
+ * @param client_lanman LANMAN password hash, as supplied by the client
+ * @param client_nt NT (MD4) password hash, as supplied by the client
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param stored_lanman LANMAN password hash, as stored on the SAM
+ * @param stored_nt NT (MD4) password hash, as stored on the SAM
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS hash_password_check(TALLOC_CTX *mem_ctx,
+ bool lanman_auth,
+ enum ntlm_auth_level ntlm_auth,
+ const struct samr_Password *client_lanman,
+ const struct samr_Password *client_nt,
+ const char *username,
+ const struct samr_Password *stored_lanman,
+ const struct samr_Password *stored_nt);
+
+/**
+ * Check a challenge-response password against the value of the NT or
+ * LM password hash.
+ *
+ * @param mem_ctx talloc context
+ * @param challenge 8-byte challenge. If all zero, forces plaintext comparison
+ * @param nt_response 'unicode' NT response to the challenge, or unicode password
+ * @param lm_response ASCII or LANMAN response to the challenge, or password in DOS code page
+ * @param username internal Samba username, for log messages
+ * @param client_username username the client used
+ * @param client_domain domain name the client used (may be mapped)
+ * @param stored_lanman LANMAN ASCII password from our passdb or similar
+ * @param stored_nt MD4 unicode password from our passdb or similar
+ * @param user_sess_key User session key
+ * @param lm_sess_key LM session key (first 8 bytes of the LM hash)
+ */
+
+NTSTATUS ntlm_password_check(TALLOC_CTX *mem_ctx,
+ bool lanman_auth,
+ enum ntlm_auth_level ntlm_auth,
+ uint32_t logon_parameters,
+ const DATA_BLOB *challenge,
+ const DATA_BLOB *lm_response,
+ const DATA_BLOB *nt_response,
+ const char *username,
+ const char *client_username,
+ const char *client_domain,
+ const struct samr_Password *stored_lanman,
+ const struct samr_Password *stored_nt,
+ DATA_BLOB *user_sess_key,
+ DATA_BLOB *lm_sess_key);
+
+#endif /* __LIBCLI_AUTH_NTLM_CHECK_H__ */
diff --git a/libcli/auth/pam_errors.c b/libcli/auth/pam_errors.c
new file mode 100644
index 0000000..5592d39
--- /dev/null
+++ b/libcli/auth/pam_errors.c
@@ -0,0 +1,143 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * PAM error mapping functions
+ * 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/>.
+ */
+
+#include "includes.h"
+#include "../libcli/auth/pam_errors.h"
+
+#ifdef WITH_PAM
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+
+#if defined(PAM_AUTHTOK_RECOVERY_ERR) && !defined(PAM_AUTHTOK_RECOVER_ERR)
+#define PAM_AUTHTOK_RECOVER_ERR PAM_AUTHTOK_RECOVERY_ERR
+#endif
+
+/* PAM -> NT_STATUS map */
+static const struct {
+ int pam_code;
+ NTSTATUS ntstatus;
+} pam_to_nt_status_map[] = {
+ {PAM_OPEN_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SYMBOL_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SERVICE_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_SYSTEM_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_BUF_ERR, NT_STATUS_NO_MEMORY},
+ {PAM_PERM_DENIED, NT_STATUS_ACCESS_DENIED},
+ {PAM_AUTH_ERR, NT_STATUS_WRONG_PASSWORD},
+ {PAM_CRED_INSUFFICIENT, NT_STATUS_INSUFFICIENT_LOGON_INFO}, /* FIXME: Is this correct? */
+ {PAM_AUTHINFO_UNAVAIL, NT_STATUS_LOGON_FAILURE},
+ {PAM_USER_UNKNOWN, NT_STATUS_NO_SUCH_USER},
+ {PAM_MAXTRIES, NT_STATUS_REMOTE_SESSION_LIMIT}, /* FIXME: Is this correct? */
+ {PAM_NEW_AUTHTOK_REQD, NT_STATUS_PASSWORD_MUST_CHANGE},
+ {PAM_ACCT_EXPIRED, NT_STATUS_ACCOUNT_EXPIRED},
+ {PAM_SESSION_ERR, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {PAM_CRED_UNAVAIL, NT_STATUS_NO_TOKEN}, /* FIXME: Is this correct? */
+ {PAM_CRED_EXPIRED, NT_STATUS_PASSWORD_EXPIRED}, /* FIXME: Is this correct? */
+ {PAM_CRED_ERR, NT_STATUS_UNSUCCESSFUL},
+ {PAM_AUTHTOK_ERR, NT_STATUS_UNSUCCESSFUL},
+#ifdef PAM_AUTHTOK_RECOVER_ERR
+ {PAM_AUTHTOK_RECOVER_ERR, NT_STATUS_UNSUCCESSFUL},
+#endif
+ {PAM_AUTHTOK_EXPIRED, NT_STATUS_PASSWORD_EXPIRED},
+ {PAM_SUCCESS, NT_STATUS_OK}
+};
+
+/* NT_STATUS -> PAM map */
+static const struct {
+ NTSTATUS ntstatus;
+ int pam_code;
+} nt_status_to_pam_map[] = {
+ {NT_STATUS_UNSUCCESSFUL, PAM_SYSTEM_ERR},
+ {NT_STATUS_NO_SUCH_USER, PAM_USER_UNKNOWN},
+ {NT_STATUS_WRONG_PASSWORD, PAM_AUTH_ERR},
+ {NT_STATUS_LOGON_FAILURE, PAM_AUTH_ERR},
+ {NT_STATUS_ACCOUNT_EXPIRED, PAM_ACCT_EXPIRED},
+ {NT_STATUS_ACCOUNT_DISABLED, PAM_ACCT_EXPIRED},
+ {NT_STATUS_PASSWORD_EXPIRED, PAM_AUTHTOK_EXPIRED},
+ {NT_STATUS_PASSWORD_MUST_CHANGE, PAM_NEW_AUTHTOK_REQD},
+ {NT_STATUS_ACCOUNT_LOCKED_OUT, PAM_MAXTRIES},
+ {NT_STATUS_NO_MEMORY, PAM_BUF_ERR},
+ {NT_STATUS_PASSWORD_RESTRICTION, PAM_AUTHTOK_ERR},
+ {NT_STATUS_PWD_HISTORY_CONFLICT, PAM_AUTHTOK_ERR},
+ {NT_STATUS_PWD_TOO_RECENT, PAM_AUTHTOK_ERR},
+ {NT_STATUS_PWD_TOO_SHORT, PAM_AUTHTOK_ERR},
+ {NT_STATUS_BACKUP_CONTROLLER, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_NO_LOGON_SERVERS, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_INVALID_WORKSTATION, PAM_PERM_DENIED},
+ {NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT, PAM_AUTHINFO_UNAVAIL},
+ {NT_STATUS_OK, PAM_SUCCESS}
+};
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error)
+{
+ int i;
+ if (pam_error == 0) return NT_STATUS_OK;
+
+ for (i=0; NT_STATUS_V(pam_to_nt_status_map[i].ntstatus); i++) {
+ if (pam_error == pam_to_nt_status_map[i].pam_code)
+ return pam_to_nt_status_map[i].ntstatus;
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status)
+{
+ int i;
+ if NT_STATUS_IS_OK(nt_status) return PAM_SUCCESS;
+
+ for (i=0; NT_STATUS_V(nt_status_to_pam_map[i].ntstatus); i++) {
+ if (NT_STATUS_EQUAL(nt_status,nt_status_to_pam_map[i].ntstatus))
+ return nt_status_to_pam_map[i].pam_code;
+ }
+ return PAM_SYSTEM_ERR;
+}
+
+#else
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error)
+{
+ if (pam_error == 0) return NT_STATUS_OK;
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status)
+{
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_OK)) return 0;
+ return 4; /* PAM_SYSTEM_ERR */
+}
+
+#endif
diff --git a/libcli/auth/pam_errors.h b/libcli/auth/pam_errors.h
new file mode 100644
index 0000000..128910f
--- /dev/null
+++ b/libcli/auth/pam_errors.h
@@ -0,0 +1,33 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * PAM error mapping functions
+ * 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 __LIBCLI_AUTH_PAM_ERRORS_H__
+#define __LIBCLI_AUTH_PAM_ERRORS_H__
+
+/*****************************************************************************
+convert a PAM error to a NT status32 code
+ *****************************************************************************/
+NTSTATUS pam_to_nt_status(int pam_error);
+
+/*****************************************************************************
+convert an NT status32 code to a PAM error
+ *****************************************************************************/
+int nt_status_to_pam(NTSTATUS nt_status);
+
+#endif /* __LIBCLI_AUTH_PAM_ERRORS_H__ */
diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
new file mode 100644
index 0000000..b202542
--- /dev/null
+++ b/libcli/auth/proto.h
@@ -0,0 +1,296 @@
+#ifndef _LIBCLI_AUTH_PROTO_H__
+#define _LIBCLI_AUTH_PROTO_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+
+#include "lib/crypto/gnutls_helpers.h"
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+
+/* The following definitions come from libcli/auth/credentials.c */
+
+bool netlogon_creds_is_random_challenge(const struct netr_Credential *challenge);
+void netlogon_creds_random_challenge(struct netr_Credential *challenge);
+
+NTSTATUS netlogon_creds_des_encrypt_LMKey(struct netlogon_creds_CredentialState *creds,
+ struct netr_LMSessionKey *key);
+NTSTATUS netlogon_creds_des_decrypt_LMKey(struct netlogon_creds_CredentialState *creds,
+ struct netr_LMSessionKey *key);
+NTSTATUS netlogon_creds_des_encrypt(struct netlogon_creds_CredentialState *creds,
+ struct samr_Password *pass);
+NTSTATUS netlogon_creds_des_decrypt(struct netlogon_creds_CredentialState *creds,
+ struct samr_Password *pass);
+NTSTATUS netlogon_creds_arcfour_crypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len);
+NTSTATUS netlogon_creds_aes_encrypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len);
+NTSTATUS netlogon_creds_aes_decrypt(struct netlogon_creds_CredentialState *creds,
+ uint8_t *data,
+ size_t len);
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the client specific functions
+******************************************************************/
+struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *mem_ctx,
+ const char *client_account,
+ const char *client_computer_name,
+ uint16_t secure_channel_type,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password,
+ struct netr_Credential *initial_credential,
+ uint32_t negotiate_flags);
+struct netlogon_creds_CredentialState *netlogon_creds_client_init_session_key(TALLOC_CTX *mem_ctx,
+ const uint8_t session_key[16]);
+NTSTATUS
+netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *creds,
+ struct netr_Authenticator *next);
+bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Credential *received_credentials);
+struct netlogon_creds_CredentialState *netlogon_creds_copy(
+ TALLOC_CTX *mem_ctx,
+ const struct netlogon_creds_CredentialState *creds_in);
+
+/*****************************************************************
+The above functions are common to the client and server interface
+next comes the server specific functions
+******************************************************************/
+struct netlogon_creds_CredentialState *netlogon_creds_server_init(TALLOC_CTX *mem_ctx,
+ const char *client_account,
+ const char *client_computer_name,
+ uint16_t secure_channel_type,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const struct samr_Password *machine_password,
+ const struct netr_Credential *credentials_in,
+ struct netr_Credential *credentials_out,
+ uint32_t negotiate_flags);
+NTSTATUS netlogon_creds_server_step_check(struct netlogon_creds_CredentialState *creds,
+ const struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator) ;
+NTSTATUS netlogon_creds_decrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation);
+NTSTATUS netlogon_creds_encrypt_samlogon_validation(struct netlogon_creds_CredentialState *creds,
+ uint16_t validation_level,
+ union netr_Validation *validation);
+NTSTATUS netlogon_creds_decrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon);
+NTSTATUS netlogon_creds_encrypt_samlogon_logon(struct netlogon_creds_CredentialState *creds,
+ enum netr_LogonInfoClass level,
+ union netr_LogonLevel *logon);
+union netr_LogonLevel *netlogon_creds_shallow_copy_logon(TALLOC_CTX *mem_ctx,
+ enum netr_LogonInfoClass level,
+ const union netr_LogonLevel *in);
+
+/* The following definitions come from libcli/auth/session.c */
+
+int sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key,
+ enum samba_gnutls_direction encrypt);
+DATA_BLOB sess_encrypt_string(const char *str, const DATA_BLOB *session_key);
+char *sess_decrypt_string(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob, const DATA_BLOB *session_key);
+DATA_BLOB sess_encrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob_in, const DATA_BLOB *session_key);
+NTSTATUS sess_decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const DATA_BLOB *session_key,
+ DATA_BLOB *ret);
+
+/* The following definitions come from libcli/auth/smbencrypt.c */
+
+int SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24]);
+bool SMBencrypt(const char *passwd, const uint8_t *c8, uint8_t p24[24]);
+
+/**
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with md4, caller allocated 16 byte buffer
+ */
+bool E_md4hash(const char *passwd, uint8_t p16[16]);
+
+/**
+ * Creates the DES forward-only Hash of the users password in DOS ASCII charset
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with DES, caller allocated 16 byte buffer
+ * @return false if password was > 14 characters, and therefore may be incorrect, otherwise true
+ * @note p16 is filled in regardless
+ */
+bool E_deshash(const char *passwd, uint8_t p16[16]);
+
+/**
+ * Creates the MD4 and DES (LM) Hash of the users password.
+ * MD4 is of the NT Unicode, DES is of the DOS UPPERCASE password.
+ * @param passwd password in 'unix' charset.
+ * @param nt_p16 return password hashed with md4, caller allocated 16 byte buffer
+ * @param p16 return password hashed with des, caller allocated 16 byte buffer
+ */
+void nt_lm_owf_gen(const char *pwd, uint8_t nt_p16[16], uint8_t p16[16]);
+bool ntv2_owf_gen(const uint8_t owf[16],
+ const char *user_in, const char *domain_in,
+ uint8_t kr_buf[16]);
+int SMBOWFencrypt(const uint8_t passwd[16], const uint8_t *c8, uint8_t p24[24]);
+int SMBNTencrypt_hash(const uint8_t nt_hash[16], const uint8_t *c8, uint8_t *p24);
+int SMBNTencrypt(const char *passwd, const uint8_t *c8, uint8_t *p24);
+NTSTATUS SMBOWFencrypt_ntv2(const uint8_t kr[16],
+ const DATA_BLOB *srv_chal,
+ const DATA_BLOB *smbcli_chal,
+ uint8_t resp_buf[16]);
+NTSTATUS SMBsesskeygen_ntv2(const uint8_t kr[16],
+ const uint8_t *nt_resp,
+ uint8_t sess_key[16]);
+void SMBsesskeygen_ntv1(const uint8_t kr[16], uint8_t sess_key[16]);
+NTSTATUS SMBsesskeygen_lm_sess_key(const uint8_t lm_hash[16],
+ const uint8_t lm_resp[24], /* only uses 8 */
+ uint8_t sess_key[16]);
+DATA_BLOB NTLMv2_generate_names_blob(TALLOC_CTX *mem_ctx,
+ const char *hostname,
+ const char *domain);
+bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx,
+ const char *user, const char *domain, const uint8_t nt_hash[16],
+ const DATA_BLOB *server_chal,
+ const NTTIME *server_timestamp,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
+bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx,
+ const char *user, const char *domain,
+ const char *password,
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key) ;
+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
+ const char *account_domain,
+ const DATA_BLOB response,
+ const struct netlogon_creds_CredentialState *creds,
+ const char *workgroup);
+
+/***********************************************************
+ encode a password buffer with a unicode password. The buffer
+ is filled with random data to make it harder to attack.
+************************************************************/
+bool encode_pw_buffer(uint8_t buffer[516], const char *password, int string_flags);
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_len is the length in bytes of the possibly mulitbyte
+ returned password including termination.
+************************************************************/
+bool decode_pw_buffer(TALLOC_CTX *ctx,
+ uint8_t in_buffer[516],
+ char **pp_new_pwrd,
+ size_t *new_pw_len,
+ charset_t string_charset);
+
+/**
+ * @brief Encode an password buffer before we encrypt it.
+ *
+ * @param buffer[514] The buffer to encode into.
+ *
+ * @param password The password we want to encode into the buffer.
+ *
+ * @param string_flags String flags for encoding (e.g. STR_UNICODE).
+ *
+ * @return true on success, false otherwise.
+ */
+bool encode_pwd_buffer514_from_str(uint8_t buffer[514],
+ const char *password,
+ uint32_t string_flags);
+
+/**
+ * @brief Extract AES password blob from buffer.
+ *
+ * This extracts the password from the in_buffer as a data blob. It should
+ * then contain an UTF-16 encoded password.
+ *
+ * @param mem_ctx The memory context to allowcate the password on.
+ *
+ * @param in_buffer[514] The input buffer to extract the password from.
+ *
+ * @param new_password A pointer to the store the extracted password blob.
+ *
+ * @return true on success, false otherwise.
+ */
+bool extract_pwd_blob_from_buffer514(TALLOC_CTX *mem_ctx,
+ const uint8_t in_buffer[514],
+ DATA_BLOB *new_password);
+
+/**
+ * @brief Decode AES password buffer to password in the given charset.
+ *
+ * @param mem_ctx The memory context to allocate the decoded password on.
+ *
+ * @param in_buffer[514] The in buffer with the decrypted password data.
+ *
+ * @param string_charset The charset to decode to.
+ *
+ * @param decoded_password A pointer to store the blob for the decoded password.
+ * It ensures that the password is NULL terminated.
+ *
+ * @return true on success, false otherwise.
+ */
+bool decode_pwd_string_from_buffer514(TALLOC_CTX *mem_ctx,
+ const uint8_t in_buffer[514],
+ charset_t string_charset,
+ DATA_BLOB *decoded_password);
+
+/***********************************************************
+ Encode an arc4 password change buffer.
+************************************************************/
+NTSTATUS encode_rc4_passwd_buffer(const char *passwd,
+ const DATA_BLOB *session_key,
+ struct samr_CryptPasswordEx *out_crypt_pwd);
+
+/***********************************************************
+ Decode an arc4 encrypted password change buffer.
+************************************************************/
+NTSTATUS decode_rc4_passwd_buffer(const DATA_BLOB *psession_key,
+ struct samr_CryptPasswordEx *inout_crypt_pwd);
+
+/***********************************************************
+ encode a password buffer with an already unicode password. The
+ rest of the buffer is filled with random data to make it harder to attack.
+************************************************************/
+bool set_pw_in_buffer(uint8_t buffer[516], const DATA_BLOB *password);
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_size is the length in bytes of the extracted unicode password
+************************************************************/
+bool extract_pw_from_buffer(TALLOC_CTX *mem_ctx,
+ uint8_t in_buffer[516], DATA_BLOB *new_pass);
+struct wkssvc_PasswordBuffer;
+WERROR encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ const char *pwd,
+ DATA_BLOB *session_key,
+ struct wkssvc_PasswordBuffer **pwd_buf);
+WERROR decode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ struct wkssvc_PasswordBuffer *pwd_buf,
+ DATA_BLOB *session_key,
+ char **pwd);
+
+/* The following definitions come from libcli/auth/smbdes.c */
+
+int des_crypt56_gnutls(uint8_t out[8], const uint8_t in[8], const uint8_t key[7],
+ enum samba_gnutls_direction encrypt);
+int E_P16(const uint8_t *p14,uint8_t *p16);
+int E_P24(const uint8_t *p21, const uint8_t *c8, uint8_t *p24);
+int E_old_pw_hash( uint8_t *p14, const uint8_t *in, uint8_t *out);
+int des_crypt128(uint8_t out[8], const uint8_t in[8], const uint8_t key[16]);
+int des_crypt112(uint8_t out[8], const uint8_t in[8], const uint8_t key[14],
+ enum samba_gnutls_direction encrypt);
+int des_crypt112_16(uint8_t out[16], const uint8_t in[16], const uint8_t key[14],
+ enum samba_gnutls_direction encrypt);
+int sam_rid_crypt(unsigned int rid, const uint8_t *in, uint8_t *out,
+ enum samba_gnutls_direction encrypt);
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif
+
diff --git a/libcli/auth/schannel.h b/libcli/auth/schannel.h
new file mode 100644
index 0000000..c53d68e
--- /dev/null
+++ b/libcli/auth/schannel.h
@@ -0,0 +1,25 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc schannel operations
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-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 "libcli/auth/libcli_auth.h"
+#include "libcli/auth/schannel_state.h"
+#include "libcli/auth/schannel_proto.h"
diff --git a/libcli/auth/schannel_proto.h b/libcli/auth/schannel_proto.h
new file mode 100644
index 0000000..bce37c8
--- /dev/null
+++ b/libcli/auth/schannel_proto.h
@@ -0,0 +1,31 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc schannel operations
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-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 _LIBCLI_AUTH_SCHANNEL_PROTO_H__
+#define _LIBCLI_AUTH_SCHANNEL_PROTO_H__
+
+struct schannel_state;
+
+struct db_context *open_schannel_session_store(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx);
+
+#endif
diff --git a/libcli/auth/schannel_state.h b/libcli/auth/schannel_state.h
new file mode 100644
index 0000000..a333098
--- /dev/null
+++ b/libcli/auth/schannel_state.h
@@ -0,0 +1,54 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ module to store/fetch session keys for the schannel server
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 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/>.
+*/
+
+#ifndef _LIBCLI_AUTH_SCHANNEL_STATE_H__
+#define _LIBCLI_AUTH_SCHANNEL_STATE_H__
+
+NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *computer_name,
+ struct netlogon_creds_CredentialState **creds);
+
+NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct netlogon_creds_CredentialState *creds);
+
+NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *computer_name,
+ struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator,
+ struct netlogon_creds_CredentialState **creds_out);
+
+NTSTATUS schannel_get_challenge(struct loadparm_context *lp_ctx,
+ struct netr_Credential *client_challenge,
+ struct netr_Credential *server_challenge,
+ const char *computer_name);
+
+NTSTATUS schannel_save_challenge(struct loadparm_context *lp_ctx,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const char *computer_name);
+
+NTSTATUS schannel_delete_challenge(struct loadparm_context *lp_ctx,
+ const char *computer_name);
+#endif
diff --git a/libcli/auth/schannel_state_tdb.c b/libcli/auth/schannel_state_tdb.c
new file mode 100644
index 0000000..2454a43
--- /dev/null
+++ b/libcli/auth/schannel_state_tdb.c
@@ -0,0 +1,646 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ module to store/fetch session keys for the schannel server
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2009
+ 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 "includes.h"
+#include "system/filesys.h"
+#include "../lib/tdb/include/tdb.h"
+#include "../lib/util/util_tdb.h"
+#include "../lib/param/param.h"
+#include "../libcli/auth/schannel.h"
+#include "../librpc/gen_ndr/ndr_schannel.h"
+#include "lib/dbwrap/dbwrap.h"
+
+#define SECRETS_SCHANNEL_STATE "SECRETS/SCHANNEL"
+
+/******************************************************************************
+ Open or create the schannel session store tdb. Non-static so it can
+ be called from parent processes to correctly handle TDB_CLEAR_IF_FIRST
+*******************************************************************************/
+
+struct db_context *open_schannel_session_store(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx)
+{
+ struct db_context *db_sc = NULL;
+ char *fname = lpcfg_private_db_path(mem_ctx, lp_ctx, "schannel_store");
+ int hash_size, tdb_flags;
+
+ if (!fname) {
+ return NULL;
+ }
+
+ hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
+ tdb_flags = lpcfg_tdb_flags(lp_ctx, TDB_CLEAR_IF_FIRST|TDB_NOSYNC);
+
+ db_sc = dbwrap_local_open(
+ mem_ctx,
+ fname,
+ hash_size,
+ tdb_flags,
+ O_RDWR|O_CREAT,
+ 0600,
+ DBWRAP_LOCK_ORDER_NONE,
+ DBWRAP_FLAG_NONE);
+
+ if (!db_sc) {
+ DEBUG(0,("open_schannel_session_store: Failed to open %s - %s\n",
+ fname, strerror(errno)));
+ TALLOC_FREE(fname);
+ return NULL;
+ }
+
+ TALLOC_FREE(fname);
+
+ return db_sc;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static
+NTSTATUS schannel_store_session_key_tdb(struct db_context *db_sc,
+ TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ TDB_DATA value;
+ char *keystr;
+ char *name_upper;
+ NTSTATUS status;
+
+ if (strlen(creds->computer_name) > 15) {
+ /*
+ * We may want to check for a completely
+ * valid netbios name.
+ */
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ name_upper = strupper_talloc(mem_ctx, creds->computer_name);
+ if (!name_upper) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ keystr = talloc_asprintf(mem_ctx, "%s/%s",
+ SECRETS_SCHANNEL_STATE, name_upper);
+ TALLOC_FREE(name_upper);
+ if (!keystr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, creds,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(keystr);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ value.dptr = blob.data;
+ value.dsize = blob.length;
+
+ status = dbwrap_store_bystring(db_sc, keystr, value, TDB_REPLACE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Unable to add %s to session key db - %s\n",
+ keystr, nt_errstr(status)));
+ talloc_free(keystr);
+ return status;
+ }
+
+ DEBUG(3,("schannel_store_session_key_tdb: stored schannel info with key %s\n",
+ keystr));
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
+ }
+
+ talloc_free(keystr);
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static
+NTSTATUS schannel_fetch_session_key_tdb(struct db_context *db_sc,
+ TALLOC_CTX *mem_ctx,
+ const char *computer_name,
+ struct netlogon_creds_CredentialState **pcreds)
+{
+ NTSTATUS status;
+ TDB_DATA value;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ char *keystr = NULL;
+ char *name_upper;
+
+ *pcreds = NULL;
+
+ name_upper = strupper_talloc(mem_ctx, computer_name);
+ if (!name_upper) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ keystr = talloc_asprintf(mem_ctx, "%s/%s",
+ SECRETS_SCHANNEL_STATE, name_upper);
+ TALLOC_FREE(name_upper);
+ if (!keystr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dbwrap_fetch_bystring(db_sc, keystr, keystr, &value);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("schannel_fetch_session_key_tdb: Failed to find entry with key %s\n",
+ keystr ));
+ goto done;
+ }
+
+ creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+ if (!creds) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ blob = data_blob_const(value.dptr, value.dsize);
+
+ ndr_err = ndr_pull_struct_blob(&blob, creds, creds,
+ (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ goto done;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
+ }
+
+ DEBUG(3,("schannel_fetch_session_key_tdb: restored schannel info key %s\n",
+ keystr));
+
+ status = NT_STATUS_OK;
+
+ done:
+
+ talloc_free(keystr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return status;
+ }
+
+ *pcreds = creds;
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Wrapper around schannel_fetch_session_key_tdb()
+ Note we must be root here.
+*******************************************************************************/
+
+NTSTATUS schannel_get_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *computer_name,
+ struct netlogon_creds_CredentialState **_creds)
+{
+ TALLOC_CTX *tmpctx;
+ struct db_context *db_sc;
+ struct netlogon_creds_CredentialState *creds;
+ NTSTATUS status;
+
+ tmpctx = talloc_named(mem_ctx, 0, "schannel_get_creds_state");
+ if (!tmpctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ db_sc = open_schannel_session_store(tmpctx, lp_ctx);
+ if (!db_sc) {
+ TALLOC_FREE(tmpctx);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
+ computer_name, &creds);
+ if (NT_STATUS_IS_OK(status)) {
+ *_creds = talloc_steal(mem_ctx, creds);
+ if (!*_creds) {
+ status = NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ talloc_free(tmpctx);
+ return status;
+}
+
+/******************************************************************************
+ Wrapper around schannel_store_session_key_tdb()
+ Note we must be root here.
+*******************************************************************************/
+
+NTSTATUS schannel_save_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct netlogon_creds_CredentialState *creds)
+{
+ TALLOC_CTX *tmpctx;
+ struct db_context *db_sc;
+ NTSTATUS status;
+
+ tmpctx = talloc_named(mem_ctx, 0, "schannel_save_creds_state");
+ if (!tmpctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ db_sc = open_schannel_session_store(tmpctx, lp_ctx);
+ if (!db_sc) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto fail;
+ }
+
+ status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
+
+fail:
+ talloc_free(tmpctx);
+ return status;
+}
+
+
+/*
+ * Create a very lossy hash of the computer name.
+ *
+ * The idea here is to compress the computer name into small space so
+ * that malicious clients cannot fill the database with junk, as only a
+ * maximum of 16k of entries are possible.
+ *
+ * Collisions are certainly possible, and the design behaves in the
+ * same way as when the hostname is reused, but clients that use the
+ * same connection do not go via the cache, and the cache only needs
+ * to function between the ReqChallenge and ServerAuthenticate
+ * packets.
+ */
+static void hash_computer_name(const char *computer_name,
+ char keystr[16])
+{
+ unsigned int hash;
+ TDB_DATA computer_tdb_data = {
+ .dptr = (uint8_t *)discard_const_p(char, computer_name),
+ .dsize = strlen(computer_name)
+ };
+ hash = tdb_jenkins_hash(&computer_tdb_data);
+
+ /* we are using 14 bits of the digest to index our connections, so
+ that we use at most 16,384 buckets.*/
+ snprintf(keystr, 15, "CHALLENGE/%x%x", hash & 0xFF,
+ (hash & 0xFF00 >> 8) & 0x3f);
+ return;
+}
+
+
+static
+NTSTATUS schannel_store_challenge_tdb(struct db_context *db_sc,
+ TALLOC_CTX *mem_ctx,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const char *computer_name)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ TDB_DATA value;
+ char *name_upper = NULL;
+ NTSTATUS status;
+ char keystr[16] = { 0, };
+ struct netlogon_cache_entry cache_entry;
+
+ if (strlen(computer_name) > 255) {
+ /*
+ * We don't make this a limit at 15 chars as Samba has
+ * a test showing this can be longer :-(
+ */
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ name_upper = strupper_talloc(mem_ctx, computer_name);
+ if (name_upper == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ hash_computer_name(name_upper, keystr);
+
+ cache_entry.computer_name = name_upper;
+ cache_entry.client_challenge = *client_challenge;
+ cache_entry.server_challenge = *server_challenge;
+
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &cache_entry,
+ (ndr_push_flags_fn_t)ndr_push_netlogon_cache_entry);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ value.dptr = blob.data;
+ value.dsize = blob.length;
+
+ status = dbwrap_store_bystring(db_sc, keystr, value, TDB_REPLACE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("%s: failed to stored challenge info for '%s' "
+ "with key %s - %s\n",
+ __func__, cache_entry.computer_name, keystr,
+ nt_errstr(status)));
+ return status;
+ }
+
+ DEBUG(3,("%s: stored challenge info for '%s' with key %s\n",
+ __func__, cache_entry.computer_name, keystr));
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_cache_entry, &cache_entry);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/********************************************************************
+ Fetch a single challenge from the TDB.
+ ********************************************************************/
+
+static
+NTSTATUS schannel_fetch_challenge_tdb(struct db_context *db_sc,
+ TALLOC_CTX *mem_ctx,
+ struct netr_Credential *client_challenge,
+ struct netr_Credential *server_challenge,
+ const char *computer_name)
+{
+ NTSTATUS status;
+ TDB_DATA value;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob;
+ char keystr[16] = { 0, };
+ struct netlogon_cache_entry cache_entry;
+ char *name_upper = NULL;
+
+ name_upper = strupper_talloc(mem_ctx, computer_name);
+ if (name_upper == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ hash_computer_name(name_upper, keystr);
+
+ status = dbwrap_fetch_bystring(db_sc, mem_ctx, keystr, &value);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3,("%s: Failed to find entry for %s with key %s - %s\n",
+ __func__, name_upper, keystr, nt_errstr(status)));
+ goto done;
+ }
+
+ blob = data_blob_const(value.dptr, value.dsize);
+
+ ndr_err = ndr_pull_struct_blob_all(&blob, mem_ctx, &cache_entry,
+ (ndr_pull_flags_fn_t)ndr_pull_netlogon_cache_entry);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(3,("%s: Failed to parse entry for %s with key %s - %s\n",
+ __func__, name_upper, keystr, nt_errstr(status)));
+ goto done;
+ }
+
+ if (DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(netlogon_cache_entry, &cache_entry);
+ }
+
+ if (strcmp(cache_entry.computer_name, name_upper) != 0) {
+ status = NT_STATUS_NOT_FOUND;
+
+ DEBUG(1, ("%s: HASH COLLISION with key %s ! "
+ "Wanted to fetch record for %s but got %s.\n",
+ __func__, keystr, name_upper,
+ cache_entry.computer_name));
+ } else {
+
+ DEBUG(3,("%s: restored key %s for %s\n",
+ __func__, keystr, cache_entry.computer_name));
+
+ *client_challenge = cache_entry.client_challenge;
+ *server_challenge = cache_entry.server_challenge;
+ }
+ done:
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Wrapper around schannel_fetch_challenge_tdb()
+ Note we must be root here.
+
+*******************************************************************************/
+
+NTSTATUS schannel_get_challenge(struct loadparm_context *lp_ctx,
+ struct netr_Credential *client_challenge,
+ struct netr_Credential *server_challenge,
+ const char *computer_name)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct db_context *db_sc;
+ NTSTATUS status;
+
+ db_sc = open_schannel_session_store(frame, lp_ctx);
+ if (!db_sc) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = schannel_fetch_challenge_tdb(db_sc, frame,
+ client_challenge,
+ server_challenge,
+ computer_name);
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/******************************************************************************
+ Wrapper around dbwrap_delete_bystring()
+ Note we must be root here.
+
+ This allows the challenge to be removed from the TDB, which should be
+ as soon as the TDB or in-memory copy it is used, to avoid reuse.
+*******************************************************************************/
+
+NTSTATUS schannel_delete_challenge(struct loadparm_context *lp_ctx,
+ const char *computer_name)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct db_context *db_sc;
+ char *name_upper;
+ char keystr[16] = { 0, };
+
+ db_sc = open_schannel_session_store(frame, lp_ctx);
+ if (!db_sc) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ name_upper = strupper_talloc(frame, computer_name);
+ if (!name_upper) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ hash_computer_name(name_upper, keystr);
+
+ /* Now delete it, we do not want to permit fetch of this twice */
+ dbwrap_delete_bystring(db_sc, keystr);
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Wrapper around schannel_store_session_key_tdb()
+ Note we must be root here.
+*******************************************************************************/
+
+NTSTATUS schannel_save_challenge(struct loadparm_context *lp_ctx,
+ const struct netr_Credential *client_challenge,
+ const struct netr_Credential *server_challenge,
+ const char *computer_name)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct db_context *db_sc;
+ NTSTATUS status;
+
+ db_sc = open_schannel_session_store(frame, lp_ctx);
+ if (!db_sc) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = schannel_store_challenge_tdb(db_sc, frame,
+ client_challenge,
+ server_challenge,
+ computer_name);
+
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/********************************************************************
+ Validate an incoming authenticator against the credentials for the
+ remote machine stored in the schannel database.
+
+ The credentials are (re)read and from the schannel database, and
+ written back after the calculations are performed.
+
+ If the creds_out parameter is not NULL returns the credentials.
+ ********************************************************************/
+
+NTSTATUS schannel_check_creds_state(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ const char *computer_name,
+ struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ TALLOC_CTX *tmpctx;
+ struct db_context *db_sc;
+ struct netlogon_creds_CredentialState *creds;
+ NTSTATUS status;
+ char *name_upper = NULL;
+ char *keystr = NULL;
+ struct db_record *record;
+ TDB_DATA key;
+
+ if (creds_out != NULL) {
+ *creds_out = NULL;
+ }
+
+ tmpctx = talloc_named(mem_ctx, 0, "schannel_check_creds_state");
+ if (!tmpctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ name_upper = strupper_talloc(tmpctx, computer_name);
+ if (!name_upper) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ keystr = talloc_asprintf(tmpctx, "%s/%s",
+ SECRETS_SCHANNEL_STATE, name_upper);
+ if (!keystr) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ key = string_term_tdb_data(keystr);
+
+ db_sc = open_schannel_session_store(tmpctx, lp_ctx);
+ if (!db_sc) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+
+ record = dbwrap_fetch_locked(db_sc, tmpctx, key);
+ if (!record) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto done;
+ }
+
+ /* Because this is a shared structure (even across
+ * disconnects) we must update the database every time we
+ * update the structure */
+
+ status = schannel_fetch_session_key_tdb(db_sc, tmpctx,
+ computer_name, &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = netlogon_creds_server_step_check(creds,
+ received_authenticator,
+ return_authenticator);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ status = schannel_store_session_key_tdb(db_sc, tmpctx, creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (creds_out) {
+ *creds_out = talloc_steal(mem_ctx, creds);
+ if (!*creds_out) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ talloc_free(tmpctx);
+ return status;
+}
+
diff --git a/libcli/auth/session.c b/libcli/auth/session.c
new file mode 100644
index 0000000..515b7ae
--- /dev/null
+++ b/libcli/auth/session.c
@@ -0,0 +1,247 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ code to encrypt/decrypt data using the user session key
+
+ 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 "libcli/auth/libcli_auth.h"
+
+/*
+ encrypt or decrypt a blob of data using the user session key
+ as used in lsa_SetSecret
+
+ before calling, the out blob must be initialised to be the same size
+ as the in blob
+*/
+int sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key,
+ enum samba_gnutls_direction encrypt)
+{
+ int i, k, rc;
+
+ if (in->length % 8 != 0) {
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if (session_key->length < 7) {
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ for (i=0,k=0;
+ i<in->length;
+ i += 8, k += 7) {
+ uint8_t bin[8], bout[8], key[7];
+
+ memcpy(bin, &in->data[i], 8);
+
+ if (k + 7 > session_key->length) {
+ k = (session_key->length - k);
+ }
+ memcpy(key, &session_key->data[k], 7);
+
+ rc = des_crypt56_gnutls(bout, bin, key, encrypt);
+ if (rc != 0) {
+ return rc;
+ }
+
+ memcpy(&out->data[i], bout, 8);
+ }
+ return 0;
+}
+
+
+/*
+ a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
+
+ note that we round the length to a multiple of 8. This seems to be needed for
+ compatibility with windows
+
+ caller should free using data_blob_free()
+*/
+DATA_BLOB sess_encrypt_string(const char *str, const DATA_BLOB *session_key)
+{
+ DATA_BLOB ret, src;
+ int slen = strlen(str);
+ int dlen = (slen+7) & ~7;
+ int rc;
+
+ src = data_blob(NULL, 8+dlen);
+ if (!src.data) {
+ return data_blob(NULL, 0);
+ }
+
+ ret = data_blob(NULL, 8+dlen);
+ if (!ret.data) {
+ data_blob_free(&src);
+ return data_blob(NULL, 0);
+ }
+
+ SIVAL(src.data, 0, slen);
+ SIVAL(src.data, 4, 1);
+ memset(src.data+8, 0, dlen);
+ memcpy(src.data+8, str, slen);
+
+ rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
+
+ data_blob_free(&src);
+ if (rc != 0) {
+ data_blob_free(&ret);
+ return data_blob(NULL, 0);
+ }
+
+ return ret;
+}
+
+/*
+ a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
+
+ caller should free the returned string
+*/
+char *sess_decrypt_string(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob, const DATA_BLOB *session_key)
+{
+ DATA_BLOB out;
+ int rc, slen;
+ char *ret;
+
+ if (blob->length < 8) {
+ return NULL;
+ }
+
+ out = data_blob_talloc(mem_ctx, NULL, blob->length);
+ if (!out.data) {
+ return NULL;
+ }
+
+ rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ data_blob_free(&out);
+ return NULL;
+ }
+
+ if (IVAL(out.data, 4) != 1) {
+ DEBUG(0,("Unexpected revision number %d in session encrypted string\n",
+ IVAL(out.data, 4)));
+ data_blob_free(&out);
+ return NULL;
+ }
+
+ slen = IVAL(out.data, 0);
+ if (slen > blob->length - 8) {
+ DEBUG(0,("Invalid crypt length %d\n", slen));
+ data_blob_free(&out);
+ return NULL;
+ }
+
+ ret = talloc_strndup(mem_ctx, (const char *)(out.data+8), slen);
+
+ data_blob_free(&out);
+
+ DEBUG(0,("decrypted string '%s' of length %d\n", ret, slen));
+
+ return ret;
+}
+
+/*
+ a convenient wrapper around sess_crypt_blob() for DATA_BLOBs, using the LSA convention
+
+ note that we round the length to a multiple of 8. This seems to be needed for
+ compatibility with windows
+
+ caller should free using data_blob_free()
+*/
+DATA_BLOB sess_encrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob_in, const DATA_BLOB *session_key)
+{
+ DATA_BLOB ret, src;
+ int dlen = (blob_in->length+7) & ~7;
+ int rc;
+
+ src = data_blob_talloc(mem_ctx, NULL, 8+dlen);
+ if (!src.data) {
+ return data_blob(NULL, 0);
+ }
+
+ ret = data_blob_talloc(mem_ctx, NULL, 8+dlen);
+ if (!ret.data) {
+ data_blob_free(&src);
+ return data_blob(NULL, 0);
+ }
+
+ SIVAL(src.data, 0, blob_in->length);
+ SIVAL(src.data, 4, 1);
+ memset(src.data+8, 0, dlen);
+ memcpy(src.data+8, blob_in->data, blob_in->length);
+
+ rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
+
+ data_blob_free(&src);
+ if (rc != 0) {
+ data_blob_free(&ret);
+ return data_blob(NULL, 0);
+ }
+
+ return ret;
+}
+
+/*
+ Decrypt a DATA_BLOB using the LSA convention
+*/
+NTSTATUS sess_decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const DATA_BLOB *session_key,
+ DATA_BLOB *ret)
+{
+ DATA_BLOB out;
+ int rc, slen;
+
+ if (blob->length < 8) {
+ DEBUG(0, ("Unexpected length %d in session encrypted secret (BLOB)\n",
+ (int)blob->length));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ out = data_blob_talloc(mem_ctx, NULL, blob->length);
+ if (!out.data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ data_blob_free(&out);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ if (IVAL(out.data, 4) != 1) {
+ DEBUG(2,("Unexpected revision number %d in session encrypted secret (BLOB)\n",
+ IVAL(out.data, 4)));
+ return NT_STATUS_UNKNOWN_REVISION;
+ }
+
+ slen = IVAL(out.data, 0);
+ if (slen > blob->length - 8) {
+ DEBUG(0,("Invalid crypt length %d in session encrypted secret (BLOB)\n", slen));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
+
+ *ret = data_blob_talloc(mem_ctx, out.data+8, slen);
+ if (slen && !ret->data) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ data_blob_free(&out);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/auth/smbdes.c b/libcli/auth/smbdes.c
new file mode 100644
index 0000000..c6c4441
--- /dev/null
+++ b/libcli/auth/smbdes.c
@@ -0,0 +1,213 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a partial implementation of DES designed for use in the
+ SMB authentication protocol
+
+ 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 "includes.h"
+#include "libcli/auth/libcli_auth.h"
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+static void str_to_key(const uint8_t *str,uint8_t *key)
+{
+ int i;
+
+ key[0] = str[0]>>1;
+ key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
+ key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
+ key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
+ key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
+ key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
+ key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
+ key[7] = str[6]&0x7F;
+ for (i=0;i<8;i++) {
+ key[i] = (key[i]<<1);
+ }
+}
+
+int des_crypt56_gnutls(uint8_t out[8], const uint8_t in[8],
+ const uint8_t key_in[7],
+ enum samba_gnutls_direction encrypt)
+{
+ /*
+ * A single block DES-CBC op, with an all-zero IV is the same as DES
+ * because the IV is combined with the data using XOR.
+ * This allows us to use GNUTLS_CIPHER_DES_CBC from GnuTLS and not
+ * implement single-DES in Samba.
+ *
+ * In turn this is used to build DES-ECB, which is used
+ * for example in the NTLM challenge/response calculation.
+ */
+ static const uint8_t iv8[8];
+ gnutls_datum_t iv = { discard_const(iv8), 8 };
+ gnutls_datum_t key;
+ gnutls_cipher_hd_t ctx;
+ uint8_t key2[8];
+ uint8_t outb[8];
+ int ret;
+
+ memset(out, 0, 8);
+
+ str_to_key(key_in, key2);
+
+ key.data = key2;
+ key.size = 8;
+
+ ret = gnutls_global_init();
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = gnutls_cipher_init(&ctx, GNUTLS_CIPHER_DES_CBC, &key, &iv);
+ if (ret != 0) {
+ return ret;
+ }
+
+ memcpy(outb, in, 8);
+ if (encrypt == SAMBA_GNUTLS_ENCRYPT) {
+ ret = gnutls_cipher_encrypt(ctx, outb, 8);
+ } else {
+ ret = gnutls_cipher_decrypt(ctx, outb, 8);
+ }
+
+ if (ret == 0) {
+ memcpy(out, outb, 8);
+ }
+
+ gnutls_cipher_deinit(ctx);
+
+ return ret;
+}
+
+int E_P16(const uint8_t *p14,uint8_t *p16)
+{
+ const uint8_t sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+ int ret;
+
+ ret = des_crypt56_gnutls(p16, sp8, p14, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(p16+8, sp8, p14+7, SAMBA_GNUTLS_ENCRYPT);
+}
+
+int E_P24(const uint8_t *p21, const uint8_t *c8, uint8_t *p24)
+{
+ int ret;
+
+ ret = des_crypt56_gnutls(p24, c8, p21, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = des_crypt56_gnutls(p24+8, c8, p21+7, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(p24+16, c8, p21+14, SAMBA_GNUTLS_ENCRYPT);
+}
+
+int E_old_pw_hash( uint8_t *p14, const uint8_t *in, uint8_t *out)
+{
+ int ret;
+
+ ret = des_crypt56_gnutls(out, in, p14, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out+8, in+8, p14+7, SAMBA_GNUTLS_ENCRYPT);
+}
+
+/* des encryption with a 128 bit key */
+int des_crypt128(uint8_t out[8], const uint8_t in[8], const uint8_t key[16])
+{
+ uint8_t buf[8];
+ int ret;
+
+ ret = des_crypt56_gnutls(buf, in, key, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out, buf, key+9, SAMBA_GNUTLS_ENCRYPT);
+}
+
+/* des encryption with a 112 bit (14 byte) key */
+int des_crypt112(uint8_t out[8], const uint8_t in[8], const uint8_t key[14],
+ enum samba_gnutls_direction encrypt)
+{
+ uint8_t buf[8];
+ int ret;
+
+ if (encrypt == SAMBA_GNUTLS_ENCRYPT) {
+ ret = des_crypt56_gnutls(buf, in, key, SAMBA_GNUTLS_ENCRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out, buf, key+7, SAMBA_GNUTLS_ENCRYPT);
+ }
+
+ ret = des_crypt56_gnutls(buf, in, key+7, SAMBA_GNUTLS_DECRYPT);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out, buf, key, SAMBA_GNUTLS_DECRYPT);
+}
+
+/* des encryption of a 16 byte lump of data with a 112 bit key */
+int des_crypt112_16(uint8_t out[16], const uint8_t in[16], const uint8_t key[14],
+ enum samba_gnutls_direction encrypt)
+{
+ int ret;
+
+ ret = des_crypt56_gnutls(out, in, key, encrypt);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return des_crypt56_gnutls(out + 8, in + 8, key+7, encrypt);
+}
+
+/* Decode a sam password hash into a password. The password hash is the
+ same method used to store passwords in the NT registry. The DES key
+ used is based on the RID of the user. */
+int sam_rid_crypt(unsigned int rid, const uint8_t *in, uint8_t *out,
+ enum samba_gnutls_direction encrypt)
+{
+ uint8_t s[14];
+ int ret;
+
+ s[0] = s[4] = s[8] = s[12] = (uint8_t)(rid & 0xFF);
+ s[1] = s[5] = s[9] = s[13] = (uint8_t)((rid >> 8) & 0xFF);
+ s[2] = s[6] = s[10] = (uint8_t)((rid >> 16) & 0xFF);
+ s[3] = s[7] = s[11] = (uint8_t)((rid >> 24) & 0xFF);
+
+ ret = des_crypt56_gnutls(out, in, s, encrypt);
+ if (ret != 0) {
+ return ret;
+ }
+ return des_crypt56_gnutls(out+8, in+8, s+7, encrypt);
+}
diff --git a/libcli/auth/smbencrypt.c b/libcli/auth/smbencrypt.c
new file mode 100644
index 0000000..725bdcb
--- /dev/null
+++ b/libcli/auth/smbencrypt.c
@@ -0,0 +1,1325 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1998
+ Modified by Jeremy Allison 1995.
+ Copyright (C) Jeremy Allison 1995-2000.
+ Copyright (C) Luke Kennethc Casson Leighton 1996-2000.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-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 "system/time.h"
+#include "../libcli/auth/msrpc_parse.h"
+#include "../lib/crypto/crypto.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "../librpc/gen_ndr/ndr_ntlmssp.h"
+#include "lib/util/bytearray.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+int SMBencrypt_hash(const uint8_t lm_hash[16], const uint8_t *c8, uint8_t p24[24])
+{
+ uint8_t p21[21];
+ int rc;
+
+ memset(p21,'\0',21);
+ memcpy(p21, lm_hash, 16);
+
+ rc = SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBencrypt_hash: lm#, challenge, response\n"));
+ dump_data(100, p21, 16);
+ dump_data(100, c8, 8);
+ dump_data(100, p24, 24);
+#endif
+
+ return rc;
+}
+
+/*
+ This implements the X/Open SMB password encryption
+ It takes a password ('unix' string), a 8 byte "crypt key"
+ and puts 24 bytes of encrypted password into p24
+
+ Returns False if password must have been truncated to create LM hash
+*/
+
+bool SMBencrypt(const char *passwd, const uint8_t *c8, uint8_t p24[24])
+{
+ bool ret;
+ uint8_t lm_hash[16];
+ int rc;
+
+ ret = E_deshash(passwd, lm_hash);
+ rc = SMBencrypt_hash(lm_hash, c8, p24);
+ if (rc != 0) {
+ ret = false;
+ }
+ return ret;
+}
+
+/**
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with md4, caller allocated 16 byte buffer
+ */
+
+bool E_md4hash(const char *passwd, uint8_t p16[16])
+{
+ size_t len;
+ smb_ucs2_t *wpwd;
+ bool ret;
+
+ ret = push_ucs2_talloc(NULL, &wpwd, passwd, &len);
+ if (!ret || len < 2) {
+ /* We don't want to return fixed data, as most callers
+ * don't check */
+ mdfour(p16, (const uint8_t *)passwd, strlen(passwd));
+ return false;
+ }
+
+ len -= 2;
+ mdfour(p16, (const uint8_t *)wpwd, len);
+
+ talloc_free(wpwd);
+ return true;
+}
+
+/**
+ * Creates the DES forward-only Hash of the users password in DOS ASCII charset
+ * @param passwd password in 'unix' charset.
+ * @param p16 return password hashed with DES, caller allocated 16 byte buffer
+ * @return false if password was > 14 characters, and therefore may be incorrect, otherwise true
+ * @note p16 is filled in regardless
+ */
+
+bool E_deshash(const char *passwd, uint8_t p16[16])
+{
+ bool ret;
+ int rc;
+ uint8_t dospwd[14];
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ size_t converted_size;
+
+ char *tmpbuf;
+
+ ZERO_STRUCT(dospwd);
+
+ tmpbuf = strupper_talloc(frame, passwd);
+ if (tmpbuf == NULL) {
+ /* Too many callers don't check this result, we need to fill in the buffer with something */
+ strlcpy((char *)dospwd, passwd ? passwd : "", sizeof(dospwd));
+ E_P16(dospwd, p16);
+ talloc_free(frame);
+ return false;
+ }
+
+ ZERO_STRUCT(dospwd);
+
+ ret = convert_string_error(CH_UNIX, CH_DOS, tmpbuf, strlen(tmpbuf), dospwd, sizeof(dospwd), &converted_size);
+ talloc_free(frame);
+
+ /* Only the first 14 chars are considered, password need not
+ * be null terminated. We do this in the error and success
+ * case to avoid returning a fixed 'password' buffer, but
+ * callers should not use it when E_deshash returns false */
+
+ rc = E_P16((const uint8_t *)dospwd, p16);
+ if (rc != 0) {
+ ret = false;
+ }
+
+ ZERO_STRUCT(dospwd);
+
+ return ret;
+}
+
+/**
+ * Creates the MD4 and DES (LM) Hash of the users password.
+ * MD4 is of the NT Unicode, DES is of the DOS UPPERCASE password.
+ * @param passwd password in 'unix' charset.
+ * @param nt_p16 return password hashed with md4, caller allocated 16 byte buffer
+ * @param p16 return password hashed with des, caller allocated 16 byte buffer
+ */
+
+/* Does both the NT and LM owfs of a user's password */
+void nt_lm_owf_gen(const char *pwd, uint8_t nt_p16[16], uint8_t p16[16])
+{
+ /* Calculate the MD4 hash (NT compatible) of the password */
+ memset(nt_p16, '\0', 16);
+ E_md4hash(pwd, nt_p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, nt#\n"));
+ dump_data(120, (const uint8_t *)pwd, strlen(pwd));
+ dump_data(100, nt_p16, 16);
+#endif
+
+ E_deshash(pwd, (uint8_t *)p16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("nt_lm_owf_gen: pwd, lm#\n"));
+ dump_data(120, (const uint8_t *)pwd, strlen(pwd));
+ dump_data(100, p16, 16);
+#endif
+}
+
+/* Does both the NTLMv2 owfs of a user's password */
+bool ntv2_owf_gen(const uint8_t owf[16],
+ const char *user_in, const char *domain_in,
+ uint8_t kr_buf[16])
+{
+ smb_ucs2_t *user;
+ smb_ucs2_t *domain;
+ size_t user_byte_len;
+ size_t domain_byte_len;
+ gnutls_hmac_hd_t hmac_hnd = NULL;
+ int rc;
+ bool ok = false;
+ TALLOC_CTX *mem_ctx = talloc_init("ntv2_owf_gen for %s\\%s", domain_in, user_in);
+
+ if (!mem_ctx) {
+ return false;
+ }
+
+ if (!user_in) {
+ user_in = "";
+ }
+
+ if (!domain_in) {
+ domain_in = "";
+ }
+
+ user_in = strupper_talloc(mem_ctx, user_in);
+ if (user_in == NULL) {
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ ok = push_ucs2_talloc(mem_ctx, &user, user_in, &user_byte_len );
+ if (!ok) {
+ DEBUG(0, ("push_uss2_talloc() for user failed)\n"));
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ ok = push_ucs2_talloc(mem_ctx, &domain, domain_in, &domain_byte_len);
+ if (!ok) {
+ DEBUG(0, ("push_ucs2_talloc() for domain failed\n"));
+ talloc_free(mem_ctx);
+ return false;
+ }
+
+ SMB_ASSERT(user_byte_len >= 2);
+ SMB_ASSERT(domain_byte_len >= 2);
+
+ /* We don't want null termination */
+ user_byte_len = user_byte_len - 2;
+ domain_byte_len = domain_byte_len - 2;
+
+ rc = gnutls_hmac_init(&hmac_hnd,
+ GNUTLS_MAC_MD5,
+ owf,
+ 16);
+ if (rc < 0) {
+ ok = false;
+ goto out;
+ }
+
+ rc = gnutls_hmac(hmac_hnd, user, user_byte_len);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ ok = false;
+ goto out;
+ }
+ rc = gnutls_hmac(hmac_hnd, domain, domain_byte_len);
+ if (rc < 0) {
+ gnutls_hmac_deinit(hmac_hnd, NULL);
+ ok = false;
+ goto out;
+ }
+
+ gnutls_hmac_deinit(hmac_hnd, kr_buf);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n"));
+ dump_data(100, (uint8_t *)user, user_byte_len);
+ dump_data(100, (uint8_t *)domain, domain_byte_len);
+ dump_data(100, owf, 16);
+ dump_data(100, kr_buf, 16);
+#endif
+
+ ok = true;
+out:
+ talloc_free(mem_ctx);
+ return ok;
+}
+
+/* Does the des encryption from the NT or LM MD4 hash. */
+int SMBOWFencrypt(const uint8_t passwd[16], const uint8_t *c8, uint8_t p24[24])
+{
+ uint8_t p21[21];
+
+ ZERO_STRUCT(p21);
+
+ memcpy(p21, passwd, 16);
+ return E_P24(p21, c8, p24);
+}
+
+/* Does the des encryption. */
+
+int SMBNTencrypt_hash(const uint8_t nt_hash[16], const uint8_t *c8, uint8_t *p24)
+{
+ uint8_t p21[21];
+ int rc;
+
+ memset(p21,'\0',21);
+ memcpy(p21, nt_hash, 16);
+ rc = SMBOWFencrypt(p21, c8, p24);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("SMBNTencrypt: nt#, challenge, response\n"));
+ dump_data(100, p21, 16);
+ dump_data(100, c8, 8);
+ dump_data(100, p24, 24);
+#endif
+
+ return rc;
+}
+
+/* Does the NT MD4 hash then des encryption. Plaintext version of the above. */
+
+int SMBNTencrypt(const char *passwd, const uint8_t *c8, uint8_t *p24)
+{
+ uint8_t nt_hash[16];
+ E_md4hash(passwd, nt_hash);
+ return SMBNTencrypt_hash(nt_hash, c8, p24);
+}
+
+
+/* Does the md5 encryption from the Key Response for NTLMv2. */
+NTSTATUS SMBOWFencrypt_ntv2(const uint8_t kr[16],
+ const DATA_BLOB *srv_chal,
+ const DATA_BLOB *smbcli_chal,
+ uint8_t resp_buf[16])
+{
+ gnutls_hmac_hd_t hmac_hnd = NULL;
+ NTSTATUS status;
+ int rc;
+
+ rc = gnutls_hmac_init(&hmac_hnd,
+ GNUTLS_MAC_MD5,
+ kr,
+ 16);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+ rc = gnutls_hmac(hmac_hnd, srv_chal->data, srv_chal->length);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ goto out;
+ }
+ rc = gnutls_hmac(hmac_hnd, smbcli_chal->data, smbcli_chal->length);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ goto out;
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, smbcli_chal, resp_buf\n"));
+ dump_data(100, srv_chal->data, srv_chal->length);
+ dump_data(100, smbcli_chal->data, smbcli_chal->length);
+ dump_data(100, resp_buf, 16);
+#endif
+
+ status = NT_STATUS_OK;
+out:
+ gnutls_hmac_deinit(hmac_hnd, resp_buf);
+ return status;
+}
+
+NTSTATUS SMBsesskeygen_ntv2(const uint8_t kr[16],
+ const uint8_t *nt_resp,
+ uint8_t sess_key[16])
+{
+ int rc;
+
+ /* a very nice, 128 bit, variable session key */
+ rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
+ kr,
+ 16,
+ nt_resp,
+ 16,
+ sess_key);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv2:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+
+ return NT_STATUS_OK;
+}
+
+void SMBsesskeygen_ntv1(const uint8_t kr[16], uint8_t sess_key[16])
+{
+ /* yes, this session key does not change - yes, this
+ is a problem - but it is 128 bits */
+
+ mdfour((uint8_t *)sess_key, kr, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_ntv1:\n"));
+ dump_data(100, sess_key, 16);
+#endif
+}
+
+NTSTATUS SMBsesskeygen_lm_sess_key(const uint8_t lm_hash[16],
+ const uint8_t lm_resp[24], /* only uses 8 */
+ uint8_t sess_key[16])
+{
+ /* Calculate the LM session key (effective length 40 bits,
+ but changes with each session) */
+ uint8_t p24[24];
+ uint8_t partial_lm_hash[14];
+ int rc;
+
+ memcpy(partial_lm_hash, lm_hash, 8);
+ memset(partial_lm_hash + 8, 0xbd, 6);
+
+ rc = des_crypt56_gnutls(p24, lm_resp, partial_lm_hash, SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ rc = des_crypt56_gnutls(p24+8, lm_resp, partial_lm_hash + 7, SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ memcpy(sess_key, p24, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("SMBsesskeygen_lm_sess_key: \n"));
+ dump_data(100, sess_key, 16);
+#endif
+
+ return NT_STATUS_OK;
+}
+
+DATA_BLOB NTLMv2_generate_names_blob(TALLOC_CTX *mem_ctx,
+ const char *hostname,
+ const char *domain)
+{
+ DATA_BLOB names_blob = data_blob_talloc(mem_ctx, NULL, 0);
+
+ /* Deliberately ignore return here.. */
+ if (hostname != NULL) {
+ (void)msrpc_gen(mem_ctx, &names_blob,
+ "aaa",
+ MsvAvNbDomainName, domain,
+ MsvAvNbComputerName, hostname,
+ MsvAvEOL, "");
+ } else {
+ (void)msrpc_gen(mem_ctx, &names_blob,
+ "aa",
+ MsvAvNbDomainName, domain,
+ MsvAvEOL, "");
+ }
+ return names_blob;
+}
+
+static DATA_BLOB NTLMv2_generate_client_data(TALLOC_CTX *mem_ctx,
+ NTTIME nttime,
+ const DATA_BLOB *names_blob)
+{
+ uint8_t client_chal[8];
+ DATA_BLOB response = data_blob(NULL, 0);
+ uint8_t long_date[8];
+
+ generate_random_buffer(client_chal, sizeof(client_chal));
+
+ push_nttime(long_date, 0, nttime);
+
+ /* See http://www.ubiqx.org/cifs/SMB.html#SMB.8.5 */
+
+ /* Deliberately ignore return here.. */
+ (void)msrpc_gen(mem_ctx, &response, "ddbbdb",
+ 0x00000101, /* Header */
+ 0, /* 'Reserved' */
+ long_date, 8, /* Timestamp */
+ client_chal, 8, /* client challenge */
+ 0, /* Unknown */
+ names_blob->data, names_blob->length); /* End of name list */
+
+ return response;
+}
+
+static DATA_BLOB NTLMv2_generate_response(TALLOC_CTX *out_mem_ctx,
+ const uint8_t ntlm_v2_hash[16],
+ const DATA_BLOB *server_chal,
+ NTTIME nttime,
+ const DATA_BLOB *names_blob)
+{
+ uint8_t ntlmv2_response[16];
+ DATA_BLOB ntlmv2_client_data;
+ DATA_BLOB final_response;
+ NTSTATUS status;
+
+ TALLOC_CTX *mem_ctx = talloc_named(out_mem_ctx, 0,
+ "NTLMv2_generate_response internal context");
+
+ if (!mem_ctx) {
+ return data_blob(NULL, 0);
+ }
+
+ /* NTLMv2 */
+ /* generate some data to pass into the response function - including
+ the hostname and domain name of the server */
+ ntlmv2_client_data = NTLMv2_generate_client_data(mem_ctx, nttime, names_blob);
+
+ /* Given that data, and the challenge from the server, generate a response */
+ status = SMBOWFencrypt_ntv2(ntlm_v2_hash,
+ server_chal,
+ &ntlmv2_client_data,
+ ntlmv2_response);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return data_blob(NULL, 0);
+ }
+
+ final_response = data_blob_talloc(out_mem_ctx, NULL, sizeof(ntlmv2_response) + ntlmv2_client_data.length);
+
+ memcpy(final_response.data, ntlmv2_response, sizeof(ntlmv2_response));
+
+ memcpy(final_response.data+sizeof(ntlmv2_response),
+ ntlmv2_client_data.data, ntlmv2_client_data.length);
+
+ talloc_free(mem_ctx);
+
+ return final_response;
+}
+
+static DATA_BLOB LMv2_generate_response(TALLOC_CTX *mem_ctx,
+ const uint8_t ntlm_v2_hash[16],
+ const DATA_BLOB *server_chal)
+{
+ uint8_t lmv2_response[16];
+ DATA_BLOB lmv2_client_data = data_blob_talloc(mem_ctx, NULL, 8);
+ DATA_BLOB final_response = data_blob_talloc(mem_ctx, NULL,24);
+ NTSTATUS status;
+
+ /* LMv2 */
+ /* client-supplied random data */
+ generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length);
+
+ /* Given that data, and the challenge from the server, generate a response */
+ status = SMBOWFencrypt_ntv2(ntlm_v2_hash,
+ server_chal,
+ &lmv2_client_data,
+ lmv2_response);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&lmv2_client_data);
+ return data_blob(NULL, 0);
+ }
+ memcpy(final_response.data, lmv2_response, sizeof(lmv2_response));
+
+ /* after the first 16 bytes is the random data we generated above,
+ so the server can verify us with it */
+ memcpy(final_response.data+sizeof(lmv2_response),
+ lmv2_client_data.data, lmv2_client_data.length);
+
+ data_blob_free(&lmv2_client_data);
+
+ return final_response;
+}
+
+bool SMBNTLMv2encrypt_hash(TALLOC_CTX *mem_ctx,
+ const char *user, const char *domain, const uint8_t nt_hash[16],
+ const DATA_BLOB *server_chal,
+ const NTTIME *server_timestamp,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
+{
+ uint8_t ntlm_v2_hash[16];
+ NTSTATUS status;
+
+ /* We don't use the NT# directly. Instead we use it mashed up with
+ the username and domain.
+ This prevents username swapping during the auth exchange
+ */
+ if (!ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash)) {
+ return false;
+ }
+
+ if (nt_response) {
+ const NTTIME *nttime = server_timestamp;
+ NTTIME _now = 0;
+
+ if (nttime == NULL) {
+ struct timeval tv_now = timeval_current();
+ _now = timeval_to_nttime(&tv_now);
+ nttime = &_now;
+ }
+
+ *nt_response = NTLMv2_generate_response(mem_ctx,
+ ntlm_v2_hash,
+ server_chal,
+ *nttime,
+ names_blob);
+ if (user_session_key) {
+ *user_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+
+ /* The NTLMv2 calculations also provide a session key, for signing etc later */
+ /* use only the first 16 bytes of nt_response for session key */
+ status = SMBsesskeygen_ntv2(ntlm_v2_hash,
+ nt_response->data,
+ user_session_key->data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ }
+ }
+
+ /* LMv2 */
+
+ if (lm_response) {
+ if (server_timestamp != NULL) {
+ *lm_response = data_blob_talloc_zero(mem_ctx, 24);
+ } else {
+ *lm_response = LMv2_generate_response(mem_ctx,
+ ntlm_v2_hash,
+ server_chal);
+ }
+ if (lm_session_key) {
+ *lm_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+
+ /* The NTLMv2 calculations also provide a session key, for signing etc later */
+ /* use only the first 16 bytes of lm_response for session key */
+ status = SMBsesskeygen_ntv2(ntlm_v2_hash,
+ lm_response->data,
+ lm_session_key->data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool SMBNTLMv2encrypt(TALLOC_CTX *mem_ctx,
+ const char *user, const char *domain,
+ const char *password,
+ const DATA_BLOB *server_chal,
+ const DATA_BLOB *names_blob,
+ DATA_BLOB *lm_response, DATA_BLOB *nt_response,
+ DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key)
+{
+ uint8_t nt_hash[16];
+ E_md4hash(password, nt_hash);
+
+ return SMBNTLMv2encrypt_hash(mem_ctx,
+ user, domain, nt_hash,
+ server_chal, NULL, names_blob,
+ lm_response, nt_response, lm_session_key, user_session_key);
+}
+
+NTSTATUS NTLMv2_RESPONSE_verify_netlogon_creds(const char *account_name,
+ const char *account_domain,
+ const DATA_BLOB response,
+ const struct netlogon_creds_CredentialState *creds,
+ const char *workgroup)
+{
+ TALLOC_CTX *frame = NULL;
+ /* RespType + HiRespType */
+ static const char *magic = "\x01\x01";
+ int cmp;
+ struct NTLMv2_RESPONSE v2_resp;
+ enum ndr_err_code err;
+ const struct AV_PAIR *av_nb_cn = NULL;
+ const struct AV_PAIR *av_nb_dn = NULL;
+
+ if (response.length < 48) {
+ /*
+ * NTLMv2_RESPONSE has at least 48 bytes.
+ */
+ return NT_STATUS_OK;
+ }
+
+ cmp = memcmp(response.data + 16, magic, 2);
+ if (cmp != 0) {
+ /*
+ * It doesn't look like a valid NTLMv2_RESPONSE
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (response.length == 95) {
+ /*
+ * ndr_pull_NTLMv2_RESPONSE() fails on this strange blob,
+ * because the AvPairs content is not valid
+ * as AvLen of the first pair is 33032 (0x8108).
+ *
+ * I saw a single machine sending the following 3 times
+ * in a row, but I'm not sure if everything is static.
+ *
+ * Note this is NTLMv2_CLIENT_CHALLENGE only, not
+ * the full NTLMv2_RESPONSE (which has Response of 16 bytes
+ * before the NTLMv2_CLIENT_CHALLENGE).
+ *
+ * Note this code only prevents
+ * ndr_pull_error(Buffer Size Error): Pull bytes 39016
+ * debug message for a known case, the actual
+ * bug is also handled below in a generic way to
+ * map NT_STATUS_BUFFER_TOO_SMALL to NT_STATUS_OK.
+ *
+ * See https://bugzilla.samba.org/show_bug.cgi?id=14932
+ */
+ static const char *netapp_magic =
+ "\x01\x01\x00\x00\x00\x00\x00\x00"
+ "\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f"
+ "\xb8\x82\x3a\xf1\xb3\xdd\x08\x15"
+ "\x00\x00\x00\x00\x11\xa2\x08\x81"
+ "\x50\x38\x22\x78\x2b\x94\x47\xfe"
+ "\x54\x94\x7b\xff\x17\x27\x5a\xb4"
+ "\xf4\x18\xba\xdc\x2c\x38\xfd\x5b"
+ "\xfb\x0e\xc1\x85\x1e\xcc\x92\xbb"
+ "\x9b\xb1\xc4\xd5\x53\x14\xff\x8c"
+ "\x76\x49\xf5\x45\x90\x19\xa2";
+ /*
+ * First we check the initial bytes
+ * and the 0x3F timestamp.
+ */
+ cmp = memcmp(response.data + 16,
+ netapp_magic,
+ 16);
+ if (cmp == 0) {
+ /*
+ * Then check everything after the
+ * client challenge
+ */
+ cmp = memcmp(response.data + 40,
+ netapp_magic + 24,
+ response.length - 40);
+ if (cmp == 0) {
+ DBG_DEBUG("Invalid NETAPP NTLMv2_RESPONSE "
+ "for user[%s\\%s] against "
+ "SEC_CHAN(%u)[%s/%s] "
+ "in workgroup[%s]\n",
+ account_domain,
+ account_name,
+ creds->secure_channel_type,
+ creds->computer_name,
+ creds->account_name,
+ workgroup);
+ return NT_STATUS_OK;
+ }
+ }
+ }
+
+ frame = talloc_stackframe();
+
+ err = ndr_pull_struct_blob(&response, frame, &v2_resp,
+ (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ NTSTATUS status;
+ status = ndr_map_error2ntstatus(err);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+ /*
+ * We are supposed to ignore invalid buffers,
+ * see https://bugzilla.samba.org/show_bug.cgi?id=14932
+ */
+ status = NT_STATUS_OK;
+ }
+ DEBUG(2,("%s: Failed to parse NTLMv2_RESPONSE length=%u "
+ "for user[%s\\%s] against SEC_CHAN(%u)[%s/%s] "
+ "in workgroup[%s] - %s %s %s\n",
+ __func__,
+ (unsigned)response.length,
+ account_domain,
+ account_name,
+ creds->secure_channel_type,
+ creds->computer_name,
+ creds->account_name,
+ workgroup,
+ ndr_map_error2string(err),
+ NT_STATUS_IS_OK(status) ? "(ignoring) =>" : "=>",
+ nt_errstr(status)));
+ dump_data(2, response.data, response.length);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &v2_resp);
+ }
+
+ /*
+ * Make sure the netbios computer name in the
+ * NTLMv2_RESPONSE matches the computer name
+ * in the secure channel credentials for workstation
+ * trusts.
+ *
+ * And the netbios domain name matches our
+ * workgroup.
+ *
+ * This prevents workstations from requesting
+ * the session key of NTLMSSP sessions of clients
+ * to other hosts.
+ */
+ if (creds->secure_channel_type == SEC_CHAN_WKSTA) {
+ av_nb_cn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvNbComputerName);
+ av_nb_dn = ndr_ntlmssp_find_av(&v2_resp.Challenge.AvPairs,
+ MsvAvNbDomainName);
+ }
+
+ if (av_nb_cn != NULL) {
+ const char *v = NULL;
+ char *a = NULL;
+ size_t len;
+
+ v = av_nb_cn->Value.AvNbComputerName;
+
+ a = talloc_strdup(frame, creds->account_name);
+ if (a == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ len = strlen(a);
+ if (len > 0 && a[len - 1] == '$') {
+ a[len - 1] = '\0';
+ }
+
+ cmp = strcasecmp_m(a, v);
+ if (cmp != 0) {
+ DEBUG(2,("%s: NTLMv2_RESPONSE with "
+ "NbComputerName[%s] rejected "
+ "for user[%s\\%s] "
+ "against SEC_CHAN_WKSTA[%s/%s] "
+ "in workgroup[%s]\n",
+ __func__, v,
+ account_domain,
+ account_name,
+ creds->computer_name,
+ creds->account_name,
+ workgroup));
+ TALLOC_FREE(frame);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+ if (av_nb_dn != NULL) {
+ const char *v = NULL;
+
+ v = av_nb_dn->Value.AvNbDomainName;
+
+ cmp = strcasecmp_m(workgroup, v);
+ if (cmp != 0) {
+ DEBUG(2,("%s: NTLMv2_RESPONSE with "
+ "NbDomainName[%s] rejected "
+ "for user[%s\\%s] "
+ "against SEC_CHAN_WKSTA[%s/%s] "
+ "in workgroup[%s]\n",
+ __func__, v,
+ account_domain,
+ account_name,
+ creds->computer_name,
+ creds->account_name,
+ workgroup));
+ TALLOC_FREE(frame);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+enum encode_order {
+ ENCODE_ORDER_PASSWORD_FIRST,
+ ENCODE_ORDER_PASSWORD_LAST,
+};
+
+#define PASSWORD_BUFFER_LEN 512
+
+static ssize_t _encode_pwd_buffer_from_str(uint8_t buf[PASSWORD_BUFFER_LEN],
+ const char *password,
+ int string_flags,
+ enum encode_order order)
+{
+ ssize_t new_pw_len;
+ size_t pw_pos = 0;
+ size_t random_pos = 0;
+ size_t random_len = 0;
+
+ /* The incoming buffer can be any alignment. */
+ string_flags |= STR_NOALIGN;
+
+ new_pw_len = push_string(buf,
+ password,
+ PASSWORD_BUFFER_LEN,
+ string_flags);
+ if (new_pw_len < 0) {
+ BURN_DATA_SIZE(buf, PASSWORD_BUFFER_LEN);
+ return -1;
+ }
+
+ if (new_pw_len == PASSWORD_BUFFER_LEN) {
+ return new_pw_len;
+ }
+
+ switch (order) {
+ case ENCODE_ORDER_PASSWORD_FIRST:
+ pw_pos = 0;
+ random_pos = new_pw_len;
+ random_len = PASSWORD_BUFFER_LEN - random_pos;
+ break;
+ case ENCODE_ORDER_PASSWORD_LAST:
+ pw_pos = PASSWORD_BUFFER_LEN - new_pw_len;
+ random_pos = 0;
+ random_len = pw_pos;
+ memmove(buf + pw_pos, buf, new_pw_len);
+ break;
+ }
+
+ generate_random_buffer(buf + random_pos, random_len);
+
+ return new_pw_len;
+}
+
+/***********************************************************
+ encode a password buffer with a unicode password. The buffer
+ is filled with random data to make it harder to attack.
+************************************************************/
+bool encode_pw_buffer(uint8_t buffer[516], const char *password, int string_flags)
+{
+ ssize_t pw_len;
+
+ pw_len = _encode_pwd_buffer_from_str(buffer,
+ password,
+ string_flags,
+ ENCODE_ORDER_PASSWORD_LAST);
+ if (pw_len < 0 || pw_len > PASSWORD_BUFFER_LEN) {
+ return false;
+ }
+
+ PUSH_LE_U32(buffer, PASSWORD_BUFFER_LEN, pw_len);
+
+ return true;
+}
+
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_len is the length in bytes of the possibly mulitbyte
+ returned password including termination.
+************************************************************/
+
+bool decode_pw_buffer(TALLOC_CTX *ctx,
+ uint8_t in_buffer[516],
+ char **pp_new_pwrd,
+ size_t *new_pw_len,
+ charset_t string_charset)
+{
+ DATA_BLOB new_password;
+ int byte_len=0;
+ bool ok;
+
+ *pp_new_pwrd = NULL;
+ *new_pw_len = 0;
+
+ ok = extract_pw_from_buffer(ctx, in_buffer, &new_password);
+ if (!ok) {
+ return false;
+ }
+
+ /*
+ Warning !!! : This function is called from some rpc call.
+ The password IN the buffer may be a UNICODE string.
+ The password IN new_pwrd is an ASCII string
+ If you reuse that code somewhere else check first.
+ */
+
+ /* decode into the return buffer. */
+ ok = convert_string_talloc(ctx,
+ string_charset,
+ CH_UNIX,
+ new_password.data,
+ new_password.length,
+ pp_new_pwrd,
+ new_pw_len);
+ data_blob_free(&new_password);
+ if (!ok) {
+ DBG_ERR("Failed to convert incoming password\n");
+ return false;
+ }
+ talloc_keep_secret(*pp_new_pwrd);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decode_pw_buffer: new_pwrd: "));
+ dump_data(100, (uint8_t *)*pp_new_pwrd, *new_pw_len);
+ DEBUG(100,("multibyte len:%lu\n", (unsigned long int)*new_pw_len));
+ DEBUG(100,("original char len:%d\n", byte_len/2));
+#endif
+
+ return true;
+}
+
+#define MAX_PASSWORD_LEN 256
+
+/*
+ * [MS-SAMR] 2.2.6.32 This creates the buffer to be sent. It is of type
+ * SAMPR_USER_PASSWORD_AES.
+ */
+bool encode_pwd_buffer514_from_str(uint8_t buffer[514],
+ const char *password,
+ uint32_t string_flags)
+{
+ ssize_t pw_len;
+
+ pw_len = _encode_pwd_buffer_from_str(buffer + 2,
+ password,
+ string_flags,
+ ENCODE_ORDER_PASSWORD_FIRST);
+ if (pw_len < 0) {
+ return false;
+ }
+
+ PUSH_LE_U16(buffer, 0, pw_len);
+
+ return true;
+}
+
+bool extract_pwd_blob_from_buffer514(TALLOC_CTX *mem_ctx,
+ const uint8_t in_buffer[514],
+ DATA_BLOB *new_password)
+{
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("in_buffer: "));
+ dump_data(100, in_buffer, 514);
+#endif
+
+ new_password->length = PULL_LE_U16(in_buffer, 0);
+ if (new_password->length == 0 || new_password->length > 512) {
+ return false;
+ }
+
+ new_password->data =
+ talloc_memdup(mem_ctx, in_buffer + 2, new_password->length);
+ if (new_password->data == NULL) {
+ return false;
+ }
+ talloc_keep_secret(new_password->data);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100, ("new_pwd_len: %zu\n", new_password->length));
+ DEBUG(100, ("new_pwd: "));
+ dump_data(100, new_password->data, new_password->length);
+#endif
+
+ return true;
+}
+
+bool decode_pwd_string_from_buffer514(TALLOC_CTX *mem_ctx,
+ const uint8_t in_buffer[514],
+ charset_t string_charset,
+ DATA_BLOB *decoded_password)
+{
+ DATA_BLOB new_password = {
+ .length = 0,
+ };
+ bool ok;
+
+ ok = extract_pwd_blob_from_buffer514(mem_ctx, in_buffer, &new_password);
+ if (!ok) {
+ return false;
+ }
+
+ ok = convert_string_talloc(mem_ctx,
+ string_charset,
+ CH_UNIX,
+ new_password.data,
+ new_password.length,
+ &decoded_password->data,
+ &decoded_password->length);
+ data_blob_free(&new_password);
+ if (!ok) {
+ return false;
+ }
+ talloc_keep_secret(decoded_password->data);
+
+ return true;
+}
+
+/***********************************************************
+ Encode an arc4 password change buffer.
+************************************************************/
+NTSTATUS encode_rc4_passwd_buffer(const char *passwd,
+ const DATA_BLOB *session_key,
+ struct samr_CryptPasswordEx *out_crypt_pwd)
+{
+ uint8_t _confounder[16] = {0};
+ DATA_BLOB confounder = data_blob_const(_confounder, 16);
+ DATA_BLOB pw_data = data_blob_const(out_crypt_pwd->data, 516);
+ bool ok;
+ int rc;
+
+ ok = encode_pw_buffer(pw_data.data, passwd, STR_UNICODE);
+ if (!ok) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ generate_random_buffer(confounder.data, confounder.length);
+
+ rc = samba_gnutls_arcfour_confounded_md5(&confounder,
+ session_key,
+ &pw_data,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ ZERO_ARRAY(_confounder);
+ data_blob_clear(&pw_data);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ /*
+ * The packet format is the 516 byte RC4 encrypted
+ * password followed by the 16 byte counfounder
+ * The confounder is a salt to prevent pre-computed hash attacks on the
+ * database.
+ */
+ memcpy(&out_crypt_pwd->data[516], confounder.data, confounder.length);
+ ZERO_ARRAY(_confounder);
+
+ return NT_STATUS_OK;
+}
+
+/***********************************************************
+ Decode an arc4 encrypted password change buffer.
+************************************************************/
+
+NTSTATUS decode_rc4_passwd_buffer(const DATA_BLOB *psession_key,
+ struct samr_CryptPasswordEx *inout_crypt_pwd)
+{
+ /* Confounder is last 16 bytes. */
+ DATA_BLOB confounder = data_blob_const(&inout_crypt_pwd->data[516], 16);
+ DATA_BLOB pw_data = data_blob_const(&inout_crypt_pwd->data, 516);
+ int rc;
+
+ rc = samba_gnutls_arcfour_confounded_md5(&confounder,
+ psession_key,
+ &pw_data,
+ SAMBA_GNUTLS_DECRYPT);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/***********************************************************
+ encode a password buffer with an already unicode password. The
+ rest of the buffer is filled with random data to make it harder to attack.
+************************************************************/
+
+static bool create_pw_buffer_from_blob(uint8_t buffer[512],
+ const DATA_BLOB *in_password,
+ enum encode_order order)
+{
+ size_t pwd_pos = 0;
+ size_t random_pos = 0;
+ size_t random_len = 0;
+
+ if (in_password->length > 512) {
+ return false;
+ }
+
+ switch (order) {
+ case ENCODE_ORDER_PASSWORD_FIRST:
+ pwd_pos = 0;
+ random_pos = in_password->length;
+ break;
+ case ENCODE_ORDER_PASSWORD_LAST:
+ pwd_pos = PASSWORD_BUFFER_LEN - in_password->length;
+ random_pos = 0;
+ break;
+ }
+ random_len = PASSWORD_BUFFER_LEN - in_password->length;
+
+ memcpy(buffer + pwd_pos, in_password->data, in_password->length);
+ generate_random_buffer(buffer + random_pos, random_len);
+
+ return true;
+}
+
+bool set_pw_in_buffer(uint8_t buffer[516], const DATA_BLOB *password)
+{
+ bool ok;
+
+ ok = create_pw_buffer_from_blob(buffer,
+ password,
+ ENCODE_ORDER_PASSWORD_LAST);
+ if (!ok) {
+ return false;
+ }
+
+ /*
+ * The length of the new password is in the last 4 bytes of
+ * the data buffer.
+ */
+ PUSH_LE_U32(buffer, PASSWORD_BUFFER_LEN, password->length);
+
+ return true;
+}
+
+/***********************************************************
+ decode a password buffer
+ *new_pw_size is the length in bytes of the extracted unicode password
+************************************************************/
+bool extract_pw_from_buffer(TALLOC_CTX *mem_ctx,
+ uint8_t in_buffer[516], DATA_BLOB *new_pass)
+{
+ int byte_len=0;
+
+ /* The length of the new password is in the last 4 bytes of the data buffer. */
+
+ byte_len = IVAL(in_buffer, 512);
+
+#ifdef DEBUG_PASSWORD
+ dump_data(100, in_buffer, 516);
+#endif
+
+ /* Password cannot be longer than the size of the password buffer */
+ if ( (byte_len < 0) || (byte_len > 512)) {
+ return false;
+ }
+
+ *new_pass = data_blob_talloc(mem_ctx, &in_buffer[512 - byte_len], byte_len);
+
+ if (!new_pass->data) {
+ return false;
+ }
+ talloc_keep_secret(new_pass->data);
+
+ return true;
+}
+
+
+/* encode a wkssvc_PasswordBuffer:
+ *
+ * similar to samr_CryptPasswordEx. Different: 8byte confounder (instead of
+ * 16byte), confounder in front of the 516 byte buffer (instead of after that
+ * buffer), calling MD5Update() first with session_key and then with confounder
+ * (vice versa in samr) - Guenther */
+
+WERROR encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ const char *pwd,
+ DATA_BLOB *session_key,
+ struct wkssvc_PasswordBuffer **out_pwd_buf)
+{
+ struct wkssvc_PasswordBuffer *pwd_buf = NULL;
+ uint8_t _confounder[8] = {0};
+ DATA_BLOB confounder = data_blob_const(_confounder, 8);
+ uint8_t pwbuf[516] = {0};
+ DATA_BLOB encrypt_pwbuf = data_blob_const(pwbuf, 516);
+ int rc;
+
+ pwd_buf = talloc_zero(mem_ctx, struct wkssvc_PasswordBuffer);
+ if (pwd_buf == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ encode_pw_buffer(pwbuf, pwd, STR_UNICODE);
+
+ generate_random_buffer(_confounder, sizeof(_confounder));
+
+ rc = samba_gnutls_arcfour_confounded_md5(session_key,
+ &confounder,
+ &encrypt_pwbuf,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ ZERO_ARRAY(_confounder);
+ TALLOC_FREE(pwd_buf);
+ return gnutls_error_to_werror(rc, WERR_CONTENT_BLOCKED);
+ }
+
+ memcpy(&pwd_buf->data[0], confounder.data, confounder.length);
+ ZERO_ARRAY(_confounder);
+ memcpy(&pwd_buf->data[8], encrypt_pwbuf.data, encrypt_pwbuf.length);
+ ZERO_ARRAY(pwbuf);
+
+ *out_pwd_buf = pwd_buf;
+
+ return WERR_OK;
+}
+
+WERROR decode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
+ struct wkssvc_PasswordBuffer *pwd_buf,
+ DATA_BLOB *session_key,
+ char **pwd)
+{
+ uint8_t _confounder[8] = { 0 };
+ DATA_BLOB confounder = data_blob_const(_confounder, 8);
+ uint8_t pwbuf[516] = {0};
+ DATA_BLOB decrypt_pwbuf = data_blob_const(pwbuf, 516);
+ bool ok;
+ int rc;
+
+ if (pwd_buf == NULL) {
+ return WERR_INVALID_PASSWORD;
+ }
+
+ *pwd = NULL;
+
+ if (session_key->length != 16) {
+ DEBUG(10,("invalid session key\n"));
+ return WERR_INVALID_PASSWORD;
+ }
+
+ confounder = data_blob_const(&pwd_buf->data[0], 8);
+ memcpy(&pwbuf, &pwd_buf->data[8], 516);
+
+ rc = samba_gnutls_arcfour_confounded_md5(session_key,
+ &confounder,
+ &decrypt_pwbuf,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ ZERO_ARRAY(_confounder);
+ TALLOC_FREE(pwd_buf);
+ return gnutls_error_to_werror(rc, WERR_CONTENT_BLOCKED);
+ }
+
+ ok = decode_pw_buffer(mem_ctx,
+ decrypt_pwbuf.data,
+ pwd,
+ &decrypt_pwbuf.length,
+ CH_UTF16);
+ ZERO_ARRAY(pwbuf);
+
+ if (!ok) {
+ return WERR_INVALID_PASSWORD;
+ }
+
+ return WERR_OK;
+}
diff --git a/libcli/auth/spnego.h b/libcli/auth/spnego.h
new file mode 100644
index 0000000..49645e0
--- /dev/null
+++ b/libcli/auth/spnego.h
@@ -0,0 +1,82 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ RFC2478 Compliant SPNEGO implementation
+
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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/>.
+*/
+
+#define OID_SPNEGO "1.3.6.1.5.5.2"
+#define OID_NTLMSSP "1.3.6.1.4.1.311.2.2.10"
+#define OID_KERBEROS5_OLD "1.2.840.48018.1.2.2"
+#define OID_KERBEROS5 "1.2.840.113554.1.2.2"
+
+#define ADS_IGNORE_PRINCIPAL "not_defined_in_RFC4178@please_ignore"
+
+#define SPNEGO_DELEG_FLAG 0x01
+#define SPNEGO_MUTUAL_FLAG 0x02
+#define SPNEGO_REPLAY_FLAG 0x04
+#define SPNEGO_SEQUENCE_FLAG 0x08
+#define SPNEGO_ANON_FLAG 0x10
+#define SPNEGO_CONF_FLAG 0x20
+#define SPNEGO_INTEG_FLAG 0x40
+
+#define TOK_ID_KRB_AP_REQ ((const uint8_t *)"\x01\x00")
+#define TOK_ID_KRB_AP_REP ((const uint8_t *)"\x02\x00")
+#define TOK_ID_KRB_ERROR ((const uint8_t *)"\x03\x00")
+#define TOK_ID_GSS_GETMIC ((const uint8_t *)"\x01\x01")
+#define TOK_ID_GSS_WRAP ((const uint8_t *)"\x02\x01")
+
+enum spnego_negResult {
+ SPNEGO_ACCEPT_COMPLETED = 0,
+ SPNEGO_ACCEPT_INCOMPLETE = 1,
+ SPNEGO_REJECT = 2,
+ SPNEGO_REQUEST_MIC = 3,
+ /*
+ * The max value is 0xff (255) on the wire
+ */
+ SPNEGO_NONE_RESULT = 256
+};
+
+struct spnego_negTokenInit {
+ const char * const *mechTypes;
+ DATA_BLOB reqFlags;
+ uint8_t reqFlagsPadding;
+ DATA_BLOB mechToken;
+ DATA_BLOB mechListMIC;
+ char *targetPrincipal;
+};
+
+struct spnego_negTokenTarg {
+ enum spnego_negResult negResult;
+ const char *supportedMech;
+ DATA_BLOB responseToken;
+ DATA_BLOB mechListMIC;
+};
+
+struct spnego_data {
+ int type;
+ struct spnego_negTokenInit negTokenInit;
+ struct spnego_negTokenTarg negTokenTarg;
+};
+
+enum spnego_message_type {
+ SPNEGO_NEG_TOKEN_INIT = 0,
+ SPNEGO_NEG_TOKEN_TARG = 1,
+};
+
+#include "../libcli/auth/spnego_proto.h"
diff --git a/libcli/auth/spnego_parse.c b/libcli/auth/spnego_parse.c
new file mode 100644
index 0000000..f7f19b1
--- /dev/null
+++ b/libcli/auth/spnego_parse.c
@@ -0,0 +1,446 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ RFC2478 Compliant SPNEGO implementation
+
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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 "../libcli/auth/spnego.h"
+#include "../lib/util/asn1.h"
+
+static bool read_negTokenInit(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+ struct spnego_negTokenInit *token)
+{
+ ZERO_STRUCTP(token);
+
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ while (asn1_tag_remaining(asn1) > 0) {
+ int i;
+ uint8_t context;
+
+ if (!asn1_peek_uint8(asn1, &context)) {
+ asn1_set_error(asn1);
+ break;
+ }
+
+ switch (context) {
+ /* Read mechTypes */
+ case ASN1_CONTEXT(0): {
+ const char **mechTypes;
+
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ mechTypes = talloc(mem_ctx, const char *);
+ if (mechTypes == NULL) {
+ asn1_set_error(asn1);
+ return false;
+ }
+ for (i = 0; asn1_tag_remaining(asn1) > 0; i++) {
+ char *oid;
+ const char **p;
+ p = talloc_realloc(mem_ctx,
+ mechTypes,
+ const char *, i+2);
+ if (p == NULL) {
+ talloc_free(mechTypes);
+ asn1_set_error(asn1);
+ return false;
+ }
+ mechTypes = p;
+
+ if (!asn1_read_OID(asn1, mechTypes, &oid)) return false;
+ mechTypes[i] = oid;
+ }
+ mechTypes[i] = NULL;
+ token->mechTypes = mechTypes;
+
+ asn1_end_tag(asn1);
+ asn1_end_tag(asn1);
+ break;
+ }
+ /* Read reqFlags */
+ case ASN1_CONTEXT(1):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_read_BitString(asn1, mem_ctx, &token->reqFlags,
+ &token->reqFlagsPadding)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ /* Read mechToken */
+ case ASN1_CONTEXT(2):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(2))) return false;
+ if (!asn1_read_OctetString(asn1, mem_ctx, &token->mechToken)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ /* Read mecListMIC */
+ case ASN1_CONTEXT(3):
+ {
+ uint8_t type_peek;
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
+ if (!asn1_peek_uint8(asn1, &type_peek)) {
+ asn1_set_error(asn1);
+ break;
+ }
+ if (type_peek == ASN1_OCTET_STRING) {
+ if (!asn1_read_OctetString(asn1, mem_ctx,
+ &token->mechListMIC)) return false;
+ } else {
+ /* RFC 2478 says we have an Octet String here,
+ but W2k sends something different... */
+ char *mechListMIC;
+ if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_read_GeneralString(asn1, mem_ctx, &mechListMIC)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+
+ token->targetPrincipal = mechListMIC;
+ }
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ }
+ default:
+ asn1_set_error(asn1);
+ break;
+ }
+ }
+
+ if (!asn1_end_tag(asn1)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+
+ return !asn1_has_error(asn1);
+}
+
+static bool write_negTokenInit(struct asn1_data *asn1, struct spnego_negTokenInit *token)
+{
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ /* Write mechTypes */
+ if (token->mechTypes && *token->mechTypes) {
+ int i;
+
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
+ for (i = 0; token->mechTypes[i]; i++) {
+ if (!asn1_write_OID(asn1, token->mechTypes[i])) return false;
+ }
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ /* write reqFlags */
+ if (token->reqFlags.length > 0) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_write_BitString(asn1, token->reqFlags.data,
+ token->reqFlags.length,
+ token->reqFlagsPadding)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ /* write mechToken */
+ if (token->mechToken.data) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(2))) return false;
+ if (!asn1_write_OctetString(asn1, token->mechToken.data,
+ token->mechToken.length)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ /* write mechListMIC */
+ if (token->mechListMIC.data) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(3))) return false;
+#if 0
+ /* This is what RFC 2478 says ... */
+ asn1_write_OctetString(asn1, token->mechListMIC.data,
+ token->mechListMIC.length);
+#else
+ /* ... but unfortunately this is what Windows
+ sends/expects */
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_push_tag(asn1, ASN1_GENERAL_STRING)) return false;
+ if (!asn1_write(asn1, token->mechListMIC.data,
+ token->mechListMIC.length)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+#endif
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+
+ return !asn1_has_error(asn1);
+}
+
+static bool read_negTokenTarg(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
+ struct spnego_negTokenTarg *token)
+{
+ ZERO_STRUCTP(token);
+
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ while (asn1_tag_remaining(asn1) > 0) {
+ uint8_t context;
+ uint8_t neg_result;
+ char *oid;
+
+ if (!asn1_peek_uint8(asn1, &context)) {
+ asn1_set_error(asn1);
+ break;
+ }
+
+ switch (context) {
+ case ASN1_CONTEXT(0):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_start_tag(asn1, ASN1_ENUMERATED)) return false;
+ if (!asn1_read_uint8(asn1, &neg_result)) return false;
+ token->negResult = neg_result;
+ if (!asn1_end_tag(asn1)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ case ASN1_CONTEXT(1):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_read_OID(asn1, mem_ctx, &oid)) return false;
+ token->supportedMech = oid;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ case ASN1_CONTEXT(2):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(2))) return false;
+ if (!asn1_read_OctetString(asn1, mem_ctx, &token->responseToken)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ case ASN1_CONTEXT(3):
+ if (!asn1_start_tag(asn1, ASN1_CONTEXT(3))) return false;
+ if (!asn1_read_OctetString(asn1, mem_ctx, &token->mechListMIC)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+ break;
+ default:
+ asn1_set_error(asn1);
+ break;
+ }
+ }
+
+ if (!asn1_end_tag(asn1)) return false;
+ if (!asn1_end_tag(asn1)) return false;
+
+ return !asn1_has_error(asn1);
+}
+
+static bool write_negTokenTarg(struct asn1_data *asn1, struct spnego_negTokenTarg *token)
+{
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) return false;
+
+ if (token->negResult != SPNEGO_NONE_RESULT) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(0))) return false;
+ if (!asn1_write_enumerated(asn1, token->negResult)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (token->supportedMech) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(1))) return false;
+ if (!asn1_write_OID(asn1, token->supportedMech)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (token->responseToken.data) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(2))) return false;
+ if (!asn1_write_OctetString(asn1, token->responseToken.data,
+ token->responseToken.length)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (token->mechListMIC.data) {
+ if (!asn1_push_tag(asn1, ASN1_CONTEXT(3))) return false;
+ if (!asn1_write_OctetString(asn1, token->mechListMIC.data,
+ token->mechListMIC.length)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+ }
+
+ if (!asn1_pop_tag(asn1)) return false;
+ if (!asn1_pop_tag(asn1)) return false;
+
+ return !asn1_has_error(asn1);
+}
+
+ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token)
+{
+ struct asn1_data *asn1;
+ ssize_t ret = -1;
+ uint8_t context;
+
+ ZERO_STRUCTP(token);
+
+ if (data.length == 0) {
+ return ret;
+ }
+
+ asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
+ if (asn1 == NULL) {
+ return -1;
+ }
+
+ if (!asn1_load(asn1, data)) goto err;
+
+ if (!asn1_peek_uint8(asn1, &context)) {
+ asn1_set_error(asn1);
+ } else {
+ switch (context) {
+ case ASN1_APPLICATION(0):
+ if (!asn1_start_tag(asn1, ASN1_APPLICATION(0))) goto err;
+ if (!asn1_check_OID(asn1, OID_SPNEGO)) goto err;
+ if (read_negTokenInit(asn1, mem_ctx, &token->negTokenInit)) {
+ token->type = SPNEGO_NEG_TOKEN_INIT;
+ }
+ if (!asn1_end_tag(asn1)) goto err;
+ break;
+ case ASN1_CONTEXT(1):
+ if (read_negTokenTarg(asn1, mem_ctx, &token->negTokenTarg)) {
+ token->type = SPNEGO_NEG_TOKEN_TARG;
+ }
+ break;
+ default:
+ asn1_set_error(asn1);
+ break;
+ }
+ }
+
+ if (!asn1_has_error(asn1)) {
+ ret = asn1_current_ofs(asn1);
+ }
+
+ err:
+
+ asn1_free(asn1);
+
+ return ret;
+}
+
+ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego)
+{
+ struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
+ ssize_t ret = -1;
+
+ if (asn1 == NULL) {
+ return -1;
+ }
+
+ switch (spnego->type) {
+ case SPNEGO_NEG_TOKEN_INIT:
+ if (!asn1_push_tag(asn1, ASN1_APPLICATION(0))) goto err;
+ if (!asn1_write_OID(asn1, OID_SPNEGO)) goto err;
+ if (!write_negTokenInit(asn1, &spnego->negTokenInit)) goto err;
+ if (!asn1_pop_tag(asn1)) goto err;
+ break;
+ case SPNEGO_NEG_TOKEN_TARG:
+ write_negTokenTarg(asn1, &spnego->negTokenTarg);
+ break;
+ default:
+ asn1_set_error(asn1);
+ break;
+ }
+
+ if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
+ goto err;
+ }
+
+ ret = asn1_current_ofs(asn1);
+
+ err:
+
+ asn1_free(asn1);
+
+ return ret;
+}
+
+bool spnego_free_data(struct spnego_data *spnego)
+{
+ bool ret = true;
+
+ if (!spnego) goto out;
+
+ switch(spnego->type) {
+ case SPNEGO_NEG_TOKEN_INIT:
+ if (spnego->negTokenInit.mechTypes) {
+ talloc_free(discard_const(spnego->negTokenInit.mechTypes));
+ }
+ data_blob_free(&spnego->negTokenInit.reqFlags);
+ data_blob_free(&spnego->negTokenInit.mechToken);
+ data_blob_free(&spnego->negTokenInit.mechListMIC);
+ talloc_free(spnego->negTokenInit.targetPrincipal);
+ break;
+ case SPNEGO_NEG_TOKEN_TARG:
+ if (spnego->negTokenTarg.supportedMech) {
+ talloc_free(discard_const(spnego->negTokenTarg.supportedMech));
+ }
+ data_blob_free(&spnego->negTokenTarg.responseToken);
+ data_blob_free(&spnego->negTokenTarg.mechListMIC);
+ break;
+ default:
+ ret = false;
+ break;
+ }
+ ZERO_STRUCTP(spnego);
+out:
+ return ret;
+}
+
+bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
+ const char * const *mech_types,
+ DATA_BLOB *blob)
+{
+ bool ret = false;
+ struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
+
+ if (asn1 == NULL) {
+ return false;
+ }
+
+ /* Write mechTypes */
+ if (mech_types && *mech_types) {
+ int i;
+
+ if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) goto err;
+ for (i = 0; mech_types[i]; i++) {
+ if (!asn1_write_OID(asn1, mech_types[i])) goto err;
+ }
+ if (!asn1_pop_tag(asn1)) goto err;
+ }
+
+ if (asn1_has_error(asn1)) {
+ goto err;
+ }
+
+ if (!asn1_extract_blob(asn1, mem_ctx, blob)) {
+ goto err;
+ }
+
+ ret = true;
+
+ err:
+
+ asn1_free(asn1);
+
+ return ret;
+}
diff --git a/libcli/auth/spnego_proto.h b/libcli/auth/spnego_proto.h
new file mode 100644
index 0000000..c0fa934
--- /dev/null
+++ b/libcli/auth/spnego_proto.h
@@ -0,0 +1,28 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ RFC2478 Compliant SPNEGO implementation
+
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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/>.
+*/
+
+ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token);
+ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego);
+bool spnego_free_data(struct spnego_data *spnego);
+bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
+ const char * const *mech_types,
+ DATA_BLOB *blob);
diff --git a/libcli/auth/tests/ntlm_check.c b/libcli/auth/tests/ntlm_check.c
new file mode 100644
index 0000000..79b8ec9
--- /dev/null
+++ b/libcli/auth/tests/ntlm_check.c
@@ -0,0 +1,413 @@
+/*
+ * Unit tests for the ntlm_check password hash check 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 <stdint.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "includes.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "libcli/auth/libcli_auth.h"
+#include "auth/credentials/credentials.h"
+
+struct ntlm_state {
+ const char *username;
+ const char *domain;
+ DATA_BLOB challenge;
+ DATA_BLOB ntlm;
+ DATA_BLOB lm;
+ DATA_BLOB ntlm_key;
+ DATA_BLOB lm_key;
+ const struct samr_Password *nt_hash;
+};
+
+static int test_ntlm_setup_with_options(void **state,
+ int flags, bool upn)
+{
+ NTSTATUS status;
+ DATA_BLOB challenge = {
+ .data = discard_const_p(uint8_t, "I am a teapot"),
+ .length = 8
+ };
+ struct ntlm_state *ntlm_state = talloc(NULL, struct ntlm_state);
+ DATA_BLOB target_info = NTLMv2_generate_names_blob(ntlm_state,
+ NULL,
+ "serverdom");
+ struct cli_credentials *creds = cli_credentials_init(ntlm_state);
+ cli_credentials_set_username(creds,
+ "testuser",
+ CRED_SPECIFIED);
+ cli_credentials_set_domain(creds,
+ "testdom",
+ CRED_SPECIFIED);
+ cli_credentials_set_workstation(creds,
+ "testwksta",
+ CRED_SPECIFIED);
+ cli_credentials_set_password(creds,
+ "testpass",
+ CRED_SPECIFIED);
+
+ if (upn) {
+ cli_credentials_set_principal(creds,
+ "testuser@samba.org",
+ CRED_SPECIFIED);
+ }
+
+ cli_credentials_get_ntlm_username_domain(creds,
+ ntlm_state,
+ &ntlm_state->username,
+ &ntlm_state->domain);
+
+ status = cli_credentials_get_ntlm_response(creds,
+ ntlm_state,
+ &flags,
+ challenge,
+ NULL,
+ target_info,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ &ntlm_state->lm_key,
+ &ntlm_state->ntlm_key);
+ ntlm_state->challenge = challenge;
+
+ ntlm_state->nt_hash = cli_credentials_get_nt_hash(creds,
+ ntlm_state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ *state = ntlm_state;
+ return 0;
+}
+
+static int test_ntlm_setup(void **state) {
+ return test_ntlm_setup_with_options(state, 0, false);
+}
+
+static int test_ntlm_and_lm_setup(void **state) {
+ return test_ntlm_setup_with_options(state,
+ CLI_CRED_LANMAN_AUTH,
+ false);
+}
+
+static int test_ntlm2_setup(void **state) {
+ return test_ntlm_setup_with_options(state,
+ CLI_CRED_NTLM2,
+ false);
+}
+
+static int test_ntlmv2_setup(void **state) {
+ return test_ntlm_setup_with_options(state,
+ CLI_CRED_NTLMv2_AUTH,
+ false);
+}
+
+static int test_ntlm_teardown(void **state)
+{
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ TALLOC_FREE(ntlm_state);
+ *state = NULL;
+ return 0;
+}
+
+static void test_ntlm_allowed(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_ON,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status), NT_STATUS_V(NT_STATUS_OK));
+}
+
+static void test_ntlm_allowed_lm_supplied(void **state)
+{
+ test_ntlm_allowed(state);
+}
+
+static void test_ntlm_disabled(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_DISABLED,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status), NT_STATUS_V(NT_STATUS_NTLM_BLOCKED));
+}
+
+static void test_ntlm2(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_ON,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ /*
+ * NTLM2 session security (where the real challenge is the
+ * MD5(challenge, client-challenge) (in the first 8 bytes of
+ * the lm) isn't decoded by ntlm_password_check(), it must
+ * first be converted back into normal NTLM by the NTLMSSP
+ * layer
+ */
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_WRONG_PASSWORD));
+}
+
+static void test_ntlm_mschapv2_only_allowed(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_MSCHAPv2_NTLMV2_ONLY,
+ MSV1_0_ALLOW_MSVCHAPV2,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status), NT_STATUS_V(NT_STATUS_OK));
+}
+
+static void test_ntlm_mschapv2_only_denied(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_MSCHAPv2_NTLMV2_ONLY,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_WRONG_PASSWORD));
+}
+
+static void test_ntlmv2_only_ntlmv2(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_NTLMV2_ONLY,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status), NT_STATUS_V(NT_STATUS_OK));
+}
+
+static void test_ntlmv2_only_ntlm(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_NTLMV2_ONLY,
+ 0,
+ &ntlm_state->challenge,
+ &ntlm_state->lm,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_WRONG_PASSWORD));
+}
+
+static void test_ntlmv2_only_ntlm_and_lanman(void **state)
+{
+ test_ntlmv2_only_ntlm(state);
+}
+
+static void test_ntlmv2_only_ntlm_once(void **state)
+{
+ DATA_BLOB user_sess_key, lm_sess_key;
+ struct ntlm_state *ntlm_state
+ = talloc_get_type_abort(*state,
+ struct ntlm_state);
+ NTSTATUS status;
+ status = ntlm_password_check(ntlm_state,
+ false,
+ NTLM_AUTH_NTLMV2_ONLY,
+ 0,
+ &ntlm_state->challenge,
+ &data_blob_null,
+ &ntlm_state->ntlm,
+ ntlm_state->username,
+ ntlm_state->username,
+ ntlm_state->domain,
+ NULL,
+ ntlm_state->nt_hash,
+ &user_sess_key,
+ &lm_sess_key);
+
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_WRONG_PASSWORD));
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_ntlm_allowed,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm_allowed_lm_supplied,
+ test_ntlm_and_lm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm_disabled,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm2,
+ test_ntlm2_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm_mschapv2_only_allowed,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlm_mschapv2_only_denied,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlmv2_only_ntlm,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlmv2_only_ntlm_and_lanman,
+ test_ntlm_and_lm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlmv2_only_ntlm_once,
+ test_ntlm_setup,
+ test_ntlm_teardown),
+ cmocka_unit_test_setup_teardown(test_ntlmv2_only_ntlmv2,
+ test_ntlmv2_setup,
+ test_ntlm_teardown)
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/auth/tests/test_encode_decode.c b/libcli/auth/tests/test_encode_decode.c
new file mode 100644
index 0000000..4683edf
--- /dev/null
+++ b/libcli/auth/tests/test_encode_decode.c
@@ -0,0 +1,162 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 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 "libcli/auth/smbencrypt.c"
+
+/* The following hexdumps are from a Windows Server 2022 time trace */
+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 void torture_encode_pwd_buffer514_from_str(void **state)
+{
+ uint8_t data[514] = {0};
+ bool ok;
+
+ ok = encode_pwd_buffer514_from_str(data, "Pa$$w0rd@2", STR_UNICODE);
+ assert_true(ok);
+
+ /* We can only compare the first 22 bytes as the rest is random data */
+ assert_memory_equal(data, plaintext_data, 22);
+ assert_memory_not_equal(data + 22,
+ plaintext_data + 22,
+ sizeof(plaintext_data) - 22);
+}
+
+static void torture_extract_pwd_blob_from_buffer514(void **state)
+{
+ DATA_BLOB new_password = {
+ .length = 0,
+ };
+ bool ok;
+
+ ok = extract_pwd_blob_from_buffer514(NULL, plaintext_data, &new_password);
+ assert_true(ok);
+ assert_int_equal(new_password.length, 20);
+ assert_memory_equal(new_password.data,
+ plaintext_data + 2,
+ new_password.length);
+ data_blob_free(&new_password);
+}
+
+static void torture_decode_pwd_string_from_buffer514(void **state)
+{
+ DATA_BLOB decoded_password = {
+ .length = 0,
+ };
+ bool ok;
+
+ ok = decode_pwd_string_from_buffer514(NULL,
+ plaintext_data,
+ CH_UTF16,
+ &decoded_password);
+ assert_true(ok);
+ assert_memory_equal(decoded_password.data, "Pa$$w0rd@2", decoded_password.length);
+ data_blob_free(&decoded_password);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_encode_pwd_buffer514_from_str),
+ cmocka_unit_test(torture_extract_pwd_blob_from_buffer514),
+ cmocka_unit_test(torture_decode_pwd_string_from_buffer514),
+ };
+
+ 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/libcli/auth/tests/test_gnutls.c b/libcli/auth/tests/test_gnutls.c
new file mode 100644
index 0000000..860f8b3
--- /dev/null
+++ b/libcli/auth/tests/test_gnutls.c
@@ -0,0 +1,524 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2019 Guenther Deschner <gd@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 "libcli/auth/libcli_auth.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+static void torture_gnutls_aes_128_cfb_flags(void **state,
+ const DATA_BLOB session_key,
+ const DATA_BLOB seq_num_initial,
+ const DATA_BLOB confounder_initial,
+ const DATA_BLOB confounder_expected,
+ const DATA_BLOB clear_initial,
+ const DATA_BLOB crypt_expected)
+{
+ uint8_t confounder[8];
+ DATA_BLOB io;
+ gnutls_cipher_hd_t cipher_hnd = NULL;
+ uint8_t sess_kf0[16] = {0};
+ gnutls_datum_t key = {
+ .data = sess_kf0,
+ .size = sizeof(sess_kf0),
+ };
+ uint32_t iv_size =
+ gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
+ uint8_t _iv[iv_size];
+ gnutls_datum_t iv = {
+ .data = _iv,
+ .size = iv_size,
+ };
+ uint32_t i;
+ int rc;
+
+ assert_int_equal(session_key.length, 16);
+ assert_int_equal(seq_num_initial.length, 8);
+ assert_int_equal(confounder_initial.length, 8);
+ assert_int_equal(confounder_expected.length, 8);
+ assert_int_equal(clear_initial.length, crypt_expected.length);
+
+ DEBUG(0,("checking buffer size: %d\n", (int)clear_initial.length));
+
+ io = data_blob_dup_talloc(NULL, clear_initial);
+ assert_non_null(io.data);
+ assert_int_equal(io.length, clear_initial.length);
+
+ memcpy(confounder, confounder_initial.data, 8);
+
+ DEBUG(0,("confounder before crypt:\n"));
+ dump_data(0, confounder, 8);
+ DEBUG(0,("initial seq num:\n"));
+ dump_data(0, seq_num_initial.data, 8);
+ DEBUG(0,("io data before crypt:\n"));
+ dump_data(0, io.data, io.length);
+
+ for (i = 0; i < key.size; i++) {
+ key.data[i] = session_key.data[i] ^ 0xf0;
+ }
+
+ ZERO_ARRAY(_iv);
+
+ memcpy(iv.data + 0, seq_num_initial.data, 8);
+ memcpy(iv.data + 8, seq_num_initial.data, 8);
+
+ rc = gnutls_cipher_init(&cipher_hnd,
+ GNUTLS_CIPHER_AES_128_CFB8,
+ &key,
+ &iv);
+ assert_int_equal(rc, 0);
+
+ rc = gnutls_cipher_encrypt(cipher_hnd,
+ confounder,
+ 8);
+ assert_int_equal(rc, 0);
+
+ rc = gnutls_cipher_encrypt(cipher_hnd,
+ io.data,
+ io.length);
+ assert_int_equal(rc, 0);
+
+ DEBUG(0,("confounder after crypt:\n"));
+ dump_data(0, confounder, 8);
+ DEBUG(0,("initial seq num:\n"));
+ dump_data(0, seq_num_initial.data, 8);
+ DEBUG(0,("io data after crypt:\n"));
+ dump_data(0, io.data, io.length);
+ assert_memory_equal(io.data, crypt_expected.data, crypt_expected.length);
+ assert_memory_equal(confounder, confounder_expected.data, confounder_expected.length);
+
+ rc = gnutls_cipher_decrypt(cipher_hnd,
+ confounder,
+ 8);
+ assert_int_equal(rc, 0);
+
+ rc = gnutls_cipher_decrypt(cipher_hnd,
+ io.data,
+ io.length);
+ assert_int_equal(rc, 0);
+ gnutls_cipher_deinit(cipher_hnd);
+
+ DEBUG(0,("confounder after decrypt:\n"));
+ dump_data(0, confounder, 8);
+ DEBUG(0,("initial seq num:\n"));
+ dump_data(0, seq_num_initial.data, 8);
+ DEBUG(0,("io data after decrypt:\n"));
+ dump_data(0, io.data, io.length);
+ assert_memory_equal(io.data, clear_initial.data, clear_initial.length);
+ assert_memory_equal(confounder, confounder_initial.data, confounder_initial.length);
+}
+
+static void torture_gnutls_aes_128_cfb(void **state)
+{
+ const uint8_t _session_key[16] = {
+ 0x8E, 0xE8, 0x27, 0x85, 0x83, 0x41, 0x3C, 0x8D,
+ 0xC9, 0x54, 0x70, 0x75, 0x8E, 0xC9, 0x69, 0x91
+ };
+ const DATA_BLOB session_key = data_blob_const(_session_key, 16);
+ const uint8_t _seq_num_initial[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB seq_num_initial =
+ data_blob_const(_seq_num_initial, 8);
+ const uint8_t _confounder_initial[8] = {
+ 0x6E, 0x09, 0x25, 0x94, 0x01, 0xA0, 0x09, 0x31
+ };
+ const DATA_BLOB confounder_initial =
+ data_blob_const(_confounder_initial, 8);
+ const uint8_t _confounder_expected[8] = {
+ 0xCA, 0xFB, 0xAC, 0xFB, 0xA8, 0x26, 0x75, 0x2A
+ };
+ const DATA_BLOB confounder_expected =
+ data_blob_const(_confounder_expected, 8);
+ const uint8_t _clear_initial[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71,
+ 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x40, 0x28, 0x00, 0x78, 0x57, 0x34, 0x12,
+ 0x34, 0x12, 0xCD, 0xAB, 0xEF, 0x00, 0x01, 0x23,
+ 0x45, 0x67, 0x89, 0xAB, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11,
+ 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB clear_initial = data_blob_const(_clear_initial,
+ sizeof(_clear_initial));
+ const uint8_t crypt_buffer[] = {
+ 0xE2, 0xE5, 0xE3, 0x26, 0x45, 0xFB, 0xFC, 0xF3,
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55,
+ 0xED, 0x8F, 0xF4, 0x92, 0xA1, 0xBD, 0xDC, 0x40,
+ 0x58, 0x6F, 0xD2, 0x5B, 0xF9, 0xC9, 0xA3, 0x87,
+ 0x46, 0x4B, 0x7F, 0xB2, 0x03, 0xD2, 0x35, 0x22,
+ 0x3E, 0x70, 0x9F, 0x1E, 0x3F, 0x1F, 0xDB, 0x7D,
+ 0x79, 0x88, 0x5A, 0x3D, 0xD3, 0x40, 0x1E, 0x69,
+ 0xD7, 0xE2, 0x1D, 0x5A, 0xE9, 0x3B, 0xE1, 0xE2,
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0xCA, 0x02, 0x00, 0x99, 0x9F, 0x0C, 0x01, 0xE6,
+ 0xD2, 0x00, 0xAF, 0xE0, 0x51, 0x88, 0x62, 0x50,
+ 0xB7, 0xE8, 0x6D, 0x63, 0x4B, 0x97, 0x05, 0xC1,
+ 0xD4, 0x83, 0x96, 0x29, 0x80, 0xAE, 0xD8, 0xA2,
+ 0xED, 0xC9, 0x5D, 0x0D, 0x29, 0xFF, 0x2C, 0x23,
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x95, 0xDF, 0x80, 0x76, 0x0B, 0x17, 0x0E, 0xD8
+ };
+ const DATA_BLOB crypt_expected = data_blob_const(crypt_buffer,
+ sizeof(crypt_buffer));
+ int buffer_sizes[] = {
+ 0, 1, 3, 7, 8, 9, 15, 16, 17
+ };
+ int i;
+
+ torture_gnutls_aes_128_cfb_flags(state,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial,
+ crypt_expected);
+
+ /* repeat the test for varying buffer sizes */
+
+ for (i = 0; i < ARRAY_SIZE(buffer_sizes); i++) {
+ DATA_BLOB clear_initial_trunc =
+ data_blob_const(clear_initial.data, buffer_sizes[i]);
+ DATA_BLOB crypt_expected_trunc =
+ data_blob_const(crypt_expected.data, buffer_sizes[i]);
+ torture_gnutls_aes_128_cfb_flags(state,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial_trunc,
+ crypt_expected_trunc);
+ }
+}
+
+static void torture_gnutls_des_crypt56(void **state)
+{
+ static const uint8_t key[7] = {
+ 0x69, 0x88, 0x96, 0x8E, 0xB5, 0x3A, 0x24
+ };
+ static const uint8_t clear[8] = {
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[8] = {
+ 0x54, 0x86, 0xCF, 0x51, 0x49, 0x3A, 0x53, 0x5B
+ };
+
+ uint8_t crypt[8];
+ uint8_t decrypt[8];
+ int rc;
+
+ rc = des_crypt56_gnutls(crypt, clear, key, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 8);
+
+ rc = des_crypt56_gnutls(decrypt, crypt, key, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt, clear, 8);
+}
+
+static void torture_gnutls_E_P16(void **state)
+{
+ static const uint8_t key[14] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x69, 0x88, 0x96, 0x8E, 0xB5, 0x3A
+ };
+ uint8_t buffer[16] = {
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55,
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x41, 0x4A, 0x7B, 0xEA, 0xAB, 0xBB, 0x95, 0xCE,
+ 0x1D, 0xEA, 0xD9, 0xFF, 0xB0, 0xA9, 0xA4, 0x05
+ };
+
+ int rc;
+
+ rc = E_P16(key, buffer);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(buffer, crypt_expected, 16);
+}
+
+static void torture_gnutls_E_P24(void **state)
+{
+ static const uint8_t key[21] = {
+ 0xFB, 0x67, 0x99, 0xA4, 0x83, 0xF3, 0xD4, 0xED,
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x69, 0x88, 0x96, 0x8E, 0x3A
+ };
+ const uint8_t c8[8] = {
+ 0x44, 0xFB, 0xAC, 0xFB, 0x83, 0xB6, 0x75, 0x2A
+ };
+ static const uint8_t crypt_expected[24] = {
+ 0x1A, 0x5E, 0x11, 0xA1, 0x59, 0xA9, 0x6B, 0x4E,
+ 0x12, 0x5D, 0x81, 0x75, 0xA6, 0x62, 0x15, 0x6D,
+ 0x5D, 0x20, 0x25, 0xC1, 0xA3, 0x92, 0xB3, 0x28
+ };
+
+ uint8_t crypt[24];
+ int rc;
+
+ rc = E_P24(key, c8, crypt);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 24);
+}
+
+static void torture_gnutls_SMBOWFencrypt(void **state)
+{
+ static const uint8_t password[16] = {
+ 'M', 'y', 'p', 'a', 's', 's', 'w', 'o',
+ 'r', 'd', 'i', 's', '1', '1', '1', '1'
+ };
+ const uint8_t c8[8] = {
+ 0x79, 0x88, 0x5A, 0x3D, 0xD3, 0x40, 0x1E, 0x69
+ };
+ static const uint8_t crypt_expected[24] = {
+ 0x3F, 0xE3, 0x53, 0x75, 0x81, 0xB4, 0xF0, 0xE7,
+ 0x0C, 0xDE, 0xCD, 0xAE, 0x39, 0x1F, 0x14, 0xB4,
+ 0xA4, 0x2B, 0x3E, 0x39, 0x16, 0xFD, 0x1D, 0x62
+ };
+
+ uint8_t crypt[24];
+ int rc;
+
+ rc = SMBOWFencrypt(password, c8, crypt);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 24);
+}
+
+static void torture_gnutls_E_old_pw_hash(void **state)
+{
+ static uint8_t key[14] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x69, 0x88, 0x96, 0x8E, 0xB5, 0x3A
+ };
+ uint8_t clear[16] = {
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55,
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x6A, 0xC7, 0x08, 0xCA, 0x2A, 0xC1, 0xAA, 0x64,
+ 0x37, 0xEF, 0xBE, 0x58, 0xC2, 0x59, 0x33, 0xEC
+ };
+ uint8_t crypt[16];
+ int rc;
+
+ rc = E_old_pw_hash(key, clear, crypt);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 16);
+}
+
+static void torture_gnutls_des_crypt128(void **state)
+{
+ static uint8_t key[16] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0xA9, 0x69, 0x88, 0x96, 0x8E, 0xB5, 0x3A, 0x24
+ };
+ static const uint8_t clear[8] = {
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[8] = {
+ 0x4C, 0xB4, 0x4B, 0xD3, 0xC8, 0xC1, 0xA5, 0x50
+ };
+
+ uint8_t crypt[8];
+ int rc;
+
+ rc = des_crypt128(crypt, clear, key);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 8);
+}
+
+static void torture_gnutls_des_crypt112(void **state)
+{
+ static uint8_t key[14] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x88, 0x96, 0x8E, 0xB5, 0x3A, 0x24
+ };
+ static const uint8_t clear[8] = {
+ 0x2F, 0x49, 0x5B, 0x20, 0xD7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[8] = {
+ 0x87, 0x35, 0xFA, 0xA4, 0x5D, 0x7A, 0xA5, 0x05
+ };
+
+ uint8_t crypt[8];
+ uint8_t decrypt[8];
+ int rc;
+
+ rc = des_crypt112(crypt, clear, key, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 8);
+
+ rc = des_crypt112(decrypt, crypt, key, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt, clear, 8);
+}
+
+static void torture_gnutls_des_crypt112_16(void **state)
+{
+ static uint8_t key[14] = {
+ 0x1E, 0x38, 0x27, 0x5B, 0x3B, 0xB8, 0x67, 0xEB,
+ 0x88, 0x96, 0x8E, 0xB5, 0x3A, 0x24
+ };
+ static const uint8_t clear[16] = {
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0xFB, 0x67, 0x99, 0xA4, 0x83, 0xF3, 0xD4, 0xED
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x3C, 0x10, 0x37, 0x67, 0x96, 0x95, 0xF7, 0x96,
+ 0xAA, 0x03, 0xB9, 0xEA, 0xD6, 0xB3, 0xC3, 0x2D
+ };
+
+ uint8_t crypt[16];
+ uint8_t decrypt[16];
+ int rc;
+
+ rc = des_crypt112_16(crypt, clear, key, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 16);
+
+ rc = des_crypt112_16(decrypt, crypt, key, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt, clear, 16);
+}
+
+static void torture_gnutls_sam_rid_crypt(void **state)
+{
+ static const uint8_t clear[16] = {
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x1E, 0x38, 0x27, 0x5B, 0x3B, 0xB8, 0x67, 0xEB,
+ 0xFB, 0x67, 0x99, 0xA4, 0x83, 0xF3, 0xD4, 0xED
+ };
+
+ uint8_t crypt[16];
+ uint8_t decrypt[16];
+ int rid = 500;
+ int rc;
+
+ rc = sam_rid_crypt(rid, clear, crypt, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt, crypt_expected, 16);
+
+ rc = sam_rid_crypt(rid, crypt, decrypt, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt, clear, 16);
+}
+
+static void torture_gnutls_SMBsesskeygen_lm_sess_key(void **state)
+{
+ static const uint8_t lm_hash[16] = {
+ 0xFB, 0x67, 0x99, 0xA4, 0x83, 0xF3, 0xD4, 0xED,
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55
+ };
+ static const uint8_t lm_resp[24] = {
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x1E, 0x38, 0x27, 0x5B, 0x3B, 0xB8, 0x67, 0xEB
+ };
+ static const uint8_t crypt_expected[16] = {
+ 0x52, 0x8D, 0xB2, 0xD3, 0x89, 0x83, 0xFB, 0x9C,
+ 0x96, 0x45, 0x15, 0x4B, 0xC3, 0xF5, 0xD5, 0x7F
+ };
+
+ uint8_t crypt_sess_key[16];
+ NTSTATUS status;
+
+ status = SMBsesskeygen_lm_sess_key(lm_hash, lm_resp, crypt_sess_key);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_memory_equal(crypt_sess_key, crypt_expected, 16);
+}
+
+static void torture_gnutls_sess_crypt_blob(void **state)
+{
+ static uint8_t _key[16] = {
+ 0x1E, 0x38, 0x27, 0x5B, 0x3B, 0xB8, 0x67, 0xEB,
+ 0xFA, 0xEE, 0xE8, 0xBA, 0x06, 0x01, 0x2D, 0x95
+ };
+ DATA_BLOB key = data_blob_const(_key, 16);
+ static const uint8_t _clear[24] = {
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x3F, 0x49, 0x5B, 0x20, 0xA7, 0x84, 0xC2, 0x34
+ };
+ DATA_BLOB clear = data_blob_const(_clear, 24);
+ static const uint8_t crypt_expected[24] = {
+ 0x2B, 0xDD, 0x3B, 0xFA, 0x48, 0xC9, 0x63, 0x56,
+ 0xAE, 0x8B, 0x3E, 0xCF, 0xEF, 0xDF, 0x7A, 0x42,
+ 0xB3, 0x00, 0x71, 0x7F, 0x5D, 0x1D, 0xE4, 0x70
+ };
+ DATA_BLOB crypt = data_blob(NULL, 24);
+ DATA_BLOB decrypt = data_blob(NULL, 24);
+ int rc;
+
+ rc = sess_crypt_blob(&crypt, &clear, &key, SAMBA_GNUTLS_ENCRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(crypt.data, crypt_expected, 24);
+
+ rc = sess_crypt_blob(&decrypt, &crypt, &key, SAMBA_GNUTLS_DECRYPT);
+ assert_int_equal(rc, 0);
+ assert_memory_equal(decrypt.data, clear.data, 24);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_gnutls_aes_128_cfb),
+ cmocka_unit_test(torture_gnutls_des_crypt56),
+ cmocka_unit_test(torture_gnutls_E_P16),
+ cmocka_unit_test(torture_gnutls_E_P24),
+ cmocka_unit_test(torture_gnutls_SMBOWFencrypt),
+ cmocka_unit_test(torture_gnutls_E_old_pw_hash),
+ cmocka_unit_test(torture_gnutls_des_crypt128),
+ cmocka_unit_test(torture_gnutls_des_crypt112),
+ cmocka_unit_test(torture_gnutls_des_crypt112_16),
+ cmocka_unit_test(torture_gnutls_sam_rid_crypt),
+ cmocka_unit_test(torture_gnutls_SMBsesskeygen_lm_sess_key),
+ cmocka_unit_test(torture_gnutls_sess_crypt_blob),
+ };
+
+ 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/libcli/auth/tests/test_rc4_passwd_buffer.c b/libcli/auth/tests/test_rc4_passwd_buffer.c
new file mode 100644
index 0000000..6d97ac6
--- /dev/null
+++ b/libcli/auth/tests/test_rc4_passwd_buffer.c
@@ -0,0 +1,336 @@
+/*
+ * 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 "includes.h"
+#include "libcli/auth/libcli_auth.h"
+#include "rpc_client/init_samr.h"
+
+#define PASSWORD "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+
+static const uint8_t encrypted_test_blob[] = {
+ 0x37, 0x8e, 0x1d, 0xd5, 0xd3, 0x9f, 0xca, 0x8e,
+ 0x2f, 0x2d, 0xee, 0xc3, 0xb5, 0x50, 0xcd, 0x4e,
+ 0xc9, 0x08, 0x04, 0x68, 0x32, 0xc3, 0xac, 0x8e,
+ 0x53, 0x69, 0xd6, 0xb7, 0x56, 0xcc, 0xc0, 0xbe,
+ 0x4e, 0x96, 0xa7, 0x74, 0xe9, 0xaa, 0x10, 0x3d,
+ 0xd5, 0x8c, 0xaa, 0x12, 0x56, 0xb6, 0xf1, 0x85,
+ 0x21, 0xfa, 0xe9, 0xa1, 0x76, 0xe6, 0xa5, 0x33,
+ 0x33, 0x2f, 0x47, 0x29, 0xd6, 0xbd, 0xde, 0x64,
+ 0x4d, 0x15, 0x3e, 0x6a, 0x11, 0x9b, 0x52, 0xbf,
+ 0x7e, 0x3a, 0xeb, 0x1c, 0x55, 0xd1, 0xb2, 0xa4,
+ 0x35, 0x03, 0x6c, 0x39, 0x61, 0x28, 0x98, 0xc3,
+ 0x2d, 0xd4, 0x70, 0x69, 0x8b, 0x83, 0xe9, 0x62,
+ 0xbe, 0xd8, 0x72, 0x4e, 0xdf, 0xd4, 0xe9, 0xe3,
+ 0x46, 0x2a, 0xf9, 0x3c, 0x0f, 0x41, 0x62, 0xe1,
+ 0x43, 0xf0, 0x91, 0xbe, 0x72, 0xa0, 0xc9, 0x08,
+ 0x73, 0x20, 0x1f, 0x0d, 0x68, 0x2e, 0x32, 0xa1,
+ 0xb8, 0x9b, 0x08, 0xa1, 0xb4, 0x81, 0x6b, 0xf1,
+ 0xde, 0x0c, 0x28, 0x34, 0xe2, 0x65, 0x62, 0x54,
+ 0xeb, 0xc0, 0x71, 0x14, 0xad, 0x36, 0x43, 0x0e,
+ 0x92, 0x4d, 0x11, 0xe8, 0xdd, 0x2d, 0x5f, 0x05,
+ 0xff, 0x07, 0xda, 0x81, 0x4e, 0x27, 0x42, 0xa8,
+ 0xa9, 0x64, 0x4c, 0x74, 0xc8, 0x05, 0xbb, 0x83,
+ 0x5a, 0xd9, 0x90, 0x3e, 0x0d, 0x9d, 0xe5, 0x2f,
+ 0x08, 0xf9, 0x1b, 0xbd, 0x26, 0xc3, 0x0d, 0xac,
+ 0x43, 0xd5, 0x17, 0xf2, 0x61, 0xf5, 0x74, 0x9b,
+ 0xf3, 0x5b, 0x5f, 0xe1, 0x8a, 0xa6, 0xfd, 0xdf,
+ 0xff, 0xb5, 0x8b, 0xf1, 0x26, 0xf7, 0xe0, 0xa7,
+ 0x4f, 0x5b, 0xb8, 0x6d, 0xeb, 0xf6, 0x52, 0x68,
+ 0x8d, 0xa3, 0xd4, 0x7f, 0x56, 0x43, 0xaa, 0xec,
+ 0x58, 0x47, 0x03, 0xee, 0x9b, 0x59, 0xd9, 0x78,
+ 0x9a, 0xfb, 0x9e, 0xe9, 0xa6, 0x61, 0x4e, 0x6d,
+ 0x92, 0x35, 0xd3, 0x37, 0x6e, 0xf2, 0x34, 0x39,
+ 0xd4, 0xd2, 0xeb, 0xcf, 0x1c, 0x10, 0xb3, 0x2b,
+ 0x3e, 0x07, 0x42, 0x3e, 0x20, 0x90, 0x07, 0x3e,
+ 0xc7, 0xed, 0xd4, 0xdf, 0x50, 0xe5, 0xff, 0xaf,
+ 0x05, 0xce, 0x29, 0xbe, 0x01, 0xf8, 0xb0, 0x30,
+ 0x96, 0xae, 0x1b, 0x62, 0x23, 0x93, 0x91, 0x1a,
+ 0x52, 0x98, 0xd9, 0x59, 0xb8, 0x11, 0xec, 0xb8,
+ 0xcf, 0x20, 0x32, 0x90, 0x9e, 0xf2, 0x06, 0x43,
+ 0xb8, 0x36, 0xe3, 0x33, 0x4e, 0x6f, 0x75, 0xeb,
+ 0xf7, 0x6c, 0xac, 0x06, 0x5f, 0x24, 0x8e, 0x4a,
+ 0x03, 0xdf, 0x50, 0x31, 0xaa, 0x91, 0xd5, 0x85,
+ 0x95, 0x78, 0x5b, 0xf4, 0x7f, 0x3e, 0xbc, 0x41,
+ 0xfa, 0x10, 0xd3, 0x0f, 0x86, 0x8b, 0x23, 0xed,
+ 0xfc, 0xcc, 0x3e, 0x7d, 0x8c, 0xb4, 0x7c, 0xec,
+ 0x04, 0x7d, 0x12, 0x53, 0xa1, 0x30, 0xc5, 0xac,
+ 0xf3, 0x1e, 0x54, 0x1f, 0x97, 0x05, 0x86, 0x74,
+ 0x51, 0x13, 0x45, 0x98, 0xb8, 0x50, 0x62, 0x18,
+ 0x0f, 0x6d, 0x66, 0xa4, 0x88, 0x31, 0x76, 0xa3,
+ 0xb0, 0x75, 0x55, 0x44, 0x18, 0x7c, 0x67, 0xc7,
+ 0x09, 0x9c, 0xab, 0x53, 0x49, 0xc0, 0xc9, 0x27,
+ 0x53, 0xa6, 0x99, 0x01, 0x10, 0x49, 0x67, 0x8e,
+ 0x5b, 0x12, 0x96, 0x40, 0x16, 0x39, 0x11, 0x53,
+ 0x44, 0x8f, 0xa9, 0xbe, 0x84, 0xbe, 0xe0, 0x45,
+ 0xe3, 0xfd, 0x48, 0x46, 0x43, 0x53, 0x13, 0x5f,
+ 0xfa, 0xcf, 0x09, 0x67, 0x90, 0xa3, 0x94, 0xaa,
+ 0x0d, 0x1f, 0xc2, 0xc3, 0xd4, 0x7e, 0xc8, 0x14,
+ 0xbe, 0x84, 0xa5, 0x55, 0xee, 0x49, 0x8e, 0x03,
+ 0x1d, 0xaf, 0xad, 0x65, 0x2f, 0xf0, 0xd5, 0x90,
+ 0x5e, 0x8d, 0x29, 0x40, 0xba, 0x57, 0x26, 0xa8,
+ 0x6c, 0x4b, 0x59, 0x40, 0x4e, 0xc2, 0xc4, 0x88,
+ 0x0a, 0x06, 0x2b, 0x6c, 0x2a, 0xc7, 0x3f, 0xfe,
+ 0x37, 0x2c, 0x41, 0x58, 0xfe, 0x7e, 0xaf, 0xd1,
+ 0xd9, 0xd2, 0x9c, 0xd7, 0x8a, 0x01, 0x0e, 0x8c,
+ 0x9e, 0x8b, 0x5d, 0x72, 0x54, 0x00, 0xbe, 0xb2,
+ 0x9a, 0xc7, 0xfd, 0x83, 0x1e, 0x9c, 0x79, 0xdd,
+ 0x15, 0x13, 0xdc, 0x15,
+};
+
+
+static const uint8_t encrypted_wkssvc_test_blob[] = {
+ 0x13, 0x79, 0x1f, 0x1a, 0x02, 0x15, 0x72, 0x1c,
+ 0xa6, 0x26, 0x37, 0xeb, 0x1d, 0x41, 0x7f, 0x76,
+ 0x11, 0x3f, 0x49, 0x4c, 0xf9, 0x69, 0x17, 0xc8,
+ 0x90, 0x92, 0x53, 0xb9, 0x3f, 0xcd, 0x06, 0xfe,
+ 0x5c, 0x17, 0x82, 0xbd, 0x86, 0xab, 0x49, 0xee,
+ 0x61, 0x76, 0x55, 0xc0, 0x10, 0x51, 0xcd, 0xd9,
+ 0x6f, 0x12, 0x86, 0xc6, 0x19, 0x59, 0x9a, 0x2f,
+ 0x27, 0x1d, 0x99, 0x30, 0x60, 0x0d, 0x65, 0xc6,
+ 0x43, 0xd6, 0xda, 0x6b, 0x66, 0x95, 0xd4, 0xca,
+ 0xf5, 0x04, 0xf7, 0x01, 0x5a, 0x55, 0xb0, 0x5e,
+ 0x72, 0x8a, 0x75, 0xe5, 0x33, 0x4c, 0xd8, 0xc4,
+ 0x0e, 0xf4, 0x6d, 0x23, 0xdd, 0x05, 0x90, 0xff,
+ 0xe0, 0x91, 0x7b, 0x62, 0x86, 0xee, 0x78, 0x31,
+ 0x07, 0xad, 0x8b, 0xf9, 0xdf, 0x6f, 0x8b, 0xbd,
+ 0x15, 0xde, 0x1b, 0xae, 0x84, 0x68, 0xe5, 0x41,
+ 0x7a, 0xe3, 0x47, 0x99, 0xba, 0x61, 0xe5, 0x51,
+ 0x64, 0x9a, 0xa0, 0x41, 0x44, 0xa1, 0x3a, 0x52,
+ 0x59, 0x7d, 0x6c, 0xcf, 0xcc, 0xf0, 0x11, 0xbc,
+ 0xb7, 0x51, 0xa9, 0xd8, 0xfd, 0xbf, 0x58, 0x77,
+ 0x28, 0x86, 0xa1, 0x27, 0x94, 0xe5, 0xf6, 0x1a,
+ 0x6b, 0x76, 0xf7, 0x72, 0x6e, 0x17, 0x09, 0xd8,
+ 0x3c, 0x6f, 0x39, 0x91, 0xea, 0x48, 0x98, 0xdc,
+ 0x1d, 0x50, 0x2e, 0x02, 0x6e, 0x7f, 0x80, 0x5d,
+ 0x6e, 0x96, 0xe1, 0xcf, 0x8b, 0x6b, 0xb6, 0xed,
+ 0xb4, 0x6a, 0x08, 0xd2, 0x45, 0x09, 0x88, 0x86,
+ 0x32, 0x58, 0xd8, 0x5e, 0x33, 0x8c, 0x29, 0x1a,
+ 0x8f, 0xc5, 0x54, 0x9b, 0xa8, 0x32, 0xb2, 0xc1,
+ 0x72, 0x14, 0x6c, 0x5d, 0x9d, 0xd3, 0xf2, 0x6c,
+ 0x6e, 0xa4, 0x84, 0x52, 0x26, 0x73, 0x7a, 0x30,
+ 0x56, 0x75, 0xef, 0xd1, 0x9d, 0xcd, 0xb7, 0x87,
+ 0xa9, 0x5c, 0xaf, 0xe6, 0xda, 0x1d, 0x3c, 0x9c,
+ 0xa3, 0xb1, 0x03, 0xb0, 0x8e, 0xf6, 0xc8, 0x8f,
+ 0x57, 0x1c, 0xce, 0x05, 0x54, 0x99, 0xf1, 0xf9,
+ 0x35, 0xe6, 0xf7, 0x67, 0x94, 0xb2, 0x67, 0x5b,
+ 0xe7, 0xa0, 0xa2, 0x1e, 0xa2, 0x74, 0xd3, 0x99,
+ 0x9c, 0xd5, 0xd9, 0x90, 0x86, 0x24, 0x0e, 0x1a,
+ 0x0d, 0xc8, 0x9e, 0x68, 0x4c, 0x43, 0x2f, 0x42,
+ 0xb1, 0x7c, 0xce, 0x1e, 0xb6, 0xac, 0x56, 0xb0,
+ 0x8d, 0x93, 0xf1, 0x53, 0x7d, 0x0e, 0x00, 0x46,
+ 0xba, 0x2e, 0x14, 0x7a, 0x0b, 0xaa, 0xcb, 0x07,
+ 0x9b, 0x09, 0x05, 0xa0, 0xd3, 0xa1, 0x80, 0xc2,
+ 0xd3, 0x59, 0x92, 0x27, 0x66, 0x1f, 0xdd, 0x76,
+ 0x36, 0xb3, 0x3c, 0xeb, 0xd7, 0x61, 0x94, 0xb1,
+ 0xf8, 0x3a, 0xe0, 0xba, 0x91, 0x0f, 0xef, 0x72,
+ 0x2b, 0x26, 0xc6, 0xb8, 0x6d, 0x0b, 0xdb, 0x60,
+ 0xf8, 0xb4, 0x98, 0xd7, 0x8b, 0x8d, 0xfb, 0xa7,
+ 0x4e, 0x27, 0xeb, 0x00, 0xe8, 0xf7, 0x5a, 0xec,
+ 0xf5, 0x60, 0x28, 0x37, 0xb2, 0xc4, 0x13, 0x48,
+ 0x2a, 0xe1, 0x34, 0xb2, 0x53, 0xcb, 0x44, 0x34,
+ 0x08, 0x7e, 0x56, 0x5c, 0x2b, 0x9b, 0xe2, 0xca,
+ 0x90, 0xb0, 0x57, 0xee, 0x10, 0x88, 0x39, 0x84,
+ 0xc6, 0x66, 0x07, 0x50, 0x63, 0xcc, 0x2a, 0x7c,
+ 0x99, 0x8c, 0x05, 0xf9, 0xf0, 0xb8, 0x62, 0xf0,
+ 0x92, 0xf7, 0x2a, 0x4a, 0x17, 0x14, 0x78, 0xa1,
+ 0x71, 0xb6, 0x42, 0xf0, 0x87, 0xa8, 0xa4, 0x48,
+ 0xeb, 0xdb, 0xed, 0x8a, 0x15, 0x19, 0x1a, 0xd9,
+ 0xfe, 0x6f, 0x07, 0x93, 0x5d, 0x39, 0xe8, 0x0e,
+ 0x47, 0xe6, 0x7a, 0x7d, 0x52, 0x2e, 0x40, 0x6f,
+ 0x31, 0x1b, 0xf6, 0x0c, 0xc2, 0x83, 0xae, 0xc1,
+ 0xf0, 0xf5, 0x71, 0xcd, 0xe2, 0xf5, 0x19, 0xb6,
+ 0xd8, 0xb0, 0x4d, 0xa9, 0x51, 0x1c, 0xb4, 0xaf,
+ 0x69, 0x9a, 0x89, 0xb6, 0x5b, 0x4d, 0xfa, 0x1b,
+ 0xca, 0xc8, 0x61, 0x92, 0x3a, 0xd6, 0x76, 0xad,
+ 0x5d, 0xa6, 0x17, 0x60, 0x3e, 0xea, 0x94, 0xcf,
+ 0x6d, 0x1b, 0x98, 0x5c, 0x19, 0x9e, 0x4e, 0xd3,
+ 0x21, 0x55, 0xda, 0xe3,
+};
+
+static void torture_decode_rc4_passwd_buffer(void **state)
+{
+ char *password_decoded = NULL;
+ size_t password_decoded_len = 0;
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct samr_CryptPasswordEx out_pwd_buf = {
+ .data = {0},
+ };
+ NTSTATUS status;
+ bool ok;
+
+ memcpy(out_pwd_buf.data,
+ encrypted_test_blob,
+ sizeof(out_pwd_buf.data));
+
+ status = decode_rc4_passwd_buffer(&session_key, &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ok = decode_pw_buffer(NULL,
+ out_pwd_buf.data,
+ &password_decoded,
+ &password_decoded_len,
+ CH_UTF16);
+ assert_true(ok);
+ assert_int_equal(password_decoded_len, strlen(PASSWORD));
+ assert_string_equal(password_decoded, PASSWORD);
+}
+
+static void torture_rc4_passwd_buffer(void **state)
+{
+ char *password_decoded = NULL;
+ size_t password_decoded_len = 0;
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct samr_CryptPasswordEx out_pwd_buf = {
+ .data = {0},
+ };
+ NTSTATUS status;
+ bool ok;
+
+ status = init_samr_CryptPasswordEx(PASSWORD,
+ &session_key,
+ &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ status = decode_rc4_passwd_buffer(&session_key, &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ok = decode_pw_buffer(NULL,
+ out_pwd_buf.data,
+ &password_decoded,
+ &password_decoded_len,
+ CH_UTF16);
+ assert_true(ok);
+ assert_int_equal(password_decoded_len, strlen(PASSWORD));
+ assert_string_equal(password_decoded, PASSWORD);
+ talloc_free(password_decoded);
+}
+
+static void torture_endode_decode_rc4_passwd_buffer(void **state)
+{
+ char *password_decoded = NULL;
+ size_t password_decoded_len = 0;
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct samr_CryptPasswordEx out_pwd_buf = {
+ .data = {0},
+ };
+ NTSTATUS status;
+ bool ok;
+
+ status = encode_rc4_passwd_buffer(PASSWORD,
+ &session_key,
+ &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ status = decode_rc4_passwd_buffer(&session_key, &out_pwd_buf);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ok = decode_pw_buffer(NULL,
+ out_pwd_buf.data,
+ &password_decoded,
+ &password_decoded_len,
+ CH_UTF16);
+ assert_true(ok);
+ assert_int_equal(password_decoded_len, strlen(PASSWORD));
+ assert_string_equal(password_decoded, PASSWORD);
+ talloc_free(password_decoded);
+}
+
+static void torture_decode_wkssvc_join_password_buffer(void **state)
+{
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct wkssvc_PasswordBuffer pwd_buf = {
+ .data = {0},
+ };
+ char *password_decoded = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ WERROR werr;
+
+ mem_ctx = talloc_new(NULL);
+ assert_non_null(mem_ctx);
+
+ memcpy(pwd_buf.data,
+ encrypted_wkssvc_test_blob,
+ sizeof(pwd_buf.data));
+
+ werr = decode_wkssvc_join_password_buffer(mem_ctx,
+ &pwd_buf,
+ &session_key,
+ &password_decoded);
+ assert_true(W_ERROR_IS_OK(werr));
+ assert_non_null(password_decoded);
+ assert_string_equal(password_decoded, PASSWORD);
+
+ TALLOC_FREE(mem_ctx);
+}
+
+static void torture_wkssvc_join_password_buffer(void **state)
+{
+ DATA_BLOB session_key = data_blob_const("SystemLibraryDTC", 16);
+ struct wkssvc_PasswordBuffer *pwd_buf = NULL;
+ char *password_decoded = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ WERROR werr;
+
+ mem_ctx = talloc_new(NULL);
+ assert_non_null(mem_ctx);
+
+ werr = encode_wkssvc_join_password_buffer(mem_ctx,
+ PASSWORD,
+ &session_key,
+ &pwd_buf);
+ assert_true(W_ERROR_IS_OK(werr));
+ assert_non_null(pwd_buf);
+
+ werr = decode_wkssvc_join_password_buffer(mem_ctx,
+ pwd_buf,
+ &session_key,
+ &password_decoded);
+ assert_true(W_ERROR_IS_OK(werr));
+ assert_non_null(password_decoded);
+ assert_string_equal(password_decoded, PASSWORD);
+
+ TALLOC_FREE(mem_ctx);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_decode_rc4_passwd_buffer),
+ cmocka_unit_test(torture_rc4_passwd_buffer),
+ cmocka_unit_test(torture_endode_decode_rc4_passwd_buffer),
+ cmocka_unit_test(torture_decode_wkssvc_join_password_buffer),
+ cmocka_unit_test(torture_wkssvc_join_password_buffer),
+ };
+
+ 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/libcli/auth/tests/test_schannel.c b/libcli/auth/tests/test_schannel.c
new file mode 100644
index 0000000..b1c88fd
--- /dev/null
+++ b/libcli/auth/tests/test_schannel.c
@@ -0,0 +1,305 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) 2019 Guenther Deschner <gd@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 "auth/gensec/schannel.c"
+
+static void torture_schannel_seal_flags(void **state, uint32_t flags,
+ const DATA_BLOB session_key,
+ const DATA_BLOB seq_num_initial,
+ const DATA_BLOB confounder_initial,
+ const DATA_BLOB confounder_expected,
+ const DATA_BLOB clear_initial,
+ const DATA_BLOB crypt_expected)
+{
+ NTSTATUS status;
+ struct schannel_state *schannel_state;
+ struct netlogon_creds_CredentialState *creds;
+ uint8_t confounder[8];
+ DATA_BLOB io;
+
+ assert_int_equal(session_key.length, 16);
+ assert_int_equal(seq_num_initial.length, 8);
+ assert_int_equal(confounder_initial.length, 8);
+ assert_int_equal(confounder_expected.length, 8);
+ assert_int_equal(clear_initial.length, crypt_expected.length);
+
+ DEBUG(0,("checking buffer size: %d\n", (int)clear_initial.length));
+
+ schannel_state = talloc_zero(NULL, struct schannel_state);
+ assert_non_null(schannel_state);
+ creds = talloc_zero(schannel_state,
+ struct netlogon_creds_CredentialState);
+ assert_non_null(creds);
+ schannel_state->creds = creds;
+
+ io = data_blob_dup_talloc(schannel_state, clear_initial);
+ assert_non_null(io.data);
+ assert_int_equal(io.length, clear_initial.length);
+
+ schannel_state->creds->negotiate_flags = flags;
+ memcpy(schannel_state->creds->session_key, session_key.data, 16);
+
+ memcpy(confounder, confounder_initial.data, 8);
+
+ DEBUG(0,("confounder before crypt:\n"));
+ dump_data(0, confounder, 8);
+ dump_data(0, seq_num_initial.data, 8);
+ dump_data(0, io.data, io.length);
+
+ status = netsec_do_seal(schannel_state,
+ seq_num_initial.data,
+ confounder,
+ io.data,
+ io.length,
+ true);
+
+ assert_true(NT_STATUS_IS_OK(status));
+ dump_data(0, io.data, io.length);
+ DEBUG(0,("confounder after crypt:\n"));
+ dump_data(0, confounder, 8);
+ dump_data(0, seq_num_initial.data, 8);
+ assert_memory_equal(io.data, crypt_expected.data, crypt_expected.length);
+ assert_memory_equal(confounder, confounder_expected.data, confounder_expected.length);
+
+ status = netsec_do_seal(schannel_state,
+ seq_num_initial.data,
+ confounder,
+ io.data,
+ io.length,
+ false);
+
+ assert_true(NT_STATUS_IS_OK(status));
+ dump_data(0, io.data, io.length);
+ DEBUG(0,("confounder after decrypt:\n"));
+ dump_data(0, confounder, 8);
+ dump_data(0, seq_num_initial.data, 8);
+ assert_memory_equal(io.data, clear_initial.data, clear_initial.length);
+ assert_memory_equal(confounder, confounder_initial.data, confounder_initial.length);
+
+ talloc_free(schannel_state);
+}
+
+static void torture_schannel_seal_rc4(void **state)
+{
+ const uint8_t _session_key[16] = {
+ 0x14, 0xD5, 0x7F, 0x8D, 0x8E, 0xCF, 0xFB, 0x56,
+ 0x71, 0x29, 0x9D, 0x9C, 0x2A, 0x75, 0x00, 0xA1
+ };
+ const DATA_BLOB session_key = data_blob_const(_session_key, 16);
+ const uint8_t _seq_num_initial[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB seq_num_initial =
+ data_blob_const(_seq_num_initial, 8);
+ const uint8_t _confounder_initial[8] = {
+ 0x1A, 0x5A, 0xE8, 0xC7, 0xBE, 0x4F, 0x1F, 0x07
+ };
+ const DATA_BLOB confounder_initial =
+ data_blob_const(_confounder_initial, 8);
+ const uint8_t _confounder_expected[8] = {
+ 0x25, 0x4A, 0x9C, 0x15, 0x82, 0x3E, 0x4A, 0x42
+ };
+ const DATA_BLOB confounder_expected =
+ data_blob_const(_confounder_expected, 8);
+ const uint8_t _clear_initial[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71,
+ 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x40, 0x28, 0x00, 0x78, 0x57, 0x34, 0x12,
+ 0x34, 0x12, 0xCD, 0xAB, 0xEF, 0x00, 0x01, 0x23,
+ 0x45, 0x67, 0x89, 0xAB, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11,
+ 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB clear_initial = data_blob_const(_clear_initial,
+ sizeof(_clear_initial));
+ const uint8_t crypt_buffer[] = {
+ 0x3E, 0x10, 0x74, 0xD2, 0x3C, 0x71, 0x57, 0x45,
+ 0xB8, 0xAA, 0xCF, 0xE3, 0x84, 0xBE, 0xC4, 0x00,
+ 0xF4, 0x4D, 0x88, 0x0A, 0x9B, 0xCC, 0x53, 0xFC,
+ 0x32, 0xAA, 0x8E, 0x4B, 0x0E, 0xDE, 0x5F, 0x7D,
+ 0x6D, 0x31, 0x4E, 0xAB, 0xE0, 0x7D, 0x37, 0x9D,
+ 0x3D, 0x16, 0xD8, 0xBA, 0x6A, 0xB0, 0xD0, 0x99,
+ 0x14, 0x05, 0x37, 0xCF, 0x63, 0xD3, 0xD7, 0x60,
+ 0x63, 0x3C, 0x03, 0x0A, 0x30, 0xA0, 0x3E, 0xC7,
+ 0xDA, 0x94, 0x3B, 0x40, 0x63, 0x74, 0xEF, 0xCF,
+ 0xE5, 0x48, 0x87, 0xE9, 0x6A, 0x5A, 0xC7, 0x61,
+ 0xF7, 0x09, 0xB7, 0x7C, 0xDE, 0xDB, 0xB0, 0x94,
+ 0x9B, 0x99, 0xC0, 0xA7, 0x7E, 0x78, 0x09, 0x35,
+ 0xB4, 0xF4, 0x11, 0xC3, 0xB3, 0x77, 0xB5, 0x77,
+ 0x25, 0xEE, 0xFD, 0x2F, 0x9A, 0x15, 0x95, 0x27,
+ 0x08, 0xDA, 0xD0, 0x28, 0xD6, 0x31, 0xB4, 0xB7,
+ 0x7A, 0x19, 0xBB, 0xF3, 0x78, 0xF8, 0xC2, 0x5B
+ };
+ const DATA_BLOB crypt_expected = data_blob_const(crypt_buffer,
+ sizeof(crypt_buffer));
+ int buffer_sizes[] = {
+ 0, 1, 3, 7, 8, 9, 15, 16, 17
+ };
+ int i;
+
+ torture_schannel_seal_flags(state, 0,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial,
+ crypt_expected);
+
+ /* repeat the test for varying buffer sizes */
+
+ for (i = 0; i < ARRAY_SIZE(buffer_sizes); i++) {
+ DATA_BLOB clear_initial_trunc =
+ data_blob_const(clear_initial.data, buffer_sizes[i]);
+ DATA_BLOB crypt_expected_trunc =
+ data_blob_const(crypt_expected.data, buffer_sizes[i]);
+ torture_schannel_seal_flags(state, 0,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial_trunc,
+ crypt_expected_trunc);
+ }
+}
+
+static void torture_schannel_seal_aes(void **state)
+{
+ const uint8_t _session_key[16] = {
+ 0x8E, 0xE8, 0x27, 0x85, 0x83, 0x41, 0x3C, 0x8D,
+ 0xC9, 0x54, 0x70, 0x75, 0x8E, 0xC9, 0x69, 0x91
+ };
+ const DATA_BLOB session_key = data_blob_const(_session_key, 16);
+ const uint8_t _seq_num_initial[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB seq_num_initial =
+ data_blob_const(_seq_num_initial, 8);
+ const uint8_t _confounder_initial[8] = {
+ 0x6E, 0x09, 0x25, 0x94, 0x01, 0xA0, 0x09, 0x31
+ };
+ const DATA_BLOB confounder_initial =
+ data_blob_const(_confounder_initial, 8);
+ const uint8_t _confounder_expected[8] = {
+ 0xCA, 0xFB, 0xAC, 0xFB, 0xA8, 0x26, 0x75, 0x2A
+ };
+ const DATA_BLOB confounder_expected =
+ data_blob_const(_confounder_expected, 8);
+ const uint8_t _clear_initial[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71,
+ 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x40, 0x28, 0x00, 0x78, 0x57, 0x34, 0x12,
+ 0x34, 0x12, 0xCD, 0xAB, 0xEF, 0x00, 0x01, 0x23,
+ 0x45, 0x67, 0x89, 0xAB, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11,
+ 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const DATA_BLOB clear_initial = data_blob_const(_clear_initial,
+ sizeof(_clear_initial));
+ const uint8_t crypt_buffer[] = {
+ 0xE2, 0xE5, 0xE3, 0x26, 0x45, 0xFB, 0xFC, 0xF3,
+ 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55,
+ 0xED, 0x8F, 0xF4, 0x92, 0xA1, 0xBD, 0xDC, 0x40,
+ 0x58, 0x6F, 0xD2, 0x5B, 0xF9, 0xC9, 0xA3, 0x87,
+ 0x46, 0x4B, 0x7F, 0xB2, 0x03, 0xD2, 0x35, 0x22,
+ 0x3E, 0x70, 0x9F, 0x1E, 0x3F, 0x1F, 0xDB, 0x7D,
+ 0x79, 0x88, 0x5A, 0x3D, 0xD3, 0x40, 0x1E, 0x69,
+ 0xD7, 0xE2, 0x1D, 0x5A, 0xE9, 0x3B, 0xE1, 0xE2,
+ 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8,
+ 0xCA, 0x02, 0x00, 0x99, 0x9F, 0x0C, 0x01, 0xE6,
+ 0xD2, 0x00, 0xAF, 0xE0, 0x51, 0x88, 0x62, 0x50,
+ 0xB7, 0xE8, 0x6D, 0x63, 0x4B, 0x97, 0x05, 0xC1,
+ 0xD4, 0x83, 0x96, 0x29, 0x80, 0xAE, 0xD8, 0xA2,
+ 0xED, 0xC9, 0x5D, 0x0D, 0x29, 0xFF, 0x2C, 0x23,
+ 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01,
+ 0x95, 0xDF, 0x80, 0x76, 0x0B, 0x17, 0x0E, 0xD8
+ };
+ const DATA_BLOB crypt_expected = data_blob_const(crypt_buffer,
+ sizeof(crypt_buffer));
+ int buffer_sizes[] = {
+ 0, 1, 3, 7, 8, 9, 15, 16, 17
+ };
+ int i;
+
+ torture_schannel_seal_flags(state, NETLOGON_NEG_SUPPORTS_AES,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial,
+ crypt_expected);
+
+ /* repeat the test for varying buffer sizes */
+
+ for (i = 0; i < ARRAY_SIZE(buffer_sizes); i++) {
+ DATA_BLOB clear_initial_trunc =
+ data_blob_const(clear_initial.data, buffer_sizes[i]);
+ DATA_BLOB crypt_expected_trunc =
+ data_blob_const(crypt_expected.data, buffer_sizes[i]);
+ torture_schannel_seal_flags(state, NETLOGON_NEG_SUPPORTS_AES,
+ session_key,
+ seq_num_initial,
+ confounder_initial,
+ confounder_expected,
+ clear_initial_trunc,
+ crypt_expected_trunc);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_schannel_seal_rc4),
+ cmocka_unit_test(torture_schannel_seal_aes),
+ };
+
+ 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/libcli/auth/wscript_build b/libcli/auth/wscript_build
new file mode 100644
index 0000000..c73e0d1
--- /dev/null
+++ b/libcli/auth/wscript_build
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('cliauth',
+ source='',
+ deps='MSRPC_PARSE LIBCLI_AUTH COMMON_SCHANNEL PAM_ERRORS SPNEGO_PARSE krb5samba samba-errors NTLM_CHECK UTIL_LSARPC',
+ private_library=True,
+ grouping_library=True)
+
+bld.SAMBA_SUBSYSTEM('MSRPC_PARSE',
+ source='msrpc_parse.c',
+ deps='talloc'
+ )
+
+bld.SAMBA_SUBSYSTEM('NTLM_CHECK',
+ source='ntlm_check.c',
+ deps = 'talloc LIBCLI_AUTH'
+ )
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_AUTH',
+ source='credentials.c session.c smbencrypt.c smbdes.c',
+ public_deps='MSRPC_PARSE gnutls GNUTLS_HELPERS util_str_escape',
+ public_headers='credentials.h:domain_credentials.h'
+ )
+
+
+bld.SAMBA_SUBSYSTEM('COMMON_SCHANNEL',
+ source='schannel_state_tdb.c',
+ deps='dbwrap util_tdb samba-hostconfig NDR_NETLOGON'
+ )
+
+bld.SAMBA_SUBSYSTEM('NETLOGON_CREDS_CLI',
+ source='netlogon_creds_cli.c',
+ deps='''
+ dbwrap
+ util_tdb
+ tevent-util
+ samba-hostconfig
+ gensec
+ RPC_NDR_NETLOGON
+ NDR_NETLOGON
+ '''
+ )
+
+bld.SAMBA_SUBSYSTEM('PAM_ERRORS',
+ source='pam_errors.c',
+ deps='talloc'
+ )
+
+bld.SAMBA_SUBSYSTEM('SPNEGO_PARSE',
+ source='spnego_parse.c',
+ deps='asn1util')
+
+bld.SAMBA_BINARY(
+ 'test_ntlm_check',
+ source='tests/ntlm_check.c',
+ deps='''
+ NTLM_CHECK
+ CREDENTIALS_NTLM
+ samba-credentials
+ cmocka
+ talloc
+ ''',
+ for_selftest=True
+ )
+
+bld.SAMBA_BINARY('test_rc4_passwd_buffer',
+ source='tests/test_rc4_passwd_buffer.c',
+ deps='''
+ INIT_SAMR
+ LIBCLI_AUTH
+ cmocka
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_schannel',
+ source='tests/test_schannel.c',
+ deps='''
+ gensec
+ cmocka
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_gnutls',
+ source='tests/test_gnutls.c',
+ deps='''
+ gnutls
+ LIBCLI_AUTH
+ cmocka
+ samba-util
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_encode_decode',
+ source='tests/test_encode_decode.c',
+ deps='''
+ LIBCLI_AUTH
+ cmocka
+ samba-util
+ ''',
+ for_selftest=True)
diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c
new file mode 100644
index 0000000..8176946
--- /dev/null
+++ b/libcli/cldap/cldap.c
@@ -0,0 +1,1209 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ cldap client library
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Stefan Metzmacher 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/>.
+*/
+
+/*
+ see RFC1798 for details of CLDAP
+
+ basic properties
+ - carried over UDP on port 389
+ - request and response matched by message ID
+ - request consists of only a single searchRequest element
+ - response can be in one of two forms
+ - a single searchResponse, followed by a searchResult
+ - a single searchResult
+*/
+
+#include "includes.h"
+#include <tevent.h>
+#include "../lib/util/dlinklist.h"
+#include "../libcli/ldap/ldap_message.h"
+#include "../libcli/ldap/ldap_ndr.h"
+#include "../libcli/cldap/cldap.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../libcli/security/dom_sid.h"
+#include "../librpc/gen_ndr/ndr_nbt.h"
+#include "../lib/util/asn1.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "lib/util/idtree_random.h"
+
+#undef strcasecmp
+
+/*
+ context structure for operations on cldap packets
+*/
+struct cldap_socket {
+ /* the low level socket */
+ struct tdgram_context *sock;
+
+ /*
+ * Are we in connected mode, which means
+ * we get ICMP errors back instead of timing
+ * out requests. And we can only send requests
+ * to the connected peer.
+ */
+ bool connected;
+
+ /* the queue for outgoing dgrams */
+ struct tevent_queue *send_queue;
+
+ /* do we have an async tsocket_recvfrom request pending */
+ struct tevent_req *recv_subreq;
+
+ struct {
+ /* a queue of pending search requests */
+ struct cldap_search_state *list;
+
+ /* mapping from message_id to pending request */
+ struct idr_context *idr;
+ } searches;
+
+ /* what to do with incoming request packets */
+ struct {
+ struct tevent_context *ev;
+ void (*handler)(struct cldap_socket *,
+ void *private_data,
+ struct cldap_incoming *);
+ void *private_data;
+ } incoming;
+};
+
+struct cldap_search_state {
+ struct cldap_search_state *prev, *next;
+
+ struct {
+ struct tevent_context *ev;
+ struct cldap_socket *cldap;
+ } caller;
+
+ int message_id;
+
+ struct {
+ uint32_t idx;
+ uint32_t delay;
+ uint32_t count;
+ struct tsocket_address *dest;
+ DATA_BLOB blob;
+ } request;
+
+ struct {
+ struct cldap_incoming *in;
+ struct asn1_data *asn1;
+ } response;
+
+ struct tevent_req *req;
+};
+
+/*
+ * For CLDAP we limit the maximum search request size to 4kb
+ */
+#define MAX_SEARCH_REQUEST 4096
+
+static int cldap_socket_destructor(struct cldap_socket *c)
+{
+ while (c->searches.list) {
+ struct cldap_search_state *s = c->searches.list;
+ DLIST_REMOVE(c->searches.list, s);
+ ZERO_STRUCT(s->caller);
+ }
+
+ talloc_free(c->recv_subreq);
+ talloc_free(c->send_queue);
+ talloc_free(c->sock);
+ return 0;
+}
+
+static void cldap_recvfrom_done(struct tevent_req *subreq);
+
+static bool cldap_recvfrom_setup(struct cldap_socket *c)
+{
+ struct tevent_context *ev;
+
+ if (c->recv_subreq) {
+ return true;
+ }
+
+ if (!c->searches.list && !c->incoming.handler) {
+ return true;
+ }
+
+ ev = c->incoming.ev;
+ if (ev == NULL) {
+ /* this shouldn't happen but should be protected against */
+ if (c->searches.list == NULL) {
+ return false;
+ }
+ ev = c->searches.list->caller.ev;
+ }
+
+ c->recv_subreq = tdgram_recvfrom_send(c, ev, c->sock);
+ if (!c->recv_subreq) {
+ return false;
+ }
+ tevent_req_set_callback(c->recv_subreq, cldap_recvfrom_done, c);
+
+ return true;
+}
+
+static void cldap_recvfrom_stop(struct cldap_socket *c)
+{
+ if (!c->recv_subreq) {
+ return;
+ }
+
+ if (c->searches.list || c->incoming.handler) {
+ return;
+ }
+
+ talloc_free(c->recv_subreq);
+ c->recv_subreq = NULL;
+}
+
+static bool cldap_socket_recv_dgram(struct cldap_socket *c,
+ struct cldap_incoming *in);
+
+static void cldap_recvfrom_done(struct tevent_req *subreq)
+{
+ struct cldap_socket *c = tevent_req_callback_data(subreq,
+ struct cldap_socket);
+ struct cldap_incoming *in = NULL;
+ ssize_t ret;
+ bool setup_done;
+
+ c->recv_subreq = NULL;
+
+ in = talloc_zero(c, struct cldap_incoming);
+ if (!in) {
+ goto nomem;
+ }
+
+ ret = tdgram_recvfrom_recv(subreq,
+ &in->recv_errno,
+ in,
+ &in->buf,
+ &in->src);
+ talloc_free(subreq);
+ subreq = NULL;
+ if (ret >= 0) {
+ in->len = ret;
+ }
+ if (ret == -1 && in->recv_errno == 0) {
+ in->recv_errno = EIO;
+ }
+
+ /* this function should free or steal 'in' */
+ setup_done = cldap_socket_recv_dgram(c, in);
+ in = NULL;
+
+ if (!setup_done && !cldap_recvfrom_setup(c)) {
+ goto nomem;
+ }
+
+ return;
+
+nomem:
+ talloc_free(subreq);
+ talloc_free(in);
+}
+
+/*
+ handle recv events on a cldap socket
+*/
+static bool cldap_socket_recv_dgram(struct cldap_socket *c,
+ struct cldap_incoming *in)
+{
+ struct asn1_data *asn1;
+ void *p;
+ struct cldap_search_state *search;
+ NTSTATUS status;
+ struct ldap_request_limits limits = {
+ .max_search_size = MAX_SEARCH_REQUEST
+ };
+
+ if (in->recv_errno != 0) {
+ goto error;
+ }
+
+ asn1 = asn1_init(in, ASN1_MAX_TREE_DEPTH);
+ if (!asn1) {
+ goto nomem;
+ }
+
+ asn1_load_nocopy(asn1, in->buf, in->len);
+
+ in->ldap_msg = talloc(in, struct ldap_message);
+ if (in->ldap_msg == NULL) {
+ goto nomem;
+ }
+
+ /* this initial decode is used to find the message id */
+ status = ldap_decode(asn1, &limits, NULL, in->ldap_msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto nterror;
+ }
+
+ /* find the pending request */
+ p = idr_find(c->searches.idr, in->ldap_msg->messageid);
+ if (p == NULL) {
+ if (!c->incoming.handler) {
+ TALLOC_FREE(in);
+ return true;
+ }
+
+ /* this function should free or steal 'in' */
+ c->incoming.handler(c, c->incoming.private_data, in);
+ return false;
+ }
+
+ search = talloc_get_type_abort(p, struct cldap_search_state);
+ search->response.in = talloc_move(search, &in);
+
+ search->response.asn1 = asn1;
+
+ asn1_load_nocopy(search->response.asn1,
+ search->response.in->buf, search->response.in->len);
+
+ DLIST_REMOVE(c->searches.list, search);
+
+ if (cldap_recvfrom_setup(c)) {
+ tevent_req_done(search->req);
+ return true;
+ }
+
+ /*
+ * This request was ok, just defer the notify of the caller
+ * and then just fail the next request if needed
+ */
+ tevent_req_defer_callback(search->req, search->caller.ev);
+ tevent_req_done(search->req);
+
+ status = NT_STATUS_NO_MEMORY;
+ /* in is NULL it this point */
+ goto nterror;
+nomem:
+ in->recv_errno = ENOMEM;
+error:
+ status = map_nt_error_from_unix_common(in->recv_errno);
+nterror:
+ TALLOC_FREE(in);
+ /* in connected mode the first pending search gets the error */
+ if (!c->connected) {
+ /* otherwise we just ignore the error */
+ return false;
+ }
+ if (!c->searches.list) {
+ return false;
+ }
+ /*
+ * We might called tevent_req_done() for a successful
+ * search before, so we better deliver the failure
+ * after the success, that is why we better also
+ * use tevent_req_defer_callback() here.
+ */
+ tevent_req_defer_callback(c->searches.list->req,
+ c->searches.list->caller.ev);
+ tevent_req_nterror(c->searches.list->req, status);
+ return false;
+}
+
+/*
+ initialise a cldap_sock
+*/
+NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
+ const struct tsocket_address *local_addr,
+ const struct tsocket_address *remote_addr,
+ struct cldap_socket **_cldap)
+{
+ struct cldap_socket *c = NULL;
+ struct tsocket_address *any = NULL;
+ NTSTATUS status;
+ int ret;
+ const char *fam = NULL;
+
+ if (local_addr == NULL && remote_addr == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (remote_addr) {
+ bool is_ipv4;
+ bool is_ipv6;
+
+ is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
+ is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
+
+ if (is_ipv4) {
+ fam = "ipv4";
+ } else if (is_ipv6) {
+ fam = "ipv6";
+ } else {
+ return NT_STATUS_INVALID_ADDRESS;
+ }
+ }
+
+ c = talloc_zero(mem_ctx, struct cldap_socket);
+ if (!c) {
+ goto nomem;
+ }
+
+ if (!local_addr) {
+ /*
+ * Here we know the address family of the remote address.
+ */
+ if (fam == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ ret = tsocket_address_inet_from_strings(c, fam,
+ NULL, 0,
+ &any);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ goto nterror;
+ }
+ local_addr = any;
+ }
+
+ c->searches.idr = idr_init(c);
+ if (!c->searches.idr) {
+ goto nomem;
+ }
+
+ ret = tdgram_inet_udp_socket(local_addr, remote_addr,
+ c, &c->sock);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ goto nterror;
+ }
+ talloc_free(any);
+
+ if (remote_addr) {
+ c->connected = true;
+ }
+
+ c->send_queue = tevent_queue_create(c, "cldap_send_queue");
+ if (!c->send_queue) {
+ goto nomem;
+ }
+
+ talloc_set_destructor(c, cldap_socket_destructor);
+
+ *_cldap = c;
+ return NT_STATUS_OK;
+
+nomem:
+ status = NT_STATUS_NO_MEMORY;
+nterror:
+ talloc_free(c);
+ return status;
+}
+
+/*
+ setup a handler for incoming requests
+*/
+NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
+ struct tevent_context *ev,
+ void (*handler)(struct cldap_socket *,
+ void *private_data,
+ struct cldap_incoming *),
+ void *private_data)
+{
+ if (c->connected) {
+ return NT_STATUS_PIPE_CONNECTED;
+ }
+
+ c->incoming.ev = ev;
+ c->incoming.handler = handler;
+ c->incoming.private_data = private_data;
+
+ if (!cldap_recvfrom_setup(c)) {
+ ZERO_STRUCT(c->incoming);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct cldap_reply_state {
+ struct tsocket_address *dest;
+ DATA_BLOB blob;
+};
+
+static void cldap_reply_state_destroy(struct tevent_req *subreq);
+
+/*
+ queue a cldap reply for send
+*/
+NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
+{
+ struct cldap_reply_state *state = NULL;
+ struct ldap_message *msg;
+ DATA_BLOB blob1, blob2;
+ NTSTATUS status;
+ struct tevent_req *subreq;
+
+ if (cldap->connected) {
+ return NT_STATUS_PIPE_CONNECTED;
+ }
+
+ if (cldap->incoming.ev == NULL) {
+ return NT_STATUS_INVALID_PIPE_STATE;
+ }
+
+ if (!io->dest) {
+ return NT_STATUS_INVALID_ADDRESS;
+ }
+
+ state = talloc(cldap, struct cldap_reply_state);
+ NT_STATUS_HAVE_NO_MEMORY(state);
+
+ state->dest = tsocket_address_copy(io->dest, state);
+ if (!state->dest) {
+ goto nomem;
+ }
+
+ msg = talloc(state, struct ldap_message);
+ if (!msg) {
+ goto nomem;
+ }
+
+ msg->messageid = io->messageid;
+ msg->controls = NULL;
+
+ if (io->response) {
+ msg->type = LDAP_TAG_SearchResultEntry;
+ msg->r.SearchResultEntry = *io->response;
+
+ if (!ldap_encode(msg, NULL, &blob1, state)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto failed;
+ }
+ } else {
+ blob1 = data_blob(NULL, 0);
+ }
+
+ msg->type = LDAP_TAG_SearchResultDone;
+ msg->r.SearchResultDone = *io->result;
+
+ if (!ldap_encode(msg, NULL, &blob2, state)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto failed;
+ }
+ talloc_free(msg);
+
+ state->blob = data_blob_talloc(state, NULL, blob1.length + blob2.length);
+ if (!state->blob.data) {
+ goto nomem;
+ }
+
+ if (blob1.data != NULL) {
+ memcpy(state->blob.data, blob1.data, blob1.length);
+ }
+ memcpy(state->blob.data+blob1.length, blob2.data, blob2.length);
+ data_blob_free(&blob1);
+ data_blob_free(&blob2);
+
+ subreq = tdgram_sendto_queue_send(state,
+ cldap->incoming.ev,
+ cldap->sock,
+ cldap->send_queue,
+ state->blob.data,
+ state->blob.length,
+ state->dest);
+ if (!subreq) {
+ goto nomem;
+ }
+ /* the callback will just free the state, as we don't need a result */
+ tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
+
+ return NT_STATUS_OK;
+
+nomem:
+ status = NT_STATUS_NO_MEMORY;
+failed:
+ talloc_free(state);
+ return status;
+}
+
+static void cldap_reply_state_destroy(struct tevent_req *subreq)
+{
+ struct cldap_reply_state *state = tevent_req_callback_data(subreq,
+ struct cldap_reply_state);
+
+ /* we don't want to know the result here, we just free the state */
+ talloc_free(subreq);
+ talloc_free(state);
+}
+
+static int cldap_search_state_destructor(struct cldap_search_state *s)
+{
+ if (s->caller.cldap) {
+ if (s->message_id != -1) {
+ idr_remove(s->caller.cldap->searches.idr, s->message_id);
+ s->message_id = -1;
+ }
+ DLIST_REMOVE(s->caller.cldap->searches.list, s);
+ cldap_recvfrom_stop(s->caller.cldap);
+ ZERO_STRUCT(s->caller);
+ }
+
+ return 0;
+}
+
+static void cldap_search_state_queue_done(struct tevent_req *subreq);
+static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
+
+/*
+ queue a cldap reply for send
+*/
+struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_search *io)
+{
+ struct tevent_req *req, *subreq;
+ struct cldap_search_state *state = NULL;
+ struct ldap_message *msg;
+ struct ldap_SearchRequest *search;
+ struct timeval now;
+ struct timeval end;
+ uint32_t i;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cldap_search_state);
+ if (!req) {
+ return NULL;
+ }
+ state->caller.ev = ev;
+ state->req = req;
+ state->caller.cldap = cldap;
+ state->message_id = -1;
+
+ talloc_set_destructor(state, cldap_search_state_destructor);
+
+ if (state->caller.cldap == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto post;
+ }
+
+ if (io->in.dest_address) {
+ if (cldap->connected) {
+ tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
+ goto post;
+ }
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ io->in.dest_address,
+ io->in.dest_port,
+ &state->request.dest);
+ if (ret != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto post;
+ }
+ } else {
+ if (!cldap->connected) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_ADDRESS);
+ goto post;
+ }
+ state->request.dest = NULL;
+ }
+
+ state->message_id = idr_get_new_random(
+ cldap->searches.idr, state, 1, UINT16_MAX);
+ if (state->message_id == -1) {
+ tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
+ goto post;
+ }
+
+ msg = talloc(state, struct ldap_message);
+ if (tevent_req_nomem(msg, req)) {
+ goto post;
+ }
+
+ msg->messageid = state->message_id;
+ msg->type = LDAP_TAG_SearchRequest;
+ msg->controls = NULL;
+ search = &msg->r.SearchRequest;
+
+ search->basedn = "";
+ search->scope = LDAP_SEARCH_SCOPE_BASE;
+ search->deref = LDAP_DEREFERENCE_NEVER;
+ search->timelimit = 0;
+ search->sizelimit = 0;
+ search->attributesonly = false;
+ search->num_attributes = str_list_length(io->in.attributes);
+ search->attributes = io->in.attributes;
+ search->tree = ldb_parse_tree(msg, io->in.filter);
+ if (tevent_req_nomem(search->tree, req)) {
+ goto post;
+ }
+
+ if (!ldap_encode(msg, NULL, &state->request.blob, state)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto post;
+ }
+ talloc_free(msg);
+
+ state->request.idx = 0;
+ state->request.delay = 10*1000*1000;
+ state->request.count = 3;
+ if (io->in.timeout > 0) {
+ state->request.delay = io->in.timeout * 1000 * 1000;
+ state->request.count = io->in.retries + 1;
+ }
+
+ now = tevent_timeval_current();
+ end = now;
+ for (i = 0; i < state->request.count; i++) {
+ end = tevent_timeval_add(&end, state->request.delay / 1000000,
+ state->request.delay % 1000000);
+ }
+
+ if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
+ goto post;
+ }
+
+ subreq = tdgram_sendto_queue_send(state,
+ state->caller.ev,
+ state->caller.cldap->sock,
+ state->caller.cldap->send_queue,
+ state->request.blob.data,
+ state->request.blob.length,
+ state->request.dest);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
+
+ DLIST_ADD_END(cldap->searches.list, state);
+
+ return req;
+
+ post:
+ return tevent_req_post(req, state->caller.ev);
+}
+
+static void cldap_search_state_queue_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cldap_search_state *state = tevent_req_data(req,
+ struct cldap_search_state);
+ ssize_t ret;
+ int sys_errno = 0;
+ struct timeval next;
+
+ ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
+ talloc_free(subreq);
+ if (ret == -1) {
+ NTSTATUS status;
+ status = map_nt_error_from_unix_common(sys_errno);
+ DLIST_REMOVE(state->caller.cldap->searches.list, state);
+ ZERO_STRUCT(state->caller.cldap);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->request.idx++;
+
+ /* wait for incoming traffic */
+ if (!cldap_recvfrom_setup(state->caller.cldap)) {
+ tevent_req_oom(req);
+ return;
+ }
+
+ if (state->request.idx > state->request.count) {
+ /* we just wait for the response or a timeout */
+ return;
+ }
+
+ next = tevent_timeval_current_ofs(state->request.delay / 1000000,
+ state->request.delay % 1000000);
+ subreq = tevent_wakeup_send(state,
+ state->caller.ev,
+ next);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cldap_search_state_wakeup_done, req);
+}
+
+static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cldap_search_state *state = tevent_req_data(req,
+ struct cldap_search_state);
+ bool ok;
+
+ ok = tevent_wakeup_recv(subreq);
+ talloc_free(subreq);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ subreq = tdgram_sendto_queue_send(state,
+ state->caller.ev,
+ state->caller.cldap->sock,
+ state->caller.cldap->send_queue,
+ state->request.blob.data,
+ state->request.blob.length,
+ state->request.dest);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
+}
+
+/*
+ receive a cldap reply
+*/
+NTSTATUS cldap_search_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_search *io)
+{
+ struct cldap_search_state *state = tevent_req_data(req,
+ struct cldap_search_state);
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ struct ldap_request_limits limits = {
+ .max_search_size = MAX_SEARCH_REQUEST
+ };
+
+ if (tevent_req_is_nterror(req, &status)) {
+ goto failed;
+ }
+
+ ldap_msg = talloc(mem_ctx, struct ldap_message);
+ if (!ldap_msg) {
+ goto nomem;
+ }
+
+ status = ldap_decode(state->response.asn1, &limits, NULL, ldap_msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ ZERO_STRUCT(io->out);
+
+ /* the first possible form has a search result in first place */
+ if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
+ io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
+ if (!io->out.response) {
+ goto nomem;
+ }
+ *io->out.response = ldap_msg->r.SearchResultEntry;
+
+ /* decode the 2nd part */
+ status = ldap_decode(
+ state->response.asn1, &limits, NULL, ldap_msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+ }
+
+ if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
+ status = NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+ goto failed;
+ }
+
+ io->out.result = talloc(mem_ctx, struct ldap_Result);
+ if (!io->out.result) {
+ goto nomem;
+ }
+ *io->out.result = ldap_msg->r.SearchResultDone;
+
+ if (io->out.result->resultcode != LDAP_SUCCESS) {
+ status = NT_STATUS_LDAP(io->out.result->resultcode);
+ goto failed;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+
+nomem:
+ status = NT_STATUS_NO_MEMORY;
+failed:
+ tevent_req_received(req);
+ return status;
+}
+
+
+/*
+ synchronous cldap search
+*/
+NTSTATUS cldap_search(struct cldap_socket *cldap,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_search *io)
+{
+ TALLOC_CTX *frame;
+ struct tevent_req *req;
+ struct tevent_context *ev;
+ NTSTATUS status;
+
+ if (cldap->searches.list) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cldap->incoming.handler) {
+ return NT_STATUS_INVALID_PIPE_STATE;
+ }
+
+ frame = talloc_stackframe();
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ req = cldap_search_send(mem_ctx, ev, cldap, io);
+ if (req == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ status = cldap_search_recv(req, mem_ctx, io);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+struct cldap_netlogon_state {
+ struct cldap_search search;
+};
+
+char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
+ const struct cldap_netlogon *io)
+{
+ char *filter;
+
+ filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
+ ldap_encode_ndr_uint32(mem_ctx, io->in.version));
+
+ if (io->in.user) {
+ talloc_asprintf_addbuf(&filter, "(User=%s)", io->in.user);
+ }
+ if (io->in.host) {
+ talloc_asprintf_addbuf(&filter, "(Host=%s)", io->in.host);
+ }
+ if (io->in.realm) {
+ talloc_asprintf_addbuf(&filter, "(DnsDomain=%s)", io->in.realm);
+ }
+ if (io->in.acct_control != -1) {
+ talloc_asprintf_addbuf(
+ &filter,
+ "(AAC=%s)",
+ ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
+ }
+ if (io->in.domain_sid) {
+ struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
+
+ talloc_asprintf_addbuf(&filter, "(domainSid=%s)",
+ ldap_encode_ndr_dom_sid(mem_ctx, sid));
+ }
+ if (io->in.domain_guid) {
+ struct GUID guid;
+ GUID_from_string(io->in.domain_guid, &guid);
+
+ talloc_asprintf_addbuf(&filter, "(DomainGuid=%s)",
+ ldap_encode_ndr_GUID(mem_ctx, &guid));
+ }
+ talloc_asprintf_addbuf(&filter, ")");
+
+ return filter;
+}
+
+static void cldap_netlogon_state_done(struct tevent_req *subreq);
+/*
+ queue a cldap netlogon for send
+*/
+struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_netlogon *io)
+{
+ struct tevent_req *req, *subreq;
+ struct cldap_netlogon_state *state;
+ char *filter;
+ static const char * const attr[] = { "NetLogon", NULL };
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cldap_netlogon_state);
+ if (!req) {
+ return NULL;
+ }
+
+ filter = cldap_netlogon_create_filter(state, io);
+ if (tevent_req_nomem(filter, req)) {
+ goto post;
+ }
+
+ if (io->in.dest_address) {
+ state->search.in.dest_address = talloc_strdup(state,
+ io->in.dest_address);
+ if (tevent_req_nomem(state->search.in.dest_address, req)) {
+ goto post;
+ }
+ state->search.in.dest_port = io->in.dest_port;
+ } else {
+ state->search.in.dest_address = NULL;
+ state->search.in.dest_port = 0;
+ }
+ state->search.in.filter = filter;
+ state->search.in.attributes = attr;
+ state->search.in.timeout = 2;
+ state->search.in.retries = 2;
+
+ subreq = cldap_search_send(state, ev, cldap, &state->search);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, cldap_netlogon_state_done, req);
+
+ return req;
+post:
+ return tevent_req_post(req, ev);
+}
+
+static void cldap_netlogon_state_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cldap_netlogon_state *state = tevent_req_data(req,
+ struct cldap_netlogon_state);
+ NTSTATUS status;
+
+ status = cldap_search_recv(subreq, state, &state->search);
+ talloc_free(subreq);
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/*
+ receive a cldap netlogon reply
+*/
+NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io)
+{
+ struct cldap_netlogon_state *state = tevent_req_data(req,
+ struct cldap_netlogon_state);
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ DATA_BLOB *data;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ goto failed;
+ }
+
+ if (state->search.out.response == NULL) {
+ status = NT_STATUS_NOT_FOUND;
+ goto failed;
+ }
+
+ if (state->search.out.response->num_attributes != 1 ||
+ strcasecmp(state->search.out.response->attributes[0].name, "netlogon") != 0 ||
+ state->search.out.response->attributes[0].num_values != 1 ||
+ state->search.out.response->attributes[0].values->length < 2) {
+ status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ goto failed;
+ }
+ data = state->search.out.response->attributes[0].values;
+
+ status = pull_netlogon_samlogon_response(data, mem_ctx,
+ &io->out.netlogon);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ if (io->in.map_response) {
+ map_netlogon_samlogon_response(&io->out.netlogon);
+ }
+
+ status = NT_STATUS_OK;
+failed:
+ tevent_req_received(req);
+ return status;
+}
+
+/*
+ sync cldap netlogon search
+*/
+NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io)
+{
+ TALLOC_CTX *frame;
+ struct tevent_req *req;
+ struct tevent_context *ev;
+ NTSTATUS status;
+
+ if (cldap->searches.list) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cldap->incoming.handler) {
+ return NT_STATUS_INVALID_PIPE_STATE;
+ }
+
+ frame = talloc_stackframe();
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
+ if (req == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ status = cldap_netlogon_recv(req, mem_ctx, io);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+
+/*
+ send an empty reply (used on any error, so the client doesn't keep waiting
+ or send the bad request again)
+*/
+NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dest)
+{
+ NTSTATUS status;
+ struct cldap_reply reply;
+ struct ldap_Result result;
+
+ reply.messageid = message_id;
+ reply.dest = dest;
+ reply.response = NULL;
+ reply.result = &result;
+
+ ZERO_STRUCT(result);
+
+ status = cldap_reply_send(cldap, &reply);
+
+ return status;
+}
+
+/*
+ send an error reply (used on any error, so the client doesn't keep waiting
+ or send the bad request again)
+*/
+NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dest,
+ int resultcode,
+ const char *errormessage)
+{
+ NTSTATUS status;
+ struct cldap_reply reply;
+ struct ldap_Result result;
+
+ reply.messageid = message_id;
+ reply.dest = dest;
+ reply.response = NULL;
+ reply.result = &result;
+
+ ZERO_STRUCT(result);
+ result.resultcode = resultcode;
+ result.errormessage = errormessage;
+
+ status = cldap_reply_send(cldap, &reply);
+
+ return status;
+}
+
+
+/*
+ send a netlogon reply
+*/
+NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dest,
+ uint32_t version,
+ struct netlogon_samlogon_response *netlogon)
+{
+ NTSTATUS status;
+ struct cldap_reply reply;
+ struct ldap_SearchResEntry response;
+ struct ldap_Result result;
+ TALLOC_CTX *tmp_ctx = talloc_new(cldap);
+ DATA_BLOB blob;
+
+ status = push_netlogon_samlogon_response(&blob, tmp_ctx,
+ netlogon);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return status;
+ }
+ reply.messageid = message_id;
+ reply.dest = dest;
+ reply.response = &response;
+ reply.result = &result;
+
+ ZERO_STRUCT(result);
+
+ response.dn = "";
+ response.num_attributes = 1;
+ response.attributes = talloc(tmp_ctx, struct ldb_message_element);
+ NT_STATUS_HAVE_NO_MEMORY(response.attributes);
+ response.attributes->name = "netlogon";
+ response.attributes->num_values = 1;
+ response.attributes->values = &blob;
+
+ status = cldap_reply_send(cldap, &reply);
+
+ talloc_free(tmp_ctx);
+
+ return status;
+}
+
diff --git a/libcli/cldap/cldap.h b/libcli/cldap/cldap.h
new file mode 100644
index 0000000..cd76fee
--- /dev/null
+++ b/libcli/cldap/cldap.h
@@ -0,0 +1,134 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a async CLDAP library
+
+ Copyright (C) Andrew Tridgell 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 "../libcli/netlogon/netlogon.h"
+
+struct ldap_message;
+struct tsocket_address;
+struct cldap_socket;
+
+struct cldap_incoming {
+ int recv_errno;
+ uint8_t *buf;
+ size_t len;
+ struct tsocket_address *src;
+ struct ldap_message *ldap_msg;
+};
+
+/*
+ a general cldap search request
+*/
+struct cldap_search {
+ struct {
+ const char *dest_address;
+ uint16_t dest_port;
+ const char *filter;
+ const char * const *attributes;
+ int timeout;
+ int retries;
+ } in;
+ struct {
+ struct ldap_SearchResEntry *response;
+ struct ldap_Result *result;
+ } out;
+};
+
+NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
+ const struct tsocket_address *local_addr,
+ const struct tsocket_address *remote_addr,
+ struct cldap_socket **_cldap);
+
+NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
+ struct tevent_context *ev,
+ void (*handler)(struct cldap_socket *,
+ void *private_data,
+ struct cldap_incoming *),
+ void *private_data);
+struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_search *io);
+NTSTATUS cldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct cldap_search *io);
+NTSTATUS cldap_search(struct cldap_socket *cldap, TALLOC_CTX *mem_ctx,
+ struct cldap_search *io);
+
+/*
+ a general cldap reply
+*/
+struct cldap_reply {
+ uint32_t messageid;
+ struct tsocket_address *dest;
+ struct ldap_SearchResEntry *response;
+ struct ldap_Result *result;
+};
+
+NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io);
+
+NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dst);
+NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dst,
+ int resultcode,
+ const char *errormessage);
+
+/*
+ a netlogon cldap request
+*/
+struct cldap_netlogon {
+ struct {
+ const char *dest_address;
+ uint16_t dest_port;
+ const char *realm;
+ const char *host;
+ const char *user;
+ const char *domain_guid;
+ const char *domain_sid;
+ int acct_control;
+ uint32_t version;
+ bool map_response;
+ } in;
+ struct {
+ struct netlogon_samlogon_response netlogon;
+ } out;
+};
+
+struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_netlogon *io);
+NTSTATUS cldap_netlogon_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io);
+NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
+ TALLOC_CTX *mem_ctx,
+ struct cldap_netlogon *io);
+char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
+ const struct cldap_netlogon *io);
+
+NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct tsocket_address *dst,
+ uint32_t version,
+ struct netlogon_samlogon_response *netlogon);
+
diff --git a/libcli/cldap/wscript_build b/libcli/cldap/wscript_build
new file mode 100644
index 0000000..889c0af
--- /dev/null
+++ b/libcli/cldap/wscript_build
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_LIBRARY('cli_cldap',
+ source='cldap.c',
+ public_deps='cli-ldap',
+ deps='LIBTSOCKET samba-util tevent-util ldb LIBCLI_NETLOGON',
+ private_library=True
+ )
+
diff --git a/libcli/dns/dns.c b/libcli/dns/dns.c
new file mode 100644
index 0000000..943b4d5
--- /dev/null
+++ b/libcli/dns/dns.c
@@ -0,0 +1,591 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Small async DNS library for Samba with socketwrapper support
+
+ Copyright (C) 2010 Kai Blin <kai@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 "system/network.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "libcli/dns/libdns.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/debug.h"
+#include "libcli/util/error.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dns.h"
+
+struct dns_udp_request_state {
+ struct tevent_context *ev;
+ struct tdgram_context *dgram;
+ size_t query_len;
+ uint8_t *reply;
+ size_t reply_len;
+};
+
+#define DNS_REQUEST_TIMEOUT 10
+
+/* Declare callback functions used below. */
+static void dns_udp_request_get_reply(struct tevent_req *subreq);
+static void dns_udp_request_done(struct tevent_req *subreq);
+
+static struct tevent_req *dns_udp_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *server_addr_string,
+ const uint8_t *query,
+ size_t query_len)
+{
+ struct tevent_req *req, *subreq;
+ struct dns_udp_request_state *state;
+ struct tsocket_address *local_addr, *server_addr;
+ struct tdgram_context *dgram;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct dns_udp_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+
+ /* Use connected UDP sockets */
+ ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
+ &local_addr);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_hostport_strings(
+ state, "ip", server_addr_string, DNS_SERVICE_PORT, &server_addr);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ state->dgram = dgram;
+ state->query_len = query_len;
+
+ dump_data(10, query, query_len);
+
+ subreq = tdgram_sendto_send(state, ev, dgram, query, query_len, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (!tevent_req_set_endtime(req, ev,
+ timeval_current_ofs(DNS_REQUEST_TIMEOUT, 0))) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq, dns_udp_request_get_reply, req);
+ return req;
+}
+
+static void dns_udp_request_get_reply(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct dns_udp_request_state *state = tevent_req_data(req,
+ struct dns_udp_request_state);
+ ssize_t len;
+ int err = 0;
+
+ len = tdgram_sendto_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+
+ if (len == -1 && err != 0) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ if (len != state->query_len) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ tevent_req_set_callback(subreq, dns_udp_request_done, req);
+}
+
+static void dns_udp_request_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct dns_udp_request_state *state = tevent_req_data(req,
+ struct dns_udp_request_state);
+
+ ssize_t len;
+ int err = 0;
+
+ len = tdgram_recvfrom_recv(subreq, &err, state, &state->reply, NULL);
+ TALLOC_FREE(subreq);
+
+ if (len == -1 && err != 0) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ state->reply_len = len;
+ dump_data(10, state->reply, state->reply_len);
+ tevent_req_done(req);
+}
+
+static int dns_udp_request_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **reply,
+ size_t *reply_len)
+{
+ struct dns_udp_request_state *state = tevent_req_data(req,
+ struct dns_udp_request_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ tevent_req_received(req);
+ return err;
+ }
+
+ *reply = talloc_move(mem_ctx, &state->reply);
+ *reply_len = state->reply_len;
+ tevent_req_received(req);
+
+ return 0;
+}
+
+struct dns_tcp_request_state {
+ struct tevent_context *ev;
+ struct tstream_context *stream;
+ const uint8_t *query;
+ size_t query_len;
+
+ uint8_t dns_msglen_hdr[2];
+ struct iovec iov[2];
+
+ size_t nread;
+ uint8_t *reply;
+};
+
+static void dns_tcp_request_connected(struct tevent_req *subreq);
+static void dns_tcp_request_sent(struct tevent_req *subreq);
+static int dns_tcp_request_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count);
+static void dns_tcp_request_received(struct tevent_req *subreq);
+
+static struct tevent_req *dns_tcp_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *server_addr_string,
+ const uint8_t *query,
+ size_t query_len)
+{
+ struct tevent_req *req, *subreq;
+ struct dns_tcp_request_state *state;
+ struct tsocket_address *local, *remote;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dns_tcp_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->query = query;
+ state->query_len = query_len;
+
+ if (query_len > UINT16_MAX) {
+ tevent_req_error(req, EMSGSIZE);
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_hostport_strings(
+ state, "ip", server_addr_string, DNS_SERVICE_PORT, &remote);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tstream_inet_tcp_connect_send(state, state->ev,
+ local, remote);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, dns_tcp_request_connected, req);
+
+ return req;
+}
+
+static void dns_tcp_request_connected(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_tcp_request_state *state = tevent_req_data(
+ req, struct dns_tcp_request_state);
+ int ret, err;
+
+ ret = tstream_inet_tcp_connect_recv(subreq, &err, state,
+ &state->stream, NULL);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ RSSVAL(state->dns_msglen_hdr, 0, state->query_len);
+ state->iov[0] = (struct iovec) {
+ .iov_base = state->dns_msglen_hdr,
+ .iov_len = sizeof(state->dns_msglen_hdr)
+ };
+ state->iov[1] = (struct iovec) {
+ .iov_base = discard_const_p(void, state->query),
+ .iov_len = state->query_len
+ };
+
+ subreq = tstream_writev_send(state, state->ev, state->stream,
+ state->iov, ARRAY_SIZE(state->iov));
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, dns_tcp_request_sent, req);
+}
+
+static void dns_tcp_request_sent(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_tcp_request_state *state = tevent_req_data(
+ req, struct dns_tcp_request_state);
+ int ret, err;
+
+ ret = tstream_writev_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ subreq = tstream_readv_pdu_send(state, state->ev, state->stream,
+ dns_tcp_request_next_vector, state);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, dns_tcp_request_received, req);
+}
+
+static int dns_tcp_request_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count)
+{
+ struct dns_tcp_request_state *state = talloc_get_type_abort(
+ private_data, struct dns_tcp_request_state);
+ struct iovec *vector;
+ uint16_t msglen;
+
+ if (state->nread == 0) {
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (vector == NULL) {
+ return -1;
+ }
+ vector[0] = (struct iovec) {
+ .iov_base = state->dns_msglen_hdr,
+ .iov_len = sizeof(state->dns_msglen_hdr)
+ };
+ state->nread = sizeof(state->dns_msglen_hdr);
+
+ *_vector = vector;
+ *_count = 1;
+ return 0;
+ }
+
+ if (state->nread == sizeof(state->dns_msglen_hdr)) {
+ msglen = RSVAL(state->dns_msglen_hdr, 0);
+
+ state->reply = talloc_array(state, uint8_t, msglen);
+ if (state->reply == NULL) {
+ return -1;
+ }
+
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (vector == NULL) {
+ return -1;
+ }
+ vector[0] = (struct iovec) {
+ .iov_base = state->reply,
+ .iov_len = msglen
+ };
+ state->nread += msglen;
+
+ *_vector = vector;
+ *_count = 1;
+ return 0;
+ }
+
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
+}
+
+static void dns_tcp_request_received(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret, err;
+
+ ret = tstream_readv_pdu_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int dns_tcp_request_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **reply,
+ size_t *reply_len)
+{
+ struct dns_tcp_request_state *state = tevent_req_data(
+ req, struct dns_tcp_request_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ tevent_req_received(req);
+ return err;
+ }
+
+ *reply_len = talloc_array_length(state->reply);
+ *reply = talloc_move(mem_ctx, &state->reply);
+ tevent_req_received(req);
+
+ return 0;
+}
+
+struct dns_cli_request_state {
+ struct tevent_context *ev;
+ const char *nameserver;
+
+ uint16_t req_id;
+
+ DATA_BLOB query;
+
+ struct dns_name_packet *reply;
+};
+
+static void dns_cli_request_udp_done(struct tevent_req *subreq);
+static void dns_cli_request_tcp_done(struct tevent_req *subreq);
+
+struct tevent_req *dns_cli_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *nameserver,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype)
+{
+ struct tevent_req *req, *subreq;
+ struct dns_cli_request_state *state;
+ struct dns_name_question question;
+ struct dns_name_packet out_packet;
+ enum ndr_err_code ndr_err;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dns_cli_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->nameserver = nameserver;
+
+ DBG_DEBUG("Asking %s for %s/%d/%d via UDP\n", nameserver,
+ name, (int)qclass, (int)qtype);
+
+ generate_random_buffer((uint8_t *)&state->req_id,
+ sizeof(state->req_id));
+
+ question = (struct dns_name_question) {
+ .name = discard_const_p(char, name),
+ .question_type = qtype, .question_class = qclass
+ };
+
+ out_packet = (struct dns_name_packet) {
+ .id = state->req_id,
+ .operation = DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED,
+ .qdcount = 1,
+ .questions = &question
+ };
+
+ ndr_err = ndr_push_struct_blob(
+ &state->query, state, &out_packet,
+ (ndr_push_flags_fn_t)ndr_push_dns_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ tevent_req_error(req, ndr_map_error2errno(ndr_err));
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = dns_udp_request_send(state, state->ev, state->nameserver,
+ state->query.data, state->query.length);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, dns_cli_request_udp_done, req);
+ return req;
+}
+
+static void dns_cli_request_udp_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_cli_request_state *state = tevent_req_data(
+ req, struct dns_cli_request_state);
+ DATA_BLOB reply;
+ enum ndr_err_code ndr_err;
+ uint16_t reply_id, operation;
+ int ret;
+
+ ret = dns_udp_request_recv(subreq, state, &reply.data, &reply.length);
+ TALLOC_FREE(subreq);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ if (reply.length < 4) {
+ DBG_DEBUG("Short DNS packet: length=%zu\n", reply.length);
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+
+ reply_id = PULL_BE_U16(reply.data, 0);
+ if (reply_id != state->req_id) {
+ DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
+ state->reply->id, state->req_id);
+ tevent_req_error(req, ENOMSG);
+ return;
+ }
+
+ operation = PULL_BE_U16(reply.data, 2);
+ if ((operation & DNS_FLAG_TRUNCATION) != 0) {
+ DBG_DEBUG("Reply was truncated, retrying TCP\n");
+ subreq = dns_tcp_request_send(
+ state,
+ state->ev,
+ state->nameserver,
+ state->query.data,
+ state->query.length);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, dns_cli_request_tcp_done, req);
+ return;
+ }
+
+ state->reply = talloc(state, struct dns_name_packet);
+ if (tevent_req_nomem(state->reply, req)) {
+ return;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ &reply, state->reply, state->reply,
+ (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ tevent_req_error(req, ndr_map_error2errno(ndr_err));
+ return;
+ }
+ TALLOC_FREE(reply.data);
+
+ tevent_req_done(req);
+}
+
+static void dns_cli_request_tcp_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_cli_request_state *state = tevent_req_data(
+ req, struct dns_cli_request_state);
+ DATA_BLOB reply;
+ enum ndr_err_code ndr_err;
+ int ret;
+
+ ret = dns_tcp_request_recv(subreq, state, &reply.data, &reply.length);
+ TALLOC_FREE(subreq);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ state->reply = talloc(state, struct dns_name_packet);
+ if (tevent_req_nomem(state->reply, req)) {
+ return;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ &reply, state->reply, state->reply,
+ (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ tevent_req_error(req, ndr_map_error2errno(ndr_err));
+ return;
+ }
+ TALLOC_FREE(reply.data);
+
+ if (state->reply->id != state->req_id) {
+ DBG_DEBUG("Got id %"PRIu16", expected %"PRIu16"\n",
+ state->reply->id, state->req_id);
+ tevent_req_error(req, ENOMSG);
+ return;
+ }
+
+ DBG_DEBUG("Got op=%x %"PRIu16"/%"PRIu16"/%"PRIu16"/%"PRIu16
+ " recs\n", (int)state->reply->operation,
+ state->reply->qdcount, state->reply->ancount,
+ state->reply->nscount, state->reply->nscount);
+
+ tevent_req_done(req);
+}
+
+int dns_cli_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply)
+{
+ struct dns_cli_request_state *state = tevent_req_data(
+ req, struct dns_cli_request_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ return err;
+ }
+ *reply = talloc_move(mem_ctx, &state->reply);
+ return 0;
+}
diff --git a/libcli/dns/dns.h b/libcli/dns/dns.h
new file mode 100644
index 0000000..34a6cf5
--- /dev/null
+++ b/libcli/dns/dns.h
@@ -0,0 +1,64 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Gerald Carter 2006.
+ * 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/>.
+ */
+
+/* DNS query section in replies */
+
+#ifndef __LIBCLI_DNS_DNS_H__
+#define __LIBCLI_DNS_DNS_H__
+
+#include "replace.h"
+#include "system/network.h"
+
+struct dns_query {
+ const char *hostname;
+ uint16_t type;
+ uint16_t in_class;
+};
+
+/* DNS RR record in reply */
+
+struct dns_rr {
+ const char *hostname;
+ uint16_t type;
+ uint16_t in_class;
+ uint32_t ttl;
+ uint16_t rdatalen;
+ uint8_t *rdata;
+};
+
+/* SRV records */
+
+struct dns_rr_srv {
+ const char *hostname;
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ size_t num_ips;
+ struct sockaddr_storage *ss_s; /* support multi-homed hosts */
+};
+
+/* NS records */
+
+struct dns_rr_ns {
+ const char *hostname;
+ struct sockaddr_storage ss;
+};
+
+#endif
diff --git a/libcli/dns/dns_lookup.c b/libcli/dns/dns_lookup.c
new file mode 100644
index 0000000..646d0a8
--- /dev/null
+++ b/libcli/dns/dns_lookup.c
@@ -0,0 +1,374 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 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 "replace.h"
+#include "libcli/dns/dns_lookup.h"
+#include "libcli/dns/resolvconf.h"
+#include "libcli/dns/libdns.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/debug.h"
+
+struct dns_lookup_state {
+ struct tevent_context *ev;
+ const char *name;
+ enum dns_qclass qclass;
+ enum dns_qtype qtype;
+
+ char **nameservers;
+ size_t num_nameservers;
+ size_t num_sent;
+
+ struct tevent_req **dns_subreqs;
+ struct tevent_req *wait_subreq;
+
+ struct dns_name_packet *reply;
+};
+
+static int dns_lookup_send_next(struct tevent_req *req);
+
+static void dns_lookup_done(struct tevent_req *subreq);
+static void dns_lookup_waited(struct tevent_req *subreq);
+
+struct tevent_req *dns_lookup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ FILE *resolv_conf_fp,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype)
+{
+ struct tevent_req *req;
+ struct dns_lookup_state *state;
+ FILE *fp = resolv_conf_fp;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct dns_lookup_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->name = name;
+ state->qclass = qclass;
+ state->qtype = qtype;
+
+ if (resolv_conf_fp == NULL) {
+ const char *resolvconf = "/etc/resolv.conf";
+
+#ifdef ENABLE_SELFTEST
+ {
+ const char *envvar = getenv("RESOLV_CONF");
+ if (envvar != NULL) {
+ resolvconf = envvar;
+ }
+ }
+#endif
+
+ fp = fopen(resolvconf, "r");
+ if (fp == NULL) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ ret = parse_resolvconf_fp(
+ fp,
+ state,
+ &state->nameservers,
+ &state->num_nameservers);
+
+ if (resolv_conf_fp == NULL) {
+ fclose(fp);
+ }
+
+ if (ret != 0) {
+ tevent_req_error(req, ret);
+ return tevent_req_post(req, ev);
+ }
+
+ if (state->num_nameservers == 0) {
+ /*
+ * glibc's getaddrinfo returns EAI_AGAIN when no
+ * nameservers are configured. EAGAIN seems closest.
+ */
+ tevent_req_error(req, EAGAIN);
+ return tevent_req_post(req, ev);
+ }
+
+ state->dns_subreqs = talloc_zero_array(
+ state,
+ struct tevent_req *,
+ state->num_nameservers);
+
+ if (tevent_req_nomem(state->dns_subreqs, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ret = dns_lookup_send_next(req);
+ if (tevent_req_error(req, ret)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static int dns_lookup_send_next(struct tevent_req *req)
+{
+ struct dns_lookup_state *state = tevent_req_data(
+ req, struct dns_lookup_state);
+
+ DBG_DEBUG("Sending DNS request #%zu to %s\n",
+ state->num_sent,
+ state->nameservers[state->num_sent]);
+
+ state->dns_subreqs[state->num_sent] = dns_cli_request_send(
+ state->dns_subreqs,
+ state->ev,
+ state->nameservers[state->num_sent],
+ state->name,
+ state->qclass,
+ state->qtype);
+
+ if (state->dns_subreqs[state->num_sent] == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(state->dns_subreqs[state->num_sent],
+ dns_lookup_done,
+ req);
+ state->num_sent += 1;
+
+ if (state->num_sent == state->num_nameservers) {
+ /*
+ * No more nameservers left
+ */
+ DBG_DEBUG("cancelling wait_subreq\n");
+ TALLOC_FREE(state->wait_subreq);
+ return 0;
+ }
+
+ if (state->wait_subreq != NULL) {
+ /*
+ * This can happen if we fire the next request upon
+ * dns_cli_request returning a network-level error
+ */
+ return 0;
+ }
+
+ state->wait_subreq = tevent_wakeup_send(
+ state,
+ state->ev,
+ tevent_timeval_current_ofs(1, 0));
+ if (state->wait_subreq == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(state->wait_subreq, dns_lookup_waited, req);
+
+ return 0;
+}
+
+static void dns_lookup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_lookup_state *state = tevent_req_data(
+ req, struct dns_lookup_state);
+ int dns_cli_request_ret;
+ size_t i;
+
+ dns_cli_request_ret = dns_cli_request_recv(
+ subreq,
+ state,
+ &state->reply);
+
+ for (i = 0; i < state->num_nameservers; i++) {
+ if (state->dns_subreqs[i] == subreq) {
+ break;
+ }
+ }
+
+ TALLOC_FREE(subreq);
+
+ if (i == state->num_nameservers) {
+ /* should never happen */
+ DBG_WARNING("Failed to find subreq\n");
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+ state->dns_subreqs[i] = NULL;
+
+ if (dns_cli_request_ret == 0) {
+ /*
+ * Success, cancel everything else
+ */
+ TALLOC_FREE(state->dns_subreqs);
+ TALLOC_FREE(state->wait_subreq);
+ tevent_req_done(req);
+ return;
+ }
+
+ DBG_DEBUG("dns_cli_request[%zu] returned %s\n", i,
+ strerror(dns_cli_request_ret));
+
+ if (state->num_sent < state->num_nameservers) {
+ /*
+ * We have a nameserver left to try
+ */
+ int ret;
+
+ ret = dns_lookup_send_next(req);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+ }
+
+ DBG_DEBUG("looking for outstanding requests\n");
+
+ for (i = 0; i<state->num_nameservers; i++) {
+ if (state->dns_subreqs[i] != NULL) {
+ break;
+ }
+ }
+
+ DBG_DEBUG("i=%zu, num_nameservers=%zu\n",
+ i, state->num_nameservers);
+
+ if (i == state->num_nameservers) {
+ /*
+ * Report the lower-level error if we have nothing
+ * outstanding anymore
+ */
+ tevent_req_error(req, dns_cli_request_ret);
+ return;
+ }
+
+ /*
+ * Do nothing: We have other nameservers that might come back
+ * with something good.
+ */
+}
+
+static void dns_lookup_waited(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct dns_lookup_state *state = tevent_req_data(
+ req, struct dns_lookup_state);
+ int ret;
+ bool ok;
+
+ DBG_DEBUG("waited\n");
+
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ tevent_req_oom(req);
+ return;
+ }
+ state->wait_subreq = NULL;
+
+ ret = dns_lookup_send_next(req);
+ if (tevent_req_error(req, ret)) {
+ return;
+ }
+
+ /*
+ * dns_lookup_send_next() has already triggered the next wakeup
+ */
+}
+
+int dns_lookup_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply)
+{
+ struct dns_lookup_state *state = tevent_req_data(
+ req, struct dns_lookup_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ return err;
+ }
+
+ *reply = talloc_move(mem_ctx, &state->reply);
+
+ tevent_req_received(req);
+ return 0;
+}
+
+int dns_lookup(FILE *resolv_conf_fp,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype,
+ TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply)
+{
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ int ret = ENOMEM;
+
+ ev = samba_tevent_context_init(mem_ctx);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = dns_lookup_send(ev, ev, resolv_conf_fp, name, qclass, qtype);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_unix(req, ev, &ret)) {
+ goto fail;
+ }
+ ret = dns_lookup_recv(req, mem_ctx, reply);
+fail:
+ TALLOC_FREE(ev);
+ return ret;
+}
+
+bool dns_res_rec_get_sockaddr(const struct dns_res_rec *rec,
+ struct sockaddr_storage *addr)
+{
+ sa_family_t family;
+ const char *src;
+ void *dst;
+ int ret;
+
+ switch (rec->rr_type) {
+ case DNS_QTYPE_A:
+ family = AF_INET;
+ src = rec->rdata.ipv4_record;
+ dst = &(((struct sockaddr_in *)addr)->sin_addr);
+ break;
+#ifdef HAVE_IPV6
+ case DNS_QTYPE_AAAA:
+ family = AF_INET6;
+ src = rec->rdata.ipv6_record;
+ dst = &(((struct sockaddr_in6 *)addr)->sin6_addr);
+ break;
+#endif
+ default:
+ /* We only care about IP addresses */
+ return false;
+ }
+
+ *addr = (struct sockaddr_storage) { .ss_family = family };
+
+ ret = inet_pton(family, src, dst);
+ if (ret != 1) {
+ DBG_DEBUG("inet_pton(%s) failed\n", src);
+ return false;
+ }
+
+ return true;
+}
diff --git a/libcli/dns/dns_lookup.h b/libcli/dns/dns_lookup.h
new file mode 100644
index 0000000..0c05e04
--- /dev/null
+++ b/libcli/dns/dns_lookup.h
@@ -0,0 +1,48 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 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 __LIBCLI_DNS_DNS_LOOKUP_H__
+#define __LIBCLI_DNS_DNS_LOOKUP_H__
+
+#include "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "librpc/gen_ndr/dns.h"
+
+struct tevent_req *dns_lookup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ FILE *resolv_conf_fp,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype);
+int dns_lookup_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply);
+int dns_lookup(FILE *resolv_conf_fp,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype,
+ TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply);
+
+bool dns_res_rec_get_sockaddr(const struct dns_res_rec *rec,
+ struct sockaddr_storage *addr);
+
+#endif
diff --git a/libcli/dns/dns_lookuptest.c b/libcli/dns/dns_lookuptest.c
new file mode 100644
index 0000000..c8e0343
--- /dev/null
+++ b/libcli/dns/dns_lookuptest.c
@@ -0,0 +1,55 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 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 <stdio.h>
+#include <string.h>
+#include <talloc.h>
+#include <errno.h>
+#include "libcli/dns/dns_lookup.h"
+#include "lib/util/debug.h"
+
+static int dns_lookuptest1(void)
+{
+ struct dns_name_packet *reply = NULL;
+ int ret;
+
+ ret = dns_lookup(NULL, "www.samba.org", DNS_QCLASS_IN, DNS_QTYPE_A,
+ NULL, &reply);
+ if (ret != 0) {
+ fprintf(stderr, "dns_lookup failed: %s\n", strerror(ret));
+ return ret;
+ }
+
+ TALLOC_FREE(reply);
+ return 0;
+}
+
+int main(int argc, const char *argv[]) {
+ int ret;
+
+ setup_logging(argv[0], DEBUG_DEFAULT_STDERR);
+ debug_parse_levels("10");
+
+ ret = dns_lookuptest1();
+ if (ret != 0) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libcli/dns/libdns.h b/libcli/dns/libdns.h
new file mode 100644
index 0000000..15ca257
--- /dev/null
+++ b/libcli/dns/libdns.h
@@ -0,0 +1,43 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Small async DNS library for Samba with socketwrapper support
+
+ Copyright (C) 2012 Kai Blin <kai@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 __LIBDNS_H__
+#define __LIBDNS_H__
+
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "librpc/gen_ndr/dns.h"
+
+/*
+ * DNS request with fallback to TCP on truncation
+ */
+
+struct tevent_req *dns_cli_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *nameserver,
+ const char *name,
+ enum dns_qclass qclass,
+ enum dns_qtype qtype);
+int dns_cli_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct dns_name_packet **reply);
+
+
+#endif /*__LIBDNS_H__*/
diff --git a/libcli/dns/resolvconf.c b/libcli/dns/resolvconf.c
new file mode 100644
index 0000000..5cf8b4e
--- /dev/null
+++ b/libcli/dns/resolvconf.c
@@ -0,0 +1,123 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 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 "replace.h"
+#include <stdio.h>
+#include <errno.h>
+#include "libcli/dns/resolvconf.h"
+#include "lib/util/memory.h"
+
+int parse_resolvconf_fp(
+ FILE *fp,
+ TALLOC_CTX *mem_ctx,
+ char ***pnameservers,
+ size_t *pnum_nameservers)
+{
+ char *line = NULL;
+ size_t len = 0;
+ char **nameservers = NULL;
+ size_t num_nameservers = 0;
+ int ret = 0;
+
+ while (true) {
+ char *saveptr = NULL, *option = NULL, *ns = NULL;
+ char **tmp = NULL;
+ ssize_t n = 0;
+
+ n = getline(&line, &len, fp);
+ if (n < 0) {
+ if (!feof(fp)) {
+ /* real error */
+ ret = errno;
+ }
+ break;
+ }
+ if ((n > 0) && (line[n-1] == '\n')) {
+ line[n-1] = '\0';
+ }
+
+ if ((line[0] == '#') || (line[0] == ';')) {
+ continue;
+ }
+
+ option = strtok_r(line, " \t", &saveptr);
+ if (option == NULL) {
+ continue;
+ }
+
+ if (strcmp(option, "nameserver") != 0) {
+ continue;
+ }
+
+ ns = strtok_r(NULL, " \t", &saveptr);
+ if (ns == NULL) {
+ continue;
+ }
+
+ tmp = talloc_realloc(
+ mem_ctx,
+ nameservers,
+ char *,
+ num_nameservers+1);
+ if (tmp == NULL) {
+ ret = ENOMEM;
+ break;
+ }
+ nameservers = tmp;
+
+ nameservers[num_nameservers] = talloc_strdup(nameservers, ns);
+ if (nameservers[num_nameservers] == NULL) {
+ ret = ENOMEM;
+ break;
+ }
+ num_nameservers += 1;
+ }
+
+ SAFE_FREE(line);
+
+ if (ret == 0) {
+ *pnameservers = nameservers;
+ *pnum_nameservers = num_nameservers;
+ } else {
+ TALLOC_FREE(nameservers);
+ }
+
+ return ret;
+}
+
+int parse_resolvconf(
+ const char *resolvconf,
+ TALLOC_CTX *mem_ctx,
+ char ***pnameservers,
+ size_t *pnum_nameservers)
+{
+ FILE *fp;
+ int ret;
+
+ fp = fopen(resolvconf ? resolvconf : "/etc/resolv.conf", "r");
+ if (fp == NULL) {
+ return errno;
+ }
+
+ ret = parse_resolvconf_fp(fp, mem_ctx, pnameservers, pnum_nameservers);
+
+ fclose(fp);
+
+ return ret;
+}
diff --git a/libcli/dns/resolvconf.h b/libcli/dns/resolvconf.h
new file mode 100644
index 0000000..3ea258c
--- /dev/null
+++ b/libcli/dns/resolvconf.h
@@ -0,0 +1,37 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 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 __LIBCLI_DNS_RESOLVCONF_H__
+#define __LIBCLI_DNS_RESOLVCONF_H__
+
+#include <talloc.h>
+#include <stdio.h>
+
+int parse_resolvconf_fp(
+ FILE *fp,
+ TALLOC_CTX *mem_ctx,
+ char ***pnameservers,
+ size_t *pnum_nameservers);
+int parse_resolvconf(
+ const char *resolvconf,
+ TALLOC_CTX *mem_ctx,
+ char ***pnameservers,
+ size_t *pnum_nameservers);
+
+#endif
diff --git a/libcli/dns/resolvconftest.c b/libcli/dns/resolvconftest.c
new file mode 100644
index 0000000..6395264
--- /dev/null
+++ b/libcli/dns/resolvconftest.c
@@ -0,0 +1,82 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Internal DNS query structures
+ * Copyright (C) Volker Lendecke 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 <stdio.h>
+#include <string.h>
+#include <talloc.h>
+#include <errno.h>
+#include "libcli/dns/resolvconf.h"
+#include "lib/util/memory.h"
+
+static int resolvconftest1(void)
+{
+ const char *content =
+ "#foo\nbar\nnameserver 1.2.3.4\nnameserver 2.3.4.5";
+ char *file;
+ FILE *fp;
+ int ret;
+ char **nameservers;
+ size_t num_nameservers;
+
+ file = strdup(content);
+ if (file == NULL) {
+ perror("strdup failed");
+ return ENOMEM;
+ }
+ fp = fmemopen(file, strlen(file), "r");
+ if (fp == NULL) {
+ perror("fmemopen failed");
+ return errno;
+ }
+
+ ret = parse_resolvconf_fp(fp, NULL, &nameservers, &num_nameservers);
+ if (ret != 0) {
+ fprintf(stderr, "parse_resolvconf_fp failed: %s\n",
+ strerror(ret));
+ return ret;
+ }
+
+ if (num_nameservers != 2) {
+ fprintf(stderr, "expected 2 nameservers, got %zu\n",
+ num_nameservers);
+ return EIO;
+ }
+ if ((strcmp(nameservers[0], "1.2.3.4") != 0) ||
+ (strcmp(nameservers[1], "2.3.4.5") != 0)) {
+ fprintf(stderr, "got wrong nameservers\n");
+ return EIO;
+ }
+
+ TALLOC_FREE(nameservers);
+ fclose(fp);
+ SAFE_FREE(file);
+
+ return 0;
+}
+
+int main(void) {
+ int ret;
+
+ ret = resolvconftest1();
+ if (ret != 0) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libcli/dns/wscript_build b/libcli/dns/wscript_build
new file mode 100644
index 0000000..2d90aa7
--- /dev/null
+++ b/libcli/dns/wscript_build
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('clidns',
+ source='dns.c resolvconf.c',
+ public_deps='LIBTSOCKET tevent-util ndr-standard',
+ private_library=True)
+
+bld.SAMBA_BINARY('resolvconftest',
+ source='resolvconftest.c',
+ deps='clidns',
+ enabled=bld.CONFIG_SET('HAVE_FMEMOPEN'),
+ for_selftest=True)
+
+bld.SAMBA_SUBSYSTEM('dns_lookup',
+ source='dns_lookup.c',
+ public_deps='clidns')
+
+bld.SAMBA_BINARY('dns_lookuptest',
+ source='dns_lookuptest.c',
+ deps='dns_lookup',
+ for_selftest=True)
diff --git a/libcli/drsuapi/drsuapi.h b/libcli/drsuapi/drsuapi.h
new file mode 100644
index 0000000..3e1e5ce
--- /dev/null
+++ b/libcli/drsuapi/drsuapi.h
@@ -0,0 +1,32 @@
+/*
+ Unix SMB/CIFS implementation.
+ Helper functions for applying replicated objects
+
+ Copyright (C) Stefan Metzmacher <metze@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/>.
+
+*/
+
+WERROR drsuapi_decrypt_attribute(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ uint32_t rid,
+ uint32_t dsdb_repl_flags,
+ struct drsuapi_DsReplicaAttribute *attr);
+
+
+WERROR drsuapi_encrypt_attribute(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ uint32_t rid,
+ struct drsuapi_DsReplicaAttribute *attr);
diff --git a/libcli/drsuapi/repl_decrypt.c b/libcli/drsuapi/repl_decrypt.c
new file mode 100644
index 0000000..d289246
--- /dev/null
+++ b/libcli/drsuapi/repl_decrypt.c
@@ -0,0 +1,391 @@
+/*
+ Unix SMB/CIFS implementation.
+ Helper functions for applying replicated objects
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+ 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 "../lib/util/dlinklist.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "zlib.h"
+#include "../libcli/drsuapi/drsuapi.h"
+#include "libcli/auth/libcli_auth.h"
+#include "dsdb/samdb/samdb.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+static WERROR drsuapi_decrypt_attribute_value(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ bool rid_crypt,
+ uint32_t rid,
+ const DATA_BLOB *in,
+ DATA_BLOB *out)
+{
+ DATA_BLOB confounder;
+ DATA_BLOB enc_buffer;
+
+ DATA_BLOB dec_buffer;
+
+ uint32_t crc32_given;
+ uint32_t crc32_calc;
+ DATA_BLOB checked_buffer;
+
+ DATA_BLOB plain_buffer;
+ WERROR result;
+ int rc;
+
+ /*
+ * users with rid == 0 should not exist
+ */
+ if (rid_crypt && rid == 0) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ /*
+ * the first 16 bytes at the beginning are the confounder
+ * followed by the 4 byte crc32 checksum
+ */
+ if (in->length < 20) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+ confounder = data_blob_const(in->data, 16);
+ enc_buffer = data_blob_const(in->data + 16, in->length - 16);
+
+ /*
+ * decrypt with the encryption key, being md5 over the session
+ * key followed by the confounder. The parameter order to
+ * samba_gnutls_arcfour_confounded_md5() matters for this!
+ *
+ * here the gensec session key is used and
+ * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
+ */
+
+ /*
+ * reference the encrypted buffer part and
+ * decrypt it using the created encryption key using arcfour
+ */
+ dec_buffer = data_blob_const(enc_buffer.data, enc_buffer.length);
+
+ rc = samba_gnutls_arcfour_confounded_md5(gensec_skey,
+ &confounder,
+ &dec_buffer,
+ SAMBA_GNUTLS_DECRYPT);
+ if (rc < 0) {
+ result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
+ goto out;
+ }
+
+ /*
+ * the first 4 byte are the crc32 checksum
+ * of the remaining bytes
+ */
+ crc32_given = IVAL(dec_buffer.data, 0);
+ crc32_calc = crc32(0, Z_NULL, 0);
+ crc32_calc = crc32(crc32_calc,
+ dec_buffer.data + 4 ,
+ dec_buffer.length - 4);
+ checked_buffer = data_blob_const(dec_buffer.data + 4, dec_buffer.length - 4);
+
+ plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length);
+ W_ERROR_HAVE_NO_MEMORY(plain_buffer.data);
+
+ if (crc32_given != crc32_calc) {
+ result = W_ERROR(HRES_ERROR_V(HRES_SEC_E_DECRYPT_FAILURE));
+ goto out;
+ }
+ /*
+ * The following rid_crypt obfuscation isn't session specific
+ * and not really needed here, because we always know the rid of the
+ * user account.
+ *
+ * some attributes with this 'additional encryption' include
+ * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
+ *
+ * But for the rest of samba it's easier when we remove this static
+ * obfuscation here
+ */
+ if (rid_crypt) {
+ uint32_t i, num_hashes;
+
+ if ((checked_buffer.length % 16) != 0) {
+ result = WERR_DS_DRA_INVALID_PARAMETER;
+ goto out;
+ }
+
+ num_hashes = plain_buffer.length / 16;
+ for (i = 0; i < num_hashes; i++) {
+ uint32_t offset = i * 16;
+ rc = sam_rid_crypt(rid, checked_buffer.data + offset,
+ plain_buffer.data + offset,
+ SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
+ goto out;
+ }
+ }
+ }
+
+ *out = plain_buffer;
+ result = WERR_OK;
+out:
+ return result;
+}
+
+WERROR drsuapi_decrypt_attribute(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ uint32_t rid,
+ uint32_t dsdb_repl_flags,
+ struct drsuapi_DsReplicaAttribute *attr)
+{
+ WERROR status;
+ DATA_BLOB *enc_data;
+ DATA_BLOB plain_data;
+ bool rid_crypt = false;
+
+ if (attr->value_ctr.num_values == 0) {
+ return WERR_OK;
+ }
+
+ switch (attr->attid) {
+ case DRSUAPI_ATTID_dBCSPwd:
+ case DRSUAPI_ATTID_unicodePwd:
+ case DRSUAPI_ATTID_ntPwdHistory:
+ case DRSUAPI_ATTID_lmPwdHistory:
+ rid_crypt = true;
+ break;
+ case DRSUAPI_ATTID_supplementalCredentials:
+ case DRSUAPI_ATTID_priorValue:
+ case DRSUAPI_ATTID_currentValue:
+ case DRSUAPI_ATTID_trustAuthOutgoing:
+ case DRSUAPI_ATTID_trustAuthIncoming:
+ case DRSUAPI_ATTID_initialAuthOutgoing:
+ case DRSUAPI_ATTID_initialAuthIncoming:
+ break;
+ default:
+ return WERR_OK;
+ }
+
+ if (dsdb_repl_flags & DSDB_REPL_FLAG_EXPECT_NO_SECRETS) {
+ return WERR_TOO_MANY_SECRETS;
+ }
+
+ if (attr->value_ctr.num_values > 1) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ if (!attr->value_ctr.values[0].blob) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ enc_data = attr->value_ctr.values[0].blob;
+
+ status = drsuapi_decrypt_attribute_value(mem_ctx,
+ gensec_skey,
+ rid_crypt,
+ rid,
+ enc_data,
+ &plain_data);
+ W_ERROR_NOT_OK_RETURN(status);
+
+ talloc_free(attr->value_ctr.values[0].blob->data);
+ *attr->value_ctr.values[0].blob = plain_data;
+
+ return WERR_OK;
+}
+
+static WERROR drsuapi_encrypt_attribute_value(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ bool rid_crypt,
+ uint32_t rid,
+ const DATA_BLOB *in,
+ DATA_BLOB *out)
+{
+ DATA_BLOB rid_crypt_out = data_blob(NULL, 0);
+ DATA_BLOB confounder;
+
+ DATA_BLOB enc_buffer;
+
+ DATA_BLOB to_encrypt;
+
+ uint32_t crc32_calc;
+ WERROR result;
+ int rc;
+
+ /*
+ * users with rid == 0 should not exist
+ */
+ if (rid_crypt && rid == 0) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ /*
+ * The following rid_crypt obfuscation isn't session specific
+ * and not really needed here, because we always know the rid of the
+ * user account.
+ *
+ * some attributes with this 'additional encryption' include
+ * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
+ *
+ * But for the rest of samba it's easier when we remove this static
+ * obfuscation here
+ */
+ if (rid_crypt) {
+ uint32_t i, num_hashes;
+ rid_crypt_out = data_blob_talloc(mem_ctx, in->data, in->length);
+ W_ERROR_HAVE_NO_MEMORY(rid_crypt_out.data);
+
+ if ((rid_crypt_out.length % 16) != 0) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ num_hashes = rid_crypt_out.length / 16;
+ for (i = 0; i < num_hashes; i++) {
+ uint32_t offset = i * 16;
+ rc = sam_rid_crypt(rid, in->data + offset,
+ rid_crypt_out.data + offset,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc != 0) {
+ result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
+ goto out;
+ }
+ }
+ in = &rid_crypt_out;
+ }
+
+ /*
+ * the first 16 bytes at the beginning are the confounder
+ * followed by the 4 byte crc32 checksum
+ */
+
+ enc_buffer = data_blob_talloc(mem_ctx, NULL, in->length+20);
+ if (!enc_buffer.data) {
+ talloc_free(rid_crypt_out.data);
+ return WERR_NOT_ENOUGH_MEMORY;
+ };
+
+ confounder = data_blob_const(enc_buffer.data, 16);
+ generate_random_buffer(confounder.data, confounder.length);
+
+ /*
+ * the first 4 byte are the crc32 checksum
+ * of the remaining bytes
+ */
+ crc32_calc = crc32(0, Z_NULL, 0);
+ crc32_calc = crc32(crc32_calc, in->data, in->length);
+ SIVAL(enc_buffer.data, 16, crc32_calc);
+
+ /*
+ * copy the plain buffer part and
+ * encrypt it using the created encryption key using arcfour
+ */
+ memcpy(enc_buffer.data+20, in->data, in->length);
+ talloc_free(rid_crypt_out.data);
+
+ to_encrypt = data_blob_const(enc_buffer.data+16,
+ enc_buffer.length-16);
+
+ /*
+ * encrypt with the encryption key, being md5 over the session
+ * key followed by the confounder. The parameter order to
+ * samba_gnutls_arcfour_confounded_md5() matters for this!
+ *
+ * here the gensec session key is used and
+ * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
+ */
+
+ rc = samba_gnutls_arcfour_confounded_md5(gensec_skey,
+ &confounder,
+ &to_encrypt,
+ SAMBA_GNUTLS_ENCRYPT);
+ if (rc < 0) {
+ result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
+ goto out;
+ }
+
+ *out = enc_buffer;
+ result = WERR_OK;
+out:
+ return result;
+}
+
+/*
+ encrypt a DRSUAPI attribute ready for sending over the wire
+ Only some attribute types are encrypted
+ */
+WERROR drsuapi_encrypt_attribute(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *gensec_skey,
+ uint32_t rid,
+ struct drsuapi_DsReplicaAttribute *attr)
+{
+ WERROR status;
+ DATA_BLOB *plain_data;
+ DATA_BLOB enc_data;
+ bool rid_crypt = false;
+
+ if (attr->value_ctr.num_values == 0) {
+ return WERR_OK;
+ }
+
+ switch (attr->attid) {
+ case DRSUAPI_ATTID_dBCSPwd:
+ case DRSUAPI_ATTID_unicodePwd:
+ case DRSUAPI_ATTID_ntPwdHistory:
+ case DRSUAPI_ATTID_lmPwdHistory:
+ rid_crypt = true;
+ break;
+ case DRSUAPI_ATTID_supplementalCredentials:
+ case DRSUAPI_ATTID_priorValue:
+ case DRSUAPI_ATTID_currentValue:
+ case DRSUAPI_ATTID_trustAuthOutgoing:
+ case DRSUAPI_ATTID_trustAuthIncoming:
+ case DRSUAPI_ATTID_initialAuthOutgoing:
+ case DRSUAPI_ATTID_initialAuthIncoming:
+ break;
+ default:
+ return WERR_OK;
+ }
+
+ if (attr->value_ctr.num_values > 1) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ if (!attr->value_ctr.values[0].blob) {
+ return WERR_DS_DRA_INVALID_PARAMETER;
+ }
+
+ plain_data = attr->value_ctr.values[0].blob;
+
+ status = drsuapi_encrypt_attribute_value(mem_ctx,
+ gensec_skey,
+ rid_crypt,
+ rid,
+ plain_data,
+ &enc_data);
+ W_ERROR_NOT_OK_RETURN(status);
+
+ talloc_free(attr->value_ctr.values[0].blob->data);
+ *attr->value_ctr.values[0].blob = enc_data;
+
+ return WERR_OK;
+}
+
diff --git a/libcli/drsuapi/tests/test_repl_decrypt.c b/libcli/drsuapi/tests/test_repl_decrypt.c
new file mode 100644
index 0000000..996c6e6
--- /dev/null
+++ b/libcli/drsuapi/tests/test_repl_decrypt.c
@@ -0,0 +1,522 @@
+/*
+ * Unit tests for source4/rpc_server/dnsserver/dnsutils.c
+ *
+ * Copyright (C) Catalyst.NET Ltd 2018
+ * 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/>.
+ *
+ */
+
+/*
+ * 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 <setjmp.h>
+#include <cmocka.h>
+
+
+#include "../repl_decrypt.c"
+
+
+/*
+ * test encryption and decryption including RID obfustincation
+ */
+static void test_drsuapi_rid_encrypt_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04 };
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ DATA_BLOB encrypted;
+ DATA_BLOB decrypted = data_blob_null;
+
+ werr = drsuapi_encrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &plaintext,
+ &encrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+ assert_int_not_equal(encrypted.length, plaintext.length);
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+
+ assert_int_equal(decrypted.length, plaintext.length);
+
+ assert_memory_equal(decrypted.data, plaintext.data, plaintext.length);
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test encryption and decryption failing RID obfustincation (data length)
+ */
+static void test_drsuapi_bad_len_rid_encrypt_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ DATA_BLOB encrypted;
+
+ werr = drsuapi_encrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &plaintext,
+ &encrypted);
+
+ assert_int_equal(W_ERROR_V(werr),
+ W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test encryption and decryption failing RID obfustincation (zero rid)
+ */
+static void test_drsuapi_zero_rid_encrypt_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04 };
+ const uint32_t rid = 0;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ DATA_BLOB encrypted;
+
+ werr = drsuapi_encrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &plaintext,
+ &encrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test encryption and decryption without RID obfustication
+ */
+static void test_drsuapi_encrypt_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ /* Ensures we can cope with odd lengths */
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ DATA_BLOB encrypted;
+ DATA_BLOB decrypted = data_blob_null;
+
+ werr = drsuapi_encrypt_attribute_value(mem_ctx,
+ &key_blob,
+ false,
+ 0,
+ &plaintext,
+ &encrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+ assert_int_not_equal(encrypted.length, plaintext.length);
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ false,
+ 0,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+
+ assert_int_equal(decrypted.length, plaintext.length);
+
+ assert_memory_equal(decrypted.data, plaintext.data, plaintext.length);
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer
+ */
+static void test_drsuapi_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ /* Ensures we can cope with odd lengths */
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+ uint8_t encrypted_test_data[] = { 0xFF, 0x5C, 0x58, 0x3F,
+ 0xD4, 0x41, 0xCA, 0xB0,
+ 0x14, 0xFE, 0xFB, 0xA6,
+ 0xB0, 0x32, 0x45, 0x45,
+ 0x9D, 0x76, 0x75, 0xD2,
+ 0xFB, 0x34, 0x77, 0xBD,
+ 0x8C, 0x1E, 0x09, 0x1A,
+ 0xF1, 0xAB, 0xD3, 0x0E,
+ 0xBE, 0x80, 0xAB, 0x19, 0xFC };
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted = data_blob_null;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ false,
+ 0,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+
+ assert_int_equal(decrypted.length, plaintext.length);
+
+ assert_memory_equal(decrypted.data, plaintext.data, plaintext.length);
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer (rid decrypt)
+ */
+static void test_drsuapi_rid_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ /* Ensures we can cope with odd lengths */
+ uint8_t test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04 };
+
+ uint8_t encrypted_test_data[] = {0x95, 0xB2, 0xE8, 0x02,
+ 0x05, 0x5E, 0xFD, 0x3D,
+ 0x7D, 0x17, 0xB9, 0x76,
+ 0x4D, 0x91, 0xED, 0x59,
+ 0x98, 0x79, 0x7A, 0xFC,
+ 0x38, 0x73, 0x28, 0x55,
+ 0x62, 0x27, 0x99, 0x3B,
+ 0xD0, 0x18, 0xBD, 0x23,
+ 0x5D, 0x98, 0xFE, 0xA8};
+
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB plaintext = data_blob_const(test_data,
+ sizeof(test_data));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted = data_blob_null;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_OK));
+
+ assert_int_equal(decrypted.length, plaintext.length);
+
+ assert_memory_equal(decrypted.data, plaintext.data, plaintext.length);
+
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer (rid decrypt)
+ */
+static void test_drsuapi_bad_len_rid_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t encrypted_test_data[] = { 0xFF, 0x5C, 0x58, 0x3F,
+ 0xD4, 0x41, 0xCA, 0xB0,
+ 0x14, 0xFE, 0xFB, 0xA6,
+ 0xB0, 0x32, 0x45, 0x45,
+ 0x9D, 0x76, 0x75, 0xD2,
+ 0xFB, 0x34, 0x77, 0xBD,
+ 0x8C, 0x1E, 0x09, 0x1A,
+ 0xF1, 0xAB, 0xD3, 0x0E,
+ 0xBE, 0x80, 0xAB, 0x19, 0xFC };
+
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer (rid decrypt)
+ */
+static void test_drsuapi_zero_rid_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t encrypted_test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+ const uint32_t rid = 0;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of fixed buffer (bad crc)
+ */
+static void test_drsuapi_bad_crc_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t encrypted_test_data[] = { 0xFF, 0x5C, 0x58, 0x3F,
+ 0xD4, 0x41, 0xCA, 0xB0,
+ 0x14, 0xFE, 0xFB, 0xA6,
+ 0xB0, 0x32, 0x45, 0x45,
+ 0x9D, 0x76, 0x75, 0xD2,
+ 0xFB, 0x34, 0x77, 0xBD,
+ 0x8C, 0x1E, 0x09, 0x1A,
+ 0xF1, 0xAB, 0xD3, 0x0E,
+ 0xBE, 0x80, 0xAB, 0x19, 0xFF };
+
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), HRES_ERROR_V(HRES_SEC_E_DECRYPT_FAILURE));
+
+ TALLOC_FREE(mem_ctx);
+}
+
+/*
+ * test decryption of short buffer
+ */
+static void test_drsuapi_short_decrypt_attribute_value(void **state)
+{
+ uint8_t key[] = { 0xa1, 0xb2, 0xc3, 0xd4,
+ 0xe1, 0xf2, 0x03, 0x14,
+ 0x21, 0x32, 0x43, 0x54,
+ 0x61, 0x72, 0x83, 0x94 };
+
+ uint8_t encrypted_test_data[] = { 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04,
+ 0x01, 0x02, 0x03, 0x04, 0x05 };
+ const uint32_t rid = 514;
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ WERROR werr;
+
+ const DATA_BLOB key_blob = data_blob_const(key, sizeof(key));
+ const DATA_BLOB encrypted
+ = data_blob_const(encrypted_test_data,
+ sizeof(encrypted_test_data));
+ DATA_BLOB decrypted;
+
+ werr = drsuapi_decrypt_attribute_value(mem_ctx,
+ &key_blob,
+ true,
+ rid,
+ &encrypted,
+ &decrypted);
+
+ assert_int_equal(W_ERROR_V(werr), W_ERROR_V(WERR_DS_DRA_INVALID_PARAMETER));
+
+ TALLOC_FREE(mem_ctx);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(
+ test_drsuapi_rid_encrypt_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_bad_len_rid_encrypt_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_zero_rid_encrypt_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_encrypt_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_bad_crc_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_rid_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_zero_rid_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_bad_len_rid_decrypt_attribute_value),
+ cmocka_unit_test(
+ test_drsuapi_short_decrypt_attribute_value),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/drsuapi/wscript_build b/libcli/drsuapi/wscript_build
new file mode 100644
index 0000000..1aee095
--- /dev/null
+++ b/libcli/drsuapi/wscript_build
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_DRSUAPI',
+ source='repl_decrypt.c',
+ public_deps='LIBCLI_AUTH samdb z'
+ )
+
+bld.SAMBA_BINARY(
+ 'test_repl_decrypt',
+ source='tests/test_repl_decrypt.c',
+ deps='''
+ LIBCLI_DRSUAPI
+ cmocka
+ talloc
+ ''',
+ for_selftest=True,
+ enabled=bld.AD_DC_BUILD_IS_ENABLED()
+)
diff --git a/libcli/echo/echo.c b/libcli/echo/echo.c
new file mode 100644
index 0000000..0f5f7f7
--- /dev/null
+++ b/libcli/echo/echo.c
@@ -0,0 +1,209 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Echo example async client library
+
+ Copyright (C) 2010 Kai Blin <kai@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 "system/network.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "libcli/util/ntstatus.h"
+#include "libcli/echo/libecho.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "libcli/util/error.h"
+
+/*
+ * Following the Samba convention for async functions, set up a state struct
+ * for this set of calls. The state is always called function_name_state for
+ * the set of async functions related to function_name_send().
+ */
+struct echo_request_state {
+ struct tevent_context *ev;
+ ssize_t orig_len;
+ struct tdgram_context *dgram;
+ char *message;
+};
+
+/* Declare callback functions used below. */
+static void echo_request_get_reply(struct tevent_req *subreq);
+static void echo_request_done(struct tevent_req *subreq);
+
+struct tevent_req *echo_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *server_addr_string,
+ const char *message)
+{
+ struct tevent_req *req, *subreq;
+ struct echo_request_state *state;
+ struct tsocket_address *local_addr, *server_addr;
+ struct tdgram_context *dgram;
+ int ret;
+
+ /*
+ * Creating the initial tevent_req is the only place where returning
+ * NULL is allowed. Everything after that should return a more
+ * meaningful error using tevent_req_post().
+ */
+ req = tevent_req_create(mem_ctx, &state, struct echo_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ /*
+ * We need to dispatch new async functions in the callbacks, hold
+ * on to the event context.
+ */
+ state->ev = ev;
+
+ /* libecho uses connected UDP sockets, take care of this here */
+ ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
+ &local_addr);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
+ ECHO_PORT, &server_addr);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
+ if (ret != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(ret));
+ return tevent_req_post(req, ev);
+ }
+
+ state->dgram = dgram;
+ state->orig_len = strlen(message) + 1;
+
+ /* Start of a subrequest for the actual data sending */
+ subreq = tdgram_sendto_send(state, ev, dgram,
+ (const uint8_t *) message,
+ state->orig_len, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * And tell tevent what to call when the subreq is done. Note that the
+ * original req structure is passed into the callback as callback data.
+ * This is used to get to the state struct in callbacks.
+ */
+ tevent_req_set_callback(subreq, echo_request_get_reply, req);
+ return req;
+}
+
+/*
+ * The following two callbacks both demonstrate the way of getting back the
+ * state struct in a callback function.
+ */
+
+static void echo_request_get_reply(struct tevent_req *subreq)
+{
+ /* Get the parent request struct from the callback data */
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ /* And get the state struct from the parent request struct */
+ struct echo_request_state *state = tevent_req_data(req,
+ struct echo_request_state);
+ ssize_t len;
+ int err = 0;
+
+ len = tdgram_sendto_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+
+ if (len == -1 && err != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+ return;
+ }
+
+ if (len != state->orig_len) {
+ tevent_req_nterror(req, NT_STATUS_UNEXPECTED_NETWORK_ERROR);
+ return;
+ }
+
+ /* Send off the second subreq here, this time to receive the reply */
+ subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ /* And set the new callback */
+ tevent_req_set_callback(subreq, echo_request_done, req);
+ return;
+}
+
+static void echo_request_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct echo_request_state *state = tevent_req_data(req,
+ struct echo_request_state);
+
+ ssize_t len;
+ int err = 0;
+
+ len = tdgram_recvfrom_recv(subreq, &err, state,
+ (uint8_t **)&state->message,
+ NULL);
+ TALLOC_FREE(subreq);
+
+ if (len == -1 && err != 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+ return;
+ }
+
+ if (len != state->orig_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->message[len-1] = '\0';
+ /* Once the async function has completed, set tevent_req_done() */
+ tevent_req_done(req);
+}
+
+/*
+ * In the recv function, we usually need to move the data from the state struct
+ * to the memory area owned by the caller. Also, the function
+ * tevent_req_received() is called to take care of freeing the memory still
+ * associated with the request.
+ */
+
+NTSTATUS echo_request_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **message)
+{
+ struct echo_request_state *state = tevent_req_data(req,
+ struct echo_request_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *message = talloc_move(mem_ctx, &state->message);
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/echo/libecho.h b/libcli/echo/libecho.h
new file mode 100644
index 0000000..35a0986
--- /dev/null
+++ b/libcli/echo/libecho.h
@@ -0,0 +1,56 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Echo structures and headers, example async client library
+
+ Copyright (C) 2010 Kai Blin <kai@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 __LIBECHO_H__
+#define __LIBECHO_H__
+
+/* The echo port is fixed, so just set a constant. */
+#define ECHO_PORT 7
+
+/** Send an echo request to an echo server
+ *
+ *@param mem_ctx talloc memory context to use
+ *@param ev tevent context to use
+ *@param server_address address of the server as a string
+ *@param message echo message to send
+ *@return tevent_req with the active request or NULL on out-of-memory
+ */
+struct tevent_req *echo_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *server_address,
+ const char *message);
+
+/** Get the echo response from an echo server
+ *
+ * Once the echo_request_send async request is finished, you can call
+ * this function to collect the echo reply.
+ *
+ *@param req tevent_req struct returned from echo_request_send
+ *@param mem_ctx talloc memory context to use for the reply string
+ *@param message pointer to a string that will be allocated and filled with
+ the echo reply.
+ *@return NTSTATUS code depending on the async request result
+ */
+NTSTATUS echo_request_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **message);
+
+#endif /*__LIBECHO_H__*/
diff --git a/libcli/echo/tests/echo.c b/libcli/echo/tests/echo.c
new file mode 100644
index 0000000..e465b99
--- /dev/null
+++ b/libcli/echo/tests/echo.c
@@ -0,0 +1,97 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Example echo torture tests
+
+ Copyright (C) 2010 Kai Blin <kai@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/smbtorture.h"
+#include "libcli/resolve/resolve.h"
+#include <tevent.h>
+#include "libcli/util/ntstatus.h"
+#include "libcli/echo/libecho.h"
+
+NTSTATUS torture_libcli_echo_init(TALLOC_CTX *);
+
+/* Basic test function that sends an echo request and checks the reply */
+static bool echo_udp_basic(struct torture_context *tctx, const char *address)
+{
+ struct tevent_req *req;
+ NTSTATUS status;
+ const char *msg_send = "This is a test string\n";
+ char *msg_recv;
+
+ req = echo_request_send(tctx, tctx->ev, address, msg_send);
+ torture_assert(tctx, req != NULL,
+ "echo_request_send returned non-null tevent_req");
+
+ while(tevent_req_is_in_progress(req)) {
+ tevent_loop_once(tctx->ev);
+ }
+
+ status = echo_request_recv(req, tctx, &msg_recv);
+ torture_assert_ntstatus_ok(tctx, status,
+ "echo_request_recv returned ok");
+
+ torture_assert_str_equal(tctx, msg_recv, msg_send,
+ "Echo server echoed request string");
+
+ return true;
+}
+
+/*Test case to set up the environment and perform UDP-based echo tests */
+static bool torture_echo_udp(struct torture_context *tctx)
+{
+ const char *address;
+ struct nbt_name name;
+ NTSTATUS status;
+ bool ret = true;
+
+ make_nbt_name_server(&name,
+ torture_setting_string(tctx, "host", NULL));
+ status = resolve_name_ex(lpcfg_resolve_context(tctx->lp_ctx),
+ 0, 0,
+ &name, tctx,
+ &address, tctx->ev);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to resolve %s - %s\n", name.name,
+ nt_errstr(status));
+ return false;
+ }
+
+ /* All tests are now called here */
+ ret &= echo_udp_basic(tctx, address);
+
+ return ret;
+}
+
+/* Test suite that bundles all the libecho tests */
+NTSTATUS torture_libcli_echo_init(TALLOC_CTX *ctx)
+{
+ struct torture_suite *suite;
+
+ suite = torture_suite_create(ctx, "echo");
+ NT_STATUS_HAVE_NO_MEMORY(suite);
+
+ torture_suite_add_simple_test(suite, "udp", torture_echo_udp);
+
+ suite->description = talloc_strdup(suite, "libcli/echo interface tests");
+ torture_register_suite(ctx, suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/echo/tests/wscript_build b/libcli/echo/tests/wscript_build
new file mode 100644
index 0000000..366c895
--- /dev/null
+++ b/libcli/echo/tests/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+bld.SAMBA_MODULE('TORTURE_LIBCLI_ECHO',
+ source='echo.c',
+ subsystem='smbtorture',
+ init_function='torture_libcli_echo_init',
+ deps='LIBTSOCKET tevent-util LIBCLI_ECHO',
+ internal_module=True);
diff --git a/libcli/echo/wscript_build b/libcli/echo/wscript_build
new file mode 100644
index 0000000..a9de131
--- /dev/null
+++ b/libcli/echo/wscript_build
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_ECHO',
+ source='echo.c',
+ deps='LIBTSOCKET tevent-util');
+
+bld.RECURSE('tests')
diff --git a/libcli/http/gensec/basic.c b/libcli/http/gensec/basic.c
new file mode 100644
index 0000000..c7a1bbb
--- /dev/null
+++ b/libcli/http/gensec/basic.c
@@ -0,0 +1,204 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library - Basic authentication mechanism gensec module
+
+ 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/>.
+*/
+
+#include "includes.h"
+#include <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
+#include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_internal.h"
+#include "auth/credentials/credentials.h"
+#include "lib/util/base64.h"
+
+_PUBLIC_ NTSTATUS gensec_http_basic_init(TALLOC_CTX *);
+
+struct gensec_http_basic_state {
+ enum {
+ GENSEC_HTTP_BASIC_START,
+ GENSEC_HTTP_BASIC_DONE,
+ GENSEC_HTTP_BASIC_ERROR,
+ } step;
+};
+
+static NTSTATUS gensec_http_basic_client_start(struct gensec_security *gensec)
+{
+ struct gensec_http_basic_state *state;
+
+ state = talloc_zero(gensec, struct gensec_http_basic_state);
+ if (state == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ gensec->private_data = state;
+
+ state->step = GENSEC_HTTP_BASIC_START;
+
+ return NT_STATUS_OK;
+}
+
+struct gensec_http_basic_update_state {
+ NTSTATUS status;
+ DATA_BLOB out;
+};
+
+static NTSTATUS gensec_http_basic_update_internal(struct gensec_security *gensec_ctx,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB in,
+ DATA_BLOB *out);
+
+static struct tevent_req *gensec_http_basic_update_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct gensec_security *gensec_security,
+ const DATA_BLOB in)
+{
+ struct tevent_req *req = NULL;
+ struct gensec_http_basic_update_state *state = NULL;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct gensec_http_basic_update_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ status = gensec_http_basic_update_internal(gensec_security,
+ state, in,
+ &state->out);
+ state->status = status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS gensec_http_basic_update_internal(struct gensec_security *gensec_ctx,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB in,
+ DATA_BLOB *out)
+{
+ struct gensec_http_basic_state *state;
+ struct cli_credentials *creds;
+ char *tmp, *b64;
+
+ state = talloc_get_type_abort(gensec_ctx->private_data,
+ struct gensec_http_basic_state);
+ creds = gensec_get_credentials(gensec_ctx);
+
+ switch (gensec_ctx->gensec_role) {
+ case GENSEC_CLIENT:
+ switch (state->step) {
+ case GENSEC_HTTP_BASIC_START:
+ tmp = talloc_asprintf(mem_ctx, "%s\\%s:%s",
+ cli_credentials_get_domain(creds),
+ cli_credentials_get_username(creds),
+ cli_credentials_get_password(creds));
+ if (tmp == NULL) {
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_NO_MEMORY;
+ }
+ *out = data_blob_string_const(tmp);
+
+ b64 = base64_encode_data_blob(mem_ctx, *out);
+ if (b64 == NULL) {
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(tmp);
+
+ tmp = talloc_asprintf(mem_ctx, "Basic %s", b64);
+ if (tmp == NULL) {
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_NO_MEMORY;
+ }
+ TALLOC_FREE(b64);
+
+ *out = data_blob_string_const(tmp);
+ state->step = GENSEC_HTTP_BASIC_DONE;
+ return NT_STATUS_OK;
+
+ case GENSEC_HTTP_BASIC_DONE:
+ case GENSEC_HTTP_BASIC_ERROR:
+ default:
+ break;
+ }
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_INTERNAL_ERROR;
+
+ case GENSEC_SERVER:
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ state->step = GENSEC_HTTP_BASIC_ERROR;
+ return NT_STATUS_INTERNAL_ERROR;
+}
+
+static NTSTATUS gensec_http_basic_update_recv(struct tevent_req *req,
+ TALLOC_CTX *out_mem_ctx,
+ DATA_BLOB *out)
+{
+ struct gensec_http_basic_update_state *state =
+ tevent_req_data(req,
+ struct gensec_http_basic_update_state);
+ NTSTATUS status;
+
+ *out = data_blob_null;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *out = state->out;
+ talloc_steal(out_mem_ctx, state->out.data);
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
+
+static const struct gensec_security_ops gensec_http_basic_security_ops = {
+ .name = "http_basic",
+ .auth_type = 0,
+ .client_start = gensec_http_basic_client_start,
+ .update_send = gensec_http_basic_update_send,
+ .update_recv = gensec_http_basic_update_recv,
+ .enabled = true,
+ .priority = GENSEC_EXTERNAL,
+};
+
+_PUBLIC_ NTSTATUS gensec_http_basic_init(TALLOC_CTX *ctx)
+{
+ NTSTATUS status;
+
+ status = gensec_register(ctx, &gensec_http_basic_security_ops);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to register '%s' gensec backend!\n",
+ gensec_http_basic_security_ops.name));
+ return status;
+ }
+
+ return status;
+}
diff --git a/libcli/http/gensec/generic.c b/libcli/http/gensec/generic.c
new file mode 100644
index 0000000..2f09b9d
--- /dev/null
+++ b/libcli/http/gensec/generic.c
@@ -0,0 +1,286 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library - NTLM authentication mechanism gensec module
+
+ 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/>.
+*/
+
+#include "includes.h"
+#include <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
+#include "auth/auth.h"
+#include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_internal.h"
+#include "lib/util/base64.h"
+
+#undef strncasecmp
+
+_PUBLIC_ NTSTATUS gensec_http_generic_init(TALLOC_CTX *);
+
+struct gensec_http_generic_state {
+ struct gensec_security *sub;
+ DATA_BLOB prefix;
+};
+
+static NTSTATUS gensec_http_generic_client_start(struct gensec_security *gensec,
+ const char *prefix_str,
+ const char *mech_oid)
+{
+ NTSTATUS status;
+ struct gensec_http_generic_state *state;
+
+ state = talloc_zero(gensec, struct gensec_http_generic_state);
+ if (state == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ gensec->private_data = state;
+
+ state->prefix = data_blob_string_const(prefix_str);
+
+ status = gensec_subcontext_start(state, gensec, &state->sub);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return gensec_start_mech_by_oid(state->sub, mech_oid);
+}
+
+static NTSTATUS gensec_http_ntlm_client_start(struct gensec_security *gensec)
+{
+ return gensec_http_generic_client_start(gensec, "NTLM",
+ GENSEC_OID_NTLMSSP);
+}
+
+static NTSTATUS gensec_http_negotiate_client_start(struct gensec_security *gensec)
+{
+ return gensec_http_generic_client_start(gensec, "Negotiate",
+ GENSEC_OID_SPNEGO);
+}
+
+struct gensec_http_generic_update_state {
+ struct gensec_security *gensec;
+ DATA_BLOB sub_in;
+ NTSTATUS status;
+ DATA_BLOB out;
+};
+
+static void gensec_http_generic_update_done(struct tevent_req *subreq);
+
+static struct tevent_req *gensec_http_generic_update_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct gensec_security *gensec_ctx,
+ const DATA_BLOB in)
+{
+ struct gensec_http_generic_state *http_generic =
+ talloc_get_type_abort(gensec_ctx->private_data,
+ struct gensec_http_generic_state);
+ struct tevent_req *req = NULL;
+ struct gensec_http_generic_update_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct gensec_http_generic_update_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->gensec = gensec_ctx;
+
+ if (in.length) {
+ int cmp;
+ DATA_BLOB b64b;
+ size_t skip = 0;
+
+ if (in.length < http_generic->prefix.length) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ cmp = strncasecmp((const char *)in.data,
+ (const char *)http_generic->prefix.data,
+ http_generic->prefix.length);
+ if (cmp != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in.length == http_generic->prefix.length) {
+ /*
+ * We expect more data, but the
+ * server just sent the prefix without
+ * a space prefixing base64 data.
+ *
+ * It means the server rejects
+ * the request with.
+ */
+ tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in.data[http_generic->prefix.length] != ' ') {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+ skip = http_generic->prefix.length + 1;
+
+ b64b = data_blob_const(in.data + skip, in.length - skip);
+ if (b64b.length != 0) {
+ char *b64 = NULL;
+
+ /*
+ * ensure it's terminated with \0' before
+ * passing to base64_decode_data_blob_talloc().
+ */
+ b64 = talloc_strndup(state, (const char *)b64b.data,
+ b64b.length);
+ if (tevent_req_nomem(b64, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->sub_in = base64_decode_data_blob_talloc(state,
+ b64);
+ TALLOC_FREE(b64);
+ if (tevent_req_nomem(state->sub_in.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+ }
+
+ subreq = gensec_update_send(state, ev,
+ http_generic->sub,
+ state->sub_in);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, gensec_http_generic_update_done, req);
+
+ return req;
+}
+
+static void gensec_http_generic_update_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct gensec_http_generic_update_state *state =
+ tevent_req_data(req,
+ struct gensec_http_generic_update_state);
+ struct gensec_http_generic_state *http_generic =
+ talloc_get_type_abort(state->gensec->private_data,
+ struct gensec_http_generic_state);
+ NTSTATUS status;
+ DATA_BLOB sub_out = data_blob_null;
+ char *b64 = NULL;
+ char *str = NULL;
+ int prefix_length;
+
+ status = gensec_update_recv(subreq, state, &sub_out);
+ TALLOC_FREE(subreq);
+ state->status = status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ status = NT_STATUS_OK;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (sub_out.length == 0) {
+ tevent_req_done(req);
+ return;
+ }
+
+ b64 = base64_encode_data_blob(state, sub_out);
+ data_blob_free(&sub_out);
+ if (tevent_req_nomem(b64, req)) {
+ return;
+ }
+
+ prefix_length = http_generic->prefix.length;
+ str = talloc_asprintf(state, "%*.*s %s", prefix_length, prefix_length,
+ (const char *)http_generic->prefix.data, b64);
+ TALLOC_FREE(b64);
+ if (tevent_req_nomem(str, req)) {
+ return;
+ }
+
+ state->out = data_blob_string_const(str);
+ tevent_req_done(req);
+}
+
+static NTSTATUS gensec_http_generic_update_recv(struct tevent_req *req,
+ TALLOC_CTX *out_mem_ctx,
+ DATA_BLOB *out)
+{
+ struct gensec_http_generic_update_state *state =
+ tevent_req_data(req,
+ struct gensec_http_generic_update_state);
+ NTSTATUS status;
+
+ *out = data_blob_null;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *out = state->out;
+ talloc_steal(out_mem_ctx, state->out.data);
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
+
+static const struct gensec_security_ops gensec_http_ntlm_security_ops = {
+ .name = "http_ntlm",
+ .auth_type = 0,
+ .client_start = gensec_http_ntlm_client_start,
+ .update_send = gensec_http_generic_update_send,
+ .update_recv = gensec_http_generic_update_recv,
+ .enabled = true,
+ .priority = GENSEC_EXTERNAL,
+};
+
+static const struct gensec_security_ops gensec_http_negotiate_security_ops = {
+ .name = "http_negotiate",
+ .auth_type = 0,
+ .client_start = gensec_http_negotiate_client_start,
+ .update_send = gensec_http_generic_update_send,
+ .update_recv = gensec_http_generic_update_recv,
+ .enabled = true,
+ .priority = GENSEC_EXTERNAL,
+ .glue = true,
+};
+
+_PUBLIC_ NTSTATUS gensec_http_generic_init(TALLOC_CTX *ctx)
+{
+ NTSTATUS status;
+
+ status = gensec_register(ctx, &gensec_http_ntlm_security_ops);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to register '%s' gensec backend!\n",
+ gensec_http_ntlm_security_ops.name));
+ return status;
+ }
+
+ status = gensec_register(ctx, &gensec_http_negotiate_security_ops);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to register '%s' gensec backend!\n",
+ gensec_http_negotiate_security_ops.name));
+ return status;
+ }
+
+ return status;
+}
diff --git a/libcli/http/http.c b/libcli/http/http.c
new file mode 100644
index 0000000..96c573a
--- /dev/null
+++ b/libcli/http/http.c
@@ -0,0 +1,882 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ Copyright (C) 2013 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/>.
+*/
+
+#include "includes.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "http.h"
+#include "http_internal.h"
+#include "util/tevent_werror.h"
+#include "lib/util/dlinklist.h"
+
+#undef strcasecmp
+
+/**
+ * Determines if a response should have a body.
+ * @return 1 if the response MUST have a body; 0 if the response MUST NOT have
+ * a body. Returns -1 on error.
+ */
+static int http_response_needs_body(struct http_request *req)
+{
+ struct http_header *h = NULL;
+
+ if (!req) return -1;
+
+ for (h = req->headers; h != NULL; h = h->next) {
+ int cmp;
+ int n;
+ char c;
+ unsigned long long v;
+
+ cmp = strcasecmp(h->key, "Content-Length");
+ if (cmp != 0) {
+ continue;
+ }
+
+ n = sscanf(h->value, "%llu%c", &v, &c);
+ if (n != 1) {
+ return -1;
+ }
+
+ req->remaining_content_length = v;
+
+ if (v != 0) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+struct http_read_response_state {
+ enum http_parser_state parser_state;
+ size_t max_headers_size;
+ uint64_t max_content_length;
+ DATA_BLOB buffer;
+ struct http_request *response;
+};
+
+/**
+ * Parses the HTTP headers
+ */
+static enum http_read_status http_parse_headers(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line = NULL;
+ char *key = NULL;
+ char *value = NULL;
+ int n = 0;
+ int ret;
+
+ /* Sanity checks */
+ if (!state || !state->response) {
+ DEBUG(0, ("%s: Invalid Parameter\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ if (state->buffer.length > state->max_headers_size) {
+ DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
+ state->buffer.length, state->max_headers_size));
+ return HTTP_DATA_TOO_LONG;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DEBUG(0, ("%s: Memory error\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ state->response->headers_size += state->buffer.length;
+
+ if (strncmp(line, "\r\n", 2) == 0) {
+ DEBUG(11,("%s: All headers read\n", __func__));
+
+ ret = http_response_needs_body(state->response);
+ switch (ret) {
+ case 1:
+ if (state->response->remaining_content_length <= state->max_content_length) {
+ DEBUG(11, ("%s: Start of read body\n", __func__));
+ state->parser_state = HTTP_READING_BODY;
+ break;
+ }
+ FALL_THROUGH;
+ case 0:
+ DEBUG(11, ("%s: Skipping body for code %d\n", __func__,
+ state->response->response_code));
+ state->parser_state = HTTP_READING_DONE;
+ break;
+ case -1:
+ DEBUG(0, ("%s_: Error in http_response_needs_body\n", __func__));
+ TALLOC_FREE(line);
+ return HTTP_DATA_CORRUPTED;
+ break;
+ }
+
+ TALLOC_FREE(line);
+ return HTTP_ALL_DATA_READ;
+ }
+
+ n = sscanf(line, "%m[^:]: %m[^\r\n]\r\n", &key, &value);
+ if (n != 2) {
+ DEBUG(0, ("%s: Error parsing header '%s'\n", __func__, line));
+ status = HTTP_DATA_CORRUPTED;
+ goto error;
+ }
+
+ if (http_add_header(state->response, &state->response->headers, key, value) == -1) {
+ DEBUG(0, ("%s: Error adding header\n", __func__));
+ status = HTTP_DATA_CORRUPTED;
+ goto error;
+ }
+
+error:
+ free(key);
+ free(value);
+ TALLOC_FREE(line);
+ return status;
+}
+
+/**
+ * Parses the first line of a HTTP response
+ */
+static bool http_parse_response_line(struct http_read_response_state *state)
+{
+ bool status = true;
+ char *protocol;
+ char *msg = NULL;
+ char major;
+ char minor;
+ int code;
+ char *line = NULL;
+ int n;
+
+ /* Sanity checks */
+ if (!state) {
+ DEBUG(0, ("%s: Input parameter is NULL\n", __func__));
+ return false;
+ }
+
+ line = talloc_strndup(state, (char*)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DEBUG(0, ("%s: Memory error\n", __func__));
+ return false;
+ }
+
+ n = sscanf(line, "%m[^/]/%c.%c %d %m[^\r\n]\r\n",
+ &protocol, &major, &minor, &code, &msg);
+
+ DEBUG(11, ("%s: Header parsed(%i): protocol->%s, major->%c, minor->%c, "
+ "code->%d, message->%s\n", __func__, n, protocol, major, minor,
+ code, msg));
+
+ if (n != 5) {
+ DEBUG(0, ("%s: Error parsing header\n", __func__));
+ status = false;
+ goto error;
+ }
+
+ if (major != '1') {
+ DEBUG(0, ("%s: Bad HTTP major number '%c'\n", __func__, major));
+ status = false;
+ goto error;
+ }
+
+ if (code == 0) {
+ DEBUG(0, ("%s: Bad response code '%d'\n", __func__, code));
+ status = false;
+ goto error;
+ }
+
+ if (msg == NULL) {
+ DEBUG(0, ("%s: Error parsing HTTP data\n", __func__));
+ status = false;
+ goto error;
+ }
+
+ state->response->major = major;
+ state->response->minor = minor;
+ state->response->response_code = code;
+ state->response->response_code_line = talloc_strndup(state->response,
+ msg, strlen(msg));
+
+error:
+ free(protocol);
+ free(msg);
+ TALLOC_FREE(line);
+ return status;
+}
+
+/*
+ * Parses header lines from a request or a response into the specified
+ * request object given a buffer.
+ *
+ * Returns
+ * HTTP_DATA_CORRUPTED on error
+ * HTTP_MORE_DATA_EXPECTED when we need to read more headers
+ * HTTP_DATA_TOO_LONG on error
+ * HTTP_ALL_DATA_READ when all headers have been read
+ */
+static enum http_read_status http_parse_firstline(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_ALL_DATA_READ;
+ char *ptr = NULL;
+ char *line;
+
+ /* Sanity checks */
+ if (!state) {
+ DEBUG(0, ("%s: Invalid Parameter\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ if (state->buffer.length > state->max_headers_size) {
+ DEBUG(0, ("%s: Headers too long: %zi, maximum length is %zi\n", __func__,
+ state->buffer.length, state->max_headers_size));
+ return HTTP_DATA_TOO_LONG;
+ }
+
+ line = talloc_strndup(state, (char *)state->buffer.data, state->buffer.length);
+ if (!line) {
+ DEBUG(0, ("%s: Not enough memory\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ ptr = strstr(line, "\r\n");
+ if (ptr == NULL) {
+ TALLOC_FREE(line);
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ state->response->headers_size = state->buffer.length;
+ if (!http_parse_response_line(state)) {
+ status = HTTP_DATA_CORRUPTED;
+ }
+
+ /* Next state, read HTTP headers */
+ state->parser_state = HTTP_READING_HEADERS;
+
+ TALLOC_FREE(line);
+ return status;
+}
+
+static enum http_read_status http_read_body(struct http_read_response_state *state)
+{
+ struct http_request *resp = state->response;
+
+ if (state->buffer.length < resp->remaining_content_length) {
+ return HTTP_MORE_DATA_EXPECTED;
+ }
+
+ resp->body = state->buffer;
+ state->buffer = data_blob_null;
+ talloc_steal(resp, resp->body.data);
+ resp->remaining_content_length = 0;
+
+ state->parser_state = HTTP_READING_DONE;
+ return HTTP_ALL_DATA_READ;
+}
+
+static enum http_read_status http_read_trailer(struct http_read_response_state *state)
+{
+ enum http_read_status status = HTTP_DATA_CORRUPTED;
+ /* TODO */
+ return status;
+}
+
+static enum http_read_status http_parse_buffer(struct http_read_response_state *state)
+{
+ if (!state) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return HTTP_DATA_CORRUPTED;
+ }
+
+ switch (state->parser_state) {
+ case HTTP_READING_FIRSTLINE:
+ return http_parse_firstline(state);
+ case HTTP_READING_HEADERS:
+ return http_parse_headers(state);
+ case HTTP_READING_BODY:
+ return http_read_body(state);
+ break;
+ case HTTP_READING_TRAILER:
+ return http_read_trailer(state);
+ break;
+ case HTTP_READING_DONE:
+ /* All read */
+ return HTTP_ALL_DATA_READ;
+ default:
+ DEBUG(0, ("%s: Illegal parser state %d\n", __func__,
+ state->parser_state));
+ break;
+ }
+ return HTTP_DATA_CORRUPTED;
+}
+
+static int http_header_is_valid_value(const char *value)
+{
+ const char *p = NULL;
+
+ /* Sanity checks */
+ if (!value) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return -1;
+ }
+ p = value;
+
+ while ((p = strpbrk(p, "\r\n")) != NULL) {
+ /* Expect only one new line */
+ p += strspn(p, "\r\n");
+ /* Expect a space or tab for continuation */
+ if (*p != ' ' && *p != '\t')
+ return (0);
+ }
+ return 1;
+}
+
+static int http_add_header_internal(TALLOC_CTX *mem_ctx,
+ struct http_header **headers,
+ const char *key, const char *value,
+ bool replace)
+{
+ struct http_header *tail = NULL;
+ struct http_header *h = NULL;
+
+ /* Sanity checks */
+ if (!headers || !key || !value) {
+ DEBUG(0, ("Invalid parameter\n"));
+ return -1;
+ }
+
+
+
+ if (replace) {
+ for (h = *headers; h != NULL; h = h->next) {
+ if (strcasecmp(key, h->key) == 0) {
+ break;
+ }
+ }
+
+ if (h != NULL) {
+ /* Replace header value */
+ if (h->value) {
+ talloc_free(h->value);
+ }
+ h->value = talloc_strdup(h, value);
+ DEBUG(11, ("%s: Replaced HTTP header: key '%s', value '%s'\n",
+ __func__, h->key, h->value));
+ return 0;
+ }
+ }
+
+ /* Add new header */
+ h = talloc(mem_ctx, struct http_header);
+ h->key = talloc_strdup(h, key);
+ h->value = talloc_strdup(h, value);
+ DLIST_ADD_END(*headers, h);
+ tail = DLIST_TAIL(*headers);
+ if (tail != h) {
+ DEBUG(0, ("%s: Error adding header\n", __func__));
+ return -1;
+ }
+ DEBUG(11, ("%s: Added HTTP header: key '%s', value '%s'\n",
+ __func__, h->key, h->value));
+ return 0;
+}
+
+int http_add_header(TALLOC_CTX *mem_ctx,
+ struct http_header **headers,
+ const char *key, const char *value)
+{
+ if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
+ DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
+ return -1;
+ }
+
+ if (!http_header_is_valid_value(value)) {
+ DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
+ return -1;
+ }
+
+ return (http_add_header_internal(mem_ctx, headers, key, value, false));
+}
+
+int http_replace_header(TALLOC_CTX *mem_ctx,
+ struct http_header **headers,
+ const char *key, const char *value)
+{
+ if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
+ DEBUG(0, ("%s: Dropping illegal header key\n", __func__));
+ return -1;
+ }
+
+ if (!http_header_is_valid_value(value)) {
+ DEBUG(0, ("%s: Dropping illegal header value\n", __func__));
+ return -1;
+ }
+
+ return (http_add_header_internal(mem_ctx, headers, key, value, true));
+}
+
+/**
+ * Remove a header from the headers list.
+ *
+ * Returns 0, if the header was successfully removed.
+ * Returns -1, if the header could not be found.
+ */
+int http_remove_header(struct http_header **headers, const char *key)
+{
+ struct http_header *header;
+
+ /* Sanity checks */
+ if (!headers || !key) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return -1;
+ }
+
+ for(header = *headers; header != NULL; header = header->next) {
+ if (strcmp(key, header->key) == 0) {
+ DLIST_REMOVE(*headers, header);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int http_read_response_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count)
+{
+ struct http_read_response_state *state;
+ struct iovec *vector;
+
+ /* Sanity checks */
+ if (!stream || !private_data || !_vector || !_count) {
+ DEBUG(0, ("%s: Invalid Parameter\n", __func__));
+ return -1;
+ }
+
+ state = talloc_get_type_abort(private_data, struct http_read_response_state);
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (!vector) {
+ DEBUG(0, ("%s: No more memory\n", __func__));
+ return -1;
+ }
+
+ if (state->buffer.data == NULL) {
+ /* Allocate buffer */
+ state->buffer.data = talloc_zero_array(state, uint8_t, 1);
+ if (!state->buffer.data) {
+ DEBUG(0, ("%s: No more memory\n", __func__));
+ return -1;
+ }
+ state->buffer.length = 1;
+
+ /* Return now, nothing to parse yet */
+ vector[0].iov_base = (void *)(state->buffer.data);
+ vector[0].iov_len = 1;
+ *_vector = vector;
+ *_count = 1;
+ return 0;
+ }
+
+ switch (http_parse_buffer(state)) {
+ case HTTP_ALL_DATA_READ:
+ if (state->parser_state == HTTP_READING_DONE) {
+ /* Full request or response parsed */
+ *_vector = NULL;
+ *_count = 0;
+ } else {
+ /* Free current buffer and allocate new one */
+ TALLOC_FREE(state->buffer.data);
+ state->buffer.data = talloc_zero_array(state, uint8_t, 1);
+ if (!state->buffer.data) {
+ return -1;
+ }
+ state->buffer.length = 1;
+
+ vector[0].iov_base = (void *)(state->buffer.data);
+ vector[0].iov_len = 1;
+ *_vector = vector;
+ *_count = 1;
+ }
+ break;
+ case HTTP_MORE_DATA_EXPECTED:
+ /* TODO Optimize, allocating byte by byte */
+ state->buffer.data = talloc_realloc(state, state->buffer.data,
+ uint8_t, state->buffer.length + 1);
+ if (!state->buffer.data) {
+ return -1;
+ }
+ state->buffer.length++;
+ vector[0].iov_base = (void *)(state->buffer.data +
+ state->buffer.length - 1);
+ vector[0].iov_len = 1;
+ *_vector = vector;
+ *_count = 1;
+ break;
+ case HTTP_DATA_CORRUPTED:
+ case HTTP_REQUEST_CANCELED:
+ case HTTP_DATA_TOO_LONG:
+ return -1;
+ break;
+ default:
+ DEBUG(0, ("%s: Unexpected status\n", __func__));
+ break;
+ }
+ return 0;
+}
+
+
+/**
+ * Reads a HTTP response
+ */
+static void http_read_response_done(struct tevent_req *);
+struct tevent_req *http_read_response_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn,
+ size_t max_content_length)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct http_read_response_state *state;
+
+ DEBUG(11, ("%s: Reading HTTP response\n", __func__));
+
+ /* Sanity checks */
+ if (ev == NULL || http_conn == NULL) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NULL;
+ }
+
+ req = tevent_req_create(mem_ctx, &state, struct http_read_response_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->max_headers_size = HTTP_MAX_HEADER_SIZE;
+ state->max_content_length = (uint64_t)max_content_length;
+ state->parser_state = HTTP_READING_FIRSTLINE;
+ state->response = talloc_zero(state, struct http_request);
+ if (tevent_req_nomem(state->response, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tstream_readv_pdu_send(state, ev, http_conn->tstreams.active,
+ http_read_response_next_vector,
+ state);
+ if (tevent_req_nomem(subreq,req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_read_response_done, req);
+
+ return req;
+}
+
+static void http_read_response_done(struct tevent_req *subreq)
+{
+ NTSTATUS status;
+ struct tevent_req *req;
+ int ret;
+ int sys_errno;
+
+ if (!subreq) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return;
+ }
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ ret = tstream_readv_pdu_recv(subreq, &sys_errno);
+ DEBUG(11, ("%s: HTTP response read (%d bytes)\n", __func__, ret));
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix_common(sys_errno);
+ DEBUG(0, ("%s: Failed to read HTTP response: %s\n",
+ __func__, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS http_read_response_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct http_request **response)
+{
+ NTSTATUS status;
+ struct http_read_response_state *state;
+
+ if (!mem_ctx || !response || !req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ state = tevent_req_data(req, struct http_read_response_state);
+ *response = state->response;
+ talloc_steal(mem_ctx, state->response);
+
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
+
+static const char *http_method_str(enum http_cmd_type type)
+{
+ const char *method;
+
+ switch (type) {
+ case HTTP_REQ_POST:
+ method = "POST";
+ break;
+ case HTTP_REQ_RPC_IN_DATA:
+ method = "RPC_IN_DATA";
+ break;
+ case HTTP_REQ_RPC_OUT_DATA:
+ method = "RPC_OUT_DATA";
+ break;
+ default:
+ method = NULL;
+ break;
+ }
+
+ return method;
+}
+
+static NTSTATUS http_push_request_line(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *buffer,
+ const struct http_request *req)
+{
+ const char *method;
+ char *str;
+
+ /* Sanity checks */
+ if (!buffer || !req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ method = http_method_str(req->type);
+ if (method == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ str = talloc_asprintf(mem_ctx, "%s %s HTTP/%c.%c\r\n", method,
+ req->uri, req->major, req->minor);
+ if (str == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (!data_blob_append(mem_ctx, buffer, str, strlen(str))) {
+ talloc_free(str);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ talloc_free(str);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS http_push_headers(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ struct http_request *req)
+{
+ struct http_header *header = NULL;
+ char *header_str = NULL;
+ size_t len;
+
+ /* Sanity checks */
+ if (!blob || !req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (header = req->headers; header != NULL; header = header->next) {
+ header_str = talloc_asprintf(mem_ctx, "%s: %s\r\n",
+ header->key, header->value);
+ if (header_str == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ len = strlen(header_str);
+ if (!data_blob_append(mem_ctx, blob, header_str, len)) {
+ talloc_free(header_str);
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_free(header_str);
+ }
+
+ if (!data_blob_append(mem_ctx, blob, "\r\n",2)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS http_push_body(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob,
+ struct http_request *req)
+{
+ /* Sanity checks */
+ if (!blob || !req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (req->body.length) {
+ if (!data_blob_append(mem_ctx, blob, req->body.data,
+ req->body.length)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct http_send_request_state {
+ struct tevent_context *ev;
+ struct loadparm_context *lp_ctx;
+ struct cli_credentials *credentials;
+ struct http_request *request;
+ DATA_BLOB buffer;
+ struct iovec iov;
+ ssize_t nwritten;
+ int sys_errno;
+};
+
+/**
+ * Sends and HTTP request
+ */
+static void http_send_request_done(struct tevent_req *);
+struct tevent_req *http_send_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn,
+ struct http_request *request)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct http_send_request_state *state = NULL;
+ NTSTATUS status;
+
+ DEBUG(11, ("%s: Sending HTTP request\n", __func__));
+
+ /* Sanity checks */
+ if (ev == NULL || request == NULL || http_conn == NULL) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NULL;
+ }
+
+ req = tevent_req_create(mem_ctx, &state, struct http_send_request_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->request = request;
+
+ /* Push the request line */
+ status = http_push_request_line(state, &state->buffer, state->request);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ /* Push the headers */
+ status = http_push_headers(mem_ctx, &state->buffer, request);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ /* Push the body */
+ status = http_push_body(mem_ctx, &state->buffer, request);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+
+ state->iov.iov_base = (char *) state->buffer.data;
+ state->iov.iov_len = state->buffer.length;
+ subreq = tstream_writev_queue_send(state,
+ ev,
+ http_conn->tstreams.active,
+ http_conn->send_queue,
+ &state->iov, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_send_request_done, req);
+
+ return req;
+}
+
+static void http_send_request_done(struct tevent_req *subreq)
+{
+ NTSTATUS status;
+ struct tevent_req *req;
+ struct http_send_request_state *state;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct http_send_request_state);
+
+ state->nwritten = tstream_writev_queue_recv(subreq, &state->sys_errno);
+ TALLOC_FREE(subreq);
+ if (state->nwritten == -1 && state->sys_errno != 0) {
+ status = map_nt_error_from_unix_common(state->sys_errno);
+ DEBUG(0, ("%s: Failed to send HTTP request: %s\n",
+ __func__, nt_errstr(status)));
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS http_send_request_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (!req) {
+ DEBUG(0, ("%s: Invalid parameter\n", __func__));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/http/http.h b/libcli/http/http.h
new file mode 100644
index 0000000..8941547
--- /dev/null
+++ b/libcli/http/http.h
@@ -0,0 +1,143 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ Copyright (C) 2013 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 _HTTP_H_
+#define _HTTP_H_
+
+#include <limits.h>
+#include <sys/uio.h>
+
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+
+/* Response codes */
+#define HTTP_OK 200 /* request completed ok */
+#define HTTP_NOCONTENT 204 /* request does not have content */
+#define HTTP_MOVEPERM 301 /* uri moved permanently */
+#define HTTP_MOVETEMP 302 /* uri moved temporarily */
+#define HTTP_NOTMODIFIED 304 /* page was not modified from last */
+#define HTTP_BADREQUEST 400 /* invalid http request was made */
+#define HTTP_NOTFOUND 404 /* could not find content for uri */
+#define HTTP_BADMETHOD 405 /* method not allowed for this uri */
+#define HTTP_ENTITYTOOLARGE 413 /* */
+#define HTTP_EXPECTATIONFAILED 417 /* can't handle this expectation */
+#define HTTP_INTERNAL 500 /* internal error */
+#define HTTP_NOTIMPLEMENTED 501 /* not implemented */
+#define HTTP_SERVUNAVAIL 503 /* server is not available */
+
+#define HTTP_MAX_HEADER_SIZE 0x1FFFF
+
+struct cli_credentials;
+
+enum http_cmd_type {
+ HTTP_REQ_GET = 1 << 0,
+ HTTP_REQ_POST = 1 << 1,
+ HTTP_REQ_HEAD = 1 << 2,
+ HTTP_REQ_PUT = 1 << 3,
+ HTTP_REQ_DELETE = 1 << 4,
+ HTTP_REQ_OPTIONS = 1 << 5,
+ HTTP_REQ_TRACE = 1 << 6,
+ HTTP_REQ_CONNECT = 1 << 7,
+ HTTP_REQ_PATCH = 1 << 8,
+ HTTP_REQ_RPC_IN_DATA = 1 << 9,
+ HTTP_REQ_RPC_OUT_DATA = 1 << 10,
+};
+
+enum http_auth_method {
+ HTTP_AUTH_BASIC=1,
+ HTTP_AUTH_NTLM,
+ HTTP_AUTH_NEGOTIATE,
+};
+
+struct http_header {
+ struct http_header *next, *prev;
+ char *key;
+ char *value;
+};
+
+struct http_request {
+ enum http_cmd_type type; /* HTTP command type */
+ char major; /* HTTP version major number */
+ char minor; /* HTTP version minor number */
+ char *uri; /* URI after HTTP request was parsed */
+ struct http_header *headers;
+ size_t headers_size;
+ unsigned int response_code; /* HTTP response code */
+ char *response_code_line; /* Readable response */
+ uint64_t remaining_content_length; /* data not represent in body */
+ DATA_BLOB body;
+};
+
+/* HTTP header handling functions */
+int http_remove_header(struct http_header **, const char *);
+int http_add_header(TALLOC_CTX *, struct http_header **, const char *, const char *);
+int http_replace_header(TALLOC_CTX *, struct http_header **, const char *, const char *);
+
+/* HTTP(s) connect */
+
+struct http_conn;
+struct tstream_tls_params;
+
+struct tevent_req *http_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *http_server,
+ uint16_t http_port,
+ struct cli_credentials *credentials,
+ struct tstream_tls_params *tls_params);
+int http_connect_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct http_conn **http_conn);
+
+struct tevent_req *http_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn);
+int http_disconnect_recv(struct tevent_req *req);
+
+struct tevent_queue *http_conn_send_queue(struct http_conn *http_conn);
+struct tstream_context *http_conn_tstream(struct http_conn *http_conn);
+
+/* HTTP request */
+struct tevent_req *http_send_request_send(TALLOC_CTX *,
+ struct tevent_context *,
+ struct http_conn *,
+ struct http_request *);
+NTSTATUS http_send_request_recv(struct tevent_req *);
+
+/* HTTP response */
+struct tevent_req *http_read_response_send(TALLOC_CTX *,
+ struct tevent_context *,
+ struct http_conn *,
+ size_t max_content_length);
+NTSTATUS http_read_response_recv(struct tevent_req *,
+ TALLOC_CTX *,
+ struct http_request **);
+
+/* HTTP authenticated request */
+struct tevent_req *http_send_auth_request_send(TALLOC_CTX *,
+ struct tevent_context *,
+ struct http_conn *,
+ const struct http_request *,
+ struct cli_credentials *,
+ struct loadparm_context *,
+ enum http_auth_method);
+NTSTATUS http_send_auth_request_recv(struct tevent_req *);
+
+#endif /* _HTTP_H_ */
diff --git a/libcli/http/http_auth.c b/libcli/http/http_auth.c
new file mode 100644
index 0000000..3dcf52c
--- /dev/null
+++ b/libcli/http/http_auth.c
@@ -0,0 +1,383 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ 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/>.
+*/
+
+#include "includes.h"
+#include "http.h"
+#include "http_internal.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/param/param.h"
+#include "tevent.h"
+#include "auth/gensec/gensec.h"
+#include "auth/credentials/credentials.h"
+#include "lib/util/data_blob.h"
+
+#undef strcasecmp
+#undef strncasecmp
+
+/**
+ * Copy the request headers from src to dst
+ */
+static NTSTATUS http_copy_header(const struct http_request *src,
+ struct http_request *dst)
+{
+ struct http_header *h;
+
+ dst->type = src->type;
+ dst->major = src->major;
+ dst->minor = src->minor;
+ dst->uri = talloc_strdup(dst, src->uri);
+
+ for (h = src->headers; h != NULL; h = h->next) {
+ http_add_header(dst, &dst->headers, h->key, h->value);
+ }
+ dst->headers_size = src->headers_size;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * Retrieve the WWW-Authenticate header from server response based on the
+ * authentication scheme being used.
+ */
+static NTSTATUS http_parse_auth_response(const DATA_BLOB prefix,
+ struct http_request *auth_response,
+ DATA_BLOB *in)
+{
+ struct http_header *h;
+
+ for (h = auth_response->headers; h != NULL; h = h->next) {
+ int cmp;
+
+ cmp = strcasecmp(h->key, "WWW-Authenticate");
+ if (cmp != 0) {
+ continue;
+ }
+
+ cmp = strncasecmp(h->value,
+ (const char *)prefix.data,
+ prefix.length);
+ if (cmp != 0) {
+ continue;
+ }
+
+ *in = data_blob_string_const(h->value);
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+struct http_auth_state {
+ struct tevent_context *ev;
+
+ struct http_conn *http_conn;
+
+ enum http_auth_method auth;
+ DATA_BLOB prefix;
+
+ struct gensec_security *gensec_ctx;
+ NTSTATUS gensec_status;
+
+ const struct http_request *original_request;
+ struct http_request *next_request;
+ struct http_request *auth_response;
+};
+
+
+static void http_send_auth_request_gensec_done(struct tevent_req *subreq);
+static void http_send_auth_request_http_req_done(struct tevent_req *subreq);
+static void http_send_auth_request_http_rep_done(struct tevent_req *subreq);
+
+struct tevent_req *http_send_auth_request_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn,
+ const struct http_request *original_request,
+ struct cli_credentials *credentials,
+ struct loadparm_context *lp_ctx,
+ enum http_auth_method auth)
+{
+ struct tevent_req *req = NULL;
+ struct http_auth_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ DATA_BLOB gensec_in = data_blob_null;
+ NTSTATUS status;
+ struct http_header *h = NULL;
+ const char *mech_name = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct http_auth_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->http_conn = http_conn;
+ state->auth = auth;
+ state->original_request = original_request;
+
+ status = gensec_init();
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_client_start(state, &state->gensec_ctx,
+ lpcfg_gensec_settings(state, lp_ctx));
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_set_credentials(state->gensec_ctx, credentials);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ for (h = original_request->headers; h != NULL; h = h->next) {
+ int cmp;
+
+ cmp = strcasecmp(h->key, "Host");
+ if (cmp != 0) {
+ continue;
+ }
+
+ status = gensec_set_target_service(state->gensec_ctx, "http");
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_set_target_hostname(state->gensec_ctx, h->value);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ break;
+ }
+
+ switch (state->auth) {
+ case HTTP_AUTH_BASIC:
+ mech_name = "http_basic";
+ state->prefix = data_blob_string_const("Basic");
+ break;
+ case HTTP_AUTH_NTLM:
+ mech_name = "http_ntlm";
+ state->prefix = data_blob_string_const("NTLM");
+ break;
+ case HTTP_AUTH_NEGOTIATE:
+ mech_name = "http_negotiate";
+ state->prefix = data_blob_string_const("Negotiate");
+ break;
+ default:
+ tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
+ return tevent_req_post(req, ev);
+ }
+
+ status = gensec_start_mech_by_name(state->gensec_ctx, mech_name);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = gensec_update_send(state, state->ev,
+ state->gensec_ctx,
+ gensec_in);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_send_auth_request_gensec_done, req);
+
+ return req;
+}
+
+static void http_send_auth_request_gensec_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct http_auth_state *state =
+ tevent_req_data(req,
+ struct http_auth_state);
+ DATA_BLOB gensec_out = data_blob_null;
+ NTSTATUS status;
+ int ret;
+
+ TALLOC_FREE(state->auth_response);
+
+ status = gensec_update_recv(subreq, state, &gensec_out);
+ TALLOC_FREE(subreq);
+ state->gensec_status = status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ status = NT_STATUS_OK;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->next_request = talloc_zero(state, struct http_request);
+ if (tevent_req_nomem(state->next_request, req)) {
+ return;
+ }
+
+ status = http_copy_header(state->original_request, state->next_request);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(state->gensec_status)) {
+ /*
+ * More preprocessing required before we
+ * can include the content.
+ */
+ ret = http_replace_header(state->next_request,
+ &state->next_request->headers,
+ "Content-Length", "0");
+ if (ret != 0) {
+ tevent_req_oom(req);
+ return;
+ }
+ } else {
+ state->next_request->body = state->original_request->body;
+ }
+
+ if (gensec_out.length > 0) {
+ ret = http_add_header(state->next_request,
+ &state->next_request->headers,
+ "Authorization",
+ (char *)gensec_out.data);
+ if (ret != 0) {
+ tevent_req_oom(req);
+ return;
+ }
+ data_blob_free(&gensec_out);
+ }
+
+ subreq = http_send_request_send(state, state->ev,
+ state->http_conn,
+ state->next_request);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ http_send_auth_request_http_req_done,
+ req);
+}
+
+static void http_send_auth_request_http_req_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct http_auth_state *state =
+ tevent_req_data(req,
+ struct http_auth_state);
+ NTSTATUS status;
+
+ TALLOC_FREE(state->next_request);
+
+ status = http_send_request_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ /*
+ * If no more processing required, it is done
+ *
+ * The caller will use http_read_response_send/recv
+ * in order to get the high level response.
+ */
+ if (NT_STATUS_IS_OK(state->gensec_status)) {
+ tevent_req_done(req);
+ return;
+ }
+
+ /*
+ * If more processing required, read the response from server
+ *
+ * We may get an empty RPCH Echo packet from the server
+ * on the "RPC_OUT_DATA" path. We need to consume this
+ * from the socket, but for now we just ignore the bytes.
+ */
+ subreq = http_read_response_send(state, state->ev,
+ state->http_conn,
+ UINT16_MAX);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ http_send_auth_request_http_rep_done,
+ req);
+}
+
+static void http_send_auth_request_http_rep_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct http_auth_state *state =
+ tevent_req_data(req,
+ struct http_auth_state);
+ DATA_BLOB gensec_in = data_blob_null;
+ NTSTATUS status;
+
+ status = http_read_response_recv(subreq, state,
+ &state->auth_response);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ /*
+ * We we asked for up to UINT16_MAX bytes of
+ * content, we don't expect
+ * state->auth_response->remaining_content_length
+ * to be set.
+ *
+ * For now we just ignore any bytes in
+ * state->auth_response->body.
+ */
+ if (state->auth_response->remaining_content_length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ status = http_parse_auth_response(state->prefix,
+ state->auth_response,
+ &gensec_in);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ subreq = gensec_update_send(state, state->ev,
+ state->gensec_ctx,
+ gensec_in);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, http_send_auth_request_gensec_done, req);
+}
+
+NTSTATUS http_send_auth_request_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/http/http_conn.c b/libcli/http/http_conn.c
new file mode 100644
index 0000000..ac39a0a
--- /dev/null
+++ b/libcli/http/http_conn.c
@@ -0,0 +1,347 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ Copyright (C) 2019 Ralph Boehme <slow@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/tevent_ntstatus.h"
+#include "libcli/dns/dns_lookup.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/util_net.h"
+#include "lib/tls/tls.h"
+#include "lib/util/tevent_unix.h"
+#include "http.h"
+#include "http_internal.h"
+
+struct http_connect_state {
+ struct tevent_context *ev;
+ const char *http_server;
+ const char *http_server_ip;
+ uint16_t http_port;
+ struct tsocket_address *local_address;
+ struct tsocket_address *remote_address;
+ struct cli_credentials *credentials;
+ struct tstream_tls_params *tls_params;
+
+ struct http_conn *http_conn;
+};
+
+static void http_connect_dns_done(struct tevent_req *subreq);
+static void http_connect_tcp_connect(struct tevent_req *req);
+static void http_connect_tcp_done(struct tevent_req *subreq);
+static void http_connect_tls_done(struct tevent_req *subreq);
+
+struct tevent_req *http_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *http_server,
+ uint16_t http_port,
+ struct cli_credentials *credentials,
+ struct tstream_tls_params *tls_params)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct http_connect_state *state = NULL;
+ int ret;
+
+ DBG_DEBUG("Connecting to [%s] over HTTP%s\n",
+ http_server, tls_params != NULL ? "S" : "");
+
+ req = tevent_req_create(mem_ctx, &state, struct http_connect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ *state = (struct http_connect_state) {
+ .ev = ev,
+ .http_port = http_port,
+ .credentials = credentials,
+ .tls_params = tls_params,
+ };
+
+ state->http_server = talloc_strdup(state, http_server);
+ if (tevent_req_nomem(state->http_server, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->http_conn = talloc_zero(state, struct http_conn);
+ if (tevent_req_nomem(state->http_conn, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->http_conn->send_queue = tevent_queue_create(state->http_conn,
+ "HTTP send queue");
+ if (tevent_req_nomem(state->http_conn->send_queue, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ NULL,
+ 0,
+ &state->local_address);
+ if (ret != 0) {
+ tevent_req_error(req, errno);
+ return tevent_req_post(req, ev);
+ }
+
+ if (!is_ipaddress(http_server)) {
+ subreq = dns_lookup_send(state,
+ ev,
+ NULL,
+ http_server,
+ DNS_QCLASS_IN,
+ DNS_QTYPE_A);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_connect_dns_done, req);
+ return req;
+ }
+ state->http_server_ip = state->http_server;
+
+ http_connect_tcp_connect(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void http_connect_dns_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ struct dns_name_packet *dns_reply = NULL;
+ struct dns_res_rec *an = NULL;
+ uint16_t i;
+ int ret;
+
+ ret = dns_lookup_recv(subreq, state, &dns_reply);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ for (i = 0; i < dns_reply->ancount; i++) {
+ an = &dns_reply->answers[i];
+ if (an->rr_type == DNS_QTYPE_A) {
+ break;
+ }
+ }
+ if (i >= dns_reply->ancount) {
+ tevent_req_error(req, ENOENT);
+ return;
+ }
+
+ state->http_server_ip = talloc_strdup(state, an->rdata.ipv4_record);
+ if (tevent_req_nomem(state->http_server_ip, req)) {
+ return;
+ }
+ http_connect_tcp_connect(req);
+}
+
+static void http_connect_tcp_connect(struct tevent_req *req)
+{
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ struct tevent_req *subreq = NULL;
+ int ret;
+
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ state->http_server_ip,
+ state->http_port,
+ &state->remote_address);
+ if (ret != 0) {
+ int saved_errno = errno;
+
+ DBG_ERR("Cannot create remote socket address, error: %s (%d)\n",
+ strerror(errno), errno);
+ tevent_req_error(req, saved_errno);
+ return;
+ }
+
+ subreq = tstream_inet_tcp_connect_send(state,
+ state->ev,
+ state->local_address,
+ state->remote_address);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, http_connect_tcp_done, req);
+}
+
+static void http_connect_tcp_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ int error;
+ int ret;
+
+ ret = tstream_inet_tcp_connect_recv(subreq,
+ &error,
+ state->http_conn,
+ &state->http_conn->tstreams.raw,
+ NULL);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_error(req, error);
+ return;
+ }
+
+ state->http_conn->tstreams.active = state->http_conn->tstreams.raw;
+ DBG_DEBUG("Socket connected\n");
+
+ if (state->tls_params == NULL) {
+ tevent_req_done(req);
+ return;
+ }
+
+ DBG_DEBUG("Starting TLS\n");
+
+ subreq = tstream_tls_connect_send(state,
+ state->ev,
+ state->http_conn->tstreams.active,
+ state->tls_params);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, http_connect_tls_done, req);
+}
+
+static void http_connect_tls_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ int error;
+ int ret;
+
+ ret = tstream_tls_connect_recv(subreq,
+ &error,
+ state->http_conn,
+ &state->http_conn->tstreams.tls);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ tevent_req_error(req, error);
+ return;
+ }
+
+ state->http_conn->tstreams.active = state->http_conn->tstreams.tls;
+
+ DBG_DEBUG("TLS handshake completed\n");
+ tevent_req_done(req);
+}
+
+int http_connect_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct http_conn **http_conn)
+{
+ struct http_connect_state *state = tevent_req_data(
+ req, struct http_connect_state);
+ int error;
+
+ if (tevent_req_is_unix_error(req, &error)) {
+ tevent_req_received(req);
+ return error;
+ }
+
+ *http_conn = talloc_move(mem_ctx, &state->http_conn);
+ tevent_req_received(req);
+
+ return 0;
+}
+
+struct tevent_queue *http_conn_send_queue(struct http_conn *http_conn)
+{
+ return http_conn->send_queue;
+}
+
+struct tstream_context *http_conn_tstream(struct http_conn *http_conn)
+{
+ return http_conn->tstreams.active;
+}
+
+struct http_conn_disconnect_state {
+ struct tevent_context *ev;
+ struct http_conn *http_conn;
+};
+
+static void http_conn_disconnect_done(struct tevent_req *subreq);
+
+struct tevent_req *http_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct http_conn *http_conn)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct http_conn_disconnect_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct http_conn_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ *state = (struct http_conn_disconnect_state) {
+ .ev = ev,
+ .http_conn = http_conn,
+ };
+
+ if (http_conn->tstreams.active == NULL) {
+ tevent_req_error(req, ENOTCONN);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tstream_disconnect_send(state, ev, http_conn->tstreams.active);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, http_conn_disconnect_done, req);
+
+ return req;
+}
+
+static void http_conn_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret;
+ int error;
+
+ ret = tstream_disconnect_recv(subreq, &error);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, error);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+int http_disconnect_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_unix(req);
+}
diff --git a/libcli/http/http_internal.h b/libcli/http/http_internal.h
new file mode 100644
index 0000000..ec17f7e
--- /dev/null
+++ b/libcli/http/http_internal.h
@@ -0,0 +1,50 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ HTTP library
+
+ 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 _HTTP_INTERNAL_H_
+#define _HTTP_INTERNAL_H_
+
+enum http_parser_state {
+ HTTP_READING_FIRSTLINE,
+ HTTP_READING_HEADERS,
+ HTTP_READING_BODY,
+ HTTP_READING_TRAILER,
+ HTTP_READING_DONE,
+};
+
+enum http_read_status {
+ HTTP_ALL_DATA_READ,
+ HTTP_MORE_DATA_EXPECTED,
+ HTTP_DATA_CORRUPTED,
+ HTTP_REQUEST_CANCELED,
+ HTTP_DATA_TOO_LONG,
+};
+
+struct http_conn {
+ struct tevent_queue *send_queue;
+ struct {
+ struct tstream_context *raw;
+ struct tstream_context *tls;
+ struct tstream_context *active;
+ } tstreams;
+};
+
+#endif /* _HTTP_INTERNAL_H_ */
diff --git a/libcli/http/wscript_build b/libcli/http/wscript_build
new file mode 100644
index 0000000..da8768f
--- /dev/null
+++ b/libcli/http/wscript_build
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('http',
+ source='http.c http_auth.c http_conn.c',
+ deps='talloc tevent gensec dns_lookup',
+ private_library=True,
+)
+
+bld.SAMBA_MODULE('gensec_http_basic',
+ source='gensec/basic.c',
+ subsystem='gensec',
+ init_function='gensec_http_basic_init',
+ deps='samba-util auth_session'
+)
+
+bld.SAMBA_MODULE('gensec_http_generic',
+ source='gensec/generic.c',
+ subsystem='gensec',
+ init_function='gensec_http_generic_init',
+ deps='samba-util auth_session'
+)
diff --git a/libcli/ldap/ldap_errors.h b/libcli/ldap/ldap_errors.h
new file mode 100644
index 0000000..fa929c6
--- /dev/null
+++ b/libcli/ldap/ldap_errors.h
@@ -0,0 +1,68 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+ 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/>.
+
+*/
+
+#ifndef _SMB_LDAP_ERRORS_H_
+#define _SMB_LDAP_ERRORS_H_
+
+#ifndef LDAP_SUCCESS
+enum ldap_result_code {
+ LDAP_SUCCESS = 0,
+ LDAP_OPERATIONS_ERROR = 1,
+ LDAP_PROTOCOL_ERROR = 2,
+ LDAP_TIME_LIMIT_EXCEEDED = 3,
+ LDAP_SIZE_LIMIT_EXCEEDED = 4,
+ LDAP_COMPARE_FALSE = 5,
+ LDAP_COMPARE_TRUE = 6,
+ LDAP_AUTH_METHOD_NOT_SUPPORTED = 7,
+ LDAP_STRONG_AUTH_REQUIRED = 8,
+ LDAP_REFERRAL = 10,
+ LDAP_ADMIN_LIMIT_EXCEEDED = 11,
+ LDAP_UNAVAILABLE_CRITICAL_EXTENSION = 12,
+ LDAP_CONFIDENTIALITY_REQUIRED = 13,
+ LDAP_SASL_BIND_IN_PROGRESS = 14,
+ LDAP_NO_SUCH_ATTRIBUTE = 16,
+ LDAP_UNDEFINED_ATTRIBUTE_TYPE = 17,
+ LDAP_INAPPROPRIATE_MATCHING = 18,
+ LDAP_CONSTRAINT_VIOLATION = 19,
+ LDAP_ATTRIBUTE_OR_VALUE_EXISTS = 20,
+ LDAP_INVALID_ATTRIBUTE_SYNTAX = 21,
+ LDAP_NO_SUCH_OBJECT = 32,
+ LDAP_ALIAS_PROBLEM = 33,
+ LDAP_INVALID_DN_SYNTAX = 34,
+ LDAP_ALIAS_DEREFERENCING_PROBLEM = 36,
+ LDAP_INAPPROPRIATE_AUTHENTICATION = 48,
+ LDAP_INVALID_CREDENTIALS = 49,
+ LDAP_INSUFFICIENT_ACCESS_RIGHTS = 50,
+ LDAP_BUSY = 51,
+ LDAP_UNAVAILABLE = 52,
+ LDAP_UNWILLING_TO_PERFORM = 53,
+ LDAP_LOOP_DETECT = 54,
+ LDAP_NAMING_VIOLATION = 64,
+ LDAP_OBJECT_CLASS_VIOLATION = 65,
+ LDAP_NOT_ALLOWED_ON_NON_LEAF = 66,
+ LDAP_NOT_ALLOWED_ON_RDN = 67,
+ LDAP_ENTRY_ALREADY_EXISTS = 68,
+ LDAP_OBJECT_CLASS_MODS_PROHIBITED = 69,
+ LDAP_AFFECTS_MULTIPLE_DSAS = 71,
+ LDAP_OTHER = 80
+};
+#endif
+
+#endif /* _SMB_LDAP_ERRORS_H_ */
diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c
new file mode 100644
index 0000000..1a537e8
--- /dev/null
+++ b/libcli/ldap/ldap_message.c
@@ -0,0 +1,1673 @@
+/*
+ Unix SMB/CIFS implementation.
+ LDAP protocol helper functions for SAMBA
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Volker Lendecke 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 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/util/asn1.h"
+#include "../libcli/ldap/ldap_message.h"
+
+_PUBLIC_ struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
+{
+ return talloc_zero(mem_ctx, struct ldap_message);
+}
+
+
+static bool add_value_to_attrib(TALLOC_CTX *mem_ctx, struct ldb_val *value,
+ struct ldb_message_element *attrib)
+{
+ attrib->values = talloc_realloc(mem_ctx,
+ attrib->values,
+ DATA_BLOB,
+ attrib->num_values+1);
+ if (attrib->values == NULL)
+ return false;
+
+ attrib->values[attrib->num_values].data = talloc_steal(attrib->values,
+ value->data);
+ attrib->values[attrib->num_values].length = value->length;
+ attrib->num_values += 1;
+ return true;
+}
+
+static bool add_attrib_to_array_talloc(TALLOC_CTX *mem_ctx,
+ const struct ldb_message_element *attrib,
+ struct ldb_message_element **attribs,
+ int *num_attribs)
+{
+ *attribs = talloc_realloc(mem_ctx,
+ *attribs,
+ struct ldb_message_element,
+ *num_attribs+1);
+
+ if (*attribs == NULL)
+ return false;
+
+ (*attribs)[*num_attribs] = *attrib;
+ talloc_steal(*attribs, attrib->values);
+ talloc_steal(*attribs, attrib->name);
+ *num_attribs += 1;
+ return true;
+}
+
+static bool add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
+ struct ldap_mod *mod,
+ struct ldap_mod **mods,
+ int *num_mods)
+{
+ *mods = talloc_realloc(mem_ctx, *mods, struct ldap_mod, (*num_mods)+1);
+
+ if (*mods == NULL)
+ return false;
+
+ (*mods)[*num_mods] = *mod;
+ *num_mods += 1;
+ return true;
+}
+
+static bool ldap_decode_control_value(void *mem_ctx, DATA_BLOB value,
+ const struct ldap_control_handler *handlers,
+ struct ldb_control *ctrl)
+{
+ int i;
+
+ if (!handlers) {
+ return true;
+ }
+
+ for (i = 0; handlers[i].oid != NULL; i++) {
+ if (strcmp(handlers[i].oid, ctrl->oid) == 0) {
+ if (!handlers[i].decode || !handlers[i].decode(mem_ctx, value, &ctrl->data)) {
+ return false;
+ }
+ break;
+ }
+ }
+ if (handlers[i].oid == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool ldap_decode_control_wrapper(void *mem_ctx, struct asn1_data *data,
+ struct ldb_control *ctrl, DATA_BLOB *value)
+{
+ DATA_BLOB oid;
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+ return false;
+ }
+
+ if (!asn1_read_OctetString(data, mem_ctx, &oid)) {
+ return false;
+ }
+ ctrl->oid = talloc_strndup(mem_ctx, (char *)oid.data, oid.length);
+ if (!ctrl->oid) {
+ return false;
+ }
+
+ if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
+ bool critical;
+ if (!asn1_read_BOOLEAN(data, &critical)) {
+ return false;
+ }
+ ctrl->critical = critical;
+ } else {
+ ctrl->critical = false;
+ }
+
+ ctrl->data = NULL;
+
+ if (!asn1_peek_tag(data, ASN1_OCTET_STRING)) {
+ *value = data_blob(NULL, 0);
+ goto end_tag;
+ }
+
+ if (!asn1_read_OctetString(data, mem_ctx, value)) {
+ return false;
+ }
+
+end_tag:
+ if (!asn1_end_tag(data)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool ldap_encode_control(void *mem_ctx, struct asn1_data *data,
+ const struct ldap_control_handler *handlers,
+ struct ldb_control *ctrl)
+{
+ DATA_BLOB value;
+ int i;
+
+ if (!handlers) {
+ return false;
+ }
+
+ for (i = 0; handlers[i].oid != NULL; i++) {
+ if (!ctrl->oid) {
+ /* not encoding this control, the OID has been
+ * set to NULL indicating it isn't really
+ * here */
+ return true;
+ }
+ if (strcmp(handlers[i].oid, ctrl->oid) == 0) {
+ if (!handlers[i].encode) {
+ if (ctrl->critical) {
+ return false;
+ } else {
+ /* not encoding this control */
+ return true;
+ }
+ }
+ if (!handlers[i].encode(mem_ctx, ctrl->data, &value)) {
+ return false;
+ }
+ break;
+ }
+ }
+ if (handlers[i].oid == NULL) {
+ return false;
+ }
+
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) {
+ return false;
+ }
+
+ if (!asn1_write_OctetString(data, ctrl->oid, strlen(ctrl->oid))) {
+ return false;
+ }
+
+ if (ctrl->critical) {
+ if (!asn1_write_BOOLEAN(data, ctrl->critical)) {
+ return false;
+ }
+ }
+
+ if (!ctrl->data) {
+ goto pop_tag;
+ }
+
+ if (!asn1_write_OctetString(data, value.data, value.length)) {
+ return false;
+ }
+
+pop_tag:
+ if (!asn1_pop_tag(data)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool ldap_push_filter(struct asn1_data *data, struct ldb_parse_tree *tree)
+{
+ int i;
+
+ switch (tree->operation) {
+ case LDB_OP_AND:
+ case LDB_OP_OR:
+ if (!asn1_push_tag(data, ASN1_CONTEXT(tree->operation==LDB_OP_AND?0:1))) return false;
+ for (i=0; i<tree->u.list.num_elements; i++) {
+ if (!ldap_push_filter(data, tree->u.list.elements[i])) {
+ return false;
+ }
+ }
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_NOT:
+ if (!asn1_push_tag(data, ASN1_CONTEXT(2))) return false;
+ if (!ldap_push_filter(data, tree->u.isnot.child)) {
+ return false;
+ }
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_EQUALITY:
+ /* equality test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(3))) return false;
+ if (!asn1_write_OctetString(data, tree->u.equality.attr,
+ strlen(tree->u.equality.attr))) return false;
+ if (!asn1_write_OctetString(data, tree->u.equality.value.data,
+ tree->u.equality.value.length)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_SUBSTRING:
+ /*
+ SubstringFilter ::= SEQUENCE {
+ type AttributeDescription,
+ -- at least one must be present
+ substrings SEQUENCE OF CHOICE {
+ initial [0] LDAPString,
+ any [1] LDAPString,
+ final [2] LDAPString } }
+ */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(4))) return false;
+ if (!asn1_write_OctetString(data, tree->u.substring.attr, strlen(tree->u.substring.attr))) return false;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
+
+ if (tree->u.substring.chunks && tree->u.substring.chunks[0]) {
+ i = 0;
+ if (!tree->u.substring.start_with_wildcard) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0))) return false;
+ if (!asn1_write_DATA_BLOB_LDAPString(data, tree->u.substring.chunks[i])) return false;
+ if (!asn1_pop_tag(data)) return false;
+ i++;
+ }
+ while (tree->u.substring.chunks[i]) {
+ int ctx;
+
+ if (( ! tree->u.substring.chunks[i + 1]) &&
+ (tree->u.substring.end_with_wildcard == 0)) {
+ ctx = 2;
+ } else {
+ ctx = 1;
+ }
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(ctx))) return false;
+ if (!asn1_write_DATA_BLOB_LDAPString(data, tree->u.substring.chunks[i])) return false;
+ if (!asn1_pop_tag(data)) return false;
+ i++;
+ }
+ }
+ if (!asn1_pop_tag(data)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_GREATER:
+ /* greaterOrEqual test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(5))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.attr,
+ strlen(tree->u.comparison.attr))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.value.data,
+ tree->u.comparison.value.length)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_LESS:
+ /* lessOrEqual test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(6))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.attr,
+ strlen(tree->u.comparison.attr))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.value.data,
+ tree->u.comparison.value.length)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_PRESENT:
+ /* present test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(7))) return false;
+ if (!asn1_write_LDAPString(data, tree->u.present.attr)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ return !asn1_has_error(data);
+
+ case LDB_OP_APPROX:
+ /* approx test */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(8))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.attr,
+ strlen(tree->u.comparison.attr))) return false;
+ if (!asn1_write_OctetString(data, tree->u.comparison.value.data,
+ tree->u.comparison.value.length)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ case LDB_OP_EXTENDED:
+ /*
+ MatchingRuleAssertion ::= SEQUENCE {
+ matchingRule [1] MatchingRuleID OPTIONAL,
+ type [2] AttributeDescription OPTIONAL,
+ matchValue [3] AssertionValue,
+ dnAttributes [4] BOOLEAN DEFAULT FALSE
+ }
+ */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(9))) return false;
+ if (tree->u.extended.rule_id) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1))) return false;
+ if (!asn1_write_LDAPString(data, tree->u.extended.rule_id)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ }
+ if (tree->u.extended.attr) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2))) return false;
+ if (!asn1_write_LDAPString(data, tree->u.extended.attr)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ }
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3))) return false;
+ if (!asn1_write_DATA_BLOB_LDAPString(data, &tree->u.extended.value)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4))) return false;
+ if (!asn1_write_uint8(data, tree->u.extended.dnAttributes)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ if (!asn1_pop_tag(data)) return false;
+ break;
+
+ default:
+ return false;
+ }
+ return !asn1_has_error(data);
+}
+
+static bool ldap_encode_response(struct asn1_data *data, struct ldap_Result *result)
+{
+ if (!asn1_write_enumerated(data, result->resultcode)) return false;
+ if (!asn1_write_OctetString(data, result->dn,
+ (result->dn) ? strlen(result->dn) : 0)) return false;
+ if (!asn1_write_OctetString(data, result->errormessage,
+ (result->errormessage) ?
+ strlen(result->errormessage) : 0)) return false;
+ if (result->referral) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT(3))) return false;
+ if (!asn1_write_OctetString(data, result->referral,
+ strlen(result->referral))) return false;
+ if (!asn1_pop_tag(data)) return false;
+ }
+ return true;
+}
+
+_PUBLIC_ bool ldap_encode(struct ldap_message *msg,
+ const struct ldap_control_handler *control_handlers,
+ DATA_BLOB *result, TALLOC_CTX *mem_ctx)
+{
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
+ int i, j;
+
+ if (!data) return false;
+
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_Integer(data, msg->messageid)) goto err;
+
+ switch (msg->type) {
+ case LDAP_TAG_BindRequest: {
+ struct ldap_BindRequest *r = &msg->r.BindRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_Integer(data, r->version)) goto err;
+ if (!asn1_write_OctetString(data, r->dn,
+ (r->dn != NULL) ? strlen(r->dn) : 0)) goto err;
+
+ switch (r->mechanism) {
+ case LDAP_AUTH_MECH_SIMPLE:
+ /* context, primitive */
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto err;
+ if (!asn1_write(data, r->creds.password,
+ strlen(r->creds.password))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ case LDAP_AUTH_MECH_SASL:
+ /* context, constructed */
+ if (!asn1_push_tag(data, ASN1_CONTEXT(3))) goto err;
+ if (!asn1_write_OctetString(data, r->creds.SASL.mechanism,
+ strlen(r->creds.SASL.mechanism))) goto err;
+ if (r->creds.SASL.secblob) {
+ if (!asn1_write_OctetString(data, r->creds.SASL.secblob->data,
+ r->creds.SASL.secblob->length)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ default:
+ goto err;
+ }
+
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_BindResponse: {
+ struct ldap_BindResponse *r = &msg->r.BindResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, &r->response)) goto err;
+ if (r->SASL.secblob) {
+ if (!asn1_write_ContextSimple(data, 7, r->SASL.secblob)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_UnbindRequest: {
+/* struct ldap_UnbindRequest *r = &msg->r.UnbindRequest; */
+ if (!asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_SearchRequest: {
+ struct ldap_SearchRequest *r = &msg->r.SearchRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->basedn, strlen(r->basedn))) goto err;
+ if (!asn1_write_enumerated(data, r->scope)) goto err;
+ if (!asn1_write_enumerated(data, r->deref)) goto err;
+ if (!asn1_write_Integer(data, r->sizelimit)) goto err;
+ if (!asn1_write_Integer(data, r->timelimit)) goto err;
+ if (!asn1_write_BOOLEAN(data, r->attributesonly)) goto err;
+
+ if (!ldap_push_filter(data, r->tree)) {
+ goto err;
+ }
+
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ for (i=0; i<r->num_attributes; i++) {
+ if (!asn1_write_OctetString(data, r->attributes[i],
+ strlen(r->attributes[i]))) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_SearchResultEntry: {
+ struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ for (i=0; i<r->num_attributes; i++) {
+ struct ldb_message_element *attr = &r->attributes[i];
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_OctetString(data, attr->name,
+ strlen(attr->name))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(1))) goto err;
+ for (j=0; j<attr->num_values; j++) {
+ if (!asn1_write_OctetString(data,
+ attr->values[j].data,
+ attr->values[j].length)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_SearchResultDone: {
+ struct ldap_Result *r = &msg->r.SearchResultDone;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ModifyRequest: {
+ struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+
+ for (i=0; i<r->num_mods; i++) {
+ struct ldb_message_element *attrib = &r->mods[i].attrib;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_enumerated(data, r->mods[i].type)) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_OctetString(data, attrib->name,
+ strlen(attrib->name))) goto err;
+ if (!asn1_push_tag(data, ASN1_SET)) goto err;
+ for (j=0; j<attrib->num_values; j++) {
+ if (!asn1_write_OctetString(data,
+ attrib->values[j].data,
+ attrib->values[j].length)) goto err;
+
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ModifyResponse: {
+ struct ldap_Result *r = &msg->r.ModifyResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_AddRequest: {
+ struct ldap_AddRequest *r = &msg->r.AddRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+
+ for (i=0; i<r->num_attributes; i++) {
+ struct ldb_message_element *attrib = &r->attributes[i];
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (attrib->name == NULL) {
+ goto err;
+ }
+ if (!asn1_write_OctetString(data, attrib->name,
+ strlen(attrib->name))) goto err;
+ if (!asn1_push_tag(data, ASN1_SET)) goto err;
+ for (j=0; j<r->attributes[i].num_values; j++) {
+ if (!asn1_write_OctetString(data,
+ attrib->values[j].data,
+ attrib->values[j].length)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_AddResponse: {
+ struct ldap_Result *r = &msg->r.AddResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_DelRequest: {
+ struct ldap_DelRequest *r = &msg->r.DelRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type))) goto err;
+ if (!asn1_write(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_DelResponse: {
+ struct ldap_Result *r = &msg->r.DelResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ModifyDNRequest: {
+ struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_write_OctetString(data, r->newrdn, strlen(r->newrdn))) goto err;
+ if (!asn1_write_BOOLEAN(data, r->deleteolddn)) goto err;
+ if (r->newsuperior) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto err;
+ if (!asn1_write(data, r->newsuperior,
+ strlen(r->newsuperior))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ModifyDNResponse: {
+ struct ldap_Result *r = &msg->r.ModifyDNResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_CompareRequest: {
+ struct ldap_CompareRequest *r = &msg->r.CompareRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->dn, strlen(r->dn))) goto err;
+ if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err;
+ if (!asn1_write_OctetString(data, r->attribute,
+ strlen(r->attribute))) goto err;
+ if (!asn1_write_OctetString(data, r->value.data,
+ r->value.length)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_CompareResponse: {
+ struct ldap_Result *r = &msg->r.ModifyDNResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, r)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_AbandonRequest: {
+ struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION_SIMPLE(msg->type))) goto err;
+ if (!asn1_write_implicit_Integer(data, r->messageid)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_SearchResultReference: {
+ struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_write_OctetString(data, r->referral, strlen(r->referral))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ExtendedRequest: {
+ struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto err;
+ if (!asn1_write(data, r->oid, strlen(r->oid))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ if (r->value) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1))) goto err;
+ if (!asn1_write(data, r->value->data, r->value->length)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ case LDAP_TAG_ExtendedResponse: {
+ struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
+ if (!asn1_push_tag(data, ASN1_APPLICATION(msg->type))) goto err;
+ if (!ldap_encode_response(data, &r->response)) goto err;
+ if (r->oid) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(10))) goto err;
+ if (!asn1_write(data, r->oid, strlen(r->oid))) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (r->value) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(11))) goto err;
+ if (!asn1_write(data, r->value->data, r->value->length)) goto err;
+ if (!asn1_pop_tag(data)) goto err;
+ }
+ if (!asn1_pop_tag(data)) goto err;
+ break;
+ }
+ default:
+ goto err;
+ }
+
+ if (msg->controls != NULL) {
+ if (!asn1_push_tag(data, ASN1_CONTEXT(0))) goto err;
+
+ for (i = 0; msg->controls[i] != NULL; i++) {
+ if (!ldap_encode_control(mem_ctx, data,
+ control_handlers,
+ msg->controls[i])) {
+ DEBUG(0,("Unable to encode control %s\n",
+ msg->controls[i]->oid));
+ goto err;
+ }
+ }
+
+ if (!asn1_pop_tag(data)) goto err;
+ }
+
+ if (!asn1_pop_tag(data)) goto err;
+
+ if (!asn1_extract_blob(data, mem_ctx, result)) {
+ goto err;
+ }
+
+ asn1_free(data);
+
+ return true;
+
+ err:
+
+ asn1_free(data);
+ return false;
+}
+
+static const char *blob2string_talloc(TALLOC_CTX *mem_ctx,
+ DATA_BLOB blob)
+{
+ char *result = talloc_array(mem_ctx, char, blob.length+1);
+ if (result == NULL) {
+ return NULL;
+ }
+ memcpy(result, blob.data, blob.length);
+ result[blob.length] = '\0';
+ return result;
+}
+
+bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
+ struct asn1_data *data,
+ const char **result)
+{
+ DATA_BLOB string;
+ if (!asn1_read_OctetString(data, mem_ctx, &string))
+ return false;
+ *result = blob2string_talloc(mem_ctx, string);
+ data_blob_free(&string);
+ return *result ? true : false;
+}
+
+static bool ldap_decode_response(TALLOC_CTX *mem_ctx,
+ struct asn1_data *data,
+ struct ldap_Result *result)
+{
+ if (!asn1_read_enumerated(data, &result->resultcode)) return false;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &result->dn)) return false;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &result->errormessage)) return false;
+ if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
+ if (!asn1_start_tag(data, ASN1_CONTEXT(3))) return false;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &result->referral)) return false;
+ if (!asn1_end_tag(data)) return false;
+ } else {
+ result->referral = NULL;
+ }
+ return true;
+}
+
+static struct ldb_val **ldap_decode_substring(TALLOC_CTX *mem_ctx, struct ldb_val **chunks, int chunk_num, char *value)
+{
+
+ chunks = talloc_realloc(mem_ctx, chunks, struct ldb_val *, chunk_num + 2);
+ if (chunks == NULL) {
+ return NULL;
+ }
+
+ chunks[chunk_num] = talloc(mem_ctx, struct ldb_val);
+ if (chunks[chunk_num] == NULL) {
+ return NULL;
+ }
+
+ chunks[chunk_num]->data = (uint8_t *)talloc_strdup(mem_ctx, value);
+ if (chunks[chunk_num]->data == NULL) {
+ return NULL;
+ }
+ chunks[chunk_num]->length = strlen(value);
+
+ chunks[chunk_num + 1] = NULL;
+
+ return chunks;
+}
+
+
+/*
+ parse the ASN.1 formatted search string into a ldb_parse_tree
+*/
+static struct ldb_parse_tree *ldap_decode_filter_tree(TALLOC_CTX *mem_ctx,
+ struct asn1_data *data)
+{
+ uint8_t filter_tag;
+ struct ldb_parse_tree *ret;
+
+ if (!asn1_peek_uint8(data, &filter_tag)) {
+ return NULL;
+ }
+
+ filter_tag &= 0x1f; /* strip off the asn1 stuff */
+
+ ret = talloc(mem_ctx, struct ldb_parse_tree);
+ if (ret == NULL) return NULL;
+
+ switch(filter_tag) {
+ case 0:
+ case 1:
+ /* AND or OR of one or more filters */
+ ret->operation = (filter_tag == 0)?LDB_OP_AND:LDB_OP_OR;
+ ret->u.list.num_elements = 0;
+ ret->u.list.elements = NULL;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
+ goto failed;
+ }
+
+ while (asn1_tag_remaining(data) > 0) {
+ struct ldb_parse_tree *subtree;
+ subtree = ldap_decode_filter_tree(ret, data);
+ if (subtree == NULL) {
+ goto failed;
+ }
+ ret->u.list.elements =
+ talloc_realloc(ret, ret->u.list.elements,
+ struct ldb_parse_tree *,
+ ret->u.list.num_elements+1);
+ if (ret->u.list.elements == NULL) {
+ goto failed;
+ }
+ talloc_steal(ret->u.list.elements, subtree);
+ ret->u.list.elements[ret->u.list.num_elements] = subtree;
+ ret->u.list.num_elements++;
+ }
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+
+ case 2:
+ /* 'not' operation */
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_NOT;
+ ret->u.isnot.child = ldap_decode_filter_tree(ret, data);
+ if (ret->u.isnot.child == NULL) {
+ goto failed;
+ }
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+
+ case 3: {
+ /* equalityMatch */
+ const char *attrib;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) goto failed;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
+ if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_EQUALITY;
+ ret->u.equality.attr = talloc_steal(ret, attrib);
+ ret->u.equality.value.data = talloc_steal(ret, value.data);
+ ret->u.equality.value.length = value.length;
+ break;
+ }
+ case 4: {
+ /* substrings */
+ DATA_BLOB attr;
+ uint8_t subs_tag;
+ char *value;
+ int chunk_num = 0;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
+ goto failed;
+ }
+ if (!asn1_read_OctetString(data, mem_ctx, &attr)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_SUBSTRING;
+ ret->u.substring.attr = talloc_strndup(ret, (char *)attr.data, attr.length);
+ if (ret->u.substring.attr == NULL) {
+ goto failed;
+ }
+ ret->u.substring.chunks = NULL;
+ ret->u.substring.start_with_wildcard = 1;
+ ret->u.substring.end_with_wildcard = 1;
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) {
+ goto failed;
+ }
+
+ while (asn1_tag_remaining(data) > 0) {
+ if (!asn1_peek_uint8(data, &subs_tag)) goto failed;
+ subs_tag &= 0x1f; /* strip off the asn1 stuff */
+ if (subs_tag > 2) goto failed;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(subs_tag))) goto failed;
+ if (!asn1_read_LDAPString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+
+ switch (subs_tag) {
+ case 0:
+ if (ret->u.substring.chunks != NULL) {
+ /* initial value found in the middle */
+ goto failed;
+ }
+
+ ret->u.substring.chunks = ldap_decode_substring(ret, NULL, 0, value);
+ if (ret->u.substring.chunks == NULL) {
+ goto failed;
+ }
+
+ ret->u.substring.start_with_wildcard = 0;
+ chunk_num = 1;
+ break;
+
+ case 1:
+ if (ret->u.substring.end_with_wildcard == 0) {
+ /* "any" value found after a "final" value */
+ goto failed;
+ }
+
+ ret->u.substring.chunks = ldap_decode_substring(ret,
+ ret->u.substring.chunks,
+ chunk_num,
+ value);
+ if (ret->u.substring.chunks == NULL) {
+ goto failed;
+ }
+
+ chunk_num++;
+ break;
+
+ case 2:
+ ret->u.substring.chunks = ldap_decode_substring(ret,
+ ret->u.substring.chunks,
+ chunk_num,
+ value);
+ if (ret->u.substring.chunks == NULL) {
+ goto failed;
+ }
+
+ ret->u.substring.end_with_wildcard = 0;
+ break;
+
+ default:
+ goto failed;
+ }
+
+ }
+
+ if (!asn1_end_tag(data)) { /* SEQUENCE */
+ goto failed;
+ }
+
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+ }
+ case 5: {
+ /* greaterOrEqual */
+ const char *attrib;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) goto failed;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
+ if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_GREATER;
+ ret->u.comparison.attr = talloc_steal(ret, attrib);
+ ret->u.comparison.value.data = talloc_steal(ret, value.data);
+ ret->u.comparison.value.length = value.length;
+ break;
+ }
+ case 6: {
+ /* lessOrEqual */
+ const char *attrib;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) goto failed;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
+ if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_LESS;
+ ret->u.comparison.attr = talloc_steal(ret, attrib);
+ ret->u.comparison.value.data = talloc_steal(ret, value.data);
+ ret->u.comparison.value.length = value.length;
+ break;
+ }
+ case 7: {
+ /* Normal presence, "attribute=*" */
+ char *attr;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(filter_tag))) {
+ goto failed;
+ }
+ if (!asn1_read_LDAPString(data, ret, &attr)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_PRESENT;
+ ret->u.present.attr = talloc_steal(ret, attr);
+
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+ }
+ case 8: {
+ /* approx */
+ const char *attrib;
+ DATA_BLOB value;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) goto failed;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib)) goto failed;
+ if (!asn1_read_OctetString(data, mem_ctx, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ if (asn1_has_error(data) || (attrib == NULL) ||
+ (value.data == NULL)) {
+ goto failed;
+ }
+
+ ret->operation = LDB_OP_APPROX;
+ ret->u.comparison.attr = talloc_steal(ret, attrib);
+ ret->u.comparison.value.data = talloc_steal(ret, value.data);
+ ret->u.comparison.value.length = value.length;
+ break;
+ }
+ case 9: {
+ char *oid = NULL, *attr = NULL, *value;
+ uint8_t dnAttributes;
+ /* an extended search */
+ if (!asn1_start_tag(data, ASN1_CONTEXT(filter_tag))) {
+ goto failed;
+ }
+
+ /* FIXME: read carefully rfc2251.txt there are a number of 'MUST's
+ we need to check we properly implement --SSS */
+ /* either oid or type must be defined */
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) { /* optional */
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(1))) goto failed;
+ if (!asn1_read_LDAPString(data, ret, &oid)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ }
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(2))) { /* optional */
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(2))) goto failed;
+ if (!asn1_read_LDAPString(data, ret, &attr)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ }
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(3))) goto failed;
+ if (!asn1_read_LDAPString(data, ret, &value)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ /* dnAttributes is marked as BOOLEAN DEFAULT FALSE
+ it is not marked as OPTIONAL but openldap tools
+ do not set this unless it is to be set as TRUE
+ NOTE: openldap tools do not work with AD as it
+ seems that AD always requires the dnAttributes
+ boolean value to be set */
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(4))) {
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(4))) goto failed;
+ if (!asn1_read_uint8(data, &dnAttributes)) goto failed;
+ if (!asn1_end_tag(data)) goto failed;
+ } else {
+ dnAttributes = 0;
+ }
+ if ((oid == NULL && attr == NULL) || (value == NULL)) {
+ goto failed;
+ }
+
+ if (oid) {
+ ret->operation = LDB_OP_EXTENDED;
+
+ /* From the RFC2251: If the type field is
+ absent and matchingRule is present, the matchValue is compared
+ against all attributes in an entry which support that matchingRule
+ */
+ if (attr) {
+ ret->u.extended.attr = talloc_steal(ret, attr);
+ } else {
+ ret->u.extended.attr = talloc_strdup(ret, "*");
+ if (ret->u.extended.attr == NULL) {
+ goto failed;
+ }
+ }
+ ret->u.extended.rule_id = talloc_steal(ret, oid);
+ ret->u.extended.value.data = (uint8_t *)talloc_steal(ret, value);
+ ret->u.extended.value.length = strlen(value);
+ ret->u.extended.dnAttributes = dnAttributes;
+ } else {
+ ret->operation = LDB_OP_EQUALITY;
+ ret->u.equality.attr = talloc_steal(ret, attr);
+ ret->u.equality.value.data = (uint8_t *)talloc_steal(ret, value);
+ ret->u.equality.value.length = strlen(value);
+ }
+ if (!asn1_end_tag(data)) {
+ goto failed;
+ }
+ break;
+ }
+
+ default:
+ goto failed;
+ }
+
+ return ret;
+
+failed:
+ talloc_free(ret);
+ return NULL;
+}
+
+/* Decode a single LDAP attribute, possibly containing multiple values */
+static bool ldap_decode_attrib(TALLOC_CTX *mem_ctx, struct asn1_data *data,
+ struct ldb_message_element *attrib)
+{
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) return false;
+ if (!asn1_read_OctetString_talloc(mem_ctx, data, &attrib->name)) return false;
+ if (!asn1_start_tag(data, ASN1_SET)) return false;
+ while (asn1_peek_tag(data, ASN1_OCTET_STRING)) {
+ DATA_BLOB blob;
+ if (!asn1_read_OctetString(data, mem_ctx, &blob)) return false;
+ add_value_to_attrib(mem_ctx, &blob, attrib);
+ }
+ if (!asn1_end_tag(data)) return false;
+ return asn1_end_tag(data);
+}
+
+/* Decode a set of LDAP attributes, as found in the dereference control */
+bool ldap_decode_attribs_bare(TALLOC_CTX *mem_ctx, struct asn1_data *data,
+ struct ldb_message_element **attributes,
+ int *num_attributes)
+{
+ while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
+ struct ldb_message_element attrib;
+ ZERO_STRUCT(attrib);
+ if (!ldap_decode_attrib(mem_ctx, data, &attrib)) return false;
+ add_attrib_to_array_talloc(mem_ctx, &attrib,
+ attributes, num_attributes);
+ }
+ return true;
+}
+
+/* Decode a set of LDAP attributes, as found in a search entry */
+static bool ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
+ struct ldb_message_element **attributes,
+ int *num_attributes)
+{
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) return false;
+ if (!ldap_decode_attribs_bare(mem_ctx, data,
+ attributes, num_attributes)) return false;
+ return asn1_end_tag(data);
+}
+
+/* This routine returns LDAP status codes */
+
+_PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
+ const struct ldap_request_limits *limits,
+ const struct ldap_control_handler *control_handlers,
+ struct ldap_message *msg)
+{
+ uint8_t tag;
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+ if (!asn1_read_Integer(data, &msg->messageid)) goto prot_err;
+
+ if (!asn1_peek_uint8(data, &tag)) goto prot_err;
+
+ switch(tag) {
+
+ case ASN1_APPLICATION(LDAP_TAG_BindRequest): {
+ struct ldap_BindRequest *r = &msg->r.BindRequest;
+ msg->type = LDAP_TAG_BindRequest;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_Integer(data, &r->version)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(0))) {
+ int pwlen;
+ r->creds.password = "";
+ r->mechanism = LDAP_AUTH_MECH_SIMPLE;
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto prot_err;
+ pwlen = asn1_tag_remaining(data);
+ if (pwlen == -1) {
+ goto prot_err;
+ }
+ if (pwlen != 0) {
+ char *pw = talloc_array(msg, char, pwlen+1);
+ if (!pw) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ if (!asn1_read(data, pw, pwlen)) goto prot_err;
+ pw[pwlen] = '\0';
+ r->creds.password = pw;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ } else if (asn1_peek_tag(data, ASN1_CONTEXT(3))){
+ if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto prot_err;
+ r->mechanism = LDAP_AUTH_MECH_SASL;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->creds.SASL.mechanism)) goto prot_err;
+ if (asn1_peek_tag(data, ASN1_OCTET_STRING)) { /* optional */
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+ if (!asn1_read_OctetString(data, msg, &tmp_blob)) goto prot_err;
+ r->creds.SASL.secblob = talloc(msg, DATA_BLOB);
+ if (!r->creds.SASL.secblob) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ *r->creds.SASL.secblob = data_blob_talloc(r->creds.SASL.secblob,
+ tmp_blob.data, tmp_blob.length);
+ data_blob_free(&tmp_blob);
+ } else {
+ r->creds.SASL.secblob = NULL;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ } else {
+ /* Neither Simple nor SASL bind */
+ goto prot_err;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_BindResponse): {
+ struct ldap_BindResponse *r = &msg->r.BindResponse;
+ msg->type = LDAP_TAG_BindResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, &r->response)) goto prot_err;
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(7))) {
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+ if (!asn1_read_ContextSimple(data, msg, 7, &tmp_blob)) goto prot_err;
+ r->SASL.secblob = talloc(msg, DATA_BLOB);
+ if (!r->SASL.secblob) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ *r->SASL.secblob = data_blob_talloc(r->SASL.secblob,
+ tmp_blob.data, tmp_blob.length);
+ data_blob_free(&tmp_blob);
+ } else {
+ r->SASL.secblob = NULL;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION_SIMPLE(LDAP_TAG_UnbindRequest): {
+ msg->type = LDAP_TAG_UnbindRequest;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_SearchRequest): {
+ struct ldap_SearchRequest *r = &msg->r.SearchRequest;
+ int sizelimit, timelimit;
+ const char **attrs = NULL;
+ size_t request_size = asn1_get_length(data);
+ msg->type = LDAP_TAG_SearchRequest;
+ if (request_size > limits->max_search_size) {
+ goto prot_err;
+ }
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->basedn)) goto prot_err;
+ if (!asn1_read_enumerated(data, (int *)(void *)&(r->scope))) goto prot_err;
+ if (!asn1_read_enumerated(data, (int *)(void *)&(r->deref))) goto prot_err;
+ if (!asn1_read_Integer(data, &sizelimit)) goto prot_err;
+ r->sizelimit = sizelimit;
+ if (!asn1_read_Integer(data, &timelimit)) goto prot_err;
+ r->timelimit = timelimit;
+ if (!asn1_read_BOOLEAN(data, &r->attributesonly)) goto prot_err;
+
+ r->tree = ldap_decode_filter_tree(msg, data);
+ if (r->tree == NULL) {
+ goto prot_err;
+ }
+
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+
+ r->num_attributes = 0;
+ r->attributes = NULL;
+
+ while (asn1_tag_remaining(data) > 0) {
+
+ const char *attr;
+ if (!asn1_read_OctetString_talloc(msg, data,
+ &attr))
+ goto prot_err;
+ if (!add_string_to_array(msg, attr,
+ &attrs,
+ &r->num_attributes))
+ goto prot_err;
+ }
+ r->attributes = attrs;
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_SearchResultEntry): {
+ struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
+ msg->type = LDAP_TAG_SearchResultEntry;
+ r->attributes = NULL;
+ r->num_attributes = 0;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (!ldap_decode_attribs(msg, data, &r->attributes,
+ &r->num_attributes)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_SearchResultDone): {
+ struct ldap_Result *r = &msg->r.SearchResultDone;
+ msg->type = LDAP_TAG_SearchResultDone;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_SearchResultReference): {
+ struct ldap_SearchResRef *r = &msg->r.SearchResultReference;
+ msg->type = LDAP_TAG_SearchResultReference;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->referral)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ModifyRequest): {
+ struct ldap_ModifyRequest *r = &msg->r.ModifyRequest;
+ msg->type = LDAP_TAG_ModifyRequest;
+ if (!asn1_start_tag(data, ASN1_APPLICATION(LDAP_TAG_ModifyRequest))) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+
+ r->num_mods = 0;
+ r->mods = NULL;
+
+ while (asn1_tag_remaining(data) > 0) {
+ struct ldap_mod mod;
+ int v;
+ ZERO_STRUCT(mod);
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+ if (!asn1_read_enumerated(data, &v)) goto prot_err;
+ mod.type = v;
+ if (!ldap_decode_attrib(msg, data, &mod.attrib)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (!add_mod_to_array_talloc(msg, &mod,
+ &r->mods, &r->num_mods)) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ }
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ModifyResponse): {
+ struct ldap_Result *r = &msg->r.ModifyResponse;
+ msg->type = LDAP_TAG_ModifyResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_AddRequest): {
+ struct ldap_AddRequest *r = &msg->r.AddRequest;
+ msg->type = LDAP_TAG_AddRequest;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+
+ r->attributes = NULL;
+ r->num_attributes = 0;
+ if (!ldap_decode_attribs(msg, data, &r->attributes,
+ &r->num_attributes)) goto prot_err;
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_AddResponse): {
+ struct ldap_Result *r = &msg->r.AddResponse;
+ msg->type = LDAP_TAG_AddResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest): {
+ struct ldap_DelRequest *r = &msg->r.DelRequest;
+ int len;
+ char *dn;
+ msg->type = LDAP_TAG_DelRequest;
+ if (!asn1_start_tag(data,
+ ASN1_APPLICATION_SIMPLE(LDAP_TAG_DelRequest))) goto prot_err;
+ len = asn1_tag_remaining(data);
+ if (len == -1) {
+ goto prot_err;
+ }
+ dn = talloc_array(msg, char, len+1);
+ if (dn == NULL)
+ break;
+ if (!asn1_read(data, dn, len)) goto prot_err;
+ dn[len] = '\0';
+ r->dn = dn;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_DelResponse): {
+ struct ldap_Result *r = &msg->r.DelResponse;
+ msg->type = LDAP_TAG_DelResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest): {
+ struct ldap_ModifyDNRequest *r = &msg->r.ModifyDNRequest;
+ msg->type = LDAP_TAG_ModifyDNRequest;
+ if (!asn1_start_tag(data,
+ ASN1_APPLICATION(LDAP_TAG_ModifyDNRequest))) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->newrdn)) goto prot_err;
+ if (!asn1_read_BOOLEAN(data, &r->deleteolddn)) goto prot_err;
+ r->newsuperior = NULL;
+ if (asn1_tag_remaining(data) > 0) {
+ int len;
+ char *newsup;
+ if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(0))) goto prot_err;
+ len = asn1_tag_remaining(data);
+ if (len == -1) {
+ goto prot_err;
+ }
+ newsup = talloc_array(msg, char, len+1);
+ if (newsup == NULL) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ if (!asn1_read(data, newsup, len)) goto prot_err;
+ newsup[len] = '\0';
+ r->newsuperior = newsup;
+ if (!asn1_end_tag(data)) goto prot_err;
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ModifyDNResponse): {
+ struct ldap_Result *r = &msg->r.ModifyDNResponse;
+ msg->type = LDAP_TAG_ModifyDNResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_CompareRequest): {
+ struct ldap_CompareRequest *r = &msg->r.CompareRequest;
+ msg->type = LDAP_TAG_CompareRequest;
+ if (!asn1_start_tag(data,
+ ASN1_APPLICATION(LDAP_TAG_CompareRequest))) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->dn)) goto prot_err;
+ if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto prot_err;
+ if (!asn1_read_OctetString_talloc(msg, data, &r->attribute)) goto prot_err;
+ if (!asn1_read_OctetString(data, msg, &r->value)) goto prot_err;
+ if (r->value.data) {
+ talloc_steal(msg, r->value.data);
+ }
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_CompareResponse): {
+ struct ldap_Result *r = &msg->r.CompareResponse;
+ msg->type = LDAP_TAG_CompareResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, r)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION_SIMPLE(LDAP_TAG_AbandonRequest): {
+ struct ldap_AbandonRequest *r = &msg->r.AbandonRequest;
+ msg->type = LDAP_TAG_AbandonRequest;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!asn1_read_implicit_Integer(data, &r->messageid)) goto prot_err;
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ExtendedRequest): {
+ struct ldap_ExtendedRequest *r = &msg->r.ExtendedRequest;
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+
+ msg->type = LDAP_TAG_ExtendedRequest;
+ if (!asn1_start_tag(data,tag)) goto prot_err;
+ if (!asn1_read_ContextSimple(data, msg, 0, &tmp_blob)) {
+ goto prot_err;
+ }
+ r->oid = blob2string_talloc(msg, tmp_blob);
+ data_blob_free(&tmp_blob);
+ if (!r->oid) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(1))) {
+ if (!asn1_read_ContextSimple(data, msg, 1, &tmp_blob)) goto prot_err;
+ r->value = talloc(msg, DATA_BLOB);
+ if (!r->value) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ *r->value = data_blob_talloc(r->value, tmp_blob.data, tmp_blob.length);
+ data_blob_free(&tmp_blob);
+ } else {
+ r->value = NULL;
+ }
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+
+ case ASN1_APPLICATION(LDAP_TAG_ExtendedResponse): {
+ struct ldap_ExtendedResponse *r = &msg->r.ExtendedResponse;
+ DATA_BLOB tmp_blob = data_blob(NULL, 0);
+
+ msg->type = LDAP_TAG_ExtendedResponse;
+ if (!asn1_start_tag(data, tag)) goto prot_err;
+ if (!ldap_decode_response(msg, data, &r->response)) goto prot_err;
+
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(10))) {
+ if (!asn1_read_ContextSimple(data, msg, 10, &tmp_blob))
+ goto prot_err;
+ r->oid = blob2string_talloc(msg, tmp_blob);
+ data_blob_free(&tmp_blob);
+ if (!r->oid) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ } else {
+ r->oid = NULL;
+ }
+
+ if (asn1_peek_tag(data, ASN1_CONTEXT_SIMPLE(11))) {
+ if (!asn1_read_ContextSimple(data, msg, 11, &tmp_blob))
+ goto prot_err;
+ r->value = talloc(msg, DATA_BLOB);
+ if (!r->value) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+ *r->value = data_blob_talloc(r->value, tmp_blob.data, tmp_blob.length);
+ data_blob_free(&tmp_blob);
+ } else {
+ r->value = NULL;
+ }
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ break;
+ }
+ default:
+ goto prot_err;
+ }
+
+ msg->controls = NULL;
+ msg->controls_decoded = NULL;
+
+ if (asn1_peek_tag(data, ASN1_CONTEXT(0))) {
+ int i = 0;
+ struct ldb_control **ctrl = NULL;
+ bool *decoded = NULL;
+
+ if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto prot_err;
+
+ while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
+ DATA_BLOB value;
+ /* asn1_start_tag(data, ASN1_SEQUENCE(0)); */
+
+ ctrl = talloc_realloc(msg, ctrl, struct ldb_control *, i+2);
+ if (!ctrl) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+
+ decoded = talloc_realloc(msg, decoded, bool, i+1);
+ if (!decoded) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+
+ ctrl[i] = talloc(ctrl, struct ldb_control);
+ if (!ctrl[i]) {
+ return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
+ }
+
+ if (!ldap_decode_control_wrapper(ctrl[i], data, ctrl[i], &value)) {
+ goto prot_err;
+ }
+
+ if (!ldap_decode_control_value(ctrl[i], value,
+ control_handlers,
+ ctrl[i])) {
+ if (ctrl[i]->critical) {
+ ctrl[i]->data = NULL;
+ decoded[i] = false;
+ i++;
+ } else {
+ talloc_free(ctrl[i]);
+ ctrl[i] = NULL;
+ }
+ } else {
+ decoded[i] = true;
+ i++;
+ }
+ }
+
+ if (ctrl != NULL) {
+ ctrl[i] = NULL;
+ }
+
+ msg->controls = ctrl;
+ msg->controls_decoded = decoded;
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ }
+
+ if (!asn1_end_tag(data)) goto prot_err;
+ if (asn1_has_error(data) || asn1_has_nesting(data)) {
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+ }
+ return NT_STATUS_OK;
+
+ prot_err:
+
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
+}
+
+
+/*
+ return NT_STATUS_OK if a blob has enough bytes in it to be a full
+ ldap packet. Set packet_size if true.
+*/
+NTSTATUS ldap_full_packet(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size)
+{
+ int ret;
+
+ if (blob.length < 6) {
+ /*
+ * We need at least 6 bytes to workout the length
+ * of the pdu.
+ */
+ return STATUS_MORE_ENTRIES;
+ }
+
+ ret = asn1_peek_full_tag(blob, ASN1_SEQUENCE(0), packet_size);
+ if (ret != 0) {
+ return map_nt_error_from_unix_common(ret);
+ }
+ return NT_STATUS_OK;
+}
diff --git a/libcli/ldap/ldap_message.h b/libcli/ldap/ldap_message.h
new file mode 100644
index 0000000..dcbd1e9
--- /dev/null
+++ b/libcli/ldap/ldap_message.h
@@ -0,0 +1,244 @@
+/*
+ Unix SMB/CIFS Implementation.
+ LDAP protocol helper functions for SAMBA
+ 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/>.
+
+*/
+
+#ifndef _LIBCLI_LDAP_MESSAGE_H_
+#define _LIBCLI_LDAP_MESSAGE_H_
+
+#include "../libcli/ldap/ldap_errors.h"
+#include <ldb.h>
+
+enum ldap_request_tag {
+ LDAP_TAG_BindRequest = 0,
+ LDAP_TAG_BindResponse = 1,
+ LDAP_TAG_UnbindRequest = 2,
+ LDAP_TAG_SearchRequest = 3,
+ LDAP_TAG_SearchResultEntry = 4,
+ LDAP_TAG_SearchResultDone = 5,
+ LDAP_TAG_ModifyRequest = 6,
+ LDAP_TAG_ModifyResponse = 7,
+ LDAP_TAG_AddRequest = 8,
+ LDAP_TAG_AddResponse = 9,
+ LDAP_TAG_DelRequest = 10,
+ LDAP_TAG_DelResponse = 11,
+ LDAP_TAG_ModifyDNRequest = 12,
+ LDAP_TAG_ModifyDNResponse = 13,
+ LDAP_TAG_CompareRequest = 14,
+ LDAP_TAG_CompareResponse = 15,
+ LDAP_TAG_AbandonRequest = 16,
+ LDAP_TAG_SearchResultReference = 19,
+ LDAP_TAG_ExtendedRequest = 23,
+ LDAP_TAG_ExtendedResponse = 24
+};
+
+enum ldap_auth_mechanism {
+ LDAP_AUTH_MECH_SIMPLE = 0,
+ LDAP_AUTH_MECH_SASL = 3
+};
+
+struct ldap_Result {
+ int resultcode;
+ const char *dn;
+ const char *errormessage;
+ const char *referral;
+};
+
+struct ldap_BindRequest {
+ int version;
+ const char *dn;
+ enum ldap_auth_mechanism mechanism;
+ union {
+ const char *password;
+ struct {
+ const char *mechanism;
+ DATA_BLOB *secblob;/* optional */
+ } SASL;
+ } creds;
+};
+
+struct ldap_BindResponse {
+ struct ldap_Result response;
+ union {
+ DATA_BLOB *secblob;/* optional */
+ } SASL;
+};
+
+struct ldap_UnbindRequest {
+ uint8_t __dummy;
+};
+
+enum ldap_scope {
+ LDAP_SEARCH_SCOPE_BASE = 0,
+ LDAP_SEARCH_SCOPE_SINGLE = 1,
+ LDAP_SEARCH_SCOPE_SUB = 2
+};
+
+enum ldap_deref {
+ LDAP_DEREFERENCE_NEVER = 0,
+ LDAP_DEREFERENCE_IN_SEARCHING = 1,
+ LDAP_DEREFERENCE_FINDING_BASE = 2,
+ LDAP_DEREFERENCE_ALWAYS
+};
+
+struct ldap_SearchRequest {
+ const char *basedn;
+ enum ldap_scope scope;
+ enum ldap_deref deref;
+ uint32_t timelimit;
+ uint32_t sizelimit;
+ bool attributesonly;
+ struct ldb_parse_tree *tree;
+ size_t num_attributes;
+ const char * const *attributes;
+};
+
+struct ldap_SearchResEntry {
+ const char *dn;
+ int num_attributes;
+ struct ldb_message_element *attributes;
+};
+
+struct ldap_SearchResRef {
+ const char *referral;
+};
+
+enum ldap_modify_type {
+ LDAP_MODIFY_NONE = -1,
+ LDAP_MODIFY_ADD = 0,
+ LDAP_MODIFY_DELETE = 1,
+ LDAP_MODIFY_REPLACE = 2
+};
+
+struct ldap_mod {
+ enum ldap_modify_type type;
+ struct ldb_message_element attrib;
+};
+
+struct ldap_ModifyRequest {
+ const char *dn;
+ int num_mods;
+ struct ldap_mod *mods;
+};
+
+struct ldap_AddRequest {
+ const char *dn;
+ int num_attributes;
+ struct ldb_message_element *attributes;
+};
+
+struct ldap_DelRequest {
+ const char *dn;
+};
+
+struct ldap_ModifyDNRequest {
+ const char *dn;
+ const char *newrdn;
+ bool deleteolddn;
+ const char *newsuperior;/* optional */
+};
+
+struct ldap_CompareRequest {
+ const char *dn;
+ const char *attribute;
+ DATA_BLOB value;
+};
+
+struct ldap_AbandonRequest {
+ int messageid;
+};
+
+struct ldap_ExtendedRequest {
+ const char *oid;
+ DATA_BLOB *value;/* optional */
+};
+
+struct ldap_ExtendedResponse {
+ struct ldap_Result response;
+ const char *oid;/* optional */
+ DATA_BLOB *value;/* optional */
+};
+
+union ldap_Request {
+ struct ldap_Result GeneralResult;
+ struct ldap_BindRequest BindRequest;
+ struct ldap_BindResponse BindResponse;
+ struct ldap_UnbindRequest UnbindRequest;
+ struct ldap_SearchRequest SearchRequest;
+ struct ldap_SearchResEntry SearchResultEntry;
+ struct ldap_Result SearchResultDone;
+ struct ldap_SearchResRef SearchResultReference;
+ struct ldap_ModifyRequest ModifyRequest;
+ struct ldap_Result ModifyResponse;
+ struct ldap_AddRequest AddRequest;
+ struct ldap_Result AddResponse;
+ struct ldap_DelRequest DelRequest;
+ struct ldap_Result DelResponse;
+ struct ldap_ModifyDNRequest ModifyDNRequest;
+ struct ldap_Result ModifyDNResponse;
+ struct ldap_CompareRequest CompareRequest;
+ struct ldap_Result CompareResponse;
+ struct ldap_AbandonRequest AbandonRequest;
+ struct ldap_ExtendedRequest ExtendedRequest;
+ struct ldap_ExtendedResponse ExtendedResponse;
+};
+
+
+struct ldap_message {
+ int messageid;
+ enum ldap_request_tag type;
+ union ldap_Request r;
+ struct ldb_control **controls;
+ bool *controls_decoded;
+};
+
+struct ldap_control_handler {
+ const char *oid;
+ bool (*decode)(void *mem_ctx, DATA_BLOB in, void *_out);
+ bool (*encode)(void *mem_ctx, void *in, DATA_BLOB *out);
+};
+
+struct ldap_request_limits {
+ unsigned max_search_size;
+};
+
+struct asn1_data;
+struct tstream_context;
+
+struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx);
+NTSTATUS ldap_decode(struct asn1_data *data,
+ const struct ldap_request_limits *limits,
+ const struct ldap_control_handler *control_handlers,
+ struct ldap_message *msg);
+bool ldap_encode(struct ldap_message *msg,
+ const struct ldap_control_handler *control_handlers,
+ DATA_BLOB *result, TALLOC_CTX *mem_ctx);
+NTSTATUS ldap_full_packet(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size);
+
+bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
+ struct asn1_data *data,
+ const char **result);
+
+bool ldap_decode_attribs_bare(TALLOC_CTX *mem_ctx, struct asn1_data *data,
+ struct ldb_message_element **attributes,
+ int *num_attributes);
+
+#endif
diff --git a/libcli/ldap/ldap_ndr.c b/libcli/ldap/ldap_ndr.c
new file mode 100644
index 0000000..4f63bc1
--- /dev/null
+++ b/libcli/ldap/ldap_ndr.c
@@ -0,0 +1,95 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ wrap/unwrap NDR encoded elements for ldap calls
+
+ Copyright (C) Andrew Tridgell 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 <ldb.h>
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "libcli/ldap/ldap_ndr.h"
+
+/*
+ encode a NDR uint32 as a ldap filter element
+*/
+char *ldap_encode_ndr_uint32(TALLOC_CTX *mem_ctx, uint32_t value)
+{
+ uint8_t buf[4];
+ struct ldb_val val;
+ SIVAL(buf, 0, value);
+ val.data = buf;
+ val.length = 4;
+ return ldb_binary_encode(mem_ctx, val);
+}
+
+/*
+ encode a NDR dom_sid as a ldap filter element
+*/
+char *ldap_encode_ndr_dom_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ char *ret;
+ ndr_err = ndr_push_struct_blob(&blob, mem_ctx, sid,
+ (ndr_push_flags_fn_t)ndr_push_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NULL;
+ }
+ ret = ldb_binary_encode(mem_ctx, blob);
+ data_blob_free(&blob);
+ return ret;
+}
+
+
+/*
+ encode a NDR GUID as a ldap filter element
+*/
+char *ldap_encode_ndr_GUID(TALLOC_CTX *mem_ctx, const struct GUID *guid)
+{
+ struct GUID_ndr_buf buf = { .buf = {0}, };
+ DATA_BLOB blob = { .data = buf.buf, .length = sizeof(buf.buf), };
+ NTSTATUS status;
+ char *ret;
+ status = GUID_to_ndr_buf(guid, &buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ ret = ldb_binary_encode(mem_ctx, blob);
+ return ret;
+}
+
+/*
+ decode a NDR GUID from a ldap filter element
+*/
+NTSTATUS ldap_decode_ndr_GUID(TALLOC_CTX *mem_ctx, struct ldb_val val, struct GUID *guid)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ blob.data = val.data;
+ blob.length = val.length;
+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, guid,
+ (ndr_pull_flags_fn_t)ndr_pull_GUID);
+ talloc_free(val.data);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ return NT_STATUS_OK;
+}
diff --git a/libcli/ldap/ldap_ndr.h b/libcli/ldap/ldap_ndr.h
new file mode 100644
index 0000000..99af081
--- /dev/null
+++ b/libcli/ldap/ldap_ndr.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ wrap/unwrap NDR encoded elements for ldap calls
+
+ Copyright (C) Andrew Tridgell 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 __LIBCLI_LDAP_LDAP_NDR_H__
+#define __LIBCLI_LDAP_LDAP_NDR_H__
+
+#include "librpc/gen_ndr/ndr_misc.h"
+
+char *ldap_encode_ndr_uint32(TALLOC_CTX *mem_ctx, uint32_t value);
+char *ldap_encode_ndr_dom_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid);
+char *ldap_encode_ndr_GUID(TALLOC_CTX *mem_ctx, const struct GUID *guid);
+NTSTATUS ldap_decode_ndr_GUID(TALLOC_CTX *mem_ctx, struct ldb_val val, struct GUID *guid);
+
+#endif /* __LIBCLI_LDAP_LDAP_NDR_H__ */
+
diff --git a/libcli/ldap/tests/data/10000-or.dat b/libcli/ldap/tests/data/10000-or.dat
new file mode 100644
index 0000000..e2d6de2
--- /dev/null
+++ b/libcli/ldap/tests/data/10000-or.dat
Binary files differ
diff --git a/libcli/ldap/tests/data/ldap-recursive.dat b/libcli/ldap/tests/data/ldap-recursive.dat
new file mode 100644
index 0000000..dd18d85
--- /dev/null
+++ b/libcli/ldap/tests/data/ldap-recursive.dat
Binary files differ
diff --git a/libcli/ldap/tests/data/ldap-starttls-response.dat b/libcli/ldap/tests/data/ldap-starttls-response.dat
new file mode 100644
index 0000000..d4294bf
--- /dev/null
+++ b/libcli/ldap/tests/data/ldap-starttls-response.dat
Binary files differ
diff --git a/libcli/ldap/tests/ldap_message_test.c b/libcli/ldap/tests/ldap_message_test.c
new file mode 100644
index 0000000..bea7b91
--- /dev/null
+++ b/libcli/ldap/tests/ldap_message_test.c
@@ -0,0 +1,345 @@
+/*
+ * Unit tests for ldap_message.
+ *
+ * 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/>.
+ *
+ */
+
+/*
+ * 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 <setjmp.h>
+#include <cmocka.h>
+
+#include "lib/util/attr.h"
+#include "includes.h"
+#include "lib/util/asn1.h"
+#include "libcli/ldap/ldap_message.h"
+#include "libcli/ldap/ldap_proto.h"
+
+/*
+ * declare the internal cmocka cm_print so we can output messages in
+ * sub unit format
+ */
+void cm_print_error(const char * const format, ...);
+/*
+ * helper function and macro to compare an ldap error code constant with the
+ * corresponding nt_status code
+ */
+#define NT_STATUS_LDAP_V(code) (0xF2000000 | code)
+static void _assert_ldap_status_equal(
+ int a,
+ NTSTATUS b,
+ const char * const file,
+ const int line)
+{
+ _assert_int_equal(NT_STATUS_LDAP_V(a), NT_STATUS_V(b), file, line);
+}
+
+#define assert_ldap_status_equal(a, b) \
+ _assert_ldap_status_equal((a), (b), __FILE__, __LINE__)
+
+/*
+ * helper function and macro to assert there were no errors in the last
+ * file operation
+ */
+static void _assert_not_ferror(
+ FILE *f,
+ const char * const file,
+ const int line)
+{
+ if (f == NULL || ferror(f)) {
+ cm_print_error("ferror (%d) %s\n", errno, strerror(errno));
+ _fail(file, line);
+ }
+}
+
+#define assert_not_ferror(f) \
+ _assert_not_ferror((f), __FILE__, __LINE__)
+
+struct test_ctx {
+};
+
+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 an empty request is handled correctly
+ */
+static void test_empty_input(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ uint8_t *buf = NULL;
+ size_t len = 0;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
+ assert_non_null(asn1);
+
+ asn1_load_nocopy(asn1, buf, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
+}
+
+/*
+ * Check that a request is rejected it it's recursion depth exceeds
+ * the maximum value specified. This test uses a very deeply nested query,
+ * 10,000 or clauses.
+ *
+ */
+static void test_recursion_depth_large(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ /*
+ * Load a test data file containing 10,000 or clauses in encoded as
+ * an ASN.1 packet.
+ */
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/10000-or.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
+}
+
+/*
+ * Check that a request is not rejected it it's recursion depth equals the
+ * maximum value
+ */
+static void test_recursion_depth_equals_max(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ int ret;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, 4);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ret = fclose(f);
+ f = NULL;
+ assert_true(ret == 0);
+}
+
+/*
+ * Check that a request is rejected it it's recursion depth is greater than the
+ * maximum value
+ */
+static void test_recursion_depth_greater_than_max(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ int ret;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, 3);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
+
+ ret = fclose(f);
+ f = NULL;
+ assert_true(ret == 0);
+}
+
+/*
+ * Check we can decode an exop response
+ */
+static void test_decode_exop_response(void **state)
+{
+ struct test_ctx *test_ctx = talloc_get_type_abort(
+ *state,
+ struct test_ctx);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ NTSTATUS status;
+ FILE *f = NULL;
+ uint8_t *buffer = NULL;
+ const size_t BUFF_SIZE = 1048576;
+ size_t len;
+ int ret;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
+
+
+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
+ f = fopen("./libcli/ldap/tests/data/ldap-starttls-response.dat", "r");
+ assert_not_ferror(f);
+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
+ assert_not_ferror(f);
+ assert_true(len > 0);
+
+ asn1 = asn1_init(test_ctx, 3);
+ assert_non_null(asn1);
+ asn1_load_nocopy(asn1, buffer, len);
+
+ ldap_msg = talloc(test_ctx, struct ldap_message);
+ assert_non_null(ldap_msg);
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ ret = fclose(f);
+ f = NULL;
+ assert_true(ret == 0);
+}
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_empty_input,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_recursion_depth_large,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_recursion_depth_equals_max,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_recursion_depth_greater_than_max,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_decode_exop_response,
+ setup,
+ teardown),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/ldap/wscript_build b/libcli/ldap/wscript_build
new file mode 100644
index 0000000..a646685
--- /dev/null
+++ b/libcli/ldap/wscript_build
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+bld.SAMBA_LIBRARY('cli-ldap-common',
+ source='ldap_message.c ldap_ndr.c',
+ public_deps='samba-errors talloc ldb',
+ private_headers='ldap_message.h ldap_errors.h ldap_ndr.h',
+ deps='samba-util asn1util NDR_SECURITY tevent',
+ private_library=True)
+
+bld.SAMBA_BINARY(
+ 'test_ldap_message',
+ source='tests/ldap_message_test.c',
+ deps='''
+ cmocka
+ talloc
+ ldb
+ samba-util
+ asn1util
+ NDR_SECURITY
+ cli-ldap
+ ''',
+ for_selftest=True
+)
diff --git a/libcli/lsarpc/util_lsarpc.c b/libcli/lsarpc/util_lsarpc.c
new file mode 100644
index 0000000..96c9848
--- /dev/null
+++ b/libcli/lsarpc/util_lsarpc.c
@@ -0,0 +1,359 @@
+/*
+ Unix SMB/CIFS implementation.
+ Authentication utility functions
+ Copyright (C) Sumit Bose 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 "../librpc/gen_ndr/ndr_drsblobs.h"
+#include "../librpc/gen_ndr/ndr_lsa.h"
+#include "libcli/lsarpc/util_lsarpc.h"
+
+static NTSTATUS ai_array_2_trust_domain_info_buffer(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct AuthenticationInformationArray *ai,
+ struct lsa_TrustDomainInfoBuffer **_b)
+{
+ NTSTATUS status;
+ struct lsa_TrustDomainInfoBuffer *b;
+ int i;
+
+ b = talloc_array(mem_ctx, struct lsa_TrustDomainInfoBuffer, count);
+ if (b == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for(i = 0; i < count; i++) {
+ size_t size = 0;
+ b[i].last_update_time = ai->array[i].LastUpdateTime;
+ b[i].AuthType = ai->array[i].AuthType;
+ switch(ai->array[i].AuthType) {
+ case TRUST_AUTH_TYPE_NONE:
+ b[i].data.size = 0;
+ b[i].data.data = NULL;
+ break;
+ case TRUST_AUTH_TYPE_NT4OWF:
+ if (ai->array[i].AuthInfo.nt4owf.size != 16) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ b[i].data.data = (uint8_t *)talloc_memdup(b,
+ &ai->array[i].AuthInfo.nt4owf.password.hash,
+ 16);
+ if (b[i].data.data == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ break;
+ case TRUST_AUTH_TYPE_CLEAR:
+ if (!convert_string_talloc(b,
+ CH_UTF16LE, CH_UNIX,
+ ai->array[i].AuthInfo.clear.password,
+ ai->array[i].AuthInfo.clear.size,
+ &b[i].data.data,
+ &size)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ b[i].data.size = size;
+ break;
+ case TRUST_AUTH_TYPE_VERSION:
+ if (ai->array[i].AuthInfo.version.size != 4) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ b[i].data.size = 4;
+ b[i].data.data = (uint8_t *)talloc_memdup(b,
+ &ai->array[i].AuthInfo.version.version, 4);
+ if (b[i].data.data == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ break;
+ default:
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ }
+
+ *_b = b;
+
+ return NT_STATUS_OK;
+
+fail:
+ talloc_free(b);
+ return status;
+}
+
+static NTSTATUS trustauth_inout_blob_2_auth_info(TALLOC_CTX *mem_ctx,
+ DATA_BLOB *inout_blob,
+ uint32_t *count,
+ struct lsa_TrustDomainInfoBuffer **current,
+ struct lsa_TrustDomainInfoBuffer **previous)
+{
+ NTSTATUS status;
+ struct trustAuthInOutBlob iopw;
+ enum ndr_err_code ndr_err;
+ TALLOC_CTX *tmp_ctx;
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_pull_struct_blob(inout_blob, tmp_ctx, &iopw,
+ (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ *count = iopw.count;
+
+ status = ai_array_2_trust_domain_info_buffer(mem_ctx, iopw.count,
+ &iopw.current, current);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (iopw.previous.count > 0) {
+ status = ai_array_2_trust_domain_info_buffer(mem_ctx, iopw.count,
+ &iopw.previous, previous);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ } else {
+ *previous = NULL;
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+NTSTATUS auth_blob_2_auth_info(TALLOC_CTX *mem_ctx,
+ DATA_BLOB incoming, DATA_BLOB outgoing,
+ struct lsa_TrustDomainInfoAuthInfo *auth_info)
+{
+ NTSTATUS status;
+
+ if (incoming.length != 0) {
+ status = trustauth_inout_blob_2_auth_info(mem_ctx,
+ &incoming,
+ &auth_info->incoming_count,
+ &auth_info->incoming_current_auth_info,
+ &auth_info->incoming_previous_auth_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ auth_info->incoming_count = 0;
+ auth_info->incoming_current_auth_info = NULL;
+ auth_info->incoming_previous_auth_info = NULL;
+ }
+
+ if (outgoing.length != 0) {
+ status = trustauth_inout_blob_2_auth_info(mem_ctx,
+ &outgoing,
+ &auth_info->outgoing_count,
+ &auth_info->outgoing_current_auth_info,
+ &auth_info->outgoing_previous_auth_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ } else {
+ auth_info->outgoing_count = 0;
+ auth_info->outgoing_current_auth_info = NULL;
+ auth_info->outgoing_previous_auth_info = NULL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS trust_domain_info_buffer_2_ai_array(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct lsa_TrustDomainInfoBuffer *b,
+ struct AuthenticationInformationArray *ai)
+{
+ NTSTATUS status;
+ int i;
+
+ ai->count = count;
+ ai->array = talloc_zero_array(mem_ctx, struct AuthenticationInformation,
+ count);
+ if (ai->array == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for(i = 0; i < count; i++) {
+ size_t size = 0;
+ ai->array[i].LastUpdateTime = b[i].last_update_time;
+ ai->array[i].AuthType = b[i].AuthType;
+ switch(ai->array[i].AuthType) {
+ case TRUST_AUTH_TYPE_NONE:
+ ai->array[i].AuthInfo.none.size = 0;
+ break;
+ case TRUST_AUTH_TYPE_NT4OWF:
+ if (b[i].data.size != 16) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ memcpy(&ai->array[i].AuthInfo.nt4owf.password.hash,
+ b[i].data.data, 16);
+ break;
+ case TRUST_AUTH_TYPE_CLEAR:
+ if (!convert_string_talloc(ai->array,
+ CH_UNIX, CH_UTF16,
+ b[i].data.data,
+ b[i].data.size,
+ &ai->array[i].AuthInfo.clear.password,
+ &size)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ai->array[i].AuthInfo.clear.size = size;
+ break;
+ case TRUST_AUTH_TYPE_VERSION:
+ if (b[i].data.size != 4) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ai->array[i].AuthInfo.version.size = 4;
+ memcpy(&ai->array[i].AuthInfo.version.version,
+ b[i].data.data, 4);
+ break;
+ default:
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ }
+
+ return NT_STATUS_OK;
+
+fail:
+ talloc_free(ai->array);
+ return status;
+}
+
+NTSTATUS auth_info_2_trustauth_inout(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct lsa_TrustDomainInfoBuffer *current,
+ struct lsa_TrustDomainInfoBuffer *previous,
+ struct trustAuthInOutBlob **iopw_out)
+{
+ NTSTATUS status;
+ struct trustAuthInOutBlob *iopw;
+
+ iopw = talloc_zero(mem_ctx, struct trustAuthInOutBlob);
+ if (iopw == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ iopw->count = count;
+ status = trust_domain_info_buffer_2_ai_array(iopw, count, current,
+ &iopw->current);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (previous != NULL) {
+ status = trust_domain_info_buffer_2_ai_array(iopw, count,
+ previous,
+ &iopw->previous);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+ } else {
+ iopw->previous.count = 0;
+ iopw->previous.array = NULL;
+ }
+
+ *iopw_out = iopw;
+
+ status = NT_STATUS_OK;
+
+done:
+ return status;
+}
+
+static NTSTATUS auth_info_2_trustauth_inout_blob(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct lsa_TrustDomainInfoBuffer *current,
+ struct lsa_TrustDomainInfoBuffer *previous,
+ DATA_BLOB *inout_blob)
+{
+ NTSTATUS status;
+ struct trustAuthInOutBlob *iopw = NULL;
+ enum ndr_err_code ndr_err;
+
+ status = auth_info_2_trustauth_inout(mem_ctx, count, current, previous, &iopw);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ ndr_err = ndr_push_struct_blob(inout_blob, mem_ctx,
+ iopw,
+ (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ talloc_free(iopw);
+ return status;
+}
+
+NTSTATUS auth_info_2_auth_blob(TALLOC_CTX *mem_ctx,
+ struct lsa_TrustDomainInfoAuthInfo *auth_info,
+ DATA_BLOB *incoming, DATA_BLOB *outgoing)
+{
+ NTSTATUS status;
+
+ if (auth_info->incoming_count == 0) {
+ incoming->length = 0;
+ incoming->data = NULL;
+ } else {
+ status = auth_info_2_trustauth_inout_blob(mem_ctx,
+ auth_info->incoming_count,
+ auth_info->incoming_current_auth_info,
+ auth_info->incoming_previous_auth_info,
+ incoming);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (auth_info->outgoing_count == 0) {
+ outgoing->length = 0;
+ outgoing->data = NULL;
+ } else {
+ status = auth_info_2_trustauth_inout_blob(mem_ctx,
+ auth_info->outgoing_count,
+ auth_info->outgoing_current_auth_info,
+ auth_info->outgoing_previous_auth_info,
+ outgoing);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/lsarpc/util_lsarpc.h b/libcli/lsarpc/util_lsarpc.h
new file mode 100644
index 0000000..8bfec28
--- /dev/null
+++ b/libcli/lsarpc/util_lsarpc.h
@@ -0,0 +1,38 @@
+/*
+ Unix SMB/CIFS implementation.
+ Authentication utility functions
+ Copyright (C) Sumit Bose 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 _LIBCLI_AUTH_UTIL_LSARPC_H_
+#define _LIBCLI_AUTH_UTIL_LSARPC_H_
+
+/* The following definitions come from libcli/auth/util_lsarpc.c */
+struct trustAuthInOutBlob;
+
+NTSTATUS auth_blob_2_auth_info(TALLOC_CTX *mem_ctx,
+ DATA_BLOB incoming, DATA_BLOB outgoing,
+ struct lsa_TrustDomainInfoAuthInfo *auth_info);
+NTSTATUS auth_info_2_trustauth_inout(TALLOC_CTX *mem_ctx,
+ uint32_t count,
+ struct lsa_TrustDomainInfoBuffer *current,
+ struct lsa_TrustDomainInfoBuffer *previous,
+ struct trustAuthInOutBlob **iopw_out);
+NTSTATUS auth_info_2_auth_blob(TALLOC_CTX *mem_ctx,
+ struct lsa_TrustDomainInfoAuthInfo *auth_info,
+ DATA_BLOB *incoming, DATA_BLOB *outgoing);
+
+#endif /* _LIBCLI_AUTH_UTIL_LSARPC_H_ */
diff --git a/libcli/lsarpc/wscript_build b/libcli/lsarpc/wscript_build
new file mode 100644
index 0000000..c613d66
--- /dev/null
+++ b/libcli/lsarpc/wscript_build
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('UTIL_LSARPC',
+ source='util_lsarpc.c',
+ deps='NDR_LSA NDR_DRSBLOBS');
diff --git a/libcli/named_pipe_auth/npa_tstream.c b/libcli/named_pipe_auth/npa_tstream.c
new file mode 100644
index 0000000..a72519e
--- /dev/null
+++ b/libcli/named_pipe_auth/npa_tstream.c
@@ -0,0 +1,1406 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 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/network.h"
+#include "../util/tevent_unix.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../lib/tsocket/tsocket_internal.h"
+#include "../librpc/gen_ndr/ndr_named_pipe_auth.h"
+#include "../libcli/named_pipe_auth/npa_tstream.h"
+#include "../libcli/named_pipe_auth/tstream_u32_read.h"
+#include "../libcli/smb/smb_constants.h"
+
+static const struct tstream_context_ops tstream_npa_ops;
+
+struct tstream_npa {
+ struct tstream_context *unix_stream;
+
+ uint16_t file_type;
+
+ struct iovec pending;
+};
+
+struct tstream_npa_connect_state {
+ struct {
+ struct tevent_context *ev;
+ } caller;
+
+ const char *unix_path;
+ struct tsocket_address *unix_laddr;
+ struct tsocket_address *unix_raddr;
+ struct tstream_context *unix_stream;
+
+ struct named_pipe_auth_req auth_req;
+ DATA_BLOB auth_req_blob;
+ struct iovec auth_req_iov;
+
+ struct named_pipe_auth_rep auth_rep;
+};
+
+static void tstream_npa_connect_unix_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *directory,
+ const char *npipe,
+ enum dcerpc_transport_t transport,
+ const struct tsocket_address *remote_client_addr,
+ const char *remote_client_name_in,
+ const struct tsocket_address *local_server_addr,
+ const char *local_server_name_in,
+ const struct auth_session_info_transport *session_info)
+{
+ struct tevent_req *req;
+ struct tstream_npa_connect_state *state;
+ struct tevent_req *subreq;
+ int ret;
+ enum ndr_err_code ndr_err;
+ char *lower_case_npipe;
+ struct named_pipe_auth_req_info8 *info8;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_connect_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.ev = ev;
+
+ lower_case_npipe = strlower_talloc(state, npipe);
+ if (tevent_req_nomem(lower_case_npipe, req)) {
+ goto post;
+ }
+
+ state->unix_path = talloc_asprintf(state, "%s/%s",
+ directory,
+ lower_case_npipe);
+ talloc_free(lower_case_npipe);
+ if (tevent_req_nomem(state->unix_path, req)) {
+ goto post;
+ }
+
+ ret = tsocket_address_unix_from_path(state,
+ "",
+ &state->unix_laddr);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ ret = tsocket_address_unix_from_path(state,
+ state->unix_path,
+ &state->unix_raddr);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ ZERO_STRUCT(state->auth_req);
+
+ if (!local_server_addr) {
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ state->auth_req.level = 8;
+ info8 = &state->auth_req.info.info8;
+
+ info8->transport = transport;
+ SMB_ASSERT(info8->transport == transport); /* Assert no overflow */
+
+ info8->remote_client_name = remote_client_name_in;
+ info8->remote_client_addr =
+ tsocket_address_inet_addr_string(remote_client_addr, state);
+ if (!info8->remote_client_addr) {
+ /* errno might be EINVAL */
+ tevent_req_error(req, errno);
+ goto post;
+ }
+ info8->remote_client_port =
+ tsocket_address_inet_port(remote_client_addr);
+ if (!info8->remote_client_name) {
+ info8->remote_client_name = info8->remote_client_addr;
+ }
+
+ info8->local_server_name = local_server_name_in;
+ info8->local_server_addr =
+ tsocket_address_inet_addr_string(local_server_addr, state);
+ if (!info8->local_server_addr) {
+ /* errno might be EINVAL */
+ tevent_req_error(req, errno);
+ goto post;
+ }
+ info8->local_server_port =
+ tsocket_address_inet_port(local_server_addr);
+ if (!info8->local_server_name) {
+ info8->local_server_name = info8->local_server_addr;
+ }
+
+ info8->session_info =
+ discard_const_p(struct auth_session_info_transport,
+ session_info);
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
+ }
+
+ ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
+ state, &state->auth_req,
+ (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ state->auth_req_iov.iov_base = (char *) state->auth_req_blob.data;
+ state->auth_req_iov.iov_len = state->auth_req_blob.length;
+
+ subreq = tstream_unix_connect_send(state,
+ state->caller.ev,
+ state->unix_laddr,
+ state->unix_raddr);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
+
+ return req;
+
+post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
+
+static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_connect_state *state =
+ tevent_req_data(req,
+ struct tstream_npa_connect_state);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_unix_connect_recv(subreq, &sys_errno,
+ state, &state->unix_stream);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ subreq = tstream_writev_send(state,
+ state->caller.ev,
+ state->unix_stream,
+ &state->auth_req_iov, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
+}
+
+static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
+
+static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_connect_state *state =
+ tevent_req_data(req,
+ struct tstream_npa_connect_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;
+ }
+
+ subreq = tstream_u32_read_send(
+ state, state->caller.ev, 0x00FFFFFF, state->unix_stream);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
+}
+
+static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_connect_state *state =
+ tevent_req_data(req,
+ struct tstream_npa_connect_state);
+ DATA_BLOB in;
+ int err;
+ enum ndr_err_code ndr_err;
+
+ err = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
+ TALLOC_FREE(subreq);
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ DBG_DEBUG("name_pipe_auth_rep(client)[%zu]\n", in.length);
+ dump_data(11, in.data, in.length);
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &in,
+ state,
+ &state->auth_rep,
+ (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
+ ndr_map_error2string(ndr_err)));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
+ }
+
+ if (state->auth_rep.length < 16) {
+ DEBUG(0, ("req invalid length: %u < 16\n",
+ state->auth_rep.length));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
+ DEBUG(0, ("req invalid magic: %s != %s\n",
+ state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
+ DEBUG(0, ("req failed: %s\n",
+ nt_errstr(state->auth_rep.status)));
+ tevent_req_error(req, EACCES);
+ return;
+ }
+
+ if (state->auth_rep.level != state->auth_req.level) {
+ DEBUG(0, ("req invalid level: %u != %u\n",
+ state->auth_rep.level, state->auth_req.level));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+int _tstream_npa_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **_stream,
+ uint16_t *_file_type,
+ uint16_t *_device_state,
+ uint64_t *_allocation_size,
+ const char *location)
+{
+ struct tstream_npa_connect_state *state =
+ tevent_req_data(req,
+ struct tstream_npa_connect_state);
+ struct tstream_context *stream;
+ struct tstream_npa *npas;
+ uint16_t device_state = 0;
+ uint64_t allocation_size = 0;
+
+ if (tevent_req_is_unix_error(req, perrno)) {
+ tevent_req_received(req);
+ return -1;
+ }
+
+ stream = tstream_context_create(mem_ctx,
+ &tstream_npa_ops,
+ &npas,
+ struct tstream_npa,
+ location);
+ if (!stream) {
+ *perrno = ENOMEM;
+ tevent_req_received(req);
+ return -1;
+ }
+ ZERO_STRUCTP(npas);
+
+ npas->unix_stream = talloc_move(stream, &state->unix_stream);
+ switch (state->auth_rep.level) {
+ case 8:
+ npas->file_type = state->auth_rep.info.info8.file_type;
+ device_state = state->auth_rep.info.info8.device_state;
+ allocation_size = state->auth_rep.info.info8.allocation_size;
+ break;
+ }
+
+ *_stream = stream;
+ *_file_type = npas->file_type;
+ *_device_state = device_state;
+ *_allocation_size = allocation_size;
+ tevent_req_received(req);
+ return 0;
+}
+
+static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
+{
+ struct tstream_npa *npas = tstream_context_data(stream,
+ struct tstream_npa);
+ ssize_t ret;
+
+ if (!npas->unix_stream) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ switch (npas->file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ ret = tstream_pending_bytes(npas->unix_stream);
+ break;
+
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ ret = npas->pending.iov_len;
+ break;
+
+ default:
+ ret = -1;
+ }
+
+ return ret;
+}
+
+struct tstream_npa_readv_state {
+ struct tstream_context *stream;
+
+ struct iovec *vector;
+ size_t count;
+
+ /* the header for message mode */
+ uint8_t hdr[2];
+ bool wait_for_hdr;
+
+ int ret;
+};
+
+static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
+static int tstream_npa_readv_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count);
+static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_npa_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_npa_readv_state *state;
+ struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
+ struct tevent_req *subreq;
+ off_t ofs;
+ size_t left;
+ uint8_t *pbase;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_readv_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->stream = stream;
+ state->ret = 0;
+
+ if (!npas->unix_stream) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ switch (npas->file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ state->vector = vector;
+ state->count = count;
+
+ subreq = tstream_readv_send(state,
+ ev,
+ npas->unix_stream,
+ state->vector,
+ state->count);
+ if (tevent_req_nomem(subreq,req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_npa_readv_byte_mode_handler,
+ req);
+
+ return req;
+
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ /*
+ * we make a copy of the vector and prepend a header
+ * with the length
+ */
+ 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;
+
+ /*
+ * copy the pending buffer first
+ */
+ ofs = 0;
+ left = npas->pending.iov_len;
+ pbase = (uint8_t *)npas->pending.iov_base;
+
+ while (left > 0 && state->count > 0) {
+ uint8_t *base;
+ base = (uint8_t *)state->vector[0].iov_base;
+ if (left < state->vector[0].iov_len) {
+ memcpy(base, pbase + ofs, left);
+
+ base += left;
+ state->vector[0].iov_base = (char *) base;
+ state->vector[0].iov_len -= left;
+
+ ofs += left;
+ left = 0;
+ TALLOC_FREE(pbase);
+ ZERO_STRUCT(npas->pending);
+ break;
+ }
+ memcpy(base, pbase + ofs, state->vector[0].iov_len);
+
+ ofs += state->vector[0].iov_len;
+ left -= state->vector[0].iov_len;
+ state->vector += 1;
+ state->count -= 1;
+
+ if (left == 0) {
+ TALLOC_FREE(pbase);
+ ZERO_STRUCT(npas->pending);
+ break;
+ }
+ }
+
+ if (left > 0) {
+ memmove(pbase, pbase + ofs, left);
+ npas->pending.iov_base = (char *) pbase;
+ npas->pending.iov_len = left;
+ /*
+ * this cannot fail and even if it
+ * fails we can handle it
+ */
+ pbase = talloc_realloc(npas, pbase, uint8_t, left);
+ if (pbase) {
+ npas->pending.iov_base = (char *) pbase;
+ }
+ pbase = NULL;
+ }
+
+ state->ret += ofs;
+
+ if (state->count == 0) {
+ tevent_req_done(req);
+ goto post;
+ }
+
+ ZERO_STRUCT(state->hdr);
+ state->wait_for_hdr = false;
+
+ subreq = tstream_readv_pdu_send(state,
+ ev,
+ npas->unix_stream,
+ tstream_npa_readv_next_vector,
+ state);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_npa_readv_msg_mode_handler,
+ req);
+
+ return req;
+ }
+
+ /* this can't happen */
+ tevent_req_error(req, EINVAL);
+ goto post;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_readv_state *state = tevent_req_data(req,
+ struct tstream_npa_readv_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->ret = ret;
+
+ tevent_req_done(req);
+}
+
+static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count)
+{
+ struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
+ struct tstream_npa_readv_state);
+ struct tstream_npa *npas = tstream_context_data(state->stream,
+ struct tstream_npa);
+ struct iovec *vector;
+ size_t count;
+ uint16_t msg_len;
+ size_t left;
+
+ if (state->count == 0) {
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
+ }
+
+ if (!state->wait_for_hdr) {
+ /* we need to get a message header */
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (!vector) {
+ return -1;
+ }
+ ZERO_STRUCT(state->hdr);
+ vector[0].iov_base = (char *) state->hdr;
+ vector[0].iov_len = sizeof(state->hdr);
+
+ count = 1;
+
+ state->wait_for_hdr = true;
+
+ *_vector = vector;
+ *_count = count;
+ return 0;
+ }
+
+ /* and now fill the callers buffers and maybe the pending buffer */
+ state->wait_for_hdr = false;
+
+ msg_len = SVAL(state->hdr, 0);
+
+ if (msg_len == 0) {
+ errno = EIO;
+ return -1;
+ }
+
+ state->wait_for_hdr = false;
+
+ /* +1 because we may need to fill the pending buffer */
+ vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
+ if (!vector) {
+ return -1;
+ }
+
+ count = 0;
+ left = msg_len;
+ while (left > 0 && state->count > 0) {
+ if (left < state->vector[0].iov_len) {
+ uint8_t *base;
+ base = (uint8_t *)state->vector[0].iov_base;
+ vector[count].iov_base = (char *) base;
+ vector[count].iov_len = left;
+ count++;
+ base += left;
+ state->vector[0].iov_base = (char *) base;
+ state->vector[0].iov_len -= left;
+ break;
+ }
+ vector[count] = state->vector[0];
+ count++;
+ left -= state->vector[0].iov_len;
+ state->vector += 1;
+ state->count -= 1;
+ }
+
+ if (left > 0) {
+ /*
+ * if the message is longer than the buffers the caller
+ * requested, we need to consume the rest of the message
+ * into the pending buffer, where the next readv can
+ * be served from.
+ */
+ npas->pending.iov_base = talloc_array(npas, char, left);
+ if (!npas->pending.iov_base) {
+ return -1;
+ }
+ npas->pending.iov_len = left;
+
+ vector[count] = npas->pending;
+ count++;
+ }
+
+ state->ret += (msg_len - left);
+
+ *_vector = vector;
+ *_count = count;
+ return 0;
+}
+
+static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ 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;
+ }
+
+ /*
+ * we do not set state->ret here as ret includes the header size.
+ * we set it in tstream_npa_readv_pdu_next_vector()
+ */
+
+ tevent_req_done(req);
+}
+
+static int tstream_npa_readv_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_npa_readv_state *state = tevent_req_data(req,
+ struct tstream_npa_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_npa_writev_state {
+ const struct iovec *vector;
+ size_t count;
+
+ /* the header for message mode */
+ bool hdr_used;
+ uint8_t hdr[2];
+
+ int ret;
+};
+
+static void tstream_npa_writev_handler(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_npa_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_npa_writev_state *state;
+ struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
+ struct tevent_req *subreq;
+ size_t msg_len;
+ size_t i;
+ struct iovec *new_vector;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_writev_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->ret = 0;
+
+ if (!npas->unix_stream) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ switch (npas->file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ state->hdr_used = false;
+ state->vector = vector;
+ state->count = count;
+ break;
+
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ /*
+ * we make a copy of the vector and prepend a header
+ * with the length
+ */
+ new_vector = talloc_array(state, struct iovec, count + 1);
+ if (tevent_req_nomem(new_vector, req)) {
+ goto post;
+ }
+ new_vector[0].iov_base = (char *) state->hdr;
+ new_vector[0].iov_len = sizeof(state->hdr);
+ memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
+
+ state->hdr_used = true;
+ state->vector = new_vector;
+ state->count = count + 1;
+
+ msg_len = 0;
+ for (i=0; i < count; i++) {
+ /*
+ * overflow check already done in tstream_writev_send
+ */
+ msg_len += vector[i].iov_len;
+ }
+
+ if (msg_len > UINT16_MAX) {
+ tevent_req_error(req, EMSGSIZE);
+ goto post;
+ }
+
+ SSVAL(state->hdr, 0, msg_len);
+ break;
+ }
+
+ subreq = tstream_writev_send(state,
+ ev,
+ npas->unix_stream,
+ state->vector,
+ state->count);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_writev_handler(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_writev_state *state = tevent_req_data(req,
+ struct tstream_npa_writev_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;
+ }
+
+ /*
+ * in message mode we need to hide the length
+ * of the hdr from the caller
+ */
+ if (state->hdr_used) {
+ ret -= sizeof(state->hdr);
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+static int tstream_npa_writev_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_npa_writev_state *state = tevent_req_data(req,
+ struct tstream_npa_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_npa_disconnect_state {
+ struct tstream_context *stream;
+};
+
+static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream)
+{
+ struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
+ struct tevent_req *req;
+ struct tstream_npa_disconnect_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->stream = stream;
+
+ if (!npas->unix_stream) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ subreq = tstream_disconnect_send(state,
+ ev,
+ npas->unix_stream);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
+
+ return req;
+
+post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_npa_disconnect_state *state = tevent_req_data(req,
+ struct tstream_npa_disconnect_state);
+ struct tstream_context *stream = state->stream;
+ struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
+ int ret;
+ int sys_errno;
+
+ ret = tstream_disconnect_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ TALLOC_FREE(npas->unix_stream);
+
+ tevent_req_done(req);
+}
+
+static int tstream_npa_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_npa_ops = {
+ .name = "npa",
+
+ .pending_bytes = tstream_npa_pending_bytes,
+
+ .readv_send = tstream_npa_readv_send,
+ .readv_recv = tstream_npa_readv_recv,
+
+ .writev_send = tstream_npa_writev_send,
+ .writev_recv = tstream_npa_writev_recv,
+
+ .disconnect_send = tstream_npa_disconnect_send,
+ .disconnect_recv = tstream_npa_disconnect_recv,
+};
+
+int _tstream_npa_existing_stream(TALLOC_CTX *mem_ctx,
+ struct tstream_context **transport,
+ uint16_t file_type,
+ struct tstream_context **_stream,
+ const char *location)
+{
+ struct tstream_context *stream;
+ struct tstream_npa *npas;
+
+ switch (file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ break;
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ stream = tstream_context_create(mem_ctx,
+ &tstream_npa_ops,
+ &npas,
+ struct tstream_npa,
+ location);
+ if (!stream) {
+ return -1;
+ }
+
+ *npas = (struct tstream_npa) {
+ .file_type = file_type,
+ .unix_stream = talloc_move(npas, transport),
+ };
+
+ *_stream = stream;
+ return 0;
+}
+
+int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t file_type,
+ struct tstream_context **_stream,
+ const char *location)
+{
+ struct tstream_context *transport = NULL;
+ int ret;
+
+ ret = _tstream_bsd_existing_socket(
+ mem_ctx, fd, &transport, location);
+ if (ret == -1) {
+ return -1;
+ }
+ /* as server we want to fail early */
+ tstream_bsd_fail_readv_first_error(transport, true);
+ return _tstream_npa_existing_stream(
+ mem_ctx, &transport, file_type, _stream, location);
+}
+
+struct tstream_npa_accept_state {
+ struct tevent_context *ev;
+ struct tstream_context *plain;
+ uint16_t file_type;
+ uint16_t device_state;
+ uint64_t alloc_size;
+
+ struct named_pipe_auth_req *pipe_request;
+
+ DATA_BLOB npa_blob;
+ struct iovec out_iov;
+
+ /* results */
+ NTSTATUS accept_status;
+ struct tsocket_address *remote_client_addr;
+ struct tsocket_address *local_server_addr;
+};
+
+static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
+static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *plain,
+ uint16_t file_type,
+ uint16_t device_state,
+ uint64_t allocation_size)
+{
+ struct tstream_npa_accept_state *state;
+ struct tevent_req *req, *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_npa_accept_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ switch (file_type) {
+ case FILE_TYPE_BYTE_MODE_PIPE:
+ break;
+ case FILE_TYPE_MESSAGE_MODE_PIPE:
+ break;
+ default:
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ state->ev = ev;
+ state->plain = plain;
+ state->file_type = file_type;
+ state->device_state = device_state;
+ state->alloc_size = allocation_size;
+
+ subreq = tstream_u32_read_send(state, ev, 0x00FFFFFF, plain);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+
+ tevent_req_set_callback(subreq,
+ tstream_npa_accept_existing_reply, req);
+
+ return req;
+
+post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_npa_accept_state *state =
+ tevent_req_data(req, struct tstream_npa_accept_state);
+ struct named_pipe_auth_req *pipe_request;
+ struct named_pipe_auth_rep pipe_reply;
+ struct named_pipe_auth_req_info8 i8;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB in, out;
+ int err;
+ int ret;
+
+ err = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
+ if (err != 0) {
+ tevent_req_error(req, err);
+ return;
+ }
+ if (in.length < 8) {
+ tevent_req_error(req, EMSGSIZE);
+ return;
+ }
+
+ if (memcmp(&in.data[4], NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
+ DBG_ERR("Wrong protocol\n");
+#if defined(EPROTONOSUPPORT)
+ err = EPROTONOSUPPORT;
+#elif defined(EPROTO)
+ err = EPROTO;
+#else
+ err = EINVAL;
+#endif
+ tevent_req_error(req, err);
+ return;
+ }
+
+ DBG_DEBUG("Received packet of length %zu\n", in.length);
+ dump_data(11, in.data, in.length);
+
+ ZERO_STRUCT(pipe_reply);
+ pipe_reply.level = 0;
+ pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
+ /*
+ * TODO: check it's a root (uid == 0) pipe
+ */
+
+ pipe_request = talloc(state, struct named_pipe_auth_req);
+ if (!pipe_request) {
+ DEBUG(0, ("Out of memory!\n"));
+ goto reply;
+ }
+ state->pipe_request = pipe_request;
+
+ /* parse the passed credentials */
+ ndr_err = ndr_pull_struct_blob_all(
+ &in,
+ pipe_request,
+ pipe_request,
+ (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
+ nt_errstr(pipe_reply.status)));
+ goto reply;
+ }
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
+ }
+
+ ZERO_STRUCT(i8);
+
+ if (pipe_request->level != 8) {
+ DEBUG(0, ("Unknown level %u\n", pipe_request->level));
+ pipe_reply.level = 0;
+ pipe_reply.status = NT_STATUS_INVALID_LEVEL;
+ goto reply;
+ }
+
+ pipe_reply.level = 8;
+ pipe_reply.status = NT_STATUS_OK;
+ pipe_reply.info.info8.file_type = state->file_type;
+ pipe_reply.info.info8.device_state = state->device_state;
+ pipe_reply.info.info8.allocation_size = state->alloc_size;
+
+ i8 = pipe_request->info.info8;
+ if (i8.local_server_addr == NULL) {
+ pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+ DEBUG(2, ("Missing local server address\n"));
+ goto reply;
+ }
+ if (i8.remote_client_addr == NULL) {
+ pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+ DEBUG(2, ("Missing remote client address\n"));
+ goto reply;
+ }
+
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ i8.local_server_addr,
+ i8.local_server_port,
+ &state->local_server_addr);
+ if (ret != 0) {
+ DEBUG(2,
+ ("Invalid local server address[%s:%u] - %s\n",
+ i8.local_server_addr,
+ i8.local_server_port,
+ strerror(errno)));
+ pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+ goto reply;
+ }
+
+ ret = tsocket_address_inet_from_strings(state,
+ "ip",
+ i8.remote_client_addr,
+ i8.remote_client_port,
+ &state->remote_client_addr);
+ if (ret != 0) {
+ DEBUG(2,
+ ("Invalid remote client address[%s:%u] - %s\n",
+ i8.remote_client_addr,
+ i8.remote_client_port,
+ strerror(errno)));
+ pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
+ goto reply;
+ }
+
+reply:
+ /* create the output */
+ ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
+ (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(2, ("Error encoding structure: %s\n",
+ ndr_map_error2string(ndr_err)));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
+ dump_data(11, out.data, out.length);
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
+ }
+
+ state->accept_status = pipe_reply.status;
+
+ state->out_iov.iov_base = (char *) out.data;
+ state->out_iov.iov_len = out.length;
+
+ subreq = tstream_writev_send(state, state->ev,
+ state->plain,
+ &state->out_iov, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ DEBUG(0, ("no memory for tstream_writev_send\n"));
+ return;
+ }
+
+ tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
+}
+
+static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ int sys_errno;
+ int ret;
+
+ ret = tstream_writev_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static struct named_pipe_auth_req_info8 *
+copy_npa_info8(TALLOC_CTX *mem_ctx,
+ const struct named_pipe_auth_req_info8 *src)
+{
+ struct named_pipe_auth_req_info8 *dst = NULL;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ dst = talloc_zero(mem_ctx, struct named_pipe_auth_req_info8);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ ndr_err = ndr_push_struct_blob(
+ &blob,
+ dst,
+ src,
+ (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req_info8);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_WARNING("ndr_push_named_pipe_auth_req_info8 failed: %s\n",
+ ndr_errstr(ndr_err));
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &blob,
+ dst,
+ dst,
+ (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req_info8);
+ TALLOC_FREE(blob.data);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_WARNING("ndr_push_named_pipe_auth_req_info8 failed: %s\n",
+ ndr_errstr(ndr_err));
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ return dst;
+}
+
+int _tstream_npa_accept_existing_recv(
+ struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ struct named_pipe_auth_req_info8 **info8,
+ enum dcerpc_transport_t *transport,
+ struct tsocket_address **remote_client_addr,
+ char **_remote_client_name,
+ struct tsocket_address **local_server_addr,
+ char **local_server_name,
+ struct auth_session_info_transport **session_info,
+ const char *location)
+{
+ struct tstream_npa_accept_state *state =
+ tevent_req_data(req, struct tstream_npa_accept_state);
+ struct named_pipe_auth_req_info8 *i8 =
+ &state->pipe_request->info.info8;
+ struct tstream_npa *npas;
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret != 0) {
+ DEBUG(2, ("Failed to accept named pipe connection: %s\n",
+ strerror(*perrno)));
+ tevent_req_received(req);
+ return -1;
+ }
+
+ if (!NT_STATUS_IS_OK(state->accept_status)) {
+#if defined(EPROTONOSUPPORT)
+ *perrno = EPROTONOSUPPORT;
+#elif defined(EPROTO)
+ *perrno = EPROTO;
+#else
+ *perrno = EINVAL;
+#endif
+ DEBUG(2, ("Failed to accept named pipe connection: %s => %s\n",
+ nt_errstr(state->accept_status),
+ strerror(*perrno)));
+ tevent_req_received(req);
+ return -1;
+ }
+
+ *stream = tstream_context_create(mem_ctx,
+ &tstream_npa_ops,
+ &npas,
+ struct tstream_npa,
+ location);
+ if (!*stream) {
+ *perrno = ENOMEM;
+ tevent_req_received(req);
+ return -1;
+ }
+ ZERO_STRUCTP(npas);
+ npas->unix_stream = state->plain;
+ npas->file_type = state->file_type;
+
+ if (info8 != NULL) {
+ /*
+ * Make a full copy of "info8" because further down we
+ * talloc_move() away substructures from
+ * state->pipe_request.
+ */
+ struct named_pipe_auth_req_info8 *dst =
+ copy_npa_info8(mem_ctx, i8);
+ if (dst == NULL) {
+ *perrno = ENOMEM;
+ tevent_req_received(req);
+ return -1;
+ }
+ *info8 = dst;
+ }
+
+ if (transport != NULL) {
+ *transport = i8->transport;
+ }
+ if (remote_client_addr != NULL) {
+ *remote_client_addr = talloc_move(
+ mem_ctx, &state->remote_client_addr);
+ }
+ if (_remote_client_name != NULL) {
+ *_remote_client_name = discard_const_p(
+ char,
+ talloc_move(mem_ctx, &i8->remote_client_name));
+ }
+ if (local_server_addr != NULL) {
+ *local_server_addr = talloc_move(
+ mem_ctx, &state->local_server_addr);
+ }
+ if (local_server_name != NULL) {
+ *local_server_name = discard_const_p(
+ char,
+ talloc_move(mem_ctx, &i8->local_server_name));
+ }
+ if (session_info != NULL) {
+ *session_info = talloc_move(mem_ctx, &i8->session_info);
+ }
+
+ tevent_req_received(req);
+ return 0;
+}
diff --git a/libcli/named_pipe_auth/npa_tstream.h b/libcli/named_pipe_auth/npa_tstream.h
new file mode 100644
index 0000000..aa60fe7
--- /dev/null
+++ b/libcli/named_pipe_auth/npa_tstream.h
@@ -0,0 +1,145 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 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 NPA_TSTREAM_H
+#define NPA_TSTREAM_H
+
+#include <replace.h>
+#include "librpc/rpc/rpc_common.h"
+
+struct tevent_req;
+struct tevent_context;
+struct auth_session_info_transport;
+struct tsocket_address;
+struct named_pipe_auth_req_info8;
+
+struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const char *directory,
+ const char *npipe,
+ enum dcerpc_transport_t transport,
+ const struct tsocket_address *remote_client_addr,
+ const char *remote_client_name_in,
+ const struct tsocket_address *local_server_addr,
+ const char *local_server_name_in,
+ const struct auth_session_info_transport *session_info);
+int _tstream_npa_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ uint16_t *file_type,
+ uint16_t *device_state,
+ uint64_t *allocation_size,
+ const char *location);
+#define tstream_npa_connect_recv(req, perrno, mem_ctx, stream, f, d, a) \
+ _tstream_npa_connect_recv(req, perrno, mem_ctx, stream, f, d, a, \
+ __location__)
+
+int _tstream_npa_existing_stream(TALLOC_CTX *mem_ctx,
+ struct tstream_context **transport,
+ uint16_t file_type,
+ struct tstream_context **_stream,
+ const char *location);
+#define tstream_npa_existing_stream(mem_ctx, transport, ft, stream) \
+ _tstream_npa_existing_stream(mem_ctx, transport, ft, stream, \
+ __location__)
+
+int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ uint16_t file_type,
+ struct tstream_context **_stream,
+ const char *location);
+#define tstream_npa_existing_socket(mem_ctx, fd, ft, stream) \
+ _tstream_npa_existing_socket(mem_ctx, fd, ft, stream, \
+ __location__)
+
+
+/**
+ * @brief Accepts a connection for authenticated named pipes
+ *
+ * @param[in] mem_ctx The memory context for the operation
+ * @param[in] ev The tevent_context for the operation
+ * @param[in] plain The plain tstream_context of the bsd unix
+ * domain socket.
+ * This must be valid for the whole life of the
+ * resulting npa tstream_context!
+ * @param[in] file_type The file_type, message mode or byte mode
+ * @param[in] device_state The reported device state
+ * @param[in] allocation_size The reported allocation size
+ *
+ * @return the tevent_req handle
+ */
+struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *plain,
+ uint16_t file_type,
+ uint16_t device_state,
+ uint64_t allocation_size);
+
+/**
+ * @brief The receive end of the previous async function
+ *
+ * @param[in] req The tevent_req handle
+ * @param[out] perrno Pointer to store the errno in case of error
+ * @param[in] mem_ctx The memory context for the results
+ * @param[out] stream The resulting stream
+ * @param[out] client The resulting client address
+ * @param[out] client_name The resulting client name
+ * @param[out] server The resulting server address
+ * @param[out] server_name The resulting server name
+ * @param[out] info3 The info3 auth for the connecting user.
+ * @param[out] session_key The resulting session key
+ * @param[out] delegated_creds Delegated credentials
+ *
+ * @return 0 if successful, -1 on failure with *perror filled.
+ */
+int _tstream_npa_accept_existing_recv(
+ struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ struct named_pipe_auth_req_info8 **info8,
+ enum dcerpc_transport_t *transport,
+ struct tsocket_address **remote_client_addr,
+ char **_remote_client_name,
+ struct tsocket_address **local_server_addr,
+ char **local_server_name,
+ struct auth_session_info_transport **session_info,
+ const char *location);
+#define tstream_npa_accept_existing_recv(req, perrno, \
+ mem_ctx, stream, \
+ info4, \
+ transport, \
+ remote_client_addr, \
+ remote_client_name, \
+ local_server_addr, \
+ local_server_name, \
+ session_info) \
+ _tstream_npa_accept_existing_recv(req, perrno, \
+ mem_ctx, stream, \
+ info4, \
+ transport, \
+ remote_client_addr, \
+ remote_client_name, \
+ local_server_addr, \
+ local_server_name, \
+ session_info, \
+ __location__)
+
+#endif /* NPA_TSTREAM_H */
diff --git a/libcli/named_pipe_auth/tstream_u32_read.c b/libcli/named_pipe_auth/tstream_u32_read.c
new file mode 100644
index 0000000..c8e95ef
--- /dev/null
+++ b/libcli/named_pipe_auth/tstream_u32_read.c
@@ -0,0 +1,159 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 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 "system/filesys.h"
+#include "tstream_u32_read.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/tevent_unix.h"
+
+struct tstream_u32_read_state {
+ size_t max_msglen;
+ size_t buflen;
+ uint8_t *buf;
+};
+
+static int tstream_u32_read_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count);
+static void tstream_u32_read_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_u32_read_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ uint32_t max_msglen,
+ struct tstream_context *stream)
+{
+ struct tevent_req *req = NULL, *subreq = NULL;
+ struct tstream_u32_read_state *state = NULL;
+
+ req = tevent_req_create(
+ mem_ctx, &state, struct tstream_u32_read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->max_msglen = max_msglen;
+
+ subreq = tstream_readv_pdu_send(
+ state,
+ ev,
+ stream,
+ tstream_u32_read_next_vector,
+ state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_u32_read_done, req);
+ return req;
+}
+
+static int tstream_u32_read_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count)
+{
+ struct tstream_u32_read_state *state = talloc_get_type_abort(
+ private_data, struct tstream_u32_read_state);
+ size_t buflen = talloc_get_size(state->buf);
+ struct iovec *vector;
+ uint32_t msg_len;
+ size_t ofs = 0;
+ size_t count;
+
+ if (buflen == 0) {
+ msg_len = 4;
+ state->buf = talloc_array(state, uint8_t, msg_len);
+ if (state->buf == NULL) {
+ return -1;
+ }
+ } else if (buflen == 4) {
+
+ ofs = 4;
+
+ msg_len = RIVAL(state->buf, 0);
+ if ((msg_len == 0) || (msg_len > state->max_msglen)) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+ msg_len += ofs;
+ if (msg_len < ofs) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ state->buf = talloc_realloc(
+ state, state->buf, uint8_t, msg_len);
+ if (state->buf == NULL) {
+ return -1;
+ }
+ } else {
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
+ }
+
+ vector = talloc(mem_ctx, struct iovec);
+ if (vector == NULL) {
+ return -1;
+ }
+ *vector = (struct iovec) {
+ .iov_base = state->buf + ofs, .iov_len = msg_len - ofs,
+ };
+ count = 1;
+
+ *_vector = vector;
+ *_count = count;
+ return 0;
+}
+
+static void tstream_u32_read_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ int ret, err;
+
+ ret = tstream_readv_pdu_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+int tstream_u32_read_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ size_t *buflen)
+{
+ struct tstream_u32_read_state *state = tevent_req_data(
+ req, struct tstream_u32_read_state);
+ int err;
+
+ if (tevent_req_is_unix_error(req, &err)) {
+ return err;
+ }
+ *buflen = talloc_get_size(state->buf);
+ *buf = talloc_move(mem_ctx, &state->buf);
+ return 0;
+}
diff --git a/libcli/named_pipe_auth/tstream_u32_read.h b/libcli/named_pipe_auth/tstream_u32_read.h
new file mode 100644
index 0000000..1356ff0
--- /dev/null
+++ b/libcli/named_pipe_auth/tstream_u32_read.h
@@ -0,0 +1,37 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 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 TSTREAM_U32_READ_H
+#define TSTREAM_U32_READ_H
+
+#include "replace.h"
+#include "tsocket.h"
+
+struct tevent_req *tstream_u32_read_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ uint32_t max_msglen,
+ struct tstream_context *stream);
+int tstream_u32_read_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ size_t *buflen);
+
+#endif
diff --git a/libcli/named_pipe_auth/wscript_build b/libcli/named_pipe_auth/wscript_build
new file mode 100644
index 0000000..4698699
--- /dev/null
+++ b/libcli/named_pipe_auth/wscript_build
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_LIBRARY('npa_tstream',
+ source='npa_tstream.c tstream_u32_read.c',
+ private_library=True,
+ public_deps='NDR_NAMED_PIPE_AUTH tevent LIBTSOCKET'
+ )
+
diff --git a/libcli/nbt/libnbt.h b/libcli/nbt/libnbt.h
new file mode 100644
index 0000000..204484b
--- /dev/null
+++ b/libcli/nbt/libnbt.h
@@ -0,0 +1,377 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ a raw async NBT library
+
+ Copyright (C) Andrew Tridgell 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 __LIBNBT_H__
+#define __LIBNBT_H__
+
+#include "librpc/gen_ndr/nbt.h"
+#include "librpc/ndr/libndr.h"
+
+/*
+ possible states for pending requests
+*/
+enum nbt_request_state {NBT_REQUEST_SEND,
+ NBT_REQUEST_WAIT,
+ NBT_REQUEST_DONE,
+ NBT_REQUEST_TIMEOUT,
+ NBT_REQUEST_ERROR};
+
+/*
+ a nbt name request
+*/
+struct nbt_name_request {
+ struct nbt_name_request *next, *prev;
+
+ enum nbt_request_state state;
+
+ NTSTATUS status;
+
+ /* the socket this was on */
+ struct nbt_name_socket *nbtsock;
+
+ /* where to send the request */
+ struct socket_address *dest;
+
+ /* timeout between retries */
+ int timeout;
+
+ /* how many retries to send on timeout */
+ int num_retries;
+
+ /* whether we have received a WACK */
+ bool received_wack;
+
+ /* the timeout event */
+ struct tevent_timer *te;
+
+ /* the name transaction id */
+ uint16_t name_trn_id;
+
+ /* is it a reply? */
+ bool is_reply;
+
+ /* the encoded request */
+ DATA_BLOB encoded;
+
+ /* shall we allow multiple replies? */
+ bool allow_multiple_replies;
+
+ unsigned int num_replies;
+ struct nbt_name_reply {
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+ } *replies;
+
+ /* information on what to do on completion */
+ struct {
+ void (*fn)(struct nbt_name_request *);
+ void *private_data;
+ } async;
+};
+
+
+
+/*
+ context structure for operations on name queries
+*/
+struct nbt_name_socket {
+ struct socket_context *sock;
+ struct tevent_context *event_ctx;
+
+ /* a queue of requests pending to be sent */
+ struct nbt_name_request *send_queue;
+
+ /* the fd event */
+ struct tevent_fd *fde;
+
+ /* mapping from name_trn_id to pending event */
+ struct idr_context *idr;
+
+ /* how many requests are waiting for a reply */
+ uint16_t num_pending;
+
+ /* what to do with incoming request packets */
+ struct {
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *);
+ void *private_data;
+ } incoming;
+
+ /* what to do with unexpected replies */
+ struct {
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *);
+ void *private_data;
+ } unexpected;
+};
+
+
+/* a simple name query */
+struct nbt_name_query {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ bool broadcast;
+ bool wins_lookup;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ int16_t num_addrs;
+ const char **reply_addrs;
+ } out;
+};
+
+/* a simple name status query */
+struct nbt_name_status {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ struct nbt_rdata_status status;
+ } out;
+};
+
+/* a name registration request */
+struct nbt_name_register {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ bool register_demand;
+ bool broadcast;
+ bool multi_homed;
+ uint32_t ttl;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
+
+/* a send 3 times then demand name broadcast name registration */
+struct nbt_name_register_bcast {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+};
+
+
+/* wins name register with multiple wins servers to try and multiple
+ addresses to register */
+struct nbt_name_register_wins {
+ struct {
+ struct nbt_name name;
+ const char **wins_servers;
+ uint16_t wins_port;
+ const char **addresses;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+ struct {
+ const char *wins_server;
+ uint8_t rcode;
+ } out;
+};
+
+
+
+/* a name refresh request */
+struct nbt_name_refresh {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ bool broadcast;
+ uint32_t ttl;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
+
+/* wins name refresh with multiple wins servers to try and multiple
+ addresses to register */
+struct nbt_name_refresh_wins {
+ struct {
+ struct nbt_name name;
+ const char **wins_servers;
+ uint16_t wins_port;
+ const char **addresses;
+ uint16_t nb_flags;
+ uint32_t ttl;
+ } in;
+ struct {
+ const char *wins_server;
+ uint8_t rcode;
+ } out;
+};
+
+
+/* a name release request */
+struct nbt_name_release {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ uint16_t dest_port;
+ const char *address;
+ uint16_t nb_flags;
+ bool broadcast;
+ int timeout; /* in seconds */
+ int retries;
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
+
+struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
+ struct tevent_context *event_ctx);
+void nbt_name_socket_handle_response_packet(struct nbt_name_request *req,
+ struct nbt_name_packet *packet,
+ struct socket_address *src);
+struct nbt_name_request *nbt_name_query_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_query *io);
+NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io);
+NTSTATUS nbt_name_query(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io);
+struct nbt_name_request *nbt_name_status_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_status *io);
+NTSTATUS nbt_name_status_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io);
+NTSTATUS nbt_name_status(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io);
+
+NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx,
+ const struct nbt_name *name,
+ struct nbt_name *newname);
+NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name);
+NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name);
+void nbt_choose_called_name(TALLOC_CTX *mem_ctx, struct nbt_name *n, const char *name, int type);
+char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name);
+NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io);
+NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io);
+NTSTATUS nbt_name_release(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io);
+NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io);
+NTSTATUS nbt_name_refresh_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io);
+NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io);
+struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register *io);
+NTSTATUS nbt_name_release_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io);
+
+struct nbt_name_request *nbt_name_release_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_release *io);
+
+NTSTATUS nbt_name_refresh_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io);
+
+NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *),
+ void *private_data);
+NTSTATUS nbt_set_unexpected_handler(struct nbt_name_socket *nbtsock,
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *),
+ void *private_data);
+NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ struct nbt_name_packet *request);
+
+
+NDR_SCALAR_PTR_PROTO(wrepl_nbt_name, struct nbt_name)
+NDR_BUFFER_PROTO(nbt_name, struct nbt_name)
+NTSTATUS nbt_rcode_to_ntstatus(uint8_t rcode);
+
+struct tevent_context;
+struct tevent_req;
+struct tevent_req *nbt_name_register_bcast_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_bcast *io);
+NTSTATUS nbt_name_register_bcast_recv(struct tevent_req *req);
+struct tevent_req *nbt_name_register_wins_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_wins *io);
+NTSTATUS nbt_name_register_wins_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io);
+struct tevent_req *nbt_name_refresh_wins_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_refresh_wins *io);
+NTSTATUS nbt_name_refresh_wins_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io);
+
+FILE *startlmhosts(const char *fname);
+bool getlmhostsent(TALLOC_CTX *ctx, FILE *fp, char **pp_name, int *name_type,
+ struct sockaddr_storage *pss);
+void endlmhosts(FILE *fp);
+
+NTSTATUS resolve_lmhosts_file_as_sockaddr(TALLOC_CTX *mem_ctx,
+ const char *lmhosts_file,
+ const char *name,
+ int name_type,
+ struct sockaddr_storage **return_iplist,
+ size_t *return_count);
+
+#endif /* __LIBNBT_H__ */
diff --git a/libcli/nbt/lmhosts.c b/libcli/nbt/lmhosts.c
new file mode 100644
index 0000000..dd06e70
--- /dev/null
+++ b/libcli/nbt/lmhosts.c
@@ -0,0 +1,243 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ manipulate nbt name structures
+
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2007
+ Copyright (C) Andrew Bartlett 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 "lib/util/util_net.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "../libcli/nbt/libnbt.h"
+
+/********************************************************
+ Start parsing the lmhosts file.
+*********************************************************/
+
+FILE *startlmhosts(const char *fname)
+{
+ FILE *fp = fopen(fname, "r");
+ if (!fp) {
+ DEBUG(4,("startlmhosts: Can't open lmhosts file %s. "
+ "Error was %s\n",
+ fname, strerror(errno)));
+ return NULL;
+ }
+ return fp;
+}
+
+/********************************************************
+ Parse the next line in the lmhosts file.
+*********************************************************/
+
+bool getlmhostsent(TALLOC_CTX *ctx, FILE *fp, char **pp_name, int *name_type,
+ struct sockaddr_storage *pss)
+{
+ char line[1024];
+
+ *pp_name = NULL;
+
+ while(!feof(fp) && !ferror(fp)) {
+ char *ip = NULL;
+ char *flags = NULL;
+ char *extra = NULL;
+ char *name = NULL;
+ const char *ptr;
+ char *ptr1 = NULL;
+ int count = 0;
+
+ *name_type = -1;
+
+ if (!fgets_slash(NULL,line,sizeof(line),fp)) {
+ continue;
+ }
+
+ if (*line == '#') {
+ continue;
+ }
+
+ ptr = line;
+
+ if (next_token_talloc(ctx, &ptr, &ip, NULL))
+ ++count;
+ if (next_token_talloc(ctx, &ptr, &name, NULL))
+ ++count;
+ if (next_token_talloc(ctx, &ptr, &flags, NULL))
+ ++count;
+ if (next_token_talloc(ctx, &ptr, &extra, NULL))
+ ++count;
+
+ if (count <= 0)
+ continue;
+
+ if (count > 0 && count < 2) {
+ DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",
+ line));
+ continue;
+ }
+
+ if (count >= 4) {
+ DEBUG(0,("getlmhostsent: too many columns "
+ "in lmhosts file (obsolete syntax)\n"));
+ continue;
+ }
+
+ if (!flags) {
+ flags = talloc_strdup(ctx, "");
+ if (!flags) {
+ continue;
+ }
+ }
+
+ DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n",
+ ip, name, flags));
+
+ if (strchr_m(flags,'G') || strchr_m(flags,'S')) {
+ DEBUG(0,("getlmhostsent: group flag "
+ "in lmhosts ignored (obsolete)\n"));
+ continue;
+ }
+
+ if (!interpret_string_addr(pss, ip, AI_NUMERICHOST)) {
+ DEBUG(0,("getlmhostsent: invalid address "
+ "%s.\n", ip));
+ }
+
+ /* Extra feature. If the name ends in '#XX',
+ * where XX is a hex number, then only add that name type. */
+ if((ptr1 = strchr_m(name, '#')) != NULL) {
+ char *endptr;
+ ptr1++;
+
+ *name_type = (int)strtol(ptr1, &endptr, 16);
+ if(!*ptr1 || (endptr == ptr1)) {
+ DEBUG(0,("getlmhostsent: invalid name "
+ "%s containing '#'.\n", name));
+ continue;
+ }
+
+ *(--ptr1) = '\0'; /* Truncate at the '#' */
+ }
+
+ *pp_name = talloc_strdup(ctx, name);
+ if (!*pp_name) {
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/********************************************************
+ Finish parsing the lmhosts file.
+*********************************************************/
+
+void endlmhosts(FILE *fp)
+{
+ fclose(fp);
+}
+
+/********************************************************
+ Resolve via "lmhosts" method.
+*********************************************************/
+
+NTSTATUS resolve_lmhosts_file_as_sockaddr(TALLOC_CTX *mem_ctx,
+ const char *lmhosts_file,
+ const char *name,
+ int name_type,
+ struct sockaddr_storage **return_iplist,
+ size_t *return_count)
+{
+ /*
+ * "lmhosts" means parse the local lmhosts file.
+ */
+
+ FILE *fp;
+ char *lmhost_name = NULL;
+ int name_type2;
+ struct sockaddr_storage return_ss;
+ NTSTATUS status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ TALLOC_CTX *ctx = NULL;
+ size_t ret_count = 0;
+ struct sockaddr_storage *iplist = NULL;
+
+ DEBUG(3,("resolve_lmhosts: "
+ "Attempting lmhosts lookup for name %s<0x%x>\n",
+ name, name_type));
+
+ fp = startlmhosts(lmhosts_file);
+
+ if ( fp == NULL )
+ return NT_STATUS_NO_SUCH_FILE;
+
+ ctx = talloc_new(mem_ctx);
+ if (!ctx) {
+ endlmhosts(fp);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while (getlmhostsent(ctx, fp, &lmhost_name, &name_type2, &return_ss)) {
+
+ if (!strequal(name, lmhost_name)) {
+ TALLOC_FREE(lmhost_name);
+ continue;
+ }
+
+ if ((name_type2 != -1) && (name_type != name_type2)) {
+ TALLOC_FREE(lmhost_name);
+ continue;
+ }
+
+ /* wrap check. */
+ if (ret_count + 1 < ret_count) {
+ TALLOC_FREE(ctx);
+ endlmhosts(fp);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ iplist = talloc_realloc(ctx, iplist,
+ struct sockaddr_storage,
+ ret_count+1);
+
+ if (iplist == NULL) {
+ TALLOC_FREE(ctx);
+ endlmhosts(fp);
+ DEBUG(3,("resolve_lmhosts: talloc_realloc fail !\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ iplist[ret_count] = return_ss;
+ ret_count += 1;
+
+ /* we found something */
+ status = NT_STATUS_OK;
+
+ /* Multiple names only for DC lookup */
+ if (name_type != 0x1c)
+ break;
+ }
+
+ *return_count = ret_count;
+ *return_iplist = talloc_move(mem_ctx, &iplist);
+ TALLOC_FREE(ctx);
+ endlmhosts(fp);
+ return status;
+}
+
diff --git a/libcli/nbt/man/nmblookup4.1.xml b/libcli/nbt/man/nmblookup4.1.xml
new file mode 100644
index 0000000..b6fe48c
--- /dev/null
+++ b/libcli/nbt/man/nmblookup4.1.xml
@@ -0,0 +1,213 @@
+<?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="nmblookup4">
+
+<refmeta>
+ <refentrytitle>nmblookup4</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">User Commands</refmiscinfo>
+ <refmiscinfo class="version">3.2</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>nmblookup4</refname>
+ <refpurpose>NetBIOS over TCP/IP client used to lookup NetBIOS
+ names</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>nmblookup4</command>
+ <arg choice="opt">-M</arg>
+ <arg choice="opt">-R</arg>
+ <arg choice="opt">-S</arg>
+ <arg choice="opt">-r</arg>
+ <arg choice="opt">-A</arg>
+ <arg choice="opt">-h</arg>
+ <arg choice="opt">-B &lt;broadcast address&gt;</arg>
+ <arg choice="opt">-U &lt;unicast address&gt;</arg>
+ <arg choice="opt">-d &lt;debug level&gt;</arg>
+ <arg choice="opt">-s &lt;smb config file&gt;</arg>
+ <arg choice="opt">-i &lt;NetBIOS scope&gt;</arg>
+ <arg choice="opt">-T</arg>
+ <arg choice="opt">-f</arg>
+ <arg choice="req">name</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>7</manvolnum></citerefentry> suite.</para>
+
+ <para><command>nmblookup4</command> is used to query NetBIOS names
+ and map them to IP addresses in a network using NetBIOS over TCP/IP
+ queries. The options allow the name queries to be directed at a
+ particular IP broadcast area or to a particular machine. All queries
+ are done over UDP.</para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-M</term>
+ <listitem><para>Searches for a master browser by looking
+ up the NetBIOS <replaceable>name</replaceable> with a
+ type of <constant>0x1d</constant>. If <replaceable>
+ name</replaceable> is "-" then it does a lookup on the special name
+ <constant>__MSBROWSE__</constant>. Please note that in order to
+ use the name "-", you need to make sure "-" isn't parsed as an
+ argument, e.g. use :
+ <userinput>nmblookup4 -M -- -</userinput>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-R</term>
+ <listitem><para>Set the recursion desired bit in the packet
+ to do a recursive lookup. This is used when sending a name
+ query to a machine running a WINS server and the user wishes
+ to query the names in the WINS server. If this bit is unset
+ the normal (broadcast responding) NetBIOS processing code
+ on a machine is used instead. See RFC1001, RFC1002 for details.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-S</term>
+ <listitem><para>Once the name query has returned an IP
+ address then do a node status query as well. A node status
+ query returns the NetBIOS names registered by a host.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-r</term>
+ <listitem><para>Try and bind to UDP port 137 to send and receive UDP
+ datagrams. The reason for this option is a bug in Windows 95
+ where it ignores the source port of the requesting packet
+ and only replies to UDP port 137. Unfortunately, on most UNIX
+ systems root privilege is needed to bind to this port, and
+ in addition, if the <citerefentry><refentrytitle>nmbd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry> daemon is running on this machine it also binds to this port.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-A</term>
+ <listitem><para>Interpret <replaceable>name</replaceable> as
+ an IP Address and do a node status query on this address.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-B &lt;broadcast address&gt;</term>
+ <listitem><para>Send the query to the given broadcast address. Without
+ this option the default behavior of nmblookup4 is to send the
+ query to the broadcast address of the network interfaces as
+ either auto-detected or defined in the <ulink
+ url="smb.conf.5.html#INTERFACES"><parameter>interfaces</parameter>
+ </ulink> parameter of the <citerefentry><refentrytitle>smb.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry> file.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-U &lt;unicast address&gt;</term>
+ <listitem><para>Do a unicast query to the specified address or
+ host <replaceable>unicast address</replaceable>. This option
+ (along with the <parameter>-R</parameter> option) is needed to
+ query a WINS server.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-T</term>
+ <listitem><para>This causes any IP addresses found in the
+ lookup to be looked up via a reverse DNS lookup into a
+ DNS name, and printed out before each</para>
+
+ <para><emphasis>IP address .... NetBIOS name</emphasis></para>
+
+ <para> pair that is the normal output.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-f</term>
+ <listitem><para>
+ Show which flags apply to the name that has been looked up. Possible
+ answers are zero or more of: Response, Authoritative,
+ Truncated, Recursion_Desired, Recursion_Available, Broadcast.
+ </para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>name</term>
+ <listitem><para>This is the NetBIOS name being queried. Depending
+ upon the previous options this may be a NetBIOS name or IP address.
+ If a NetBIOS name then the different name types may be specified
+ by appending '#&lt;type&gt;' to the name. This name may also be
+ '*', which will return all registered names within a broadcast
+ area.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>EXAMPLES</title>
+
+ <para><command>nmblookup4</command> can be used to query
+ a WINS server (in the same way <command>nslookup</command> is
+ used to query DNS servers). To query a WINS server, <command>nmblookup4</command>
+ must be called like this:</para>
+
+ <para><command>nmblookup4 -U server -R 'name'</command></para>
+
+ <para>For example, running :</para>
+
+ <para><command>nmblookup4 -U samba.org -R 'IRIX#1B'</command></para>
+
+ <para>would query the WINS server samba.org for the domain
+ master browser (1B name type) for the IRIX workgroup.</para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 3 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry><refentrytitle>nmbd</refentrytitle>
+ <manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>samba</refentrytitle>
+ <manvolnum>7</manvolnum></citerefentry>, and <citerefentry><refentrytitle>smb.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry>.</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 original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter. The conversion to DocBook
+ XML 4.2 for Samba 3.0 was done by Alexander Bokovoy.</para>
+</refsect1>
+
+</refentry>
diff --git a/libcli/nbt/namequery.c b/libcli/nbt/namequery.c
new file mode 100644
index 0000000..49ab10c
--- /dev/null
+++ b/libcli/nbt/namequery.c
@@ -0,0 +1,234 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ make nbt name query requests
+
+ Copyright (C) Andrew Tridgell 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 "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+
+/**
+ send a nbt name query
+*/
+_PUBLIC_ struct nbt_name_request *nbt_name_query_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_query *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->operation = NBT_OPCODE_QUERY;
+ if (io->in.broadcast) {
+ packet->operation |= NBT_FLAG_BROADCAST;
+ }
+ if (io->in.wins_lookup) {
+ packet->operation |= NBT_FLAG_RECURSION_DESIRED;
+ }
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/**
+ wait for a name query reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+ int i;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if ((packet->operation & NBT_RCODE) != 0) {
+ status = nbt_rcode_to_ntstatus(packet->operation & NBT_RCODE);
+ talloc_free(req);
+ return status;
+ }
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return status;
+ }
+
+ io->out.name = packet->answers[0].name;
+ io->out.num_addrs = packet->answers[0].rdata.netbios.length / 6;
+ io->out.reply_addrs = talloc_array(mem_ctx, const char *, io->out.num_addrs+1);
+ if (io->out.reply_addrs == NULL) {
+ talloc_free(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i=0;i<io->out.num_addrs;i++) {
+ io->out.reply_addrs[i] = talloc_steal(io->out.reply_addrs,
+ packet->answers[0].rdata.netbios.addresses[i].ipaddr);
+ }
+ io->out.reply_addrs[i] = NULL;
+
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/**
+ wait for a name query reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_query(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_query *io)
+{
+ struct nbt_name_request *req = nbt_name_query_send(nbtsock, io);
+ return nbt_name_query_recv(req, mem_ctx, io);
+}
+
+
+/**
+ send a nbt name status
+*/
+_PUBLIC_ struct nbt_name_request *nbt_name_status_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_status *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->operation = NBT_OPCODE_QUERY;
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_STATUS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/**
+ wait for a name status reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_status_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+ int i;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if ((packet->operation & NBT_RCODE) != 0) {
+ status = nbt_rcode_to_ntstatus(packet->operation & NBT_RCODE);
+ talloc_free(req);
+ return status;
+ }
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_STATUS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ io->out.name = packet->answers[0].name;
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ io->out.status = packet->answers[0].rdata.status;
+ talloc_steal(mem_ctx, io->out.status.names);
+ for (i=0;i<io->out.status.num_names;i++) {
+ talloc_steal(io->out.status.names, io->out.status.names[i].name);
+ }
+
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/**
+ wait for a name status reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_status(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_status *io)
+{
+ struct nbt_name_request *req = nbt_name_status_send(nbtsock, io);
+ return nbt_name_status_recv(req, mem_ctx, io);
+}
+
+
diff --git a/libcli/nbt/namerefresh.c b/libcli/nbt/namerefresh.c
new file mode 100644
index 0000000..b3aef76
--- /dev/null
+++ b/libcli/nbt/namerefresh.c
@@ -0,0 +1,347 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ send out a name refresh request
+
+ Copyright (C) Andrew Tridgell 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 <tevent.h>
+#include "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+#include "lib/util/tevent_ntstatus.h"
+
+/*
+ send a nbt name refresh request
+*/
+struct nbt_name_request *nbt_name_refresh_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_refresh *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->arcount = 1;
+ packet->operation = NBT_OPCODE_REFRESH;
+ if (io->in.broadcast) {
+ packet->operation |= NBT_FLAG_BROADCAST;
+ }
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
+ if (packet->additional == NULL) goto failed;
+
+ packet->additional[0].name = io->in.name;
+ packet->additional[0].rr_type = NBT_QTYPE_NETBIOS;
+ packet->additional[0].rr_class = NBT_QCLASS_IP;
+ packet->additional[0].ttl = io->in.ttl;
+ packet->additional[0].rdata.netbios.length = 6;
+ packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
+ struct nbt_rdata_address, 1);
+ if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
+ packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
+ packet->additional[0].rdata.netbios.addresses[0].ipaddr =
+ talloc_strdup(packet->additional, io->in.address);
+
+ dest = socket_address_from_strings(nbtsock,
+ nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/*
+ wait for a refresh reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_refresh_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ io->out.rcode = packet->operation & NBT_RCODE;
+ io->out.name = packet->answers[0].name;
+ if (packet->answers[0].rdata.netbios.length < 6) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ io->out.reply_addr = talloc_steal(mem_ctx,
+ packet->answers[0].rdata.netbios.addresses[0].ipaddr);
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ synchronous name refresh request
+*/
+_PUBLIC_ NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io)
+{
+ struct nbt_name_request *req = nbt_name_refresh_send(nbtsock, io);
+ return nbt_name_refresh_recv(req, mem_ctx, io);
+}
+
+
+
+/**
+ a wins name refresh with multiple WINS servers and multiple
+ addresses to refresh. Try each WINS server in turn, until we get a
+ reply for each address
+*/
+struct nbt_name_refresh_wins_state {
+ struct nbt_name_socket *nbtsock;
+ struct nbt_name_refresh *io;
+ char **wins_servers;
+ uint16_t wins_port;
+ char **addresses;
+ int address_idx;
+};
+
+static void nbt_name_refresh_wins_handler(struct nbt_name_request *subreq);
+
+/**
+ the async send call for a multi-server WINS refresh
+*/
+_PUBLIC_ struct tevent_req *nbt_name_refresh_wins_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_refresh_wins *io)
+{
+ struct tevent_req *req;
+ struct nbt_name_refresh_wins_state *state;
+ struct nbt_name_request *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct nbt_name_refresh_wins_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->io = talloc(state, struct nbt_name_refresh);
+ if (tevent_req_nomem(state->io, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.wins_servers == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.wins_servers[0] == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.addresses == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.addresses[0] == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->wins_port = io->in.wins_port;
+ state->wins_servers = str_list_copy(state, io->in.wins_servers);
+ if (tevent_req_nomem(state->wins_servers, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->addresses = str_list_copy(state, io->in.addresses);
+ if (tevent_req_nomem(state->addresses, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->io->in.name = io->in.name;
+ state->io->in.dest_addr = state->wins_servers[0];
+ state->io->in.dest_port = state->wins_port;
+ state->io->in.address = io->in.addresses[0];
+ state->io->in.nb_flags = io->in.nb_flags;
+ state->io->in.broadcast = false;
+ state->io->in.ttl = io->in.ttl;
+ state->io->in.timeout = 2;
+ state->io->in.retries = 2;
+
+ state->nbtsock = nbtsock;
+ state->address_idx = 0;
+
+ subreq = nbt_name_refresh_send(nbtsock, state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq->async.fn = nbt_name_refresh_wins_handler;
+ subreq->async.private_data = req;
+
+ return req;
+}
+
+static void nbt_name_refresh_wins_handler(struct nbt_name_request *subreq)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(subreq->async.private_data,
+ struct tevent_req);
+ struct nbt_name_refresh_wins_state *state =
+ tevent_req_data(req,
+ struct nbt_name_refresh_wins_state);
+ NTSTATUS status;
+
+ status = nbt_name_refresh_recv(subreq, state, state->io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ /* the refresh timed out - try the next WINS server */
+ state->wins_servers++;
+ if (state->wins_servers[0] == NULL) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->address_idx = 0;
+ state->io->in.dest_addr = state->wins_servers[0];
+ state->io->in.dest_port = state->wins_port;
+ state->io->in.address = state->addresses[0];
+
+ subreq = nbt_name_refresh_send(state->nbtsock, state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ subreq->async.fn = nbt_name_refresh_wins_handler;
+ subreq->async.private_data = req;
+ } else if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (state->io->out.rcode == 0 &&
+ state->addresses[state->address_idx+1] != NULL) {
+ /* refresh our next address */
+ state->io->in.address = state->addresses[++(state->address_idx)];
+ subreq = nbt_name_refresh_send(state->nbtsock, state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ subreq->async.fn = nbt_name_refresh_wins_handler;
+ subreq->async.private_data = req;
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/*
+ multi-homed WINS name refresh - recv side
+*/
+_PUBLIC_ NTSTATUS nbt_name_refresh_wins_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io)
+{
+ struct nbt_name_refresh_wins_state *state =
+ tevent_req_data(req,
+ struct nbt_name_refresh_wins_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ io->out.wins_server = talloc_move(mem_ctx, &state->wins_servers[0]);
+ io->out.rcode = state->io->out.rcode;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*
+ multi-homed WINS refresh - sync interface
+*/
+_PUBLIC_ NTSTATUS nbt_name_refresh_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_refresh_wins *io)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *subreq;
+ NTSTATUS status;
+
+ /*
+ * TODO: create a temporary event context
+ */
+ ev = nbtsock->event_ctx;
+
+ subreq = nbt_name_refresh_wins_send(frame, ev, nbtsock, io);
+ if (subreq == NULL) {
+ talloc_free(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(subreq, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ talloc_free(frame);
+ return status;
+ }
+
+ status = nbt_name_refresh_wins_recv(subreq, mem_ctx, io);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
diff --git a/libcli/nbt/nameregister.c b/libcli/nbt/nameregister.c
new file mode 100644
index 0000000..8e8271d
--- /dev/null
+++ b/libcli/nbt/nameregister.c
@@ -0,0 +1,514 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ send out a name registration request
+
+ Copyright (C) Andrew Tridgell 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 <tevent.h>
+#include "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "../lib/util/tevent_ntstatus.h"
+
+/*
+ send a nbt name registration request
+*/
+struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->arcount = 1;
+ if (io->in.multi_homed) {
+ packet->operation = NBT_OPCODE_MULTI_HOME_REG;
+ } else {
+ packet->operation = NBT_OPCODE_REGISTER;
+ }
+ if (io->in.broadcast) {
+ packet->operation |= NBT_FLAG_BROADCAST;
+ }
+ if (io->in.register_demand) {
+ packet->operation |= NBT_FLAG_RECURSION_DESIRED;
+ }
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
+ if (packet->additional == NULL) goto failed;
+
+ packet->additional[0].name = io->in.name;
+ packet->additional[0].rr_type = NBT_QTYPE_NETBIOS;
+ packet->additional[0].rr_class = NBT_QCLASS_IP;
+ packet->additional[0].ttl = io->in.ttl;
+ packet->additional[0].rdata.netbios.length = 6;
+ packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
+ struct nbt_rdata_address, 1);
+ if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
+ packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
+ packet->additional[0].rdata.netbios.addresses[0].ipaddr =
+ talloc_strdup(packet->additional, io->in.address);
+ if (packet->additional[0].rdata.netbios.addresses[0].ipaddr == NULL) goto failed;
+
+ dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/*
+ wait for a registration reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ io->out.rcode = packet->operation & NBT_RCODE;
+ io->out.name = packet->answers[0].name;
+ if (packet->answers[0].rdata.netbios.length < 6) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ io->out.reply_addr = talloc_steal(mem_ctx,
+ packet->answers[0].rdata.netbios.addresses[0].ipaddr);
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ synchronous name registration request
+*/
+_PUBLIC_ NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
+{
+ struct nbt_name_request *req = nbt_name_register_send(nbtsock, io);
+ return nbt_name_register_recv(req, mem_ctx, io);
+}
+
+
+/*
+ a 4 step broadcast registration. 3 lots of name registration requests, followed by
+ a name registration demand
+*/
+struct nbt_name_register_bcast_state {
+ struct nbt_name_socket *nbtsock;
+ struct nbt_name_register io;
+};
+
+static void nbt_name_register_bcast_handler(struct nbt_name_request *subreq);
+
+/*
+ the async send call for a 4 stage name registration
+*/
+_PUBLIC_ struct tevent_req *nbt_name_register_bcast_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_bcast *io)
+{
+ struct tevent_req *req;
+ struct nbt_name_register_bcast_state *state;
+ struct nbt_name_request *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct nbt_name_register_bcast_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->io.in.name = io->in.name;
+ state->io.in.dest_addr = io->in.dest_addr;
+ state->io.in.dest_port = io->in.dest_port;
+ state->io.in.address = io->in.address;
+ state->io.in.nb_flags = io->in.nb_flags;
+ state->io.in.register_demand = false;
+ state->io.in.broadcast = true;
+ state->io.in.multi_homed = false;
+ state->io.in.ttl = io->in.ttl;
+ state->io.in.timeout = 1;
+ state->io.in.retries = 2;
+
+ state->nbtsock = nbtsock;
+
+ subreq = nbt_name_register_send(nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq->async.fn = nbt_name_register_bcast_handler;
+ subreq->async.private_data = req;
+
+ return req;
+}
+
+static void nbt_name_register_bcast_handler(struct nbt_name_request *subreq)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(subreq->async.private_data,
+ struct tevent_req);
+ struct nbt_name_register_bcast_state *state =
+ tevent_req_data(req,
+ struct nbt_name_register_bcast_state);
+ NTSTATUS status;
+
+ status = nbt_name_register_recv(subreq, state, &state->io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ if (state->io.in.register_demand == true) {
+ tevent_req_done(req);
+ return;
+ }
+
+ /* the registration timed out - good, send the demand */
+ state->io.in.register_demand = true;
+ state->io.in.retries = 0;
+
+ subreq = nbt_name_register_send(state->nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ subreq->async.fn = nbt_name_register_bcast_handler;
+ subreq->async.private_data = req;
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ DEBUG(3,("Name registration conflict from %s for %s with ip %s - rcode %d\n",
+ state->io.out.reply_from,
+ nbt_name_string(state, &state->io.out.name),
+ state->io.out.reply_addr,
+ state->io.out.rcode));
+
+ tevent_req_nterror(req, NT_STATUS_CONFLICTING_ADDRESSES);
+}
+
+/*
+ broadcast 4 part name register - recv
+*/
+_PUBLIC_ NTSTATUS nbt_name_register_bcast_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*
+ broadcast 4 part name register - sync interface
+*/
+NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_bcast *io)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *subreq;
+ NTSTATUS status;
+
+ /*
+ * TODO: create a temporary event context
+ */
+ ev = nbtsock->event_ctx;
+
+ subreq = nbt_name_register_bcast_send(frame, ev, nbtsock, io);
+ if (subreq == NULL) {
+ talloc_free(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(subreq, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ talloc_free(frame);
+ return status;
+ }
+
+ status = nbt_name_register_bcast_recv(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+
+/*
+ a wins name register with multiple WINS servers and multiple
+ addresses to register. Try each WINS server in turn, until we get a
+ reply for each address
+*/
+struct nbt_name_register_wins_state {
+ struct nbt_name_socket *nbtsock;
+ struct nbt_name_register io;
+ char **wins_servers;
+ uint16_t wins_port;
+ char **addresses;
+ uint32_t address_idx;
+};
+
+static void nbt_name_register_wins_handler(struct nbt_name_request *subreq);
+
+/*
+ the async send call for a multi-server WINS register
+*/
+_PUBLIC_ struct tevent_req *nbt_name_register_wins_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_wins *io)
+{
+ struct tevent_req *req;
+ struct nbt_name_register_wins_state *state;
+ struct nbt_name_request *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct nbt_name_register_wins_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (io->in.wins_servers == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.wins_servers[0] == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.addresses == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ if (io->in.addresses[0] == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->wins_port = io->in.wins_port;
+ state->wins_servers = str_list_copy(state, io->in.wins_servers);
+ if (tevent_req_nomem(state->wins_servers, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->addresses = str_list_copy(state, io->in.addresses);
+ if (tevent_req_nomem(state->addresses, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->io.in.name = io->in.name;
+ state->io.in.dest_addr = state->wins_servers[0];
+ state->io.in.dest_port = state->wins_port;
+ state->io.in.address = io->in.addresses[0];
+ state->io.in.nb_flags = io->in.nb_flags;
+ state->io.in.broadcast = false;
+ state->io.in.register_demand = false;
+ state->io.in.multi_homed = (io->in.nb_flags & NBT_NM_GROUP)?false:true;
+ state->io.in.ttl = io->in.ttl;
+ state->io.in.timeout = 3;
+ state->io.in.retries = 2;
+
+ state->nbtsock = nbtsock;
+ state->address_idx = 0;
+
+ subreq = nbt_name_register_send(nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq->async.fn = nbt_name_register_wins_handler;
+ subreq->async.private_data = req;
+
+ return req;
+}
+
+/*
+ state handler for WINS multi-homed multi-server name register
+*/
+static void nbt_name_register_wins_handler(struct nbt_name_request *subreq)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(subreq->async.private_data,
+ struct tevent_req);
+ struct nbt_name_register_wins_state *state =
+ tevent_req_data(req,
+ struct nbt_name_register_wins_state);
+ NTSTATUS status;
+
+ status = nbt_name_register_recv(subreq, state, &state->io);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+ /* the register timed out - try the next WINS server */
+ state->wins_servers++;
+ if (state->wins_servers[0] == NULL) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ state->address_idx = 0;
+ state->io.in.dest_addr = state->wins_servers[0];
+ state->io.in.dest_port = state->wins_port;
+ state->io.in.address = state->addresses[0];
+
+ subreq = nbt_name_register_send(state->nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ subreq->async.fn = nbt_name_register_wins_handler;
+ subreq->async.private_data = req;
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (state->io.out.rcode == 0 &&
+ state->addresses[state->address_idx+1] != NULL) {
+ /* register our next address */
+ state->io.in.address = state->addresses[++(state->address_idx)];
+
+ subreq = nbt_name_register_send(state->nbtsock, &state->io);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+
+ subreq->async.fn = nbt_name_register_wins_handler;
+ subreq->async.private_data = req;
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/*
+ multi-homed WINS name register - recv side
+*/
+_PUBLIC_ NTSTATUS nbt_name_register_wins_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io)
+{
+ struct nbt_name_register_wins_state *state =
+ tevent_req_data(req,
+ struct nbt_name_register_wins_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ io->out.wins_server = talloc_move(mem_ctx, &state->wins_servers[0]);
+ io->out.rcode = state->io.out.rcode;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+/*
+ multi-homed WINS register - sync interface
+*/
+_PUBLIC_ NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx,
+ struct nbt_name_register_wins *io)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *subreq;
+ NTSTATUS status;
+
+ /*
+ * TODO: create a temporary event context
+ */
+ ev = nbtsock->event_ctx;
+
+ subreq = nbt_name_register_wins_send(frame, ev, nbtsock, io);
+ if (subreq == NULL) {
+ talloc_free(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!tevent_req_poll(subreq, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ talloc_free(frame);
+ return status;
+ }
+
+ status = nbt_name_register_wins_recv(subreq, mem_ctx, io);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(frame);
+ return status;
+ }
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
diff --git a/libcli/nbt/namerelease.c b/libcli/nbt/namerelease.c
new file mode 100644
index 0000000..68c8252
--- /dev/null
+++ b/libcli/nbt/namerelease.c
@@ -0,0 +1,134 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ send out a name release request
+
+ Copyright (C) Andrew Tridgell 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 "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+
+/*
+ send a nbt name release request
+*/
+_PUBLIC_ struct nbt_name_request *nbt_name_release_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_release *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+ struct socket_address *dest;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->arcount = 1;
+ packet->operation = NBT_OPCODE_RELEASE;
+ if (io->in.broadcast) {
+ packet->operation |= NBT_FLAG_BROADCAST;
+ }
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
+ if (packet->additional == NULL) goto failed;
+
+ packet->additional[0].name = io->in.name;
+ packet->additional[0].rr_type = NBT_QTYPE_NETBIOS;
+ packet->additional[0].rr_class = NBT_QCLASS_IP;
+ packet->additional[0].ttl = 0;
+ packet->additional[0].rdata.netbios.length = 6;
+ packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
+ struct nbt_rdata_address, 1);
+ if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
+ packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
+ packet->additional[0].rdata.netbios.addresses[0].ipaddr =
+ talloc_strdup(packet->additional, io->in.address);
+
+ dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
+ io->in.dest_addr, io->in.dest_port);
+ if (dest == NULL) goto failed;
+ req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
+ io->in.timeout, io->in.retries, false);
+ if (req == NULL) goto failed;
+
+ talloc_free(packet);
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/*
+ wait for a release reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_release_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ io->out.rcode = packet->operation & NBT_RCODE;
+ io->out.name = packet->answers[0].name;
+ if (packet->answers[0].rdata.netbios.length < 6) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ io->out.reply_addr = talloc_steal(mem_ctx,
+ packet->answers[0].rdata.netbios.addresses[0].ipaddr);
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ synchronous name release request
+*/
+_PUBLIC_ NTSTATUS nbt_name_release(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_release *io)
+{
+ struct nbt_name_request *req = nbt_name_release_send(nbtsock, io);
+ return nbt_name_release_recv(req, mem_ctx, io);
+}
diff --git a/libcli/nbt/nbt_proto.h b/libcli/nbt/nbt_proto.h
new file mode 100644
index 0000000..e6ee46b
--- /dev/null
+++ b/libcli/nbt/nbt_proto.h
@@ -0,0 +1,65 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ manipulate nbt name structures
+
+ Copyright (C) Andrew Tridgell 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 _____LIBCLI_NBT_NBT_PROTO_H__
+#define _____LIBCLI_NBT_NBT_PROTO_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+/* This file was automatically generated by mkproto.pl. DO NOT EDIT */
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+
+/* The following definitions come from ../libcli/nbt/nbtsocket.c */
+
+struct nbt_name_request *nbt_name_request_send(TALLOC_CTX *mem_ctx,
+ struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ struct nbt_name_packet *request,
+ int timeout, int retries,
+ bool allow_multiple_replies);
+NTSTATUS nbt_name_request_recv(struct nbt_name_request *req);
+
+/* The following definitions come from ../libcli/nbt/namequery.c */
+
+
+/* The following definitions come from ../libcli/nbt/nameregister.c */
+
+struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register *io);
+NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register_bcast *io);
+
+/* The following definitions come from ../libcli/nbt/namerefresh.c */
+
+struct nbt_name_request *nbt_name_refresh_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_refresh *io);
+
+/* The following definitions come from ../libcli/nbt/namerelease.c */
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif /* _____LIBCLI_NBT_NBT_PROTO_H__ */
+
diff --git a/libcli/nbt/nbtname.c b/libcli/nbt/nbtname.c
new file mode 100644
index 0000000..a2b0d34
--- /dev/null
+++ b/libcli/nbt/nbtname.c
@@ -0,0 +1,486 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ manipulate nbt name structures
+
+ Copyright (C) Andrew Tridgell 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/>.
+*/
+
+/*
+ see rfc1002 for the detailed format of compressed names
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "system/locale.h"
+#include "lib/util/util_net.h"
+#include "libcli/nbt/libnbt.h"
+
+/*
+ decompress a 'compressed' name component
+ */
+static bool decompress_name(char *name, enum nbt_name_type *type)
+{
+ int i;
+ for (i=0;name[2*i];i++) {
+ uint8_t c1 = name[2*i];
+ uint8_t c2 = name[1+(2*i)];
+ if (c1 < 'A' || c1 > 'P' ||
+ c2 < 'A' || c2 > 'P') {
+ return false;
+ }
+ name[i] = ((c1-'A')<<4) | (c2-'A');
+ }
+ name[i] = 0;
+ if (i == 16) {
+ *type = (enum nbt_name_type)(name[15]);
+ name[15] = 0;
+ i--;
+ } else {
+ *type = NBT_NAME_CLIENT;
+ }
+
+ /* trim trailing spaces */
+ for (;i>0 && name[i-1]==' ';i--) {
+ name[i-1] = 0;
+ }
+
+ return true;
+}
+
+
+/*
+ compress a name component
+ */
+static uint8_t *compress_name(TALLOC_CTX *mem_ctx,
+ const uint8_t *name, enum nbt_name_type type)
+{
+ uint8_t *cname;
+ int i;
+ uint8_t pad_char;
+
+ if (strlen((const char *)name) > 15) {
+ return NULL;
+ }
+
+ cname = talloc_array(mem_ctx, uint8_t, 33);
+ if (cname == NULL) return NULL;
+
+ for (i=0;name[i];i++) {
+ cname[2*i] = 'A' + (name[i]>>4);
+ cname[1+2*i] = 'A' + (name[i]&0xF);
+ }
+ if (strcmp((const char *)name, "*") == 0) {
+ pad_char = 0;
+ } else {
+ pad_char = ' ';
+ }
+ for (;i<15;i++) {
+ cname[2*i] = 'A' + (pad_char>>4);
+ cname[1+2*i] = 'A' + (pad_char&0xF);
+ }
+
+ pad_char = type;
+ cname[2*i] = 'A' + (pad_char>>4);
+ cname[1+2*i] = 'A' + (pad_char&0xF);
+
+ cname[32] = 0;
+ return cname;
+}
+
+
+/**
+ pull a nbt name from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct nbt_name *r)
+{
+ uint8_t *scope;
+ char *cname;
+ const char *s;
+ bool ok;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ NDR_CHECK(ndr_pull_nbt_string(ndr, ndr_flags, &s));
+
+ scope = (uint8_t *)strchr(s, '.');
+ if (scope) {
+ *scope = 0;
+ r->scope = talloc_strdup(ndr->current_mem_ctx, (const char *)&scope[1]);
+ NDR_ERR_HAVE_NO_MEMORY(r->scope);
+ } else {
+ r->scope = NULL;
+ }
+
+ cname = discard_const_p(char, s);
+
+ /* the first component is limited to 16 bytes in the DOS charset,
+ which is 32 in the 'compressed' form */
+ if (strlen(cname) > 32) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "NBT NAME cname > 32");
+ }
+
+ /* decompress the first component */
+ ok = decompress_name(cname, &r->type);
+ if (!ok) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "NBT NAME failed to decompress");
+ }
+
+ r->name = talloc_strdup(ndr->current_mem_ctx, cname);
+ NDR_ERR_HAVE_NO_MEMORY(r->name);
+
+ talloc_free(cname);
+
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a nbt name to the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct nbt_name *r)
+{
+ uint8_t *cname, *fullname;
+ enum ndr_err_code ndr_err;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (strlen(r->name) > 15) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "nbt_name longer as 15 chars: %s",
+ r->name);
+ }
+
+ cname = compress_name(ndr, (const uint8_t *)r->name, r->type);
+ NDR_ERR_HAVE_NO_MEMORY(cname);
+
+ if (r->scope) {
+ fullname = (uint8_t *)talloc_asprintf(ndr, "%s.%s", cname, r->scope);
+ NDR_ERR_HAVE_NO_MEMORY(fullname);
+ talloc_free(cname);
+ } else {
+ fullname = cname;
+ }
+
+ ndr_err = ndr_push_nbt_string(ndr, ndr_flags, (const char *)fullname);
+
+ return ndr_err;
+}
+
+
+/**
+ copy a nbt name structure
+*/
+_PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx,
+ const struct nbt_name *name,
+ struct nbt_name *newname)
+{
+ *newname = *name;
+ newname->name = talloc_strdup(mem_ctx, newname->name);
+ NT_STATUS_HAVE_NO_MEMORY(newname->name);
+ newname->scope = talloc_strdup(mem_ctx, newname->scope);
+ if (name->scope) {
+ NT_STATUS_HAVE_NO_MEMORY(newname->scope);
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ push a nbt name into a blob
+*/
+_PUBLIC_ NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name)
+{
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(blob, mem_ctx, name, (ndr_push_flags_fn_t)ndr_push_nbt_name);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ pull a nbt name from a blob
+*/
+_PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name)
+{
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_pull_struct_blob(blob, mem_ctx, name,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_name);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ choose a name to use when calling a server in a NBT session request.
+ we use heuristics to see if the name we have been given is a IP
+ address, or a too-long name. If it is then use *SMBSERVER, or a
+ truncated name
+*/
+_PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx,
+ struct nbt_name *n, const char *name, int type)
+{
+ n->scope = NULL;
+ n->type = type;
+
+ if ((name == NULL) || is_ipaddress(name)) {
+ n->name = "*SMBSERVER";
+ return;
+ }
+ if (strlen(name) > 15) {
+ const char *p = strchr(name, '.');
+ char *s;
+ if (p - name > 15) {
+ n->name = "*SMBSERVER";
+ return;
+ }
+ s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
+ n->name = talloc_strdup_upper(mem_ctx, s);
+ return;
+ }
+
+ n->name = talloc_strdup_upper(mem_ctx, name);
+}
+
+
+/*
+ escape a string into a form containing only a small set of characters,
+ the rest is hex encoded. This is similar to URL encoding
+*/
+static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
+{
+ int i, len;
+ char *ret;
+ const char *valid_chars = "_-.$@ ";
+#define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c))
+
+ for (len=i=0;s[i];i++,len++) {
+ if (!NBT_CHAR_ALLOW(s[i])) {
+ len += 2;
+ }
+ }
+
+ ret = talloc_array(mem_ctx, char, len+1);
+ if (ret == NULL) return NULL;
+
+ for (len=i=0;s[i];i++) {
+ if (NBT_CHAR_ALLOW(s[i])) {
+ ret[len++] = s[i];
+ } else {
+ snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]);
+ len += 3;
+ }
+ }
+ ret[len] = 0;
+
+ return ret;
+}
+
+
+/**
+ form a string for a NBT name
+*/
+_PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ char *ret;
+ if (name->scope) {
+ ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
+ nbt_hex_encode(tmp_ctx, name->name),
+ name->type,
+ nbt_hex_encode(tmp_ctx, name->scope));
+ } else {
+ ret = talloc_asprintf(mem_ctx, "%s<%02x>",
+ nbt_hex_encode(tmp_ctx, name->name),
+ name->type);
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/**
+ pull a nbt name, WINS Replication uses another on wire format for nbt name
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct nbt_name **_r)
+{
+ struct nbt_name *r;
+ uint8_t *namebuf;
+ uint32_t namebuf_len;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &namebuf_len));
+ if (namebuf_len < 1 || namebuf_len > 255) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "value (%"PRIu32") out of range (1 - 255)", namebuf_len);
+ }
+ NDR_PULL_ALLOC_N(ndr, namebuf, namebuf_len);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
+
+ if ((namebuf_len % 4) == 0) {
+ /*
+ * [MS-WINSRA] — v20091104 was wrong
+ * regarding section "2.2.10.1 Name Record"
+ *
+ * If the name buffer is already 4 byte aligned
+ * Windows (at least 2003 SP1 and 2008) add 4 extra
+ * bytes. This can happen when the name has a scope.
+ */
+ uint32_t pad;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &pad));
+ }
+
+ NDR_PULL_ALLOC(ndr, r);
+
+ /* oh wow, what a nasty bug in windows ... */
+ if (namebuf[0] == 0x1b && namebuf_len >= 16) {
+ namebuf[0] = namebuf[15];
+ namebuf[15] = 0x1b;
+ }
+
+ if (namebuf_len < 17) {
+ r->type = 0x00;
+
+ r->name = talloc_strndup(r, (char *)namebuf, namebuf_len);
+ if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
+
+ r->scope= NULL;
+
+ talloc_free(namebuf);
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+ }
+
+ r->type = namebuf[15];
+
+ namebuf[15] = '\0';
+ trim_string((char *)namebuf, NULL, " ");
+ r->name = talloc_strdup(r, (char *)namebuf);
+ if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
+
+ if (namebuf_len > 17) {
+ r->scope = talloc_strndup(r, (char *)(namebuf+16), namebuf_len-17);
+ if (!r->scope) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory");
+ } else {
+ r->scope = NULL;
+ }
+
+ talloc_free(namebuf);
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a nbt name, WINS Replication uses another on wire format for nbt name
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_wrepl_nbt_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct nbt_name *r)
+{
+ uint8_t *namebuf;
+ uint32_t namebuf_len;
+ uint32_t _name_len;
+ uint32_t scope_len = 0;
+
+ if (r == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER,
+ "wrepl_nbt_name NULL pointer");
+ }
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ _name_len = strlen(r->name);
+ if (_name_len > 15) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "wrepl_nbt_name longer as 15 chars: %s",
+ r->name);
+ }
+
+ if (r->scope) {
+ scope_len = strlen(r->scope);
+ }
+ if (scope_len > 238) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "wrepl_nbt_name scope longer as 238 chars: %s",
+ r->scope);
+ }
+
+ namebuf = (uint8_t *)talloc_asprintf(ndr, "%-15s%c%s",
+ r->name, 'X',
+ (r->scope?r->scope:""));
+ if (!namebuf) return ndr_push_error(ndr, NDR_ERR_ALLOC, "out of memory");
+
+ namebuf_len = strlen((char *)namebuf) + 1;
+
+ /*
+ * we need to set the type here, and use a place-holder in the talloc_asprintf()
+ * as the type can be 0x00, and then the namebuf_len = strlen(namebuf); would give wrong results
+ */
+ namebuf[15] = r->type;
+
+ /* oh wow, what a nasty bug in windows ... */
+ if (r->type == 0x1b) {
+ namebuf[15] = namebuf[0];
+ namebuf[0] = 0x1b;
+ }
+
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, namebuf_len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len));
+
+ if ((namebuf_len % 4) == 0) {
+ /*
+ * [MS-WINSRA] — v20091104 was wrong
+ * regarding section "2.2.10.1 Name Record"
+ *
+ * If the name buffer is already 4 byte aligned
+ * Windows (at least 2003 SP1 and 2008) add 4 extra
+ * bytes. This can happen when the name has a scope.
+ */
+ NDR_CHECK(ndr_push_zero(ndr, 4));
+ }
+
+ talloc_free(namebuf);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_wrepl_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r)
+{
+ char *s = nbt_name_string(ndr, r);
+ ndr_print_string(ndr, name, s);
+ talloc_free(s);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_qtype(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum nbt_qtype r)
+{
+ /* For WACK replies, we need to send NBT_QTYPE_NETBIOS on the wire. */
+ NDR_CHECK(ndr_push_enum_uint16(ndr, NDR_SCALARS, (r == NBT_QTYPE_WACK) ? NBT_QTYPE_NETBIOS : r));
+ return NDR_ERR_SUCCESS;
+}
diff --git a/libcli/nbt/nbtsocket.c b/libcli/nbt/nbtsocket.c
new file mode 100644
index 0000000..47e73cf
--- /dev/null
+++ b/libcli/nbt/nbtsocket.c
@@ -0,0 +1,566 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ low level socket handling for nbt requests
+
+ Copyright (C) Andrew Tridgell 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 "lib/events/events.h"
+#include "../lib/util/dlinklist.h"
+#include "../libcli/nbt/libnbt.h"
+#include "../libcli/nbt/nbt_proto.h"
+#include "lib/socket/socket.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "param/param.h"
+#include "lib/util/idtree_random.h"
+
+#define NBT_MAX_REPLIES 1000
+
+/*
+ destroy a pending request
+*/
+static int nbt_name_request_destructor(struct nbt_name_request *req)
+{
+ if (req->state == NBT_REQUEST_SEND) {
+ DLIST_REMOVE(req->nbtsock->send_queue, req);
+ }
+ if (req->state == NBT_REQUEST_WAIT) {
+ req->nbtsock->num_pending--;
+ }
+ if (req->name_trn_id != 0 && !req->is_reply) {
+ idr_remove(req->nbtsock->idr, req->name_trn_id);
+ req->name_trn_id = 0;
+ }
+ TALLOC_FREE(req->te);
+ if (req->nbtsock->send_queue == NULL) {
+ TEVENT_FD_NOT_WRITEABLE(req->nbtsock->fde);
+ }
+ if (req->nbtsock->num_pending == 0 &&
+ req->nbtsock->incoming.handler == NULL) {
+ TEVENT_FD_NOT_READABLE(req->nbtsock->fde);
+ }
+ return 0;
+}
+
+
+/*
+ handle send events on a nbt name socket
+*/
+static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
+{
+ struct nbt_name_request *req;
+ TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
+ NTSTATUS status;
+
+ while ((req = nbtsock->send_queue)) {
+ size_t len;
+
+ len = req->encoded.length;
+ status = socket_sendto(nbtsock->sock, &req->encoded, &len,
+ req->dest);
+ if (NT_STATUS_IS_ERR(status)) goto failed;
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ DLIST_REMOVE(nbtsock->send_queue, req);
+ req->state = NBT_REQUEST_WAIT;
+ if (req->is_reply) {
+ talloc_free(req);
+ } else {
+ TEVENT_FD_READABLE(nbtsock->fde);
+ nbtsock->num_pending++;
+ }
+ }
+
+ TEVENT_FD_NOT_WRITEABLE(nbtsock->fde);
+ talloc_free(tmp_ctx);
+ return;
+
+failed:
+ DLIST_REMOVE(nbtsock->send_queue, req);
+ nbt_name_request_destructor(req);
+ req->status = status;
+ req->state = NBT_REQUEST_ERROR;
+ talloc_free(tmp_ctx);
+ if (req->async.fn) {
+ req->async.fn(req);
+ } else if (req->is_reply) {
+ talloc_free(req);
+ }
+ return;
+}
+
+
+/*
+ handle a request timeout
+*/
+static void nbt_name_socket_timeout(struct tevent_context *ev, struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct nbt_name_request *req = talloc_get_type(private_data,
+ struct nbt_name_request);
+
+ if (req->num_retries != 0) {
+ req->num_retries--;
+ req->te = tevent_add_timer(req->nbtsock->event_ctx, req,
+ timeval_add(&t, req->timeout, 0),
+ nbt_name_socket_timeout, req);
+ if (req->state != NBT_REQUEST_SEND) {
+ req->state = NBT_REQUEST_SEND;
+ DLIST_ADD_END(req->nbtsock->send_queue, req);
+ }
+ TEVENT_FD_WRITEABLE(req->nbtsock->fde);
+ return;
+ }
+
+ nbt_name_request_destructor(req);
+ if (req->num_replies == 0) {
+ req->state = NBT_REQUEST_TIMEOUT;
+ req->status = NT_STATUS_IO_TIMEOUT;
+ } else {
+ req->state = NBT_REQUEST_DONE;
+ req->status = NT_STATUS_OK;
+ }
+ if (req->async.fn) {
+ req->async.fn(req);
+ } else if (req->is_reply) {
+ talloc_free(req);
+ }
+}
+
+
+
+/**
+ handle recv events on a nbt name socket
+*/
+static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ struct socket_address *src;
+ DATA_BLOB blob;
+ size_t nread, dsize;
+ struct nbt_name_packet *packet;
+ struct nbt_name_request *req;
+
+ status = socket_pending(nbtsock->sock, &dsize);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ /*
+ * Given a zero length, data_blob_talloc() returns the
+ * NULL blob {NULL, 0}.
+ *
+ * We only want to error return here on a real out of memory condition
+ * (i.e. dsize != 0, so the UDP packet has data, but the return of the
+ * allocation failed, so blob.data==NULL).
+ *
+ * Given an actual zero length UDP packet having blob.data == NULL
+ * isn't an out of memory error condition, that's the defined semantics
+ * of data_blob_talloc() when asked for zero bytes.
+ *
+ * We still need to continue to do the zero-length socket_recvfrom()
+ * read in order to clear the "read pending" condition on the socket.
+ */
+ blob = data_blob_talloc(tmp_ctx, NULL, dsize);
+ if (blob.data == NULL && dsize != 0) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ status = socket_recvfrom(nbtsock->sock, blob.data, blob.length, &nread,
+ tmp_ctx, &src);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ packet = talloc(tmp_ctx, struct nbt_name_packet);
+ if (packet == NULL) {
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ /* parse the request */
+ ndr_err = ndr_pull_struct_blob(&blob, packet, packet,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(2,("Failed to parse incoming NBT name packet - %s\n",
+ nt_errstr(status)));
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ if (DEBUGLVL(10)) {
+ DEBUG(10,("Received nbt packet of length %d from %s:%d\n",
+ (int)blob.length, src->addr, src->port));
+ NDR_PRINT_DEBUG(nbt_name_packet, packet);
+ }
+
+ /* if its not a reply then pass it off to the incoming request
+ handler, if any */
+ if (!(packet->operation & NBT_FLAG_REPLY)) {
+ if (nbtsock->incoming.handler) {
+ nbtsock->incoming.handler(nbtsock, packet, src);
+ }
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ /* find the matching request */
+ req = (struct nbt_name_request *)idr_find(nbtsock->idr,
+ packet->name_trn_id);
+ if (req == NULL) {
+ if (nbtsock->unexpected.handler) {
+ nbtsock->unexpected.handler(nbtsock, packet, src);
+ } else {
+ DEBUG(10,("Failed to match request for incoming name packet id 0x%04x on %p\n",
+ packet->name_trn_id, nbtsock));
+ }
+ talloc_free(tmp_ctx);
+ return;
+ }
+
+ talloc_steal(req, packet);
+ talloc_steal(req, src);
+ talloc_free(tmp_ctx);
+ nbt_name_socket_handle_response_packet(req, packet, src);
+}
+
+void nbt_name_socket_handle_response_packet(struct nbt_name_request *req,
+ struct nbt_name_packet *packet,
+ struct socket_address *src)
+{
+ /* if this is a WACK response, this we need to go back to waiting,
+ but perhaps increase the timeout */
+ if ((packet->operation & NBT_OPCODE) == NBT_OPCODE_WACK) {
+ uint32_t ttl;
+ if (req->received_wack || packet->ancount < 1) {
+ nbt_name_request_destructor(req);
+ req->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ req->state = NBT_REQUEST_ERROR;
+ goto done;
+ }
+ talloc_free(req->te);
+ /* we know we won't need any more retries - the server
+ has received our request */
+ req->num_retries = 0;
+ req->received_wack = true;
+ /*
+ * there is a timeout in the packet,
+ * it is 5 + 4 * num_old_addresses
+ *
+ * although w2k3 screws it up
+ * and uses num_old_addresses = 0
+ *
+ * so we better fallback to the maximum
+ * of num_old_addresses = 25 if we got
+ * a timeout of less than 9s (5 + 4*1)
+ * or more than 105s (5 + 4*25).
+ */
+ ttl = packet->answers[0].ttl;
+ if ((ttl < (5 + 4*1)) || (ttl > (5 + 4*25))) {
+ ttl = 5 + 4*25;
+ }
+ req->timeout = ttl;
+ req->te = tevent_add_timer(req->nbtsock->event_ctx, req,
+ timeval_current_ofs(req->timeout, 0),
+ nbt_name_socket_timeout, req);
+ return;
+ }
+
+
+ req->replies = talloc_realloc(req, req->replies, struct nbt_name_reply, req->num_replies+1);
+ if (req->replies == NULL) {
+ nbt_name_request_destructor(req);
+ req->state = NBT_REQUEST_ERROR;
+ req->status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ talloc_steal(req, src);
+ req->replies[req->num_replies].dest = src;
+ talloc_steal(req, packet);
+ req->replies[req->num_replies].packet = packet;
+ req->num_replies++;
+
+ /* if we don't want multiple replies then we are done */
+ if (req->allow_multiple_replies &&
+ req->num_replies < NBT_MAX_REPLIES) {
+ return;
+ }
+
+ nbt_name_request_destructor(req);
+ req->state = NBT_REQUEST_DONE;
+ req->status = NT_STATUS_OK;
+
+done:
+ if (req->async.fn) {
+ req->async.fn(req);
+ }
+}
+
+/*
+ handle fd events on a nbt_name_socket
+*/
+static void nbt_name_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *private_data)
+{
+ struct nbt_name_socket *nbtsock = talloc_get_type(private_data,
+ struct nbt_name_socket);
+ if (flags & TEVENT_FD_WRITE) {
+ nbt_name_socket_send(nbtsock);
+ }
+ if (flags & TEVENT_FD_READ) {
+ nbt_name_socket_recv(nbtsock);
+ }
+}
+
+
+/*
+ initialise a nbt_name_socket. The event_ctx is optional, if provided
+ then operations will use that event context
+*/
+_PUBLIC_ struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx,
+ struct tevent_context *event_ctx)
+{
+ struct nbt_name_socket *nbtsock;
+ NTSTATUS status;
+
+ nbtsock = talloc(mem_ctx, struct nbt_name_socket);
+ if (nbtsock == NULL) goto failed;
+
+ nbtsock->event_ctx = event_ctx;
+ if (nbtsock->event_ctx == NULL) goto failed;
+
+ status = socket_create(nbtsock, "ip", SOCKET_TYPE_DGRAM,
+ &nbtsock->sock, 0);
+ if (!NT_STATUS_IS_OK(status)) goto failed;
+
+ socket_set_option(nbtsock->sock, "SO_BROADCAST", "1");
+
+ nbtsock->idr = idr_init(nbtsock);
+ if (nbtsock->idr == NULL) goto failed;
+
+ nbtsock->send_queue = NULL;
+ nbtsock->num_pending = 0;
+ nbtsock->incoming.handler = NULL;
+ nbtsock->unexpected.handler = NULL;
+
+ nbtsock->fde = tevent_add_fd(nbtsock->event_ctx, nbtsock,
+ socket_get_fd(nbtsock->sock), 0,
+ nbt_name_socket_handler, nbtsock);
+
+ return nbtsock;
+
+failed:
+ talloc_free(nbtsock);
+ return NULL;
+}
+
+/*
+ send off a nbt name request
+*/
+struct nbt_name_request *nbt_name_request_send(TALLOC_CTX *mem_ctx,
+ struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ struct nbt_name_packet *request,
+ int timeout, int retries,
+ bool allow_multiple_replies)
+{
+ struct nbt_name_request *req;
+ int id;
+ enum ndr_err_code ndr_err;
+
+ req = talloc_zero(mem_ctx, struct nbt_name_request);
+ if (req == NULL) goto failed;
+
+ req->nbtsock = nbtsock;
+ req->allow_multiple_replies = allow_multiple_replies;
+ req->state = NBT_REQUEST_SEND;
+ req->is_reply = false;
+ req->timeout = timeout;
+ req->num_retries = retries;
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) goto failed;
+
+ /* we select a random transaction id unless the user supplied one */
+ if (request->name_trn_id == 0) {
+ id = idr_get_new_random(
+ req->nbtsock->idr, req, 1, UINT16_MAX);
+ } else {
+ if (idr_find(req->nbtsock->idr, request->name_trn_id)) goto failed;
+ id = idr_get_new_above(req->nbtsock->idr, req, request->name_trn_id,
+ UINT16_MAX);
+ }
+ if (id == -1) goto failed;
+
+ request->name_trn_id = id;
+ req->name_trn_id = id;
+
+ req->te = tevent_add_timer(nbtsock->event_ctx, req,
+ timeval_current_ofs(req->timeout, 0),
+ nbt_name_socket_timeout, req);
+
+ talloc_set_destructor(req, nbt_name_request_destructor);
+
+ ndr_err = ndr_push_struct_blob(&req->encoded, req,
+ request,
+ (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
+
+ DLIST_ADD_END(nbtsock->send_queue, req);
+
+ if (DEBUGLVL(10)) {
+ DEBUG(10,("Queueing nbt packet to %s:%d\n",
+ req->dest->addr, req->dest->port));
+ NDR_PRINT_DEBUG(nbt_name_packet, request);
+ }
+
+ TEVENT_FD_WRITEABLE(nbtsock->fde);
+
+ return req;
+
+failed:
+ talloc_free(req);
+ return NULL;
+}
+
+
+/*
+ send off a nbt name reply
+*/
+_PUBLIC_ NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
+ struct socket_address *dest,
+ struct nbt_name_packet *request)
+{
+ struct nbt_name_request *req;
+ enum ndr_err_code ndr_err;
+
+ req = talloc_zero(nbtsock, struct nbt_name_request);
+ NT_STATUS_HAVE_NO_MEMORY(req);
+
+ req->nbtsock = nbtsock;
+ req->dest = socket_address_copy(req, dest);
+ if (req->dest == NULL) goto failed;
+ req->state = NBT_REQUEST_SEND;
+ req->is_reply = true;
+
+ talloc_set_destructor(req, nbt_name_request_destructor);
+
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(nbt_name_packet, request);
+ }
+
+ ndr_err = ndr_push_struct_blob(&req->encoded, req,
+ request,
+ (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(req);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ DLIST_ADD_END(nbtsock->send_queue, req);
+
+ TEVENT_FD_WRITEABLE(nbtsock->fde);
+
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(req);
+ return NT_STATUS_NO_MEMORY;
+}
+
+/*
+ wait for a nbt request to complete
+*/
+NTSTATUS nbt_name_request_recv(struct nbt_name_request *req)
+{
+ if (!req) return NT_STATUS_NO_MEMORY;
+
+ while (req->state < NBT_REQUEST_DONE) {
+ if (tevent_loop_once(req->nbtsock->event_ctx) != 0) {
+ req->state = NBT_REQUEST_ERROR;
+ req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ break;
+ }
+ }
+ return req->status;
+}
+
+
+/*
+ setup a handler for incoming requests
+*/
+_PUBLIC_ NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *),
+ void *private_data)
+{
+ nbtsock->incoming.handler = handler;
+ nbtsock->incoming.private_data = private_data;
+ TEVENT_FD_READABLE(nbtsock->fde);
+ return NT_STATUS_OK;
+}
+
+/*
+ setup a handler for unexpected requests
+*/
+NTSTATUS nbt_set_unexpected_handler(struct nbt_name_socket *nbtsock,
+ void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *,
+ struct socket_address *),
+ void *private_data)
+{
+ nbtsock->unexpected.handler = handler;
+ nbtsock->unexpected.private_data = private_data;
+ TEVENT_FD_READABLE(nbtsock->fde);
+ return NT_STATUS_OK;
+}
+
+/*
+ turn a NBT rcode into a NTSTATUS
+*/
+_PUBLIC_ NTSTATUS nbt_rcode_to_ntstatus(uint8_t rcode)
+{
+ size_t i;
+ struct {
+ enum nbt_rcode rcode;
+ NTSTATUS status;
+ } map[] = {
+ { NBT_RCODE_FMT, NT_STATUS_INVALID_PARAMETER },
+ { NBT_RCODE_SVR, NT_STATUS_SERVER_DISABLED },
+ { NBT_RCODE_NAM, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { NBT_RCODE_IMP, NT_STATUS_NOT_SUPPORTED },
+ { NBT_RCODE_RFS, NT_STATUS_ACCESS_DENIED },
+ { NBT_RCODE_ACT, NT_STATUS_ADDRESS_ALREADY_EXISTS },
+ { NBT_RCODE_CFT, NT_STATUS_CONFLICTING_ADDRESSES }
+ };
+ for (i=0;i<ARRAY_SIZE(map);i++) {
+ if (map[i].rcode == rcode) {
+ return map[i].status;
+ }
+ }
+ return NT_STATUS_UNSUCCESSFUL;
+}
diff --git a/libcli/nbt/pynbt.c b/libcli/nbt/pynbt.c
new file mode 100644
index 0000000..e0a72fa
--- /dev/null
+++ b/libcli/nbt/pynbt.c
@@ -0,0 +1,447 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright © 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 "lib/replace/system/python.h"
+#include "includes.h"
+#include "python/py3compat.h"
+#include "libcli/util/pyerrors.h"
+#include "python/modules.h"
+#include "../libcli/nbt/libnbt.h"
+#include "lib/events/events.h"
+
+void initnetbios(void);
+
+extern PyTypeObject nbt_node_Type;
+
+typedef struct {
+ PyObject_HEAD
+ TALLOC_CTX *mem_ctx;
+ struct nbt_name_socket *socket;
+} nbt_node_Object;
+
+static void py_nbt_node_dealloc(nbt_node_Object *self)
+{
+ talloc_free(self->mem_ctx);
+ Py_TYPE(self)->tp_free(self);
+}
+
+static PyObject *py_nbt_node_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
+{
+ struct tevent_context *ev;
+ nbt_node_Object *ret = PyObject_New(nbt_node_Object, &nbt_node_Type);
+
+ ret->mem_ctx = talloc_new(NULL);
+ if (ret->mem_ctx == NULL)
+ return NULL;
+
+ ev = s4_event_context_init(ret->mem_ctx);
+ ret->socket = nbt_name_socket_init(ret->mem_ctx, ev);
+ return (PyObject *)ret;
+}
+
+static bool PyObject_AsDestinationTuple(PyObject *obj, const char **dest_addr, uint16_t *dest_port)
+{
+ if (PyUnicode_Check(obj)) {
+ *dest_addr = PyUnicode_AsUTF8(obj);
+ *dest_port = NBT_NAME_SERVICE_PORT;
+ return true;
+ }
+
+ if (PyTuple_Check(obj)) {
+ if (PyTuple_Size(obj) < 1) {
+ PyErr_SetString(PyExc_TypeError, "Destination tuple size invalid");
+ return false;
+ }
+
+ if (!PyUnicode_Check(PyTuple_GetItem(obj, 0))) {
+ PyErr_SetString(PyExc_TypeError, "Destination tuple first element not string");
+ return false;
+ }
+
+ *dest_addr = PyUnicode_AsUTF8(obj);
+
+ if (PyTuple_Size(obj) == 1) {
+ *dest_port = NBT_NAME_SERVICE_PORT;
+ return true;
+ } else if (PyLong_Check(PyTuple_GetItem(obj, 1))) {
+ *dest_port = PyLong_AsLong(PyTuple_GetItem(obj, 1));
+ return true;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Destination tuple second element not a port");
+ return false;
+ }
+ }
+
+ PyErr_SetString(PyExc_TypeError, "Destination tuple second element not a port");
+ return false;
+}
+
+static bool PyObject_AsNBTName(PyObject *obj, struct nbt_name_socket *name_socket, struct nbt_name *name)
+{
+ if (PyTuple_Check(obj)) {
+ if (PyTuple_Size(obj) == 2) {
+ name->name = PyUnicode_AsUTF8(PyTuple_GetItem(obj, 0));
+ if (name->name == NULL) {
+ goto err;
+ }
+ name->type = PyLong_AsLong(PyTuple_GetItem(obj, 1));
+ if (name->type == -1 && PyErr_Occurred()) {
+ goto err;
+ }
+ name->scope = NULL;
+ return true;
+ } else if (PyTuple_Size(obj) == 3) {
+ name->name = PyUnicode_AsUTF8(PyTuple_GetItem(obj, 0));
+ if (name->name == NULL) {
+ goto err;
+ }
+ name->scope = PyUnicode_AsUTF8(PyTuple_GetItem(obj, 1));
+ if (name->scope == NULL) {
+ goto err;
+ }
+ name->type = PyLong_AsLong(PyTuple_GetItem(obj, 2));
+ if (name->type == -1 && PyErr_Occurred()) {
+ goto err;
+ }
+ return true;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Invalid tuple size");
+ return false;
+ }
+ }
+
+ if (PyUnicode_Check(obj)) {
+ /* FIXME: Parse string to be able to interpret things like RHONWYN<02> ? */
+ name->name = PyUnicode_AsUTF8(obj);
+ if (name->name == NULL) {
+ goto err;
+ }
+ name->scope = NULL;
+ name->type = 0;
+ return true;
+ }
+err:
+ PyErr_SetString(PyExc_TypeError, "Invalid type for object");
+ return false;
+}
+
+static PyObject *PyObject_FromNBTName(struct nbt_name_socket *name_socket,
+ struct nbt_name *name)
+{
+ if (name->scope) {
+ return Py_BuildValue("(ssi)", name->name, name->scope, name->type);
+ } else {
+ return Py_BuildValue("(si)", name->name, name->type);
+ }
+}
+
+static PyObject *py_nbt_name_query(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ nbt_node_Object *node = (nbt_node_Object *)self;
+ PyObject *ret, *reply_addrs, *py_dest, *py_name;
+ struct nbt_name_query io;
+ NTSTATUS status;
+ int i;
+
+ const char *kwnames[] = { "name", "dest", "broadcast", "wins", "timeout",
+ "retries", NULL };
+ io.in.broadcast = true;
+ io.in.wins_lookup = false;
+ io.in.timeout = 0;
+ io.in.retries = 3;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bbii:query_name",
+ discard_const_p(char *, kwnames),
+ &py_name, &py_dest,
+ &io.in.broadcast, &io.in.wins_lookup,
+ &io.in.timeout, &io.in.retries)) {
+ return NULL;
+ }
+
+ if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port))
+ return NULL;
+
+ if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name))
+ return NULL;
+
+ status = nbt_name_query(node->socket, NULL, &io);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ ret = PyTuple_New(3);
+ if (ret == NULL)
+ return NULL;
+ PyTuple_SetItem(ret, 0, PyUnicode_FromString(io.out.reply_from));
+
+ py_name = PyObject_FromNBTName(node->socket, &io.out.name);
+ if (py_name == NULL)
+ return NULL;
+
+ PyTuple_SetItem(ret, 1, py_name);
+
+ reply_addrs = PyList_New(io.out.num_addrs);
+ if (reply_addrs == NULL) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ for (i = 0; i < io.out.num_addrs; i++) {
+ PyList_SetItem(reply_addrs, i, PyUnicode_FromString(io.out.reply_addrs[i]));
+ }
+
+ PyTuple_SetItem(ret, 2, reply_addrs);
+ return ret;
+}
+
+static PyObject *py_nbt_name_status(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ nbt_node_Object *node = (nbt_node_Object *)self;
+ PyObject *ret, *py_dest, *py_name, *py_names;
+ struct nbt_name_status io;
+ int i;
+ NTSTATUS status;
+
+ const char *kwnames[] = { "name", "dest", "timeout", "retries", NULL };
+
+ io.in.timeout = 0;
+ io.in.retries = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ii:name_status",
+ discard_const_p(char *, kwnames),
+ &py_name, &py_dest,
+ &io.in.timeout, &io.in.retries)) {
+ return NULL;
+ }
+
+ if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port))
+ return NULL;
+
+ if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name))
+ return NULL;
+
+ status = nbt_name_status(node->socket, NULL, &io);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ ret = PyTuple_New(3);
+ if (ret == NULL)
+ return NULL;
+ PyTuple_SetItem(ret, 0, PyUnicode_FromString(io.out.reply_from));
+
+ py_name = PyObject_FromNBTName(node->socket, &io.out.name);
+ if (py_name == NULL)
+ return NULL;
+
+ PyTuple_SetItem(ret, 1, py_name);
+
+ py_names = PyList_New(io.out.status.num_names);
+
+ for (i = 0; i < io.out.status.num_names; i++) {
+ PyList_SetItem(py_names, i, Py_BuildValue("(sii)",
+ io.out.status.names[i].name,
+ io.out.status.names[i].nb_flags,
+ io.out.status.names[i].type));
+ }
+
+ PyTuple_SetItem(ret, 2, py_names);
+
+ return ret;
+}
+
+static PyObject *py_nbt_name_register(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ nbt_node_Object *node = (nbt_node_Object *)self;
+ PyObject *ret, *py_dest, *py_name;
+ struct nbt_name_register io;
+ NTSTATUS status;
+
+ const char *kwnames[] = { "name", "address", "dest", "register_demand", "broadcast",
+ "multi_homed", "ttl", "timeout", "retries", NULL };
+
+ io.in.broadcast = true;
+ io.in.multi_homed = true;
+ io.in.register_demand = true;
+ io.in.ttl = 0;
+ io.in.timeout = 0;
+ io.in.retries = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OsO|bbbiii:query_name",
+ discard_const_p(char *, kwnames),
+ &py_name, &io.in.address, &py_dest,
+ &io.in.register_demand,
+ &io.in.broadcast, &io.in.multi_homed,
+ &io.in.ttl, &io.in.timeout, &io.in.retries)) {
+ return NULL;
+ }
+
+ if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port))
+ return NULL;
+
+ if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name))
+ return NULL;
+
+ status = nbt_name_register(node->socket, NULL, &io);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ ret = PyTuple_New(4);
+ if (ret == NULL)
+ return NULL;
+ PyTuple_SetItem(ret, 0, PyUnicode_FromString(io.out.reply_from));
+
+ py_name = PyObject_FromNBTName(node->socket, &io.out.name);
+ if (py_name == NULL)
+ return NULL;
+
+ PyTuple_SetItem(ret, 1, py_name);
+
+ PyTuple_SetItem(ret, 2, PyUnicode_FromString(io.out.reply_addr));
+
+ PyTuple_SetItem(ret, 3, PyLong_FromLong(io.out.rcode));
+
+ return ret;
+}
+
+static PyObject *py_nbt_name_refresh(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ nbt_node_Object *node = (nbt_node_Object *)self;
+ PyObject *ret, *py_dest, *py_name;
+ struct nbt_name_refresh io;
+ NTSTATUS status;
+
+ const char *kwnames[] = { "name", "address", "dest", "nb_flags", "broadcast",
+ "ttl", "timeout", "retries", NULL };
+
+ io.in.broadcast = true;
+ io.in.nb_flags = 0;
+ io.in.ttl = 0;
+ io.in.timeout = 0;
+ io.in.retries = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OsO|ibiii:query_name",
+ discard_const_p(char *, kwnames),
+ &py_name, &io.in.address, &py_dest,
+ &io.in.nb_flags,
+ &io.in.broadcast,
+ &io.in.ttl, &io.in.timeout, &io.in.retries)) {
+ return NULL;
+ }
+
+ if (!PyObject_AsDestinationTuple(py_dest, &io.in.dest_addr, &io.in.dest_port))
+ return NULL;
+
+ if (!PyObject_AsNBTName(py_name, node->socket, &io.in.name))
+ return NULL;
+
+ status = nbt_name_refresh(node->socket, NULL, &io);
+
+ if (NT_STATUS_IS_ERR(status)) {
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ ret = PyTuple_New(3);
+ if (ret == NULL)
+ return NULL;
+ PyTuple_SetItem(ret, 0, PyUnicode_FromString(io.out.reply_from));
+
+ py_name = PyObject_FromNBTName(node->socket, &io.out.name);
+ if (py_name == NULL)
+ return NULL;
+
+ PyTuple_SetItem(ret, 1, py_name);
+
+ PyTuple_SetItem(ret, 2, PyUnicode_FromString(io.out.reply_addr));
+
+ PyTuple_SetItem(ret, 3, PyLong_FromLong(io.out.rcode));
+
+ return ret;
+}
+
+static PyObject *py_nbt_name_release(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ Py_RETURN_NONE; /* FIXME */
+}
+
+static PyMethodDef py_nbt_methods[] = {
+ { "query_name", PY_DISCARD_FUNC_SIG(PyCFunction, py_nbt_name_query),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.query_name(name, dest, broadcast=True, wins=False, timeout=0, retries=3) -> (reply_from, name, reply_addr)\n"
+ "Query for a NetBIOS name" },
+ { "register_name", PY_DISCARD_FUNC_SIG(PyCFunction,
+ py_nbt_name_register),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.register_name(name, address, dest, register_demand=True, broadcast=True, multi_homed=True, ttl=0, timeout=0, retries=0) -> (reply_from, name, reply_addr, rcode)\n"
+ "Register a new name" },
+ { "release_name", PY_DISCARD_FUNC_SIG(PyCFunction, py_nbt_name_release),
+ METH_VARARGS|METH_KEYWORDS, "S.release_name(name, address, dest, nb_flags=0, broadcast=true, timeout=0, retries=3) -> (reply_from, name, reply_addr, rcode)\n"
+ "release a previously registered name" },
+ { "refresh_name", PY_DISCARD_FUNC_SIG(PyCFunction, py_nbt_name_refresh),
+ METH_VARARGS|METH_KEYWORDS, "S.refresh_name(name, address, dest, nb_flags=0, broadcast=True, ttl=0, timeout=0, retries=0) -> (reply_from, name, reply_addr, rcode)\n"
+ "release a previously registered name" },
+ { "name_status", PY_DISCARD_FUNC_SIG(PyCFunction, py_nbt_name_status),
+ METH_VARARGS|METH_KEYWORDS,
+ "S.name_status(name, dest, timeout=0, retries=0) -> (reply_from, name, status)\n"
+ "Find the status of a name" },
+
+ {0}
+};
+
+PyTypeObject nbt_node_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "netbios.Node",
+ .tp_basicsize = sizeof(nbt_node_Object),
+ .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
+ .tp_new = py_nbt_node_init,
+ .tp_dealloc = (destructor)py_nbt_node_dealloc,
+ .tp_methods = py_nbt_methods,
+ .tp_doc = "Node()\n"
+ "Create a new NetBIOS node\n"
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "netbios",
+ .m_doc = "NetBIOS over TCP/IP support",
+ .m_size = -1,
+ .m_methods = NULL,
+};
+
+MODULE_INIT_FUNC(netbios)
+{
+ PyObject *mod = NULL;
+ if (PyType_Ready(&nbt_node_Type) < 0)
+ return mod;
+
+ mod = PyModule_Create(&moduledef);
+
+
+ Py_INCREF((PyObject *)&nbt_node_Type);
+ PyModule_AddObject(mod, "Node", (PyObject *)&nbt_node_Type);
+ return mod;
+}
diff --git a/libcli/nbt/tools/nmblookup.c b/libcli/nbt/tools/nmblookup.c
new file mode 100644
index 0000000..6ca38fa
--- /dev/null
+++ b/libcli/nbt/tools/nmblookup.c
@@ -0,0 +1,477 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ NBT client - used to lookup netbios names
+
+ Copyright (C) Andrew Tridgell 1994-2005
+ Copyright (C) Jelmer Vernooij 2003 (Conversion to popt)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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"
+#include "lib/socket/socket.h"
+#include "lib/events/events.h"
+#include "system/network.h"
+#include "system/locale.h"
+#include "lib/socket/netif.h"
+#include "librpc/gen_ndr/nbt.h"
+#include "../libcli/nbt/libnbt.h"
+#include "param/param.h"
+
+#include <string.h>
+
+#define MAX_NETBIOSNAME_LEN 16
+
+/* command line options */
+static struct {
+ const char *broadcast_address;
+ const char *unicast_address;
+ bool find_master;
+ bool wins_lookup;
+ bool node_status;
+ bool root_port;
+ bool lookup_by_ip;
+ bool case_sensitive;
+} options;
+
+/*
+ clean any binary from a node name
+*/
+static const char *clean_name(TALLOC_CTX *mem_ctx, const char *name)
+{
+ char *ret = talloc_strdup(mem_ctx, name);
+ int i;
+ for (i=0;ret[i];i++) {
+ if (!isprint((unsigned char)ret[i])) ret[i] = '.';
+ }
+ return ret;
+}
+
+/*
+ turn a node status flags field into a string
+*/
+static char *node_status_flags(TALLOC_CTX *mem_ctx, uint16_t flags)
+{
+ char *ret;
+ const char *group = " ";
+ const char *type = "B";
+
+ if (flags & NBT_NM_GROUP) {
+ group = "<GROUP>";
+ }
+
+ switch (flags & NBT_NM_OWNER_TYPE) {
+ case NBT_NODE_B:
+ type = "B";
+ break;
+ case NBT_NODE_P:
+ type = "P";
+ break;
+ case NBT_NODE_M:
+ type = "M";
+ break;
+ case NBT_NODE_H:
+ type = "H";
+ break;
+ }
+
+ ret = talloc_asprintf(mem_ctx, "%s %s", group, type);
+
+ if (flags & NBT_NM_DEREGISTER) {
+ ret = talloc_asprintf_append_buffer(ret, " <DEREGISTERING>");
+ }
+ if (flags & NBT_NM_CONFLICT) {
+ ret = talloc_asprintf_append_buffer(ret, " <CONFLICT>");
+ }
+ if (flags & NBT_NM_ACTIVE) {
+ ret = talloc_asprintf_append_buffer(ret, " <ACTIVE>");
+ }
+ if (flags & NBT_NM_PERMANENT) {
+ ret = talloc_asprintf_append_buffer(ret, " <PERMANENT>");
+ }
+
+ return ret;
+}
+
+/* do a single node status */
+static bool do_node_status(struct nbt_name_socket *nbtsock,
+ const char *addr, uint16_t port)
+{
+ struct nbt_name_status io;
+ NTSTATUS status;
+
+ io.in.name.name = "*";
+ io.in.name.type = NBT_NAME_CLIENT;
+ io.in.name.scope = NULL;
+ io.in.dest_addr = addr;
+ io.in.dest_port = port;
+ io.in.timeout = 1;
+ io.in.retries = 2;
+
+ status = nbt_name_status(nbtsock, nbtsock, &io);
+ if (NT_STATUS_IS_OK(status)) {
+ int i;
+ printf("Node status reply from %s\n",
+ io.out.reply_from);
+ for (i=0;i<io.out.status.num_names;i++) {
+ d_printf("\t%-16s <%02x> %s\n",
+ clean_name(nbtsock, io.out.status.names[i].name),
+ io.out.status.names[i].type,
+ node_status_flags(nbtsock, io.out.status.names[i].nb_flags));
+ }
+ printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
+ io.out.status.statistics.unit_id[0],
+ io.out.status.statistics.unit_id[1],
+ io.out.status.statistics.unit_id[2],
+ io.out.status.statistics.unit_id[3],
+ io.out.status.statistics.unit_id[4],
+ io.out.status.statistics.unit_id[5]);
+ return true;
+ }
+
+ return false;
+}
+
+/* do a single node query */
+static NTSTATUS do_node_query(struct nbt_name_socket *nbtsock,
+ const char *addr,
+ uint16_t port,
+ const char *node_name,
+ enum nbt_name_type node_type,
+ bool broadcast)
+{
+ struct nbt_name_query io;
+ NTSTATUS status;
+ int i;
+
+ io.in.name.name = node_name;
+ io.in.name.type = node_type;
+ io.in.name.scope = NULL;
+ io.in.dest_addr = addr;
+ io.in.dest_port = port;
+ io.in.broadcast = broadcast;
+ io.in.wins_lookup = options.wins_lookup;
+ io.in.timeout = 1;
+ io.in.retries = 2;
+
+ status = nbt_name_query(nbtsock, nbtsock, &io);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ for (i=0;i<io.out.num_addrs;i++) {
+ printf("%s %s<%02x>\n",
+ io.out.reply_addrs[i],
+ io.out.name.name,
+ io.out.name.type);
+ }
+ if (options.node_status && io.out.num_addrs > 0) {
+ do_node_status(nbtsock, io.out.reply_addrs[0], port);
+ }
+
+ return status;
+}
+
+
+static bool process_one(struct loadparm_context *lp_ctx, struct tevent_context *ev,
+ struct interface *ifaces, const char *name, int nbt_port)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ enum nbt_name_type node_type = NBT_NAME_CLIENT;
+ char *node_name, *p;
+ struct socket_address *all_zero_addr;
+ struct nbt_name_socket *nbtsock;
+ NTSTATUS status = NT_STATUS_OK;
+ size_t nbt_len;
+ bool ret = true;
+
+ if (!options.case_sensitive) {
+ name = strupper_talloc(tmp_ctx, name);
+ }
+
+ if (options.find_master) {
+ node_type = NBT_NAME_MASTER;
+ if (*name == '-' || *name == '_') {
+ name = "\01\02__MSBROWSE__\02";
+ node_type = NBT_NAME_MS;
+ }
+ }
+
+ p = strchr(name, '#');
+ if (p) {
+ node_name = talloc_strndup(tmp_ctx, name, PTR_DIFF(p,name));
+ node_type = (enum nbt_name_type)strtol(p+1, NULL, 16);
+ } else {
+ node_name = talloc_strdup(tmp_ctx, name);
+ }
+
+ nbt_len = strlen(node_name);
+ if (nbt_len > MAX_NETBIOSNAME_LEN - 1) {
+ printf("The specified netbios name [%s] is too long.\n",
+ node_name);
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ nbtsock = nbt_name_socket_init(tmp_ctx, ev);
+
+ if (options.root_port) {
+ all_zero_addr = socket_address_from_strings(tmp_ctx, nbtsock->sock->backend_name,
+ "0.0.0.0", NBT_NAME_SERVICE_PORT);
+
+ if (!all_zero_addr) {
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ status = socket_listen(nbtsock->sock, all_zero_addr, 0, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to bind to local port 137 - %s\n", nt_errstr(status));
+ talloc_free(tmp_ctx);
+ return false;
+ }
+ }
+
+ if (options.lookup_by_ip) {
+ ret = do_node_status(nbtsock, name, nbt_port);
+ talloc_free(tmp_ctx);
+ return ret;
+ }
+
+ if (options.broadcast_address) {
+ status = do_node_query(nbtsock, options.broadcast_address, nbt_port,
+ node_name, node_type, true);
+ } else if (options.unicast_address) {
+ status = do_node_query(nbtsock, options.unicast_address,
+ nbt_port, node_name, node_type, false);
+ } else {
+ int i, num_interfaces;
+
+ num_interfaces = iface_list_count(ifaces);
+ for (i=0;i<num_interfaces;i++) {
+ const char *bcast = iface_list_n_bcast(ifaces, i);
+ if (bcast == NULL) continue;
+ status = do_node_query(nbtsock, bcast, nbt_port,
+ node_name, node_type, true);
+ if (NT_STATUS_IS_OK(status)) break;
+ }
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Lookup failed - %s\n", nt_errstr(status));
+ ret = false;
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+/*
+ main program
+*/
+int main(int argc, const char *argv[])
+{
+ bool ret = true;
+ struct interface *ifaces;
+ struct tevent_context *ev;
+ poptContext pc;
+ int opt;
+ struct loadparm_context *lp_ctx = NULL;
+ TALLOC_CTX *mem_ctx = NULL;
+ bool ok;
+ enum {
+ OPT_BROADCAST_ADDRESS = 1000,
+ OPT_UNICAST_ADDRESS,
+ OPT_FIND_MASTER,
+ OPT_WINS_LOOKUP,
+ OPT_NODE_STATUS,
+ OPT_ROOT_PORT,
+ OPT_LOOKUP_BY_IP,
+ OPT_CASE_SENSITIVE
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {
+ .longName = "broadcast",
+ .shortName = 'B',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = OPT_BROADCAST_ADDRESS,
+ .descrip = "Specify address to use for broadcasts",
+ .argDescrip = "BROADCAST-ADDRESS"
+ },
+ {
+ .longName = "unicast",
+ .shortName = 'U',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = OPT_UNICAST_ADDRESS,
+ .descrip = "Specify address to use for unicast",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "master-browser",
+ .shortName = 'M',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_FIND_MASTER,
+ .descrip = "Search for a master browser",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "wins",
+ .shortName = 'W',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_WINS_LOOKUP,
+ .descrip = "Do a WINS lookup",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "status",
+ .shortName = 'S',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_NODE_STATUS,
+ .descrip = "Lookup node status as well",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "root-port",
+ .shortName = 'r',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_ROOT_PORT,
+ .descrip = "Use root port 137 (Win95 only replies to this)",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "lookup-by-ip",
+ .shortName = 'A',
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_LOOKUP_BY_IP,
+ .descrip = "Do a node status on <name> as an IP Address",
+ .argDescrip = NULL
+ },
+ {
+ .longName = "case-sensitive",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = NULL,
+ .val = OPT_CASE_SENSITIVE,
+ .descrip = "Don't uppercase the name before sending",
+ .argDescrip = NULL
+ },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_VERSION
+ POPT_TABLEEND
+ };
+
+ mem_ctx = talloc_init("nmblookup.c/main");
+ if (mem_ctx == NULL) {
+ exit(ENOMEM);
+ }
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv,
+ long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ poptSetOtherOptionHelp(pc, "<NODE> ...");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ case OPT_BROADCAST_ADDRESS:
+ options.broadcast_address = poptGetOptArg(pc);
+ break;
+ case OPT_UNICAST_ADDRESS:
+ options.unicast_address = poptGetOptArg(pc);
+ break;
+ case OPT_FIND_MASTER:
+ options.find_master = true;
+ break;
+ case OPT_WINS_LOOKUP:
+ options.wins_lookup = true;
+ break;
+ case OPT_NODE_STATUS:
+ options.node_status = true;
+ break;
+ case OPT_ROOT_PORT:
+ options.root_port = true;
+ break;
+ case OPT_LOOKUP_BY_IP:
+ options.lookup_by_ip = true;
+ break;
+ case OPT_CASE_SENSITIVE:
+ options.case_sensitive = true;
+ break;
+ case POPT_ERROR_BADOPT:
+ fprintf(stderr, "\nInvalid option %s: %s\n\n",
+ poptBadOption(pc, 0), poptStrerror(opt));
+ poptPrintUsage(pc, stderr, 0);
+ exit(1);
+ }
+ }
+
+ /* swallow argv[0] */
+ poptGetArg(pc);
+
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ lp_ctx = samba_cmdline_get_lp_ctx();
+
+ load_interface_list(mem_ctx, lp_ctx, &ifaces);
+
+ ev = s4_event_context_init(mem_ctx);
+
+ while (poptPeekArg(pc)) {
+ const char *name = poptGetArg(pc);
+
+ ret &= process_one(lp_ctx,
+ ev,
+ ifaces,
+ name,
+ lpcfg_nbt_port(lp_ctx));
+ }
+
+ poptFreeContext(pc);
+ TALLOC_FREE(mem_ctx);
+
+ if (!ret) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/libcli/nbt/wscript_build b/libcli/nbt/wscript_build
new file mode 100644
index 0000000..0e2a13f
--- /dev/null
+++ b/libcli/nbt/wscript_build
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('NDR_NBT_BUF',
+ source='nbtname.c',
+ deps='talloc',
+ autoproto='nbtname.h'
+ )
+
+bld.SAMBA_SUBSYSTEM('lmhosts',
+ source='lmhosts.c',
+ deps='replace talloc'
+ )
+
+bld.SAMBA_LIBRARY('cli-nbt',
+ source='nbtsocket.c namequery.c nameregister.c namerefresh.c namerelease.c',
+ public_deps='ndr ndr_nbt tevent tevent-util NDR_SECURITY samba_socket samba-util lmhosts',
+ private_library=True
+ )
+
+bld.SAMBA_BINARY('nmblookup' + bld.env.suffix4,
+ source='tools/nmblookup.c',
+ manpages='man/nmblookup4.1',
+ deps='samba-hostconfig samba-util cli-nbt popt CMDLINE_S4 netif LIBCLI_RESOLVE',
+ install=False,
+ )
+
+bld.SAMBA_PYTHON('python_netbios',
+ source='pynbt.c',
+ public_deps='cli-nbt DYNCONFIG samba-hostconfig',
+ realname='samba/netbios.so'
+ )
+
diff --git a/libcli/netlogon/netlogon.c b/libcli/netlogon/netlogon.c
new file mode 100644
index 0000000..15e8087
--- /dev/null
+++ b/libcli/netlogon/netlogon.c
@@ -0,0 +1,285 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ CLDAP server structures
+
+ Copyright (C) Andrew Bartlett <abartlet@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 "../libcli/netlogon/netlogon.h"
+
+NTSTATUS push_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct netlogon_samlogon_response *response)
+{
+ enum ndr_err_code ndr_err;
+ if (response->ntver == NETLOGON_NT_VERSION_1) {
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.nt4,
+ (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_NT40);
+ } else if (response->ntver & NETLOGON_NT_VERSION_5EX) {
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.nt5_ex,
+ (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags);
+ } else if (response->ntver & NETLOGON_NT_VERSION_5) {
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.nt5,
+ (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE);
+ } else {
+ DEBUG(0, ("Asked to push unknown netlogon response type 0x%02x\n", response->ntver));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(2,("failed to push netlogon response of type 0x%02x\n",
+ response->ntver));
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS pull_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct netlogon_samlogon_response *response)
+{
+ uint32_t ntver;
+ enum ndr_err_code ndr_err;
+
+ if (data->length < 8) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* lmnttoken */
+ if (SVAL(data->data, data->length - 4) != 0xffff) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ /* lm20token */
+ if (SVAL(data->data, data->length - 2) != 0xffff) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ ntver = IVAL(data->data, data->length - 8);
+
+ if (ntver == NETLOGON_NT_VERSION_1) {
+ ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
+ &response->data.nt4,
+ (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_NT40);
+ response->ntver = NETLOGON_NT_VERSION_1;
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_NT40,
+ &response->data.nt4);
+ }
+
+ } else if (ntver & NETLOGON_NT_VERSION_5EX) {
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(data, mem_ctx);
+ if (!ndr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ndr_err = ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(
+ ndr, NDR_SCALARS|NDR_BUFFERS, &response->data.nt5_ex,
+ ntver);
+ if (ndr->offset < ndr->data_size) {
+ TALLOC_FREE(ndr);
+ /*
+ * We need to handle a bug in IPA (at least <= 4.1.2).
+ *
+ * They include the ip address information without setting
+ * NETLOGON_NT_VERSION_5EX_WITH_IP, while using
+ * ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX instead of
+ * ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags.
+ */
+ ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
+ &response->data.nt5,
+ (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX);
+ }
+ response->ntver = NETLOGON_NT_VERSION_5EX;
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_EX,
+ &response->data.nt5_ex);
+ }
+
+ } else if (ntver & NETLOGON_NT_VERSION_5) {
+ ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
+ &response->data.nt5,
+ (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE);
+ response->ntver = NETLOGON_NT_VERSION_5;
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
+ NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE,
+ &response->data.nt5);
+ }
+ } else {
+ DEBUG(2,("failed to parse netlogon response of type 0x%02x - unknown response type\n",
+ ntver));
+ dump_data(10, data->data, data->length);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(2,("failed to parse netlogon response of type 0x%02x\n",
+ ntver));
+ dump_data(10, data->data, data->length);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+void map_netlogon_samlogon_response(struct netlogon_samlogon_response *response)
+{
+ struct NETLOGON_SAM_LOGON_RESPONSE_EX response_5_ex;
+ switch (response->ntver) {
+ case NETLOGON_NT_VERSION_5EX:
+ break;
+ case NETLOGON_NT_VERSION_5:
+ ZERO_STRUCT(response_5_ex);
+ response_5_ex.command = response->data.nt5.command;
+ response_5_ex.pdc_name = response->data.nt5.pdc_name;
+ response_5_ex.user_name = response->data.nt5.user_name;
+ response_5_ex.domain_name = response->data.nt5.domain_name;
+ response_5_ex.domain_uuid = response->data.nt5.domain_uuid;
+ response_5_ex.forest = response->data.nt5.forest;
+ response_5_ex.dns_domain = response->data.nt5.dns_domain;
+ response_5_ex.pdc_dns_name = response->data.nt5.pdc_dns_name;
+ response_5_ex.sockaddr.pdc_ip = response->data.nt5.pdc_ip;
+ response_5_ex.server_type = response->data.nt5.server_type;
+ response_5_ex.nt_version = response->data.nt5.nt_version;
+ response_5_ex.lmnt_token = response->data.nt5.lmnt_token;
+ response_5_ex.lm20_token = response->data.nt5.lm20_token;
+ response->ntver = NETLOGON_NT_VERSION_5EX;
+ response->data.nt5_ex = response_5_ex;
+ break;
+
+ case NETLOGON_NT_VERSION_1:
+ ZERO_STRUCT(response_5_ex);
+ response_5_ex.command = response->data.nt4.command;
+ response_5_ex.pdc_name = response->data.nt4.pdc_name;
+ response_5_ex.user_name = response->data.nt4.user_name;
+ response_5_ex.domain_name = response->data.nt4.domain_name;
+ response_5_ex.nt_version = response->data.nt4.nt_version;
+ response_5_ex.lmnt_token = response->data.nt4.lmnt_token;
+ response_5_ex.lm20_token = response->data.nt4.lm20_token;
+ response->ntver = NETLOGON_NT_VERSION_5EX;
+ response->data.nt5_ex = response_5_ex;
+ break;
+ }
+ return;
+}
+
+NTSTATUS push_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct nbt_netlogon_response *response)
+{
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ switch (response->response_type) {
+ case NETLOGON_GET_PDC:
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.get_pdc,
+ (ndr_push_flags_fn_t)ndr_push_nbt_netlogon_response_from_pdc);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("Failed to parse netlogon packet of length %d: %s\n",
+ (int)data->length, nt_errstr(status)));
+ if (DEBUGLVL(10)) {
+ (void)file_save("netlogon.dat", data->data, data->length);
+ }
+ return status;
+ }
+ status = NT_STATUS_OK;
+ break;
+ case NETLOGON_SAMLOGON:
+ status = push_netlogon_samlogon_response(
+ data, mem_ctx,
+ &response->data.samlogon);
+ break;
+ case NETLOGON_RESPONSE2:
+ ndr_err = ndr_push_struct_blob(data, mem_ctx,
+ &response->data.response2,
+ (ndr_push_flags_fn_t)ndr_push_nbt_netlogon_response2);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ status = NT_STATUS_OK;
+ break;
+ default:
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ break;
+ }
+
+ return status;
+}
+
+
+NTSTATUS pull_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct nbt_netlogon_response *response)
+{
+ NTSTATUS status;
+ enum netlogon_command command;
+ enum ndr_err_code ndr_err;
+ if (data->length < 4) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ command = SVAL(data->data, 0);
+
+ switch (command) {
+ case NETLOGON_RESPONSE_FROM_PDC:
+ ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
+ &response->data.get_pdc,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_netlogon_response_from_pdc);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(0,("Failed to parse netlogon packet of length %d: %s\n",
+ (int)data->length, nt_errstr(status)));
+ if (DEBUGLVL(10)) {
+ (void)file_save("netlogon.dat", data->data, data->length);
+ }
+ return status;
+ }
+ status = NT_STATUS_OK;
+ response->response_type = NETLOGON_GET_PDC;
+ break;
+ case LOGON_RESPONSE2:
+ ndr_err = ndr_pull_struct_blob(data, mem_ctx, &response->data.response2,
+ (ndr_pull_flags_fn_t)ndr_pull_nbt_netlogon_response2);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ status = NT_STATUS_OK;
+ response->response_type = NETLOGON_RESPONSE2;
+ break;
+ case LOGON_SAM_LOGON_RESPONSE:
+ case LOGON_SAM_LOGON_PAUSE_RESPONSE:
+ case LOGON_SAM_LOGON_USER_UNKNOWN:
+ case LOGON_SAM_LOGON_RESPONSE_EX:
+ case LOGON_SAM_LOGON_PAUSE_RESPONSE_EX:
+ case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
+ status = pull_netlogon_samlogon_response(
+ data, mem_ctx,
+ &response->data.samlogon);
+ response->response_type = NETLOGON_SAMLOGON;
+ break;
+
+ /* These levels are queries, not responses */
+ case LOGON_PRIMARY_QUERY:
+ case LOGON_REQUEST:
+ case NETLOGON_ANNOUNCE_UAS:
+ case LOGON_SAM_LOGON_REQUEST:
+ default:
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ return status;
+
+}
diff --git a/libcli/netlogon/netlogon.h b/libcli/netlogon/netlogon.h
new file mode 100644
index 0000000..0bf2a4c
--- /dev/null
+++ b/libcli/netlogon/netlogon.h
@@ -0,0 +1,41 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ CLDAP server structures
+
+ Copyright (C) Andrew Bartlett <abartlet@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 __LIBCLI_NETLOGON_H__
+#define __LIBCLI_NETLOGON_H__
+
+#include "librpc/gen_ndr/ndr_nbt.h"
+
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+struct nbt_netlogon_response
+{
+ enum {NETLOGON_GET_PDC, NETLOGON_SAMLOGON, NETLOGON_RESPONSE2} response_type;
+ union {
+ struct nbt_netlogon_response_from_pdc get_pdc;
+ struct netlogon_samlogon_response samlogon;
+ struct nbt_netlogon_response2 response2;
+ } data;
+};
+
+#include "../libcli/netlogon/netlogon_proto.h"
+#endif /* __CLDAP_SERVER_PROTO_H__ */
diff --git a/libcli/netlogon/netlogon_proto.h b/libcli/netlogon/netlogon_proto.h
new file mode 100644
index 0000000..53c7d00
--- /dev/null
+++ b/libcli/netlogon/netlogon_proto.h
@@ -0,0 +1,28 @@
+#ifndef _____LIBCLI_NETLOGON_PROTO_H__
+#define _____LIBCLI_NETLOGON_PROTO_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+/* This file was automatically generated by mkproto.pl. DO NOT EDIT */
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+
+/* The following definitions come from ../libcli/netlogon.c */
+
+NTSTATUS push_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct netlogon_samlogon_response *response);
+NTSTATUS pull_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct netlogon_samlogon_response *response);
+void map_netlogon_samlogon_response(struct netlogon_samlogon_response *response);
+NTSTATUS push_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct nbt_netlogon_response *response);
+NTSTATUS pull_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
+ struct nbt_netlogon_response *response);
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif /* _____LIBCLI_NETLOGON_PROTO_H__ */
+
diff --git a/libcli/netlogon/wscript_build b/libcli/netlogon/wscript_build
new file mode 100644
index 0000000..ab49599
--- /dev/null
+++ b/libcli/netlogon/wscript_build
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_NETLOGON',
+ source='netlogon.c',
+ public_deps='samba-util ndr_nbt'
+ )
diff --git a/libcli/registry/util_reg.c b/libcli/registry/util_reg.c
new file mode 100644
index 0000000..3139fc3
--- /dev/null
+++ b/libcli/registry/util_reg.c
@@ -0,0 +1,138 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Registry helper routines
+ * Copyright (C) Volker Lendecke 2006
+ * Copyright (C) Guenther Deschner 2009
+ * Copyright (C) Jelmer Vernooij 2003-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 "../librpc/gen_ndr/ndr_misc.h"
+#include "../libcli/registry/util_reg.h"
+
+/**
+ * @file
+ * @brief Registry utility functions
+ */
+
+static const struct {
+ uint32_t id;
+ const char *name;
+} reg_value_types[] = {
+ { REG_NONE, "REG_NONE" },
+ { REG_SZ, "REG_SZ" },
+ { REG_EXPAND_SZ, "REG_EXPAND_SZ" },
+ { REG_BINARY, "REG_BINARY" },
+ { REG_DWORD, "REG_DWORD" },
+ { REG_DWORD_BIG_ENDIAN, "REG_DWORD_BIG_ENDIAN" },
+ { REG_LINK, "REG_LINK" },
+ { REG_MULTI_SZ, "REG_MULTI_SZ" },
+ { REG_RESOURCE_LIST, "REG_RESOURCE_LIST" },
+ { REG_FULL_RESOURCE_DESCRIPTOR, "REG_FULL_RESOURCE_DESCRIPTOR" },
+ { REG_RESOURCE_REQUIREMENTS_LIST, "REG_RESOURCE_REQUIREMENTS_LIST" },
+ { REG_QWORD, "REG_QWORD" },
+
+ { 0, NULL }
+};
+
+/** Return string description of registry value type */
+_PUBLIC_ const char *str_regtype(int type)
+{
+ unsigned int i;
+ for (i = 0; reg_value_types[i].name; i++) {
+ if (reg_value_types[i].id == type)
+ return reg_value_types[i].name;
+ }
+
+ return "Unknown";
+}
+
+/** Return registry value type for string description */
+_PUBLIC_ int regtype_by_string(const char *str)
+{
+ unsigned int i;
+ for (i = 0; reg_value_types[i].name; i++) {
+ if (strequal(reg_value_types[i].name, str))
+ return reg_value_types[i].id;
+ }
+
+ return -1;
+}
+
+/*******************************************************************
+ push a string in unix charset into a REG_SZ UCS2 null terminated blob
+ ********************************************************************/
+
+bool push_reg_sz(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *s)
+{
+ union winreg_Data data;
+ enum ndr_err_code ndr_err;
+ data.string = s;
+ ndr_err = ndr_push_union_blob(blob, mem_ctx, &data, REG_SZ,
+ (ndr_push_flags_fn_t)ndr_push_winreg_Data);
+ return NDR_ERR_CODE_IS_SUCCESS(ndr_err);
+}
+
+/*******************************************************************
+ push a string_array in unix charset into a REG_MULTI_SZ UCS2 double-null
+ terminated blob
+ ********************************************************************/
+
+bool push_reg_multi_sz(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char **a)
+{
+ union winreg_Data data;
+ enum ndr_err_code ndr_err;
+ data.string_array = a;
+ ndr_err = ndr_push_union_blob(blob, mem_ctx, &data, REG_MULTI_SZ,
+ (ndr_push_flags_fn_t)ndr_push_winreg_Data);
+ return NDR_ERR_CODE_IS_SUCCESS(ndr_err);
+}
+
+/*******************************************************************
+ pull a string in unix charset out of a REG_SZ UCS2 null terminated blob
+ ********************************************************************/
+
+bool pull_reg_sz(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const char **s)
+{
+ union winreg_Data data;
+ enum ndr_err_code ndr_err;
+ ndr_err = ndr_pull_union_blob(blob, mem_ctx, &data, REG_SZ,
+ (ndr_pull_flags_fn_t)ndr_pull_winreg_Data);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+ *s = data.string;
+ return true;
+}
+
+/*******************************************************************
+ pull a string_array in unix charset out of a REG_MULTI_SZ UCS2 double-null
+ terminated blob
+ ********************************************************************/
+
+bool pull_reg_multi_sz(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob, const char ***a)
+{
+ union winreg_Data data;
+ enum ndr_err_code ndr_err;
+ ndr_err = ndr_pull_union_blob(blob, mem_ctx, &data, REG_MULTI_SZ,
+ (ndr_pull_flags_fn_t)ndr_pull_winreg_Data);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+ *a = data.string_array;
+ return true;
+}
diff --git a/libcli/registry/util_reg.h b/libcli/registry/util_reg.h
new file mode 100644
index 0000000..0250b45
--- /dev/null
+++ b/libcli/registry/util_reg.h
@@ -0,0 +1,32 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Registry helper routines
+ * Copyright (C) Volker Lendecke 2006
+ * Copyright (C) Guenther Deschner 2009
+ * Copyright (C) Jelmer Vernooij 2003-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 __LIBCLI_REGISTRY_UTIL_REG_H__
+#define __LIBCLI_REGISTRY_UTIL_REG_H__
+
+const char *str_regtype(int type);
+int regtype_by_string(const char *str);
+bool push_reg_sz(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *s);
+bool push_reg_multi_sz(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char **a);
+bool pull_reg_sz(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const char **s);
+bool pull_reg_multi_sz(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const char ***a);
+
+#endif /* __LIBCLI_REGISTRY_UTIL_REG_H__ */
diff --git a/libcli/registry/wscript_build b/libcli/registry/wscript_build
new file mode 100644
index 0000000..ec3fdd3
--- /dev/null
+++ b/libcli/registry/wscript_build
@@ -0,0 +1,5 @@
+
+bld.SAMBA_LIBRARY('util_reg',
+ source='util_reg.c',
+ deps='ndr',
+ private_library=True)
diff --git a/libcli/samsync/decrypt.c b/libcli/samsync/decrypt.c
new file mode 100644
index 0000000..77ef932
--- /dev/null
+++ b/libcli/samsync/decrypt.c
@@ -0,0 +1,209 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Extract the user/system database from a remote SamSync server
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+ Copyright (C) Guenther Deschner <gd@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 "../libcli/auth/libcli_auth.h"
+#include "../libcli/samsync/samsync.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "lib/crypto/gnutls_helpers.h"
+
+/**
+ * Decrypt and extract the user's passwords.
+ *
+ * The writes decrypted (no longer 'RID encrypted' or arcfour encrypted)
+ * passwords back into the structure
+ */
+
+static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *delta)
+{
+
+ uint32_t rid = delta->delta_id_union.rid;
+ struct netr_DELTA_USER *user = delta->delta_union.user;
+ struct samr_Password lm_hash;
+ struct samr_Password nt_hash;
+ int rc;
+
+ /* Note that win2000 may send us all zeros
+ * for the hashes if it doesn't
+ * think this channel is secure enough. */
+ if (user->lm_password_present) {
+ if (!all_zero(user->lmpassword.hash, 16)) {
+ rc = sam_rid_crypt(rid, user->lmpassword.hash,
+ lm_hash.hash, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
+ }
+ user->lmpassword = lm_hash;
+ }
+
+ if (user->nt_password_present) {
+ if (!all_zero(user->ntpassword.hash, 16)) {
+ rc = sam_rid_crypt(rid, user->ntpassword.hash,
+ nt_hash.hash, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
+ }
+ user->ntpassword = nt_hash;
+ }
+
+ if (user->user_private_info.SensitiveData) {
+ DATA_BLOB data;
+ struct netr_USER_KEYS keys;
+ enum ndr_err_code ndr_err;
+ NTSTATUS status;
+
+ data.data = user->user_private_info.SensitiveData;
+ data.length = user->user_private_info.DataLength;
+
+ status = netlogon_creds_arcfour_crypt(creds,
+ data.data,
+ data.length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ user->user_private_info.SensitiveData = data.data;
+ user->user_private_info.DataLength = data.length;
+
+ ndr_err = ndr_pull_struct_blob(&data, mem_ctx, &keys,
+ (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ dump_data(10, data.data, data.length);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ /* Note that win2000 may send us all zeros
+ * for the hashes if it doesn't
+ * think this channel is secure enough. */
+ if (keys.keys.keys2.lmpassword.length == 16) {
+ if (!all_zero(keys.keys.keys2.lmpassword.pwd.hash,
+ 16)) {
+ rc = sam_rid_crypt(rid,
+ keys.keys.keys2.lmpassword.pwd.hash,
+ lm_hash.hash, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
+ }
+ user->lmpassword = lm_hash;
+ user->lm_password_present = true;
+ }
+ if (keys.keys.keys2.ntpassword.length == 16) {
+ if (!all_zero(keys.keys.keys2.ntpassword.pwd.hash,
+ 16)) {
+ rc = sam_rid_crypt(rid,
+ keys.keys.keys2.ntpassword.pwd.hash,
+ nt_hash.hash, SAMBA_GNUTLS_DECRYPT);
+ if (rc != 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
+ }
+ } else {
+ memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
+ }
+ user->ntpassword = nt_hash;
+ user->nt_password_present = true;
+ }
+ /* TODO: rid decrypt history fields */
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Decrypt and extract the secrets
+ *
+ * The writes decrypted secrets back into the structure
+ */
+static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds,
+ enum netr_SamDatabaseID database,
+ struct netr_DELTA_ENUM *delta)
+{
+ struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
+ NTSTATUS status;
+
+ status = netlogon_creds_arcfour_crypt(creds,
+ secret->current_cipher.cipher_data,
+ secret->current_cipher.maxlen);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = netlogon_creds_arcfour_crypt(creds,
+ secret->old_cipher.cipher_data,
+ secret->old_cipher.maxlen);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Fix up the delta, dealing with encryption issues so that the final
+ * callback need only do the printing or application logic
+ */
+
+NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *delta)
+{
+ NTSTATUS status = NT_STATUS_OK;
+
+ switch (delta->delta_type) {
+ case NETR_DELTA_USER:
+
+ status = fix_user(mem_ctx,
+ creds,
+ database_id,
+ delta);
+ break;
+ case NETR_DELTA_SECRET:
+
+ status = fix_secret(mem_ctx,
+ creds,
+ database_id,
+ delta);
+ break;
+ default:
+ break;
+ }
+
+ return status;
+}
+
diff --git a/libcli/samsync/samsync.h b/libcli/samsync/samsync.h
new file mode 100644
index 0000000..0cd55e4
--- /dev/null
+++ b/libcli/samsync/samsync.h
@@ -0,0 +1,36 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Extract the user/system database from a remote SamSync server
+
+ Copyright (C) Guenther Deschner <gd@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 __SAMSYNC_SAMSYNC_H__
+#define __SAMSYNC_SAMSYNC_H__
+
+struct netlogon_creds_CredentialState;
+
+/**
+ * Fix up the delta, dealing with encryption issues so that the final
+ * callback need only do the printing or application logic
+ */
+NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
+ struct netlogon_creds_CredentialState *creds,
+ enum netr_SamDatabaseID database_id,
+ struct netr_DELTA_ENUM *delta);
+
+#endif /* __SAMSYNC_SAMSYNC_H__ */
diff --git a/libcli/samsync/wscript_build b/libcli/samsync/wscript_build
new file mode 100644
index 0000000..767f7da
--- /dev/null
+++ b/libcli/samsync/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_SUBSYSTEM('LIBCLI_SAMSYNC',
+ source='decrypt.c',
+ public_deps='LIBCLI_AUTH'
+ )
+
diff --git a/libcli/security/access_check.c b/libcli/security/access_check.c
new file mode 100644
index 0000000..e3dfe3d
--- /dev/null
+++ b/libcli/security/access_check.c
@@ -0,0 +1,958 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Gerald Carter 2005
+ Copyright (C) Volker Lendecke 2007
+ Copyright (C) Jeremy Allison 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 "replace.h"
+#include "lib/util/debug.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/conditional_ace.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
+ objects. Each type of object has its own mapping of generic to object
+ specific access rights. */
+
+void se_map_generic(uint32_t *access_mask, const struct generic_mapping *mapping)
+{
+ uint32_t old_mask = *access_mask;
+
+ if (*access_mask & GENERIC_READ_ACCESS) {
+ *access_mask &= ~GENERIC_READ_ACCESS;
+ *access_mask |= mapping->generic_read;
+ }
+
+ if (*access_mask & GENERIC_WRITE_ACCESS) {
+ *access_mask &= ~GENERIC_WRITE_ACCESS;
+ *access_mask |= mapping->generic_write;
+ }
+
+ if (*access_mask & GENERIC_EXECUTE_ACCESS) {
+ *access_mask &= ~GENERIC_EXECUTE_ACCESS;
+ *access_mask |= mapping->generic_execute;
+ }
+
+ if (*access_mask & GENERIC_ALL_ACCESS) {
+ *access_mask &= ~GENERIC_ALL_ACCESS;
+ *access_mask |= mapping->generic_all;
+ }
+
+ if (old_mask != *access_mask) {
+ DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
+ old_mask, *access_mask));
+ }
+}
+
+/* Map generic access rights to object specific rights for all the ACE's
+ * in a security_acl.
+ */
+
+void security_acl_map_generic(struct security_acl *sa,
+ const struct generic_mapping *mapping)
+{
+ unsigned int i;
+
+ if (!sa) {
+ return;
+ }
+
+ for (i = 0; i < sa->num_aces; i++) {
+ se_map_generic(&sa->aces[i].access_mask, mapping);
+ }
+}
+
+/* Map standard access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of standard to object
+ specific access rights. */
+
+void se_map_standard(uint32_t *access_mask, const struct standard_mapping *mapping)
+{
+ uint32_t old_mask = *access_mask;
+
+ if (*access_mask & SEC_STD_READ_CONTROL) {
+ *access_mask &= ~SEC_STD_READ_CONTROL;
+ *access_mask |= mapping->std_read;
+ }
+
+ if (*access_mask & (SEC_STD_DELETE|SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|SEC_STD_SYNCHRONIZE)) {
+ *access_mask &= ~(SEC_STD_DELETE|SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|SEC_STD_SYNCHRONIZE);
+ *access_mask |= mapping->std_all;
+ }
+
+ if (old_mask != *access_mask) {
+ DEBUG(10, ("se_map_standard(): mapped mask 0x%08x to 0x%08x\n",
+ old_mask, *access_mask));
+ }
+}
+
+enum ace_callback_result {
+ ACE_CALLBACK_DENY,
+ ACE_CALLBACK_ALLOW,
+ ACE_CALLBACK_SKIP, /* do not apply this ACE */
+ ACE_CALLBACK_INVALID /* we don't want to process the conditional ACE */
+};
+
+
+static enum ace_callback_result check_callback_ace_allow(
+ const struct security_ace *ace,
+ const struct security_token *token,
+ const struct security_descriptor *sd)
+{
+ bool ok;
+ int result;
+
+ switch (token->evaluate_claims) {
+ case CLAIMS_EVALUATION_ALWAYS:
+ break;
+
+ case CLAIMS_EVALUATION_INVALID_STATE:
+ DBG_WARNING("Refusing to evaluate ACL with "
+ "conditional ACE against security "
+ "token with CLAIMS_EVALUATION_INVALID_STATE\n");
+ return ACE_CALLBACK_INVALID;
+ case CLAIMS_EVALUATION_NEVER:
+ default:
+ /*
+ * We are asked to pretend we never understood this
+ * ACE type.
+ *
+ * By returning SKIP, this ACE will not adjust any
+ * permission bits making it an effective no-op, which
+ * was the default behaviour up to Samba 4.19.
+ */
+ return ACE_CALLBACK_SKIP;
+ }
+
+ if (ace->type != SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK &&
+ ace->type != SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT) {
+ /* This indicates a programming error */
+ DBG_ERR("bad conditional allow ACE type: %u\n", ace->type);
+ return ACE_CALLBACK_INVALID;
+ }
+
+ /*
+ * Until we discover otherwise, we assume all callback ACEs
+ * are conditional ACEs.
+ */
+ ok = access_check_conditional_ace(ace, token, sd, &result);
+ if (!ok) {
+ /*
+ * An error in processing the conditional ACE is
+ * treated as UNKNOWN, which amounts to a DENY/SKIP
+ * result.
+ *
+ * This is different from the INVALID result which
+ * means we should not be thinking about conditional
+ * ACES at all, and will abort the whole access check.
+ */
+ DBG_WARNING("callback ACE was not a valid conditional ACE\n");
+ return ACE_CALLBACK_SKIP;
+ }
+ if (result == ACE_CONDITION_TRUE) {
+ return ACE_CALLBACK_ALLOW;
+ }
+ /* UNKNOWN means do not allow */
+ return ACE_CALLBACK_SKIP;
+}
+
+
+static enum ace_callback_result check_callback_ace_deny(
+ const struct security_ace *ace,
+ const struct security_token *token,
+ const struct security_descriptor *sd)
+{
+ bool ok;
+ int result;
+
+ switch (token->evaluate_claims) {
+ case CLAIMS_EVALUATION_ALWAYS:
+ break;
+
+ case CLAIMS_EVALUATION_INVALID_STATE:
+ DBG_WARNING("Refusing to evaluate ACL with "
+ "conditional ACE against security "
+ "token with CLAIMS_EVALUATION_INVALID_STATE\n");
+ return ACE_CALLBACK_INVALID;
+ case CLAIMS_EVALUATION_NEVER:
+ default:
+ /*
+ * We are asked to pretend we never understood this
+ * ACE type.
+ */
+ return ACE_CALLBACK_SKIP;
+ }
+
+ if (ace->type != SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK &&
+ ace->type != SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT) {
+ DBG_ERR("bad conditional deny ACE type: %u\n", ace->type);
+ return ACE_CALLBACK_INVALID;
+ }
+
+ /*
+ * Until we discover otherwise, we assume all callback ACEs
+ * are conditional ACEs.
+ */
+ ok = access_check_conditional_ace(ace, token, sd, &result);
+ if (!ok) {
+ /*
+ * An error in processing the conditional ACE is
+ * treated as UNKNOWN, which means DENY.
+ */
+ DBG_WARNING("callback ACE was not a valid conditional ACE\n");
+ return ACE_CALLBACK_DENY;
+ }
+ if (result != ACE_CONDITION_FALSE) {
+ /* UNKNOWN means deny */
+ return ACE_CALLBACK_DENY;
+ }
+ return ACE_CALLBACK_SKIP;
+}
+
+
+/*
+ perform a SEC_FLAG_MAXIMUM_ALLOWED access check
+*/
+static uint32_t access_check_max_allowed(const struct security_descriptor *sd,
+ const struct security_token *token,
+ enum implicit_owner_rights implicit_owner_rights)
+{
+ uint32_t denied = 0, granted = 0;
+ bool am_owner = false;
+ bool have_owner_rights_ace = false;
+ unsigned i;
+
+ if (sd->dacl == NULL) {
+ if (security_token_has_sid(token, sd->owner_sid)) {
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ granted |= SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ granted |= SEC_STD_READ_CONTROL;
+ break;
+ }
+ }
+ return granted;
+ }
+
+ if (security_token_has_sid(token, sd->owner_sid)) {
+ /*
+ * Check for explicit owner rights: if there are none, we remove
+ * the default owner right SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL
+ * from remaining_access. Otherwise we just process the
+ * explicitly granted rights when processing the ACEs.
+ */
+ am_owner = true;
+
+ for (i=0; i < sd->dacl->num_aces; i++) {
+ struct security_ace *ace = &sd->dacl->aces[i];
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ have_owner_rights_ace = dom_sid_equal(
+ &ace->trustee, &global_sid_Owner_Rights);
+ if (have_owner_rights_ace) {
+ break;
+ }
+ }
+ }
+
+ if (am_owner && !have_owner_rights_ace) {
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ granted |= SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ granted |= SEC_STD_READ_CONTROL;
+ break;
+ }
+ }
+
+ for (i = 0;i<sd->dacl->num_aces; i++) {
+ struct security_ace *ace = &sd->dacl->aces[i];
+ bool is_owner_rights_ace = false;
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ if (am_owner) {
+ is_owner_rights_ace = dom_sid_equal(
+ &ace->trustee, &global_sid_Owner_Rights);
+ }
+
+ if (!is_owner_rights_ace &&
+ !security_token_has_sid(token, &ace->trustee))
+ {
+ continue;
+ }
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ granted |= ace->access_mask;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ denied |= ~granted & ace->access_mask;
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK:
+ {
+ enum ace_callback_result allow =
+ check_callback_ace_allow(ace, token, sd);
+ if (allow == ACE_CALLBACK_INVALID) {
+ return 0;
+ }
+ if (allow == ACE_CALLBACK_ALLOW) {
+ granted |= ace->access_mask;
+ }
+ break;
+ }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK:
+ {
+ enum ace_callback_result deny =
+ check_callback_ace_deny(ace, token, sd);
+ if (deny == ACE_CALLBACK_INVALID) {
+ return 0;
+ }
+ if (deny == ACE_CALLBACK_DENY) {
+ denied |= ~granted & ace->access_mask;
+ }
+ break;
+ }
+
+ default: /* Other ACE types not handled/supported */
+ break;
+ }
+ }
+
+ return granted & ~denied;
+}
+
+
+
+static NTSTATUS se_access_check_implicit_owner(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ enum implicit_owner_rights implicit_owner_rights)
+{
+ uint32_t i;
+ uint32_t bits_remaining;
+ uint32_t explicitly_denied_bits = 0;
+ bool am_owner = false;
+ bool have_owner_rights_ace = false;
+
+ switch (token->evaluate_claims) {
+ case CLAIMS_EVALUATION_INVALID_STATE:
+ if (token->num_local_claims > 0 ||
+ token->num_user_claims > 0 ||
+ token->num_device_claims > 0 ||
+ token->num_device_sids > 0) {
+ DBG_WARNING("Refusing to evaluate token with claims or device SIDs but also "
+ "with CLAIMS_EVALUATION_INVALID_STATE\n");
+ return NT_STATUS_INVALID_TOKEN;
+ }
+ break;
+ case CLAIMS_EVALUATION_ALWAYS:
+ case CLAIMS_EVALUATION_NEVER:
+ break;
+ }
+
+ *access_granted = access_desired;
+ bits_remaining = access_desired;
+
+ /* handle the maximum allowed flag */
+ if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
+ uint32_t orig_access_desired = access_desired;
+
+ access_desired |= access_check_max_allowed(sd, token, implicit_owner_rights);
+ access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
+ *access_granted = access_desired;
+ bits_remaining = access_desired;
+
+ DEBUG(10,("se_access_check: MAX desired = 0x%x, granted = 0x%x, remaining = 0x%x\n",
+ orig_access_desired,
+ *access_granted,
+ bits_remaining));
+ }
+
+ /* a NULL dacl allows access */
+ if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
+ *access_granted = access_desired;
+ return NT_STATUS_OK;
+ }
+
+ if (sd->dacl == NULL) {
+ goto done;
+ }
+
+ if (security_token_has_sid(token, sd->owner_sid)) {
+ /*
+ * Check for explicit owner rights: if there are none, we remove
+ * the default owner right SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL
+ * from remaining_access. Otherwise we just process the
+ * explicitly granted rights when processing the ACEs.
+ */
+ am_owner = true;
+
+ for (i=0; i < sd->dacl->num_aces; i++) {
+ struct security_ace *ace = &sd->dacl->aces[i];
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ have_owner_rights_ace = dom_sid_equal(
+ &ace->trustee, &global_sid_Owner_Rights);
+ if (have_owner_rights_ace) {
+ break;
+ }
+ }
+ }
+ if (am_owner && !have_owner_rights_ace) {
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ bits_remaining &= ~SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ bits_remaining &= ~SEC_STD_READ_CONTROL;
+ break;
+ }
+ }
+
+ /* check each ace in turn. */
+ for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
+ struct security_ace *ace = &sd->dacl->aces[i];
+ bool is_owner_rights_ace = false;
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ if (am_owner) {
+ is_owner_rights_ace = dom_sid_equal(
+ &ace->trustee, &global_sid_Owner_Rights);
+ }
+
+ if (!is_owner_rights_ace &&
+ !security_token_has_sid(token, &ace->trustee))
+ {
+ continue;
+ }
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ bits_remaining &= ~ace->access_mask;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ explicitly_denied_bits |= (bits_remaining & ace->access_mask);
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK:
+ {
+ enum ace_callback_result allow =
+ check_callback_ace_allow(ace, token, sd);
+ if (allow == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (allow == ACE_CALLBACK_ALLOW) {
+ bits_remaining &= ~ace->access_mask;
+ }
+ break;
+ }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK:
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT:
+ {
+ enum ace_callback_result deny =
+ check_callback_ace_deny(ace, token, sd);
+ if (deny == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (deny == ACE_CALLBACK_DENY) {
+ explicitly_denied_bits |= (bits_remaining & ace->access_mask);
+ }
+ break;
+ }
+
+ default: /* Other ACE types not handled/supported */
+ break;
+ }
+ }
+
+ /* Explicitly denied bits always override */
+ bits_remaining |= explicitly_denied_bits;
+
+ /*
+ * We check privileges here because they override even DENY entries.
+ */
+
+ /* Does the user have the privilege to gain SEC_PRIV_SECURITY? */
+ if (bits_remaining & SEC_FLAG_SYSTEM_SECURITY) {
+ if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
+ bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
+ } else {
+ return NT_STATUS_PRIVILEGE_NOT_HELD;
+ }
+ }
+
+ if ((bits_remaining & SEC_STD_WRITE_OWNER) &&
+ security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
+ bits_remaining &= ~(SEC_STD_WRITE_OWNER);
+ }
+
+done:
+ if (bits_remaining != 0) {
+ *access_granted = bits_remaining;
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ The main entry point for access checking. If returning ACCESS_DENIED
+ this function returns the denied bits in the uint32_t pointed
+ to by the access_granted pointer.
+*/
+NTSTATUS se_access_check(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted)
+{
+ return se_access_check_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
+}
+
+/*
+ The main entry point for access checking FOR THE FILE SERVER ONLY !
+ If returning ACCESS_DENIED this function returns the denied bits in
+ the uint32_t pointed to by the access_granted pointer.
+*/
+NTSTATUS se_file_access_check(const struct security_descriptor *sd,
+ const struct security_token *token,
+ bool priv_open_requested,
+ uint32_t access_desired,
+ uint32_t *access_granted)
+{
+ uint32_t bits_remaining;
+ NTSTATUS status;
+
+ if (!priv_open_requested) {
+ /* Fall back to generic se_access_check(). */
+ return se_access_check_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
+ }
+
+ /*
+ * We need to handle the maximum allowed flag
+ * outside of se_access_check(), as we need to
+ * add in the access allowed by the privileges
+ * as well.
+ */
+
+ if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
+ uint32_t orig_access_desired = access_desired;
+
+ access_desired |= access_check_max_allowed(sd, token, true);
+ access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
+
+ if (security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
+ access_desired |= SEC_RIGHTS_PRIV_BACKUP;
+ }
+
+ if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
+ access_desired |= SEC_RIGHTS_PRIV_RESTORE;
+ }
+
+ DEBUG(10,("se_file_access_check: MAX desired = 0x%x "
+ "mapped to 0x%x\n",
+ orig_access_desired,
+ access_desired));
+ }
+
+ status = se_access_check_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ return status;
+ }
+
+ bits_remaining = *access_granted;
+
+ /* Check if we should override with privileges. */
+ if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) &&
+ security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
+ bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP);
+ }
+ if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
+ security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
+ bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE);
+ }
+ if (bits_remaining != 0) {
+ *access_granted = bits_remaining;
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static const struct GUID *get_ace_object_type(const struct security_ace *ace)
+{
+ if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
+ return &ace->object.object.type.type;
+ }
+
+ return NULL;
+}
+
+/**
+ * Evaluates access rights specified in a object-specific ACE for an AD object.
+ * This logic corresponds to MS-ADTS 5.1.3.3.3 Checking Object-Specific Access.
+ * @param[in] ace - the ACE being processed
+ * @param[in/out] tree - remaining_access gets updated for the tree
+ * @param[out] grant_access - set to true if the ACE grants sufficient access
+ * rights to the object/attribute
+ * @returns NT_STATUS_OK, unless access was denied
+ */
+static NTSTATUS check_object_specific_access(const struct security_ace *ace,
+ struct object_tree *tree,
+ bool *grant_access)
+{
+ struct object_tree *node = NULL;
+ const struct GUID *type = NULL;
+
+ *grant_access = false;
+
+ /* if no tree was supplied, we can't do object-specific access checks */
+ if (!tree) {
+ return NT_STATUS_OK;
+ }
+
+ /* Get the ObjectType GUID this ACE applies to */
+ type = get_ace_object_type(ace);
+
+ /*
+ * If the ACE doesn't have a type, then apply it to the whole tree, i.e.
+ * treat 'OA' ACEs as 'A' and 'OD' as 'D'
+ */
+ if (!type) {
+ node = tree;
+ } else {
+
+ /* skip it if the ACE's ObjectType GUID is not in the tree */
+ node = get_object_tree_by_GUID(tree, type);
+ if (!node) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+ ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT) {
+ /* apply the access rights to this node, and any children */
+ object_tree_modify_access(node, ace->access_mask);
+
+ /*
+ * Currently all nodes in the tree request the same access mask,
+ * so we can use any node to check if processing this ACE now
+ * means the requested access has been granted
+ */
+ if (node->remaining_access == 0) {
+ *grant_access = true;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * As per 5.1.3.3.4 Checking Control Access Right-Based Access,
+ * if the CONTROL_ACCESS right is present, then we can grant
+ * access and stop any further access checks
+ */
+ if (ace->access_mask & SEC_ADS_CONTROL_ACCESS) {
+ *grant_access = true;
+ return NT_STATUS_OK;
+ }
+ } else {
+
+ /* this ACE denies access to the requested object/attribute */
+ if (node->remaining_access & ace->access_mask){
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ const struct dom_sid *replace_sid,
+ enum implicit_owner_rights implicit_owner_rights)
+{
+ uint32_t i;
+ uint32_t bits_remaining;
+
+ *access_granted = access_desired;
+ bits_remaining = access_desired;
+
+ /* handle the maximum allowed flag */
+ if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
+ access_desired |= access_check_max_allowed(sd, token, implicit_owner_rights);
+ access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
+ *access_granted = access_desired;
+ bits_remaining = access_desired;
+ }
+
+ if (access_desired & SEC_FLAG_SYSTEM_SECURITY) {
+ if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
+ bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
+ } else {
+ return NT_STATUS_PRIVILEGE_NOT_HELD;
+ }
+ }
+
+ /* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */
+ if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) &&
+ security_token_has_sid(token, sd->owner_sid)) {
+ switch (implicit_owner_rights) {
+ case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
+ bits_remaining &= ~SEC_STD_WRITE_DAC;
+ FALL_THROUGH;
+ case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
+ bits_remaining &= ~SEC_STD_READ_CONTROL;
+ break;
+ }
+ }
+
+ /* SEC_PRIV_TAKE_OWNERSHIP grants SEC_STD_WRITE_OWNER */
+ if ((bits_remaining & (SEC_STD_WRITE_OWNER)) &&
+ security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
+ bits_remaining &= ~(SEC_STD_WRITE_OWNER);
+ }
+
+ /* a NULL dacl allows access */
+ if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
+ *access_granted = access_desired;
+ return NT_STATUS_OK;
+ }
+
+ if (sd->dacl == NULL) {
+ goto done;
+ }
+
+ /* check each ace in turn. */
+ for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
+ const struct dom_sid *trustee;
+ const struct security_ace *ace = &sd->dacl->aces[i];
+ NTSTATUS status;
+ bool grant_access = false;
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+
+ if (dom_sid_equal(&ace->trustee, &global_sid_Self) && replace_sid) {
+ trustee = replace_sid;
+ } else {
+ trustee = &ace->trustee;
+ }
+
+ if (!security_token_has_sid(token, trustee)) {
+ continue;
+ }
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ if (tree) {
+ object_tree_modify_access(tree, ace->access_mask);
+ }
+
+ bits_remaining &= ~ace->access_mask;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ if (bits_remaining & ace->access_mask) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK:
+ {
+ enum ace_callback_result allow =
+ check_callback_ace_allow(ace, token, sd);
+ if (allow == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (allow == ACE_CALLBACK_ALLOW) {
+ bits_remaining &= ~ace->access_mask;
+ }
+ break;
+ }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK:
+ {
+ enum ace_callback_result deny =
+ check_callback_ace_deny(ace, token, sd);
+ if (deny == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (deny == ACE_CALLBACK_DENY) {
+ if (bits_remaining & ace->access_mask) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+ break;
+ }
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ status = check_object_specific_access(ace, tree,
+ &grant_access);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (grant_access) {
+ return NT_STATUS_OK;
+ }
+ break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT:
+ {
+ /*
+ * if the callback says ALLOW, we treat this as a
+ * SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT.
+ *
+ * Otherwise we act as if this ACE does not exist.
+ */
+ enum ace_callback_result allow =
+ check_callback_ace_allow(ace, token, sd);
+ if (allow == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (allow != ACE_CALLBACK_ALLOW) {
+ break;
+ }
+
+ status = check_object_specific_access(ace, tree,
+ &grant_access);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (grant_access) {
+ return NT_STATUS_OK;
+ }
+ break;
+ }
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT:
+ {
+ /*
+ * ACCESS_DENIED_OBJECT ACEs can't grant access --
+ * they either don't match the object and slide
+ * harmlessly past or they return
+ * NT_STATUS_ACCESS_DENIED.
+ *
+ * ACCESS_DENIED_CALLBACK_OBJECT ACEs add another way
+ * of not applying, and another way of failing.
+ */
+ enum ace_callback_result deny =
+ check_callback_ace_deny(ace, token, sd);
+ if (deny == ACE_CALLBACK_INVALID) {
+ return NT_STATUS_INVALID_ACE_CONDITION;
+ }
+ if (deny != ACE_CALLBACK_DENY) {
+ break;
+ }
+ status = check_object_specific_access(ace, tree,
+ &grant_access);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ break;
+ }
+ default: /* Other ACE types not handled/supported */
+ break;
+ }
+ }
+
+done:
+ if (bits_remaining != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * @brief Perform directoryservice (DS) related access checks for a given user
+ *
+ * Perform DS access checks for the user represented by its security_token, on
+ * the provided security descriptor. If an tree associating GUID and access
+ * required is provided then object access (OA) are checked as well. *
+ * @param[in] sd The security descriptor against which the required
+ * access are requested
+ *
+ * @param[in] token The security_token associated with the user to
+ * test
+ *
+ * @param[in] access_desired A bitfield of rights that must be granted for the
+ * given user in the specified SD.
+ *
+ * If one
+ * of the entry in the tree grants all the requested rights for the given GUID
+ * FIXME
+ * tree can be null if not null it's the
+ * Lots of code duplication, it will be united in just one
+ * function eventually */
+
+NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ struct dom_sid *replace_sid)
+{
+ return sec_access_check_ds_implicit_owner(sd,
+ token,
+ access_desired,
+ access_granted,
+ tree,
+ replace_sid,
+ IMPLICIT_OWNER_READ_CONTROL_RIGHTS);
+}
diff --git a/libcli/security/access_check.h b/libcli/security/access_check.h
new file mode 100644
index 0000000..7c424b9
--- /dev/null
+++ b/libcli/security/access_check.h
@@ -0,0 +1,100 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Gerald Carter 2005
+ Copyright (C) Volker Lendecke 2007
+ Copyright (C) Jeremy Allison 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/>.
+*/
+#ifndef _ACCESS_CHECK_H_
+#define _ACCESS_CHECK_H_
+
+#include "librpc/gen_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
+ objects. Each type of object has its own mapping of generic to object
+ specific access rights. */
+
+void se_map_generic(uint32_t *access_mask, const struct generic_mapping *mapping);
+
+/* Map generic access rights to object specific rights for all the ACE's
+ * in a security_acl.
+ */
+void security_acl_map_generic(struct security_acl *sa,
+ const struct generic_mapping *mapping);
+
+/* Map standard access rights to object specific rights. This technique is
+ used to give meaning to assigning read, write, execute and all access to
+ objects. Each type of object has its own mapping of standard to object
+ specific access rights. */
+void se_map_standard(uint32_t *access_mask, const struct standard_mapping *mapping);
+
+/*
+ The main entry point for access checking. If returning ACCESS_DENIED
+ this function returns the denied bits in the uint32_t pointed
+ to by the access_granted pointer.
+*/
+NTSTATUS se_access_check(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted);
+
+/*
+ The main entry point for access checking FOR THE FILE SERVER ONLY !
+ If returning ACCESS_DENIED this function returns the denied bits in
+ the uint32_t pointed to by the access_granted pointer.
+*/
+NTSTATUS se_file_access_check(const struct security_descriptor *sd,
+ const struct security_token *token,
+ bool priv_open_requested,
+ uint32_t access_desired,
+ uint32_t *access_granted);
+
+NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ const struct dom_sid *replace_sid,
+ enum implicit_owner_rights implicit_owner_rights);
+
+/* modified access check for the purposes of DS security
+ * Lots of code duplication, it will be united in just one
+ * function eventually */
+
+NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
+ const struct security_token *token,
+ uint32_t access_desired,
+ uint32_t *access_granted,
+ struct object_tree *tree,
+ struct dom_sid *replace_sid);
+
+bool insert_in_object_tree(TALLOC_CTX *mem_ctx,
+ const struct GUID *guid,
+ uint32_t init_access,
+ struct object_tree *root,
+ struct object_tree **new_node_out);
+
+/* search by GUID */
+struct object_tree *get_object_tree_by_GUID(struct object_tree *root,
+ const struct GUID *guid);
+
+/* Change the granted access per each ACE */
+void object_tree_modify_access(struct object_tree *root,
+ uint32_t access_mask);
+#endif
diff --git a/libcli/security/claims-conversions.c b/libcli/security/claims-conversions.c
new file mode 100644
index 0000000..ccf1375
--- /dev/null
+++ b/libcli/security/claims-conversions.c
@@ -0,0 +1,1216 @@
+/*
+ * Unix SMB implementation.
+ * Utility functions for converting between claims formats.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 "librpc/gen_ndr/ndr_conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+#include "lib/util/debug.h"
+#include "lib/util/stable_sort.h"
+
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "librpc/gen_ndr/claims.h"
+
+/*
+ * We support three formats for claims, all slightly different.
+ *
+ * 1. MS-ADTS 2.2.18.* claims sets, blobs, arrays, or whatever, which
+ * are used in the PAC.
+ *
+ * 2. MS-DTYP 2.4.10.1 CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1
+ * structures, used in security tokens and resource SACL ACEs.
+ *
+ * 3. MS-DTYP 2.4.4.17 Conditional ACE tokens.
+ *
+ * The types don't map perfectly onto each other -- in particular,
+ * Conditional ACEs don't have unsigned integer or boolean types, but
+ * do have short integer types which the other forms don't.
+ *
+ * We don't support the format used by the Win32 API function
+ * AddResourceAttributeAce(), which is called CLAIM_SECURITY_ATTRIBUTE_V1.
+ * Nobody has ever used that function in public, and the format is not used
+ * on the wire.
+ */
+
+
+static bool claim_v1_string_to_ace_string(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ char *s = talloc_strdup(mem_ctx,
+ claim->values[offset].string_value);
+ if (s == NULL) {
+ return false;
+ }
+
+ result->type = CONDITIONAL_ACE_TOKEN_UNICODE;
+ result->data.unicode.value = s;
+ return true;
+}
+
+
+static bool claim_v1_octet_string_to_ace_octet_string(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ DATA_BLOB *v = NULL;
+ DATA_BLOB w = data_blob_null;
+
+ v = claim->values[offset].octet_value;
+
+ if (v->length > CONDITIONAL_ACE_MAX_LENGTH) {
+ DBG_WARNING("claim has octet string of unexpected length %zu "
+ "(expected range 1 - %u)\n",
+ v->length, CONDITIONAL_ACE_MAX_LENGTH);
+ return false;
+ }
+ if (v->length != 0) {
+ w = data_blob_talloc(mem_ctx, v->data, v->length);
+ if (w.data == NULL) {
+ return false;
+ }
+ }
+
+ result->type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
+ result->data.bytes = w;
+ return true;
+}
+
+
+static bool blob_string_sid_to_sid(DATA_BLOB *blob,
+ struct dom_sid *sid)
+{
+ /*
+ * Resource ACE claim SIDs are stored as SID strings in
+ * CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_RELATIVE blobs. These are in
+ * ACEs, which means we don't quite know who wrote them, and it is
+ * unspecified whether the blob should contain a terminating NUL byte.
+ * Therefore we accept either form, copying into a temporary buffer if
+ * there is no '\0'. Apart from this special case, we don't accept
+ * SIDs that are shorter than the blob.
+ *
+ * It doesn't seem like SDDL short SIDs ("WD") are accepted here. This
+ * isn't SDDL.
+ */
+ bool ok;
+ size_t len = blob->length;
+ char buf[DOM_SID_STR_BUFLEN + 1]; /* 191 + 1 */
+ const char *end = NULL;
+ char *str = NULL;
+
+ if (len < 5 || len >= DOM_SID_STR_BUFLEN) {
+ return false;
+ }
+ if (blob->data[len - 1] == '\0') {
+ str = (char *)blob->data;
+ len--;
+ } else {
+ memcpy(buf, blob->data, len);
+ buf[len] = 0;
+ str = buf;
+ }
+
+ ok = dom_sid_parse_endp(str, sid, &end);
+ if (!ok) {
+ return false;
+ }
+
+ if (end - str != len) {
+ return false;
+ }
+ return true;
+}
+
+
+static bool claim_v1_sid_to_ace_sid(
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ /*
+ * In the _V1 struct, SIDs are stored as octet string blobs,
+ * as *SID strings*.
+ *
+ * In the conditional ACE they are stored as struct dom_sid.
+ *
+ * There are no SIDs in ADTS claims, but there can be in
+ * resource ACEs.
+ */
+ DATA_BLOB *v = NULL;
+ bool ok;
+
+ v = claim->values[offset].sid_value;
+
+ ok = blob_string_sid_to_sid(v, &result->data.sid.sid);
+ if (! ok) {
+ DBG_WARNING("claim has invalid SID string of length %zu.\n",
+ v->length);
+ return false;
+ }
+
+ result->type = CONDITIONAL_ACE_TOKEN_SID;
+ return true;
+}
+
+
+static bool claim_v1_int_to_ace_int(
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ int64_t v = *claim->values[offset].int_value;
+ result->type = CONDITIONAL_ACE_TOKEN_INT64;
+ result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
+ result->data.int64.value = v;
+
+ /*
+ * The sign flag (and the base flag above) determines how the
+ * ACE token will be displayed if converted to SDDL. These
+ * values are not likely to end up as SDDL, but we might as
+ * well get it right. A negative flag means it will be
+ * displayed with a minus sign, and a positive flag means a
+ * plus sign is shown. The none flag means no + or -.
+ */
+ if (v < 0) {
+ result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NEGATIVE;
+ } else {
+ result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
+ }
+
+ return true;
+}
+
+
+static bool claim_v1_unsigned_int_to_ace_int(
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ uint64_t v = *claim->values[offset].uint_value;
+ if (v > INT64_MAX) {
+ /*
+ * The unsigned value can't be represented in a
+ * conditional ACE type.
+ *
+ * XXX or can it? does the positive flag make it
+ * unsigned?
+ */
+ return false;
+ }
+ result->type = CONDITIONAL_ACE_TOKEN_INT64;
+ result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
+ result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_POSITIVE;
+ result->data.int64.value = v;
+ return true;
+}
+
+
+static bool claim_v1_bool_to_ace_int(
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ uint64_t v = *claim->values[offset].uint_value;
+ result->type = CONDITIONAL_ACE_TOKEN_INT64;
+ result->data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
+ result->data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
+ result->data.int64.value = v ? 1 : 0;
+ return true;
+}
+
+
+static bool claim_v1_offset_to_ace_token(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset,
+ struct ace_condition_token *result)
+{
+ /*
+ * A claim structure has an array of claims of a certain type,
+ * and this converts a single one into a conditional ACE token.
+ *
+ * For example, if offset is 3, claim->values[3] will be
+ * turned into *result.
+ *
+ * conditional ace token will have flags to indicate that it
+ * comes from a claim attribute, and whether or not that
+ * attribute should be compared case-sensitively (only
+ * affecting unicode strings).
+ *
+ * The CLAIM_SECURITY_ATTRIBUTE_CASE_SENSITIVE (from the
+ * claim_flags enum in security.idl) is used for both.
+ */
+ uint8_t f = claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ result->flags = f | CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR;
+
+ if (claim->values[offset].int_value == NULL) {
+ return false;
+ }
+ switch (claim->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ return claim_v1_int_to_ace_int(claim, offset, result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ return claim_v1_unsigned_int_to_ace_int(claim, offset, result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ return claim_v1_string_to_ace_string(mem_ctx, claim, offset,
+ result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ return claim_v1_sid_to_ace_sid(claim, offset, result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
+ return claim_v1_bool_to_ace_int(claim, offset, result);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ return claim_v1_octet_string_to_ace_octet_string(mem_ctx,
+ claim,
+ offset,
+ result);
+ default:
+ return false;
+ }
+}
+
+
+static bool claim_v1_copy(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *dest,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *src);
+
+
+
+bool claim_v1_to_ace_composite_unchecked(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result)
+{
+ /*
+ * This converts a claim object into a conditional ACE
+ * composite without checking whether it is a valid and sorted
+ * claim. It is called in two places:
+ *
+ * 1. claim_v1_to_ace_token() below (which does do those
+ * checks, and is the function you want).
+ *
+ * 2. sddl_resource_attr_from_claim() in which a resource
+ * attribute claim needs to pass through a conditional ACE
+ * composite structure on its way to becoming SDDL. In that
+ * case we don't want to check validity.
+ */
+ size_t i;
+ struct ace_condition_token *tokens = NULL;
+ bool ok;
+
+ tokens = talloc_array(mem_ctx,
+ struct ace_condition_token,
+ claim->value_count);
+ if (tokens == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < claim->value_count; i++) {
+ ok = claim_v1_offset_to_ace_token(tokens,
+ claim,
+ i,
+ &tokens[i]);
+ if (! ok) {
+ TALLOC_FREE(tokens);
+ return false;
+ }
+ }
+
+ result->type = CONDITIONAL_ACE_TOKEN_COMPOSITE;
+ result->data.composite.tokens = tokens;
+ result->data.composite.n_members = claim->value_count;
+ result->flags = claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ return true;
+}
+
+
+bool claim_v1_to_ace_token(TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result)
+{
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim_copy = NULL;
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *sorted_claim = NULL;
+ NTSTATUS status;
+ bool ok;
+ bool case_sensitive = claim->flags & \
+ CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+
+ if (claim->value_count < 1 ||
+ claim->value_count >= CONDITIONAL_ACE_MAX_TOKENS) {
+ DBG_WARNING("rejecting claim with %"PRIu32" tokens\n",
+ claim->value_count);
+ return false;
+ }
+ /*
+ * if there is one, we return a single thing of that type; if
+ * there are many, we return a composite.
+ */
+
+ if (claim->value_count == 1) {
+ return claim_v1_offset_to_ace_token(mem_ctx,
+ claim,
+ 0,
+ result);
+ }
+
+ if (claim->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED) {
+ /*
+ * We can avoid making a sorted copy.
+ *
+ * This is normal case for wire claims, where the
+ * sorting and duplicate checking happens earlier in
+ * token_claims_to_claims_v1().
+ */
+ sorted_claim = claim;
+ } else {
+ /*
+ * This is presumably a resource attribute ACE, which
+ * is stored in the ACE as struct
+ * CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1, and we don't
+ * really want to mutate that copy -- even if there
+ * aren't currently realistic pathways that read an
+ * ACE, trigger this, and write it back (outside of
+ * tests).
+ */
+ claim_copy = talloc(mem_ctx, struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
+ if (claim_copy == NULL) {
+ return false;
+ }
+
+ ok = claim_v1_copy(claim_copy, claim_copy, claim);
+ if (!ok) {
+ TALLOC_FREE(claim_copy);
+ return false;
+ }
+
+ status = claim_v1_check_and_sort(claim_copy, claim_copy,
+ case_sensitive);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("resource attribute claim sort failed with %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(claim_copy);
+ return false;
+ }
+ sorted_claim = claim_copy;
+ }
+ ok = claim_v1_to_ace_composite_unchecked(mem_ctx, sorted_claim, result);
+ if (! ok) {
+ TALLOC_FREE(claim_copy);
+ return false;
+ }
+
+ /*
+ * The multiple values will get turned into a composite
+ * literal in the conditional ACE. Each element of the
+ * composite will have flags set by
+ * claim_v1_offset_to_ace_token(), but they also need to be
+ * set here (at least the _FROM_ATTR flag) or the child values
+ * will not be reached.
+ */
+ result->flags |= (
+ CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR |
+ CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED);
+
+ return true;
+}
+
+
+
+static bool ace_int_to_claim_v1_int(TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ int64_t *v = talloc(mem_ctx, int64_t);
+ if (v == NULL) {
+ return false;
+ }
+ *v = tok->data.int64.value;
+ claim->values[offset].int_value = v;
+ return true;
+}
+
+
+static bool ace_string_to_claim_v1_string(TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ const char *s = talloc_strdup(mem_ctx,
+ tok->data.unicode.value);
+ if (s == NULL) {
+ return false;
+ }
+ claim->values[offset].string_value = s;
+ return true;
+
+}
+
+
+static bool ace_sid_to_claim_v1_sid(TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ /* claim_v1 sid is an "S-1-*" string data blob, not struct dom_sid. */
+ char *s = NULL;
+
+ DATA_BLOB *blob = NULL;
+ blob = talloc(mem_ctx, DATA_BLOB);
+ if (blob == NULL) {
+ return false;
+ }
+ s = dom_sid_string(blob, &tok->data.sid.sid);
+ if (s == NULL) {
+ TALLOC_FREE(blob);
+ return false;
+ }
+ *blob = data_blob_string_const(s);
+ claim->values[offset].sid_value = blob;
+ return true;
+}
+
+static bool ace_octet_string_to_claim_v1_octet_string(
+ TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ DATA_BLOB *v = talloc(mem_ctx, DATA_BLOB);
+ if (v == NULL) {
+ return false;
+ }
+
+ *v = data_blob_talloc(v,
+ tok->data.bytes.data,
+ tok->data.bytes.length);
+ if (v->data == NULL) {
+ return false;
+ }
+
+ claim->values[offset].octet_value = v;
+ return true;
+}
+
+
+
+static bool ace_token_to_claim_v1_offset(TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ size_t offset)
+{
+ /*
+ * A claim structure has an array of claims of a certain type,
+ * and this converts a single one into a conditional ACE token.
+ *
+ * For example, if offset is 3, claim->values[3] will be
+ * turned into *result.
+ */
+ if (offset >= claim->value_count) {
+ return false;
+ }
+ switch (claim->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ return ace_int_to_claim_v1_int(mem_ctx, tok, claim, offset);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ return ace_string_to_claim_v1_string(mem_ctx, tok, claim, offset);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ return ace_sid_to_claim_v1_sid(mem_ctx, tok, claim, offset);
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ return ace_octet_string_to_claim_v1_octet_string(mem_ctx,
+ tok,
+ claim,
+ offset);
+ default:
+ /*bool unimplemented, because unreachable */
+ return false;
+ }
+}
+
+
+bool ace_token_to_claim_v1(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **claim,
+ uint32_t flags)
+{
+ size_t i;
+ bool ok;
+ bool is_comp = false;
+ int claim_type = -1;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *_claim = NULL;
+ uint32_t value_count;
+
+ if (name == NULL || claim == NULL || tok == NULL) {
+ return false;
+ }
+ *claim = NULL;
+
+ if (tok->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ is_comp = true;
+ /* there must be values, all of the same type */
+ if (tok->data.composite.n_members == 0) {
+ DBG_WARNING("Empty ACE composite list\n");
+ return false;
+ }
+ if (tok->data.composite.n_members > 1) {
+ for (i = 1; i < tok->data.composite.n_members; i++) {
+ if (tok->data.composite.tokens[i].type !=
+ tok->data.composite.tokens[0].type) {
+ DBG_WARNING(
+ "ACE composite list has varying "
+ "types (at least %u and %u)\n",
+ tok->data.composite.tokens[i].type,
+ tok->data.composite.tokens[0].type);
+ return false;
+ }
+ }
+ }
+ value_count = tok->data.composite.n_members;
+
+ switch (tok->data.composite.tokens[0].type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
+ break;
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING;
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_SID;
+ break;
+ default:
+ /* reject nested composites, no uint or bool. */
+ DBG_WARNING("ACE composite list has invalid type %u\n",
+ tok->data.composite.tokens[0].type);
+ return false;
+ }
+ } else {
+ value_count = 1;
+ switch(tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
+ break;
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING;
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ claim_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_SID;
+ break;
+ default:
+ /*
+ * no way of creating bool or uint values,
+ * composite is handled above.
+ */
+ DBG_WARNING("ACE token has invalid type %u\n",
+ tok->data.composite.tokens[0].type);
+ return false;
+ }
+ }
+
+ _claim = talloc(mem_ctx, struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
+ if (_claim == NULL) {
+ return false;
+ }
+
+ _claim->value_count = value_count;
+ _claim->value_type = claim_type;
+ _claim->flags = flags;
+ _claim->name = talloc_strdup(mem_ctx, name);
+ if (_claim->name == NULL) {
+ TALLOC_FREE(_claim);
+ return false;
+ }
+ /*
+ * The values array is actually an array of pointers to
+ * values, even when the values are ints or bools.
+ */
+ _claim->values = talloc_array(_claim, union claim_values, value_count);
+ if (_claim->values == NULL) {
+ TALLOC_FREE(_claim);
+ return false;
+ }
+ if (! is_comp) {
+ /* there is one value, not a list */
+ ok = ace_token_to_claim_v1_offset(_claim,
+ tok,
+ _claim,
+ 0);
+ if (! ok) {
+ TALLOC_FREE(_claim);
+ return false;
+ }
+ } else {
+ /* a composite list of values */
+ for (i = 0; i < value_count; i++) {
+ struct ace_condition_token *t = &tok->data.composite.tokens[i];
+ ok = ace_token_to_claim_v1_offset(mem_ctx,
+ t,
+ _claim,
+ i);
+ if (! ok) {
+ TALLOC_FREE(_claim);
+ return false;
+ }
+ }
+ }
+
+
+ if (_claim->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64) {
+ /*
+ * Conditional ACE tokens don't have a UINT type but
+ * claims do. Windows tends to use UINT types in
+ * claims when it can, so so do we.
+ */
+ bool could_be_uint = true;
+ for (i = 0; i < value_count; i++) {
+ if (*_claim->values[i].int_value < 0) {
+ could_be_uint = false;
+ break;
+ }
+ }
+ if (could_be_uint) {
+ _claim->value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64;
+ }
+ }
+
+ *claim = _claim;
+ return true;
+}
+
+
+
+static bool claim_v1_copy(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *dest,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *src)
+{
+ DATA_BLOB blob = {0};
+ enum ndr_err_code ndr_err;
+
+ /*
+ * FIXME, could be more efficient! but copying these
+ * structures is fiddly, and it might be worth coming up
+ * with a better API for adding claims.
+ */
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, src,
+ (ndr_push_flags_fn_t)ndr_push_CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob, mem_ctx, dest,
+ (ndr_pull_flags_fn_t)ndr_pull_CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(blob.data);
+ return false;
+ }
+ TALLOC_FREE(blob.data);
+ return true;
+}
+
+
+
+bool add_claim_to_token(TALLOC_CTX *mem_ctx,
+ struct security_token *token,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ const char *claim_type)
+{
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *tmp = NULL;
+ NTSTATUS status;
+ uint32_t *n = NULL;
+ bool ok;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **list = NULL;
+ if (strcmp(claim_type, "device") == 0) {
+ n = &token->num_device_claims;
+ list = &token->device_claims;
+ } else if (strcmp(claim_type, "local") == 0) {
+ n = &token->num_local_claims;
+ list = &token->local_claims;
+ } else if (strcmp(claim_type, "user") == 0) {
+ n = &token->num_user_claims;
+ list = &token->user_claims;
+ } else {
+ return false;
+ }
+ if ((*n) == UINT32_MAX) {
+ return false;
+ }
+
+ tmp = talloc_realloc(mem_ctx,
+ *list,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1,
+ (*n) + 1);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ ok = claim_v1_copy(mem_ctx, &tmp[*n], claim);
+ if (! ok ) {
+ TALLOC_FREE(tmp);
+ return false;
+ }
+
+ status = claim_v1_check_and_sort(tmp, &tmp[*n],
+ claim->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("resource attribute claim sort failed with %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(tmp);
+ return false;
+ }
+
+ (*n)++;
+ *list = tmp;
+ return true;
+}
+
+
+static NTSTATUS claim_v1_check_and_sort_boolean(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim)
+{
+ /*
+ * There are so few valid orders in a boolean claim that we can
+ * enumerate them all.
+ */
+ switch (claim->value_count) {
+ case 0:
+ return NT_STATUS_OK;
+ case 1:
+ if (*claim->values[0].uint_value == 0 ||
+ *claim->values[0].uint_value == 1) {
+ return NT_STATUS_OK;
+ }
+ break;
+ case 2:
+ if (*claim->values[0].uint_value == 1) {
+ /* switch the order. */
+ *claim->values[0].uint_value = *claim->values[1].uint_value;
+ *claim->values[1].uint_value = 1;
+ }
+ if (*claim->values[0].uint_value == 0 &&
+ *claim->values[1].uint_value == 1) {
+ return NT_STATUS_OK;
+ }
+ break;
+ default:
+ /* 3 or more must have duplicates. */
+ break;
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+
+struct claim_sort_context {
+ uint16_t value_type;
+ bool failed;
+ bool case_sensitive;
+};
+
+static int claim_sort_cmp(const union claim_values *lhs,
+ const union claim_values *rhs,
+ struct claim_sort_context *ctx)
+{
+ /*
+ * These comparisons have to match those used in
+ * conditional_ace.c.
+ */
+ int cmp;
+
+ switch (ctx->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ {
+ /*
+ * We sort as signed integers, even for uint64,
+ * because a) we don't actually care about the true
+ * order, just uniqueness, and b) the conditional ACEs
+ * only know of signed values.
+ */
+ int64_t a, b;
+ if (ctx->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64) {
+ a = *lhs->int_value;
+ b = *rhs->int_value;
+ } else {
+ a = (int64_t)*lhs->uint_value;
+ b = (int64_t)*rhs->uint_value;
+ }
+ if (a < b) {
+ return -1;
+ }
+ if (a == b) {
+ return 0;
+ }
+ return 1;
+ }
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ {
+ const char *a = lhs->string_value;
+ const char *b = rhs->string_value;
+ if (ctx->case_sensitive) {
+ return strcmp(a, b);
+ }
+ return strcasecmp_m(a, b);
+ }
+
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ {
+ /*
+ * The blobs in a claim are "S-1-.." strings, not struct
+ * dom_sid as used in conditional ACEs, and to sort them the
+ * same as ACEs we need to make temporary structs.
+ *
+ * We don't accept SID claims over the wire -- these
+ * are resource attribute ACEs only.
+ */
+ struct dom_sid a, b;
+ bool lhs_ok, rhs_ok;
+
+ lhs_ok = blob_string_sid_to_sid(lhs->sid_value, &a);
+ rhs_ok = blob_string_sid_to_sid(rhs->sid_value, &b);
+ if (!(lhs_ok && rhs_ok)) {
+ ctx->failed = true;
+ return -1;
+ }
+ cmp = dom_sid_compare(&a, &b);
+ return cmp;
+ }
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ {
+ const DATA_BLOB *a = lhs->octet_value;
+ const DATA_BLOB *b = rhs->octet_value;
+ return data_blob_cmp(a, b);
+ }
+ default:
+ ctx->failed = true;
+ break;
+ }
+ return -1;
+}
+
+
+NTSTATUS claim_v1_check_and_sort(TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ bool case_sensitive)
+{
+ bool ok;
+ uint32_t i;
+ struct claim_sort_context sort_ctx = {
+ .failed = false,
+ .value_type = claim->value_type,
+ .case_sensitive = case_sensitive
+ };
+
+ /*
+ * It could be that the values array contains a NULL pointer, in which
+ * case we don't need to worry about what type it is.
+ */
+ for (i = 0; i < claim->value_count; i++) {
+ if (claim->values[i].int_value == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (claim->value_type == CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN) {
+ NTSTATUS status = claim_v1_check_and_sort_boolean(mem_ctx, claim);
+ if (NT_STATUS_IS_OK(status)) {
+ claim->flags |= CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED;
+ }
+ return status;
+ }
+
+ ok = stable_sort_talloc_r(mem_ctx,
+ claim->values,
+ claim->value_count,
+ sizeof(union claim_values),
+ (samba_compare_with_context_fn_t)claim_sort_cmp,
+ &sort_ctx);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (sort_ctx.failed) {
+ /* this failure probably means a bad SID string */
+ DBG_WARNING("claim sort of %"PRIu32" members, type %"PRIu16" failed\n",
+ claim->value_count,
+ claim->value_type);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (i = 1; i < claim->value_count; i++) {
+ int cmp = claim_sort_cmp(&claim->values[i - 1],
+ &claim->values[i],
+ &sort_ctx);
+ if (cmp == 0) {
+ DBG_WARNING("duplicate values in claim\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (cmp > 0) {
+ DBG_ERR("claim sort failed!\n");
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+ if (case_sensitive) {
+ claim->flags |= CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ }
+ claim->flags |= CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED;
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS token_claims_to_claims_v1(TALLOC_CTX *mem_ctx,
+ const struct CLAIMS_SET *claims_set,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **out_claims,
+ uint32_t *out_n_claims)
+{
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claims = NULL;
+ uint32_t n_claims = 0;
+ uint32_t expected_n_claims = 0;
+ uint32_t i;
+ NTSTATUS status;
+
+ if (out_claims == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ if (out_n_claims == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ *out_claims = NULL;
+ *out_n_claims = 0;
+
+ if (claims_set == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * The outgoing number of claims is (at most) the sum of the
+ * claims_counts of each claims_array.
+ */
+ for (i = 0; i < claims_set->claims_array_count; ++i) {
+ uint32_t count = claims_set->claims_arrays[i].claims_count;
+ expected_n_claims += count;
+ if (expected_n_claims < count) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ claims = talloc_array(mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1,
+ expected_n_claims);
+ if (claims == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (i = 0; i < claims_set->claims_array_count; ++i) {
+ const struct CLAIMS_ARRAY *claims_array = &claims_set->claims_arrays[i];
+ uint32_t j;
+
+ switch (claims_array->claims_source_type) {
+ case CLAIMS_SOURCE_TYPE_AD:
+ case CLAIMS_SOURCE_TYPE_CERTIFICATE:
+ break;
+ default:
+ /* Ignore any claims of a type we don’t recognize. */
+ continue;
+ }
+
+ for (j = 0; j < claims_array->claims_count; ++j) {
+ const struct CLAIM_ENTRY *claim_entry = &claims_array->claim_entries[j];
+ const char *name = NULL;
+ union claim_values *claim_values = NULL;
+ uint32_t n_values;
+ enum security_claim_value_type value_type;
+
+ switch (claim_entry->type) {
+ case CLAIM_TYPE_INT64:
+ {
+ const struct CLAIM_INT64 *values = &claim_entry->values.claim_int64;
+ uint32_t k;
+ int64_t *claim_values_int64 = NULL;
+
+ n_values = values->value_count;
+ value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64;
+
+ claim_values = talloc_array(claims,
+ union claim_values,
+ n_values);
+ if (claim_values == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+ claim_values_int64 = talloc_array(claims,
+ int64_t,
+ n_values);
+ if (claim_values_int64 == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (k = 0; k < n_values; ++k) {
+ claim_values_int64[k] = values->values[k];
+ claim_values[k].int_value = &claim_values_int64[k];
+ }
+
+ break;
+ }
+ case CLAIM_TYPE_UINT64:
+ case CLAIM_TYPE_BOOLEAN:
+ {
+ const struct CLAIM_UINT64 *values = &claim_entry->values.claim_uint64;
+ uint32_t k;
+ uint64_t *claim_values_uint64 = NULL;
+
+ n_values = values->value_count;
+ value_type = (claim_entry->type == CLAIM_TYPE_UINT64)
+ ? CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64
+ : CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN;
+
+ claim_values = talloc_array(claims,
+ union claim_values,
+ n_values);
+ if (claim_values == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ claim_values_uint64 = talloc_array(claims,
+ uint64_t,
+ n_values);
+ if (claim_values_uint64 == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (k = 0; k < n_values; ++k) {
+ claim_values_uint64[k] = values->values[k];
+ claim_values[k].uint_value = &claim_values_uint64[k];
+ }
+
+ break;
+ }
+ case CLAIM_TYPE_STRING:
+ {
+ const struct CLAIM_STRING *values = &claim_entry->values.claim_string;
+ uint32_t k, m;
+ bool seen_empty = false;
+ n_values = values->value_count;
+ value_type = CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING;
+
+ claim_values = talloc_array(claims,
+ union claim_values,
+ n_values);
+ if (claim_values == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ m = 0;
+ for (k = 0; k < n_values; ++k) {
+ const char *string_value = NULL;
+
+ if (values->values[k] != NULL) {
+ string_value = talloc_strdup(claim_values, values->values[k]);
+ if (string_value == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+ claim_values[m].string_value = string_value;
+ m++;
+ } else {
+ /*
+ * We allow one NULL string
+ * per claim, but not two,
+ * because two would be a
+ * duplicate, and we don't
+ * want those (duplicates in
+ * actual values are checked
+ * later).
+ */
+ if (seen_empty) {
+ talloc_free(claims);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ seen_empty = true;
+ }
+ }
+ n_values = m;
+ break;
+ }
+ default:
+ /*
+ * Other claim types are unsupported — just skip
+ * them.
+ */
+ continue;
+ }
+
+ if (claim_entry->id != NULL) {
+ name = talloc_strdup(claims, claim_entry->id);
+ if (name == NULL) {
+ talloc_free(claims);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ claims[n_claims] = (struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1) {
+ .name = name,
+ .value_type = value_type,
+ .flags = 0,
+ .value_count = n_values,
+ .values = claim_values,
+ };
+
+ status = claim_v1_check_and_sort(claims, &claims[n_claims],
+ false);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(claims);
+ DBG_WARNING("claim sort and uniqueness test failed with %s\n",
+ nt_errstr(status));
+ return status;
+ }
+ n_claims++;
+ }
+ }
+ *out_claims = claims;
+ *out_n_claims = n_claims;
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/security/claims-conversions.h b/libcli/security/claims-conversions.h
new file mode 100644
index 0000000..78d8e91
--- /dev/null
+++ b/libcli/security/claims-conversions.h
@@ -0,0 +1,60 @@
+/*
+ * Unix SMB implementation.
+ * Utility functions for converting between claims formats.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 LIBCLI_SECURITY_CLAIMS_CONVERSIONS_H
+#define LIBCLI_SECURITY_CLAIMS_CONVERSIONS_H
+
+#include "replace.h"
+#include <talloc.h>
+#include "libcli/util/ntstatus.h"
+
+struct CLAIMS_SET;
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1;
+struct ace_condition_token;
+struct security_token;
+
+bool claim_v1_to_ace_token(TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result);
+
+bool ace_token_to_claim_v1(TALLOC_CTX *mem_ctx,
+ const char *name,
+ const struct ace_condition_token *tok,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **claim,
+ uint32_t flags);
+
+bool add_claim_to_token(TALLOC_CTX *mem_ctx,
+ struct security_token *token,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ const char *claim_type);
+
+NTSTATUS token_claims_to_claims_v1(TALLOC_CTX *mem_ctx,
+ const struct CLAIMS_SET *claims_set,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 **out_claims,
+ uint32_t *out_n_claims);
+
+bool claim_v1_to_ace_composite_unchecked(TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result);
+
+NTSTATUS claim_v1_check_and_sort(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ bool case_sensitive);
+
+#endif /* LIBCLI_SECURITY_CLAIMS_CONVERSIONS_H */
diff --git a/libcli/security/conditional_ace.c b/libcli/security/conditional_ace.c
new file mode 100644
index 0000000..158c8ec
--- /dev/null
+++ b/libcli/security/conditional_ace.c
@@ -0,0 +1,2550 @@
+/*
+ * Unix SMB implementation.
+ * Functions for understanding conditional ACEs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 "librpc/gen_ndr/ndr_conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+#include "lib/util/tsort.h"
+#include "lib/util/debug.h"
+#include "lib/util/bytearray.h"
+#include "lib/util/talloc_stack.h"
+#include "util/discard.h"
+#include "lib/util/stable_sort.h"
+/*
+ * Conditional ACE logic truth tables.
+ *
+ * Conditional ACES use a ternary logic, with "unknown" as well as true and
+ * false. The ultimate meaning of unknown depends on the context; in a deny
+ * ace, unknown means yes, in an allow ace, unknown means no. That is, we
+ * treat unknown results with maximum suspicion.
+ *
+ * AND true false unknown
+ * true T F ?
+ * false F F F
+ * unknown ? F ?
+ *
+ * OR true false unknown
+ * true T T T
+ * false T F ?
+ * unknown T ? ?
+ *
+ * NOT
+ * true F
+ * false T
+ * unknown ?
+ *
+ * This can be summed up by saying unknown values taint the result except in
+ * the cases where short circuit evaluation could apply (true OR anything,
+ * false AND anything, which hold their value).
+ *
+ * What counts as unknown
+ *
+ * - NULL attributes.
+ * - certain comparisons between incompatible types
+ *
+ * What counts as false
+ *
+ * - zero
+ * - empty strings
+ *
+ * An error means the entire expression is unknown.
+ */
+
+
+static bool check_integer_range(const struct ace_condition_token *tok)
+{
+ int64_t val = tok->data.int64.value;
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ if (val < -128 || val > 127) {
+ return false;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ if (val < INT16_MIN || val > INT16_MAX) {
+ return false;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ if (val < INT32_MIN || val > INT32_MAX) {
+ return false;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ /* val has these limits naturally */
+ break;
+ default:
+ return false;
+ }
+
+ if (tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_8 &&
+ tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_10 &&
+ tok->data.int64.base != CONDITIONAL_ACE_INT_BASE_16) {
+ return false;
+ }
+ if (tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_POSITIVE &&
+ tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NEGATIVE &&
+ tok->data.int64.sign != CONDITIONAL_ACE_INT_SIGN_NONE) {
+ return false;
+ }
+ return true;
+}
+
+
+static ssize_t pull_integer(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ struct ace_condition_int *tok)
+{
+ ssize_t bytes_used;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v = data_blob_const(data, length);
+ struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
+ if (ndr == NULL) {
+ return -1;
+ }
+ ndr_err = ndr_pull_ace_condition_int(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(ndr);
+ return -1;
+ }
+ bytes_used = ndr->offset;
+ TALLOC_FREE(ndr);
+ return bytes_used;
+}
+
+static ssize_t push_integer(uint8_t *data, size_t available,
+ const struct ace_condition_int *tok)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v;
+ ndr_err = ndr_push_struct_blob(&v, NULL,
+ tok,
+ (ndr_push_flags_fn_t)ndr_push_ace_condition_int);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ if (available < v.length) {
+ talloc_free(v.data);
+ return -1;
+ }
+ memcpy(data, v.data, v.length);
+ talloc_free(v.data);
+ return v.length;
+}
+
+
+static ssize_t pull_unicode(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ struct ace_condition_unicode *tok)
+{
+ ssize_t bytes_used;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v = data_blob_const(data, length);
+ struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
+ if (ndr == NULL) {
+ return -1;
+ }
+ ndr_err = ndr_pull_ace_condition_unicode(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(ndr);
+ return -1;
+ }
+ bytes_used = ndr->offset;
+ TALLOC_FREE(ndr);
+ return bytes_used;
+}
+
+static ssize_t push_unicode(uint8_t *data, size_t available,
+ const struct ace_condition_unicode *tok)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v;
+ ndr_err = ndr_push_struct_blob(&v, NULL,
+ tok,
+ (ndr_push_flags_fn_t)ndr_push_ace_condition_unicode);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ if (available < v.length) {
+ talloc_free(v.data);
+ return -1;
+ }
+ memcpy(data, v.data, v.length);
+ talloc_free(v.data);
+ return v.length;
+}
+
+
+static ssize_t pull_bytes(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ DATA_BLOB *tok)
+{
+ ssize_t bytes_used;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v = data_blob_const(data, length);
+ struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
+ if (ndr == NULL) {
+ return -1;
+ }
+ ndr_err = ndr_pull_DATA_BLOB(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(ndr);
+ return -1;
+ }
+ bytes_used = ndr->offset;
+ talloc_free(ndr);
+ return bytes_used;
+}
+
+static ssize_t push_bytes(uint8_t *data, size_t available,
+ const DATA_BLOB *tok)
+{
+ size_t offset;
+ enum ndr_err_code ndr_err;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct ndr_push *ndr = ndr_push_init_ctx(frame);
+ if (ndr == NULL) {
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ ndr_err = ndr_push_DATA_BLOB(ndr, NDR_SCALARS|NDR_BUFFERS, *tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return -1;
+ }
+
+ if (available < ndr->offset) {
+ TALLOC_FREE(frame);
+ return -1;
+ }
+ memcpy(data, ndr->data, ndr->offset);
+ offset = ndr->offset;
+ TALLOC_FREE(frame);
+ return offset;
+}
+
+static ssize_t pull_sid(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ struct ace_condition_sid *tok)
+{
+ ssize_t bytes_used;
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v = data_blob_const(data, length);
+ struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
+ if (ndr == NULL) {
+ return -1;
+ }
+ ndr->flags |= LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES;
+
+ ndr_err = ndr_pull_ace_condition_sid(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(ndr);
+ return -1;
+ }
+ bytes_used = ndr->offset;
+ TALLOC_FREE(ndr);
+ return bytes_used;
+}
+
+static ssize_t push_sid(uint8_t *data, size_t available,
+ const struct ace_condition_sid *tok)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB v;
+ ndr_err = ndr_push_struct_blob(&v, NULL,
+ tok,
+ (ndr_push_flags_fn_t)ndr_push_ace_condition_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ if (available < v.length) {
+ talloc_free(v.data);
+ return -1;
+ }
+ memcpy(data, v.data, v.length);
+ talloc_free(v.data);
+ return v.length;
+}
+
+
+static ssize_t pull_composite(TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ struct ace_condition_composite *tok)
+{
+ size_t i, j;
+ size_t alloc_length;
+ size_t byte_size;
+ struct ace_condition_token *tokens = NULL;
+ if (length < 4) {
+ return -1;
+ }
+ byte_size = PULL_LE_U32(data, 0);
+ if (byte_size > length - 4) {
+ return -1;
+ }
+ /*
+ * There is a list of other literal tokens (possibly including nested
+ * composites), which we will store in an array.
+ *
+ * This array can *only* be literals.
+ */
+ alloc_length = byte_size;
+ tokens = talloc_array(mem_ctx,
+ struct ace_condition_token,
+ alloc_length);
+ if (tokens == NULL) {
+ return -1;
+ }
+ byte_size += 4;
+ i = 4;
+ j = 0;
+ while (i < byte_size) {
+ struct ace_condition_token *el = &tokens[j];
+ ssize_t consumed;
+ uint8_t *el_data = NULL;
+ size_t available;
+ bool ok;
+ *el = (struct ace_condition_token) { .type = data[i] };
+ i++;
+
+ el_data = data + i;
+ available = byte_size - i;
+
+ switch (el->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ consumed = pull_integer(mem_ctx,
+ el_data,
+ available,
+ &el->data.int64);
+ ok = check_integer_range(el);
+ if (! ok) {
+ goto error;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ consumed = pull_unicode(mem_ctx,
+ el_data,
+ available,
+ &el->data.unicode);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ consumed = pull_bytes(mem_ctx,
+ el_data,
+ available,
+ &el->data.bytes);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ consumed = pull_sid(mem_ctx,
+ el_data,
+ available,
+ &el->data.sid);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ DBG_ERR("recursive composite tokens in conditional "
+ "ACEs are not currently supported\n");
+ goto error;
+ default:
+ goto error;
+ }
+
+ if (consumed < 0 || consumed + i > length) {
+ goto error;
+ }
+ i += consumed;
+ j++;
+ if (j == UINT16_MAX) {
+ talloc_free(tokens);
+ return -1;
+ }
+ if (j == alloc_length) {
+ struct ace_condition_token *new_tokens = NULL;
+
+ alloc_length += 5;
+ new_tokens = talloc_realloc(mem_ctx,
+ tokens,
+ struct ace_condition_token,
+ alloc_length);
+
+ if (new_tokens == NULL) {
+ goto error;
+ }
+ tokens = new_tokens;
+ }
+ }
+ tok->n_members = j;
+ tok->tokens = tokens;
+ return byte_size;
+error:
+ talloc_free(tokens);
+ return -1;
+}
+
+
+static ssize_t push_composite(uint8_t *data, size_t length,
+ const struct ace_condition_composite *tok)
+{
+ size_t i;
+ uint8_t *byte_length_ptr;
+ size_t used = 0;
+ if (length < 4) {
+ return -1;
+ }
+ /*
+ * We have no idea what the eventual length will be, so we keep a
+ * pointer to write it in at the end.
+ */
+ byte_length_ptr = data;
+ PUSH_LE_U32(data, 0, 0);
+ used = 4;
+
+ for (i = 0; i < tok->n_members && used < length; i++) {
+ struct ace_condition_token *el = &tok->tokens[i];
+ ssize_t consumed;
+ uint8_t *el_data = NULL;
+ size_t available;
+ bool ok;
+ data[used] = el->type;
+ used++;
+ if (used == length) {
+ /*
+ * used == length is not expected here; the token
+ * types that only have an opcode and no data are not
+ * literals that can be in composites.
+ */
+ return -1;
+ }
+ el_data = data + used;
+ available = length - used;
+
+ switch (el->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ ok = check_integer_range(el);
+ if (! ok) {
+ return -1;
+ }
+ consumed = push_integer(el_data,
+ available,
+ &el->data.int64);
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ consumed = push_unicode(el_data,
+ available,
+ &el->data.unicode);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ consumed = push_bytes(el_data,
+ available,
+ &el->data.bytes);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ consumed = push_sid(el_data,
+ available,
+ &el->data.sid);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ consumed = push_composite(el_data,
+ available,
+ &el->data.composite);
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (consumed < 0) {
+ return -1;
+ }
+ used += consumed;
+ }
+ if (used > length) {
+ return -1;
+ }
+
+ PUSH_LE_U32(byte_length_ptr, 0, used - 4);
+ return used;
+}
+
+static ssize_t pull_end_padding(uint8_t *data, size_t length)
+{
+ /*
+ * We just check that we have the right kind of number of zero
+ * bytes. The blob must end on a multiple of 4. One zero byte
+ * has already been swallowed as tok->type, which sends us
+ * here, so we expect 1 or two more -- total padding is 0, 1,
+ * 2, or 3.
+ *
+ * zero is also called CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING.
+ */
+ ssize_t i;
+ if (length > 2) {
+ return -1;
+ }
+ for (i = 0; i < length; i++) {
+ if (data[i] != 0) {
+ return -1;
+ }
+ }
+ return length;
+}
+
+
+struct ace_condition_script *parse_conditional_ace(TALLOC_CTX *mem_ctx,
+ DATA_BLOB data)
+{
+ size_t i, j;
+ struct ace_condition_token *tokens = NULL;
+ size_t alloc_length;
+ struct ace_condition_script *program = NULL;
+
+ if (data.length < 4 ||
+ data.data[0] != 'a' ||
+ data.data[1] != 'r' ||
+ data.data[2] != 't' ||
+ data.data[3] != 'x') {
+ /*
+ * lacks the "artx" conditional ace identifier magic.
+ * NULL returns will deny access.
+ */
+ return NULL;
+ }
+ if (data.length > CONDITIONAL_ACE_MAX_LENGTH ||
+ (data.length & 3) != 0) {
+ /*
+ * >= 64k or non-multiples of 4 are not possible in the ACE
+ * wire format.
+ */
+ return NULL;
+ }
+
+ program = talloc(mem_ctx, struct ace_condition_script);
+ if (program == NULL) {
+ return NULL;
+ }
+
+ /*
+ * We will normally end up with fewer than data.length tokens, as
+ * values are stored in multiple bytes (all integers are 10 bytes,
+ * strings and attributes are utf16 + length, SIDs are SID-size +
+ * length, etc). But operators are one byte, so something like
+ * !(!(!(!(!(!(x)))))) -- where each '!(..)' is one byte -- will bring
+ * the number of tokens close to the number of bytes.
+ *
+ * This is all to say we're guessing a token length that hopes to
+ * avoid reallocs without wasting too much up front.
+ */
+ alloc_length = data.length / 2 + 1;
+ tokens = talloc_array(program,
+ struct ace_condition_token,
+ alloc_length);
+ if (tokens == NULL) {
+ TALLOC_FREE(program);
+ return NULL;
+ }
+
+ i = 4;
+ j = 0;
+ while(i < data.length) {
+ struct ace_condition_token *tok = &tokens[j];
+ ssize_t consumed = 0;
+ uint8_t *tok_data = NULL;
+ size_t available;
+ bool ok;
+ tok->type = data.data[i];
+ tok->flags = 0;
+ i++;
+ tok_data = data.data + i;
+ available = data.length - i;
+
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ consumed = pull_integer(program,
+ tok_data,
+ available,
+ &tok->data.int64);
+ ok = check_integer_range(tok);
+ if (! ok) {
+ goto fail;
+ }
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ /*
+ * The next four are pulled as unicode, but are
+ * processed as user attribute look-ups.
+ */
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ consumed = pull_unicode(program,
+ tok_data,
+ available,
+ &tok->data.unicode);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ consumed = pull_bytes(program,
+ tok_data,
+ available,
+ &tok->data.bytes);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ consumed = pull_sid(program,
+ tok_data,
+ available,
+ &tok->data.sid);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ consumed = pull_composite(program,
+ tok_data,
+ available,
+ &tok->data.composite);
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ /*
+ * these require a SID or composite SID list operand,
+ * and we could check that now in most cases.
+ */
+ break;
+ /* binary relational operators */
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ /* unary logical operators */
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ /* binary logical operators */
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ break;
+ case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
+ /* this is only valid at the end */
+ consumed = pull_end_padding(tok_data,
+ available);
+ j--; /* don't add this token */
+ break;
+ default:
+ goto fail;
+ }
+
+ if (consumed < 0) {
+ goto fail;
+ }
+ if (consumed + i < i || consumed + i > data.length) {
+ goto fail;
+ }
+ i += consumed;
+ j++;
+ if (j == alloc_length) {
+ alloc_length *= 2;
+ tokens = talloc_realloc(program,
+ tokens,
+ struct ace_condition_token,
+ alloc_length);
+ if (tokens == NULL) {
+ goto fail;
+ }
+ }
+ }
+ program->length = j;
+ program->tokens = talloc_realloc(program,
+ tokens,
+ struct ace_condition_token,
+ program->length + 1);
+ if (program->tokens == NULL) {
+ goto fail;
+ }
+ /*
+ * When interpreting the program we will need a stack, which in the
+ * very worst case can be as deep as the program is long.
+ */
+ program->stack = talloc_array(program,
+ struct ace_condition_token,
+ program->length + 1);
+ if (program->stack == NULL) {
+ goto fail;
+ }
+
+ return program;
+ fail:
+ talloc_free(program);
+ return NULL;
+ }
+
+
+static bool claim_lookup_internal(
+ TALLOC_CTX *mem_ctx,
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim,
+ struct ace_condition_token *result)
+{
+ bool ok = claim_v1_to_ace_token(mem_ctx, claim, result);
+ return ok;
+}
+
+
+static bool resource_claim_lookup(
+ TALLOC_CTX *mem_ctx,
+ const struct ace_condition_token *op,
+ const struct security_descriptor *sd,
+ struct ace_condition_token *result)
+{
+ /*
+ * For a @Resource.attr, the claims come from a resource ACE
+ * in the object's SACL. That's why we need a security descriptor.
+ *
+ * If there is no matching resource ACE, a NULL result is returned,
+ * which should compare UNKNOWN to anything. The NULL will have the
+ * CONDITIONAL_ACE_FLAG_NULL_MEANS_ERROR flag set if it seems failure
+ * is not simply due to the sought claim not existing. This is useful for
+ * the Exists and Not_Exists operators.
+ */
+ size_t i;
+ struct ace_condition_unicode name;
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL;
+
+ if (op->type != CONDITIONAL_ACE_RESOURCE_ATTRIBUTE) {
+ /* what are we even doing here? */
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
+ return false;
+ }
+
+ name = op->data.resource_attr;
+
+ if (sd->sacl == NULL) {
+ DBG_NOTICE("Resource attribute ACE '%s' not found, "
+ "because there is no SACL\n",
+ name.value);
+ return true;
+ }
+
+ for (i = 0; i < sd->sacl->num_aces; i++) {
+ struct security_ace *ace = &sd->sacl->aces[i];
+ bool ok;
+
+ if (ace->type != SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) {
+ continue;
+ }
+ if (strcasecmp_m(name.value,
+ ace->coda.claim.name) != 0) {
+ continue;
+ }
+ /* this is the one */
+ ok = claim_lookup_internal(mem_ctx, &ace->coda.claim, result);
+ if (ok) {
+ return true;
+ }
+ }
+ DBG_NOTICE("Resource attribute ACE '%s' not found.\n",
+ name.value);
+ return false;
+}
+
+
+static bool token_claim_lookup(
+ TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ struct ace_condition_token *result)
+{
+ /*
+ * The operator has an attribute name; if there is a claim of
+ * the right type with that name, that is returned as the result.
+ *
+ * XXX what happens otherwise? NULL result?
+ */
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claims = NULL;
+ size_t num_claims;
+ bool ok;
+ const struct ace_condition_unicode *name = NULL;
+ size_t i;
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_NULL;
+
+ switch (op->type) {
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ claims = token->local_claims;
+ num_claims = token->num_local_claims;
+ name = &op->data.local_attr;
+ break;
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ claims = token->user_claims;
+ num_claims = token->num_user_claims;
+ name = &op->data.user_attr;
+ break;
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ claims = token->device_claims;
+ num_claims = token->num_device_claims;
+ name = &op->data.device_attr;
+ break;
+ default:
+ DBG_WARNING("Conditional ACE claim lookup got bad arg type %u\n",
+ op->type);
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
+ return false;
+ }
+
+ if (num_claims == 0) {
+ DBG_NOTICE("There are no type %u claims\n", op->type);
+ return false;
+ }
+ if (claims == NULL) {
+ DBG_ERR("Type %u claim list unexpectedly NULL!\n", op->type);
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR;
+ return false;
+ }
+ /*
+ * Loop backwards: a later claim will override an earlier one with the
+ * same name.
+ */
+ for (i = num_claims - 1; i < num_claims; i--) {
+ if (claims[i].name == NULL) {
+ DBG_ERR("claim %zu has no name!\n", i);
+ continue;
+ }
+ if (strcasecmp_m(claims[i].name, name->value) == 0) {
+ /* this is the one */
+ ok = claim_lookup_internal(mem_ctx, &claims[i], result);
+ return ok;
+ }
+ }
+ DBG_NOTICE("Claim not found\n");
+ return false;
+}
+
+
+
+
+static bool member_lookup(
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ const struct ace_condition_token *arg,
+ struct ace_condition_token *result)
+{
+ /*
+ * We need to compare the lists of SIDs in the token with the
+ * SID[s] in the argument. There are 8 combinations of
+ * operation, depending on whether we want to match all or any
+ * of the SIDs, whether we're using the device SIDs or user
+ * SIDs, and whether the operator name starts with "Not_".
+ *
+ * _MEMBER_OF User has all operand SIDs
+ * _DEVICE_MEMBER_OF Device has all operand SIDs
+ * _MEMBER_OF_ANY User has one or more operand SIDs
+ * _DEVICE_MEMBER_OF_ANY Device has one or more operand SIDs
+ *
+ * NOT_* has the effect of !(the operator without NOT_).
+ *
+ * The operand can either be a composite of SIDs or a single SID.
+ * This adds an additional branch.
+ */
+ bool match = false;
+ bool it_is_a_not_op;
+ bool it_is_an_any_op;
+ bool it_is_a_device_op;
+ bool arg_is_a_single_sid;
+ struct dom_sid *sid_array = NULL;
+ size_t num_sids, i, j;
+ const struct dom_sid *sid = NULL;
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ switch (arg->type) {
+ case CONDITIONAL_ACE_TOKEN_SID:
+ arg_is_a_single_sid = true;
+ break;
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ arg_is_a_single_sid = false;
+ break;
+ default:
+ DBG_WARNING("Conditional ACE Member_Of got bad arg type %u\n",
+ arg->type);
+ return false;
+ }
+
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ it_is_a_not_op = true;
+ it_is_a_device_op = false;
+ break;
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ it_is_a_not_op = true;
+ it_is_a_device_op = true;
+ break;
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ it_is_a_not_op = false;
+ it_is_a_device_op = false;
+ break;
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ it_is_a_not_op = false;
+ it_is_a_device_op = true;
+ break;
+ default:
+ DBG_WARNING("Conditional ACE Member_Of got bad op type %u\n",
+ op->type);
+ return false;
+ }
+
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ it_is_an_any_op = true;
+ break;
+ default:
+ it_is_an_any_op = false;
+ }
+
+ if (it_is_a_device_op) {
+ sid_array = token->device_sids;
+ num_sids = token->num_device_sids;
+ } else {
+ sid_array = token->sids;
+ num_sids = token->num_sids;
+ }
+
+ if (arg_is_a_single_sid) {
+ /*
+ * In this case the any and all operations are the
+ * same.
+ */
+ sid = &arg->data.sid.sid;
+ match = false;
+ for (i = 0; i < num_sids; i++) {
+ match = dom_sid_equal(sid, &sid_array[i]);
+ if (match) {
+ break;
+ }
+ }
+ if (it_is_a_not_op) {
+ match = ! match;
+ }
+ if (match) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ } else {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ }
+ return true;
+ }
+
+ /* This is a composite list (hopefully of SIDs) */
+ if (arg->data.composite.n_members == 0) {
+ DBG_WARNING("Conditional ACE Member_Of argument is empty\n");
+ return false;
+ }
+
+ for (j = 0; j < arg->data.composite.n_members; j++) {
+ const struct ace_condition_token *member =
+ &arg->data.composite.tokens[j];
+ if (member->type != CONDITIONAL_ACE_TOKEN_SID) {
+ DBG_WARNING("Conditional ACE Member_Of argument contains "
+ "non-sid element [%zu]: %u\n",
+ j, member->type);
+ return false;
+ }
+ sid = &member->data.sid.sid;
+ match = false;
+ for (i = 0; i < num_sids; i++) {
+ match = dom_sid_equal(sid, &sid_array[i]);
+ if (match) {
+ break;
+ }
+ }
+ if (it_is_an_any_op) {
+ if (match) {
+ /* we have matched one SID, which is enough */
+ goto apply_not;
+ }
+ } else { /* an all op */
+ if (! match) {
+ /* failing one is enough */
+ goto apply_not;
+ }
+ }
+ }
+ /*
+ * Reaching the end of that loop means either:
+ * 1. it was an ALL op and we never failed to find one, or
+ * 2. it was an ANY op, and we didn't find one.
+ */
+ match = !it_is_an_any_op;
+
+ apply_not:
+ if (it_is_a_not_op) {
+ match = ! match;
+ }
+ if (match) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ } else {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ }
+
+ return true;
+}
+
+
+static bool ternary_value(
+ const struct ace_condition_token *arg,
+ struct ace_condition_token *result)
+{
+ /*
+ * Find the truth value of the argument, stored in the result token.
+ *
+ * A return value of false means the operation is invalid, and the
+ * result is undefined.
+ */
+ if (arg->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
+ /* pass through */
+ *result = *arg;
+ return true;
+ }
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ if (IS_INT_TOKEN(arg)) {
+ /* zero is false */
+ if (arg->data.int64.value == 0) {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ } else {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ }
+ return true;
+ }
+ if (arg->type == CONDITIONAL_ACE_TOKEN_UNICODE) {
+ /* empty is false */
+ if (arg->data.unicode.value[0] == '\0') {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ } else {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ }
+ return true;
+ }
+
+ /*
+ * everything else in UNKNOWN. This includes NULL values (i.e. an
+ * unsuccessful look-up).
+ */
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+ return true;
+}
+
+static bool not_operator(
+ const struct ace_condition_token *arg,
+ struct ace_condition_token *result)
+{
+ bool ok;
+ if (IS_LITERAL_TOKEN(arg)) {
+ /*
+ * Logic operators don't work on literals.
+ */
+ return false;
+ }
+
+ ok = ternary_value(arg, result);
+ if (! ok) {
+ return false;
+ }
+ if (result->data.result.value == ACE_CONDITION_FALSE) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ } else if (result->data.result.value == ACE_CONDITION_TRUE) {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ }
+ /* unknown stays unknown */
+ return true;
+}
+
+
+static bool unary_logic_operator(
+ TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ const struct ace_condition_token *arg,
+ const struct security_descriptor *sd,
+ struct ace_condition_token *result)
+{
+
+ bool ok;
+ bool found;
+ struct ace_condition_token claim = {
+ .type = CONDITIONAL_ACE_SAMBA_RESULT_ERROR
+ };
+ if (op->type == CONDITIONAL_ACE_TOKEN_NOT) {
+ return not_operator(arg, result);
+ }
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ /*
+ * Not_Exists and Exists require the same work, except we negate the
+ * answer in one case. From [MS-DTYP] 2.4.4.17.7:
+ *
+ * If the type of the operand is "Local Attribute"
+ * If the value is non-null return TRUE
+ * Else return FALSE
+ * Else if the type of the operand is "Resource Attribute"
+ * Return TRUE if value is non-null; FALSE otherwise.
+ * Else return Error
+ */
+ switch (op->type) {
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ ok = token_claim_lookup(mem_ctx, token, arg, &claim);
+ /*
+ * "not ok" usually means a failure to find the attribute,
+ * which is the false condition and not an error.
+ *
+ * XXX or do we need an extra flag?
+ */
+ break;
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ ok = resource_claim_lookup(mem_ctx, arg, sd, &claim);
+ break;
+ default:
+ return false;
+ }
+
+ /*
+ *
+ */
+
+ if (claim.type != CONDITIONAL_ACE_SAMBA_RESULT_NULL) {
+ found = true;
+ } else if (ok) {
+ found = false;
+ } else {
+ return false;
+ }
+
+
+
+ if (op->type == CONDITIONAL_ACE_TOKEN_NOT_EXISTS) {
+ found = ! found;
+ } else if (op->type != CONDITIONAL_ACE_TOKEN_EXISTS) {
+ /* should not get here */
+ return false;
+ }
+
+ result->data.result.value = found ? ACE_CONDITION_TRUE: ACE_CONDITION_FALSE;
+ return true;
+}
+
+
+
+static bool binary_logic_operator(
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ struct ace_condition_token *result)
+{
+ struct ace_condition_token at, bt;
+ int a, b;
+ bool ok;
+
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ if (IS_LITERAL_TOKEN(lhs) || IS_LITERAL_TOKEN(rhs)) {
+ /*
+ * Logic operators don't work on literals.
+ */
+ return false;
+ }
+
+ ok = ternary_value(lhs, &at);
+ if (! ok) {
+ return false;
+ }
+ ok = ternary_value(rhs, &bt);
+ if (! ok) {
+ return false;
+ }
+ a = at.data.result.value;
+ b = bt.data.result.value;
+
+ if (op->type == CONDITIONAL_ACE_TOKEN_AND) {
+ /*
+ * AND true false unknown
+ * true T F ?
+ * false F F F
+ * unknown ? F ?
+ *
+ * unknown unless BOTH true or EITHER false
+ */
+ if (a == ACE_CONDITION_TRUE &&
+ b == ACE_CONDITION_TRUE) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ return true;
+ }
+ if (a == ACE_CONDITION_FALSE ||
+ b == ACE_CONDITION_FALSE) {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ return true;
+ }
+ /*
+ * Neither value is False, so the result is Unknown,
+ * as set at the start of this function.
+ */
+ return true;
+ }
+ /*
+ * OR true false unknown
+ * true T T T
+ * false T F ?
+ * unknown T ? ?
+ *
+ * unknown unless EITHER true or BOTH false
+ */
+ if (a == ACE_CONDITION_TRUE ||
+ b == ACE_CONDITION_TRUE) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ return true;
+ }
+ if (a == ACE_CONDITION_FALSE &&
+ b == ACE_CONDITION_FALSE) {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ return true;
+ }
+ return true;
+}
+
+
+static bool tokens_are_comparable(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs)
+{
+ uint64_t n;
+ /*
+ * we can't compare different types *unless* they are both
+ * integers, or one is a bool and the other is an integer 0 or
+ * 1, and the operator is == or != (or NULL, which for convenience,
+ * is treated as ==).
+ */
+ //XXX actually it says "literal integers", do we need to check flags?
+ if (lhs->type == rhs->type) {
+ return true;
+ }
+
+ if (IS_INT_TOKEN(lhs) && IS_INT_TOKEN(rhs)) {
+ /* don't block e.g. comparing an int32 to an int64 */
+ return true;
+ }
+
+ /* is it == or != */
+ if (op != NULL &&
+ op->type != CONDITIONAL_ACE_TOKEN_EQUAL &&
+ op->type != CONDITIONAL_ACE_TOKEN_NOT_EQUAL) {
+ return false;
+ }
+ /* is one a bool and the other an int? */
+ if (IS_INT_TOKEN(lhs) && IS_BOOL_TOKEN(rhs)) {
+ n = lhs->data.int64.value;
+ } else if (IS_INT_TOKEN(rhs) && IS_BOOL_TOKEN(lhs)) {
+ n = rhs->data.int64.value;
+ } else {
+ return false;
+ }
+ if (n == 0 || n == 1) {
+ return true;
+ }
+ return false;
+}
+
+
+static bool cmp_to_result(const struct ace_condition_token *op,
+ struct ace_condition_token *result,
+ int cmp)
+{
+ bool answer;
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ answer = cmp == 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ answer = cmp != 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ answer = cmp < 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ answer = cmp <= 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ answer = cmp > 0;
+ break;
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ answer = cmp >= 0;
+ break;
+ default:
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+ return false;
+ }
+ result->data.result.value = \
+ answer ? ACE_CONDITION_TRUE : ACE_CONDITION_FALSE;
+ return true;
+}
+
+
+
+static bool compare_unicode(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ struct ace_condition_unicode a = lhs->data.unicode;
+ struct ace_condition_unicode b = rhs->data.unicode;
+ /*
+ * Comparison is case-insensitive UNLESS the claim structure
+ * has the case-sensitive flag, which is passed through as a
+ * flag on the token. Usually only the LHS is a claim value,
+ * but in the event that they both are, we allow either to
+ * request case-sensitivity.
+ *
+ * For greater than and less than, the sort order is utf-8 order,
+ * which is not exactly what Windows does, but we don't sort like
+ * Windows does anywhere else either.
+ */
+ uint8_t flags = lhs->flags | rhs->flags;
+ if (flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE) {
+ *cmp = strcmp(a.value, b.value);
+ } else {
+ *cmp = strcasecmp_m(a.value, b.value);
+ }
+ return true;
+}
+
+
+static bool compare_bytes(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ DATA_BLOB a = lhs->data.bytes;
+ DATA_BLOB b = rhs->data.bytes;
+ *cmp = data_blob_cmp(&a, &b);
+ return true;
+}
+
+
+static bool compare_sids(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ *cmp = dom_sid_compare(&lhs->data.sid.sid,
+ &rhs->data.sid.sid);
+ return true;
+}
+
+
+static bool compare_ints(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ int64_t a = lhs->data.int64.value;
+ int64_t b = rhs->data.int64.value;
+
+ if (a < b) {
+ *cmp = -1;
+ } else if (a == b) {
+ *cmp = 0;
+ } else {
+ *cmp = 1;
+ }
+ return true;
+}
+
+
+static bool compare_bools(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ bool ok;
+ struct ace_condition_token a, b;
+ *cmp = -1;
+
+ if (IS_LITERAL_TOKEN(lhs)) {
+ /*
+ * we can compare a boolean LHS to a literal RHS, but not
+ * vice versa
+ */
+ return false;
+ }
+ ok = ternary_value(lhs, &a);
+ if (! ok) {
+ return false;
+ }
+ ok = ternary_value(rhs, &b);
+ if (! ok) {
+ return false;
+ }
+ if (a.data.result.value == ACE_CONDITION_UNKNOWN ||
+ b.data.result.value == ACE_CONDITION_UNKNOWN) {
+ return false;
+ }
+
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ *cmp = a.data.result.value - b.data.result.value;
+ break;
+ default:
+ /* we are not allowing non-equality comparisons with bools */
+ return false;
+ }
+ return true;
+}
+
+
+static bool simple_relational_operator(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp);
+
+
+struct composite_sort_context {
+ bool failed;
+};
+
+static int composite_sort_cmp(const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ struct composite_sort_context *ctx)
+{
+ bool ok;
+ int cmp = -1;
+ /*
+ * simple_relational_operator uses the operator token only to
+ * decide whether the comparison is allowed for the type. In
+ * particular, boolean result and composite arguments can only
+ * be used with equality operators. We want those to fail (we
+ * should not see them here, remembering that claim booleans
+ * become composite integers), so we use a non-equality op.
+ */
+ static const struct ace_condition_token op = {
+ .type = CONDITIONAL_ACE_TOKEN_LESS_THAN
+ };
+
+ ok = simple_relational_operator(&op, lhs, rhs, &cmp);
+ if (ok) {
+ return cmp;
+ }
+ /*
+ * This sort isn't going to work out, but the sort function
+ * will only find out at the end.
+ */
+ ctx->failed = true;
+ return cmp;
+}
+
+
+/*
+ * Return a sorted copy of the composite tokens array.
+ *
+ * The copy is shallow, so the actual string pointers are the same, which is
+ * fine for the purposes of comparison.
+ */
+
+static struct ace_condition_token *composite_sorted_copy(
+ TALLOC_CTX *mem_ctx,
+ const struct ace_condition_composite *c,
+ bool case_sensitive)
+{
+ struct ace_condition_token *copy = NULL;
+ bool ok;
+ size_t i;
+ struct composite_sort_context sort_ctx = {
+ .failed = false
+ };
+
+ /*
+ * Case sensitivity is a bit tricky. Each token can have a flag saying
+ * it should be sorted case-sensitively and when comparing two tokens,
+ * we should respect this flag on either side. The flag can only come
+ * from claims (including resource attribute ACEs), and as there is only
+ * one flag per claim, it must apply the same to all members (in fact we
+ * don't set it on the members, only the composite). So to be sure we
+ * sort in the way we want, we might need to set the flag on all the
+ * members of the copy *before* sorting it.
+ *
+ * When it comes to comparing two composites, we want to be
+ * case-sensitive if either side has the flag. This can have odd
+ * effects. Think of these RA claims:
+ *
+ * (RA;;;;;WD;("foo",TS,0,"a","A"))
+ * (RA;;;;;WD;("bar",TS,2,"a","A")) <-- 2 is the case-sensitive flag
+ * (RA;;;;;WD;("baz",TS,0,"a"))
+ *
+ * (@Resource.foo == @Resource.bar) is true
+ * (@Resource.bar == @Resource.foo) is true
+ * (@Resource.bar == @Resource.bar) is true
+ * (@Resource.foo == @Resource.foo) is an error (duplicate values on LHS)
+ * (@Resource.baz == @Resource.foo) is true (RHS case-folds down)
+ * (@Resource.baz == @Resource.bar) is false
+ * (@Resource.bar == {"A", "a"}) is true
+ * (@Resource.baz == {"A", "a"}) is true
+ * (@Resource.foo == {"A", "a"}) is an error
+ */
+ copy = talloc_array(mem_ctx, struct ace_condition_token, c->n_members);
+ if (copy == NULL) {
+ return NULL;
+ }
+ memcpy(copy, c->tokens, sizeof(struct ace_condition_token) * c->n_members);
+
+ if (case_sensitive) {
+ for (i = 0; i < c->n_members; i++) {
+ c->tokens[i].flags |= CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ }
+ }
+
+ ok = stable_sort_talloc_r(mem_ctx,
+ copy,
+ c->n_members,
+ sizeof(struct ace_condition_token),
+ (samba_compare_with_context_fn_t)composite_sort_cmp,
+ &sort_ctx);
+
+ if (!ok || sort_ctx.failed) {
+ DBG_NOTICE("composite sort of %"PRIu32" members failed\n",
+ c->n_members);
+ TALLOC_FREE(copy);
+ return NULL;
+ }
+ return copy;
+}
+
+
+/*
+ * This is a helper for compare composites.
+ */
+static bool compare_composites_via_sort(const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ const struct ace_condition_composite *lc = &lhs->data.composite;
+ const struct ace_condition_composite *rc = &rhs->data.composite;
+ size_t i;
+ TALLOC_CTX *tmp_ctx = NULL;
+ bool ok;
+ int cmp_pair;
+ bool case_sensitive, rhs_case_sensitive;
+ bool rhs_sorted;
+ struct ace_condition_token *ltok = lc->tokens;
+ struct ace_condition_token *rtok = rc->tokens;
+ static const struct ace_condition_token eq = {
+ .type = CONDITIONAL_ACE_TOKEN_EQUAL
+ };
+ *cmp = -1;
+ if (lc->n_members == 0 ||
+ rc->n_members < lc->n_members) {
+ /* we should not have got this far */
+ return false;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return false;
+ }
+
+ case_sensitive = lhs->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ rhs_case_sensitive = rhs->flags & CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ rhs_sorted = rhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED;
+
+ if (lc->tokens[0].type != CONDITIONAL_ACE_TOKEN_UNICODE) {
+ /*
+ * All LHS tokens are the same type (because it is a
+ * claim), and that type is not one that cares about
+ * case, so nor do we.
+ */
+ case_sensitive = false;
+ } else if (case_sensitive == rhs_case_sensitive) {
+ /* phew, no extra work */
+ } else if (case_sensitive) {
+ /* trigger a sorted copy */
+ rhs_sorted = false;
+ } else if (rhs_case_sensitive) {
+ /*
+ * Do we need to rescan for uniqueness, given the new
+ * comparison function? No! The strings were already
+ * unique in the looser comparison, and now they can
+ * only be more so. The number of unique values can't
+ * change, just their order.
+ */
+ case_sensitive = true;
+ ltok = composite_sorted_copy(tmp_ctx, lc, case_sensitive);
+ if (ltok == NULL) {
+ DBG_WARNING("sort of LHS failed\n");
+ goto error;
+ }
+ }
+
+ if (! rhs_sorted) {
+ /*
+ * we need an RHS sorted copy (it's a literal, or
+ * there was a case sensitivity disagreement).
+ */
+ rtok = composite_sorted_copy(tmp_ctx, rc, case_sensitive);
+ if (rtok == NULL) {
+ DBG_WARNING("sort of RHS failed\n");
+ goto error;
+ }
+ }
+ /*
+ * Each member of LHS must match one or more members of RHS.
+ * Each member of RHS must match at least one of LHS.
+ *
+ * If they are the same length we can compare directly, so let's get
+ * rid of duplicates in RHS. This can only happen with literal
+ * composites.
+ */
+ if (rc->n_members > lc->n_members) {
+ size_t gap = 0;
+ for (i = 1; i < rc->n_members; i++) {
+ ok = simple_relational_operator(&eq,
+ &rtok[i - 1],
+ &rtok[i],
+ &cmp_pair);
+ if (! ok) {
+ goto error;
+ }
+ if (cmp_pair == 0) {
+ gap++;
+ }
+ if (gap != 0) {
+ rtok[i - gap] = rtok[i];
+ }
+ }
+ if (rc->n_members - lc->n_members != gap) {
+ /*
+ * There were too many or too few duplicates to account
+ * for the difference, and no further comparison is
+ * necessary.
+ */
+ goto not_equal;
+ }
+ }
+ /*
+ * OK, now we know LHS and RHS are the same length and sorted in the
+ * same way, so we can just iterate over them and check each pair.
+ */
+
+ for (i = 0; i < lc->n_members; i++) {
+ ok = simple_relational_operator(&eq,
+ &ltok[i],
+ &rtok[i],
+ &cmp_pair);
+ if (! ok){
+ goto error;
+ }
+ if (cmp_pair != 0) {
+ goto not_equal;
+ }
+ }
+
+ *cmp = 0;
+
+not_equal:
+ TALLOC_FREE(tmp_ctx);
+ return true;
+error:
+ TALLOC_FREE(tmp_ctx);
+ return false;
+}
+
+
+static bool composite_is_comparable(const struct ace_condition_token *tok,
+ const struct ace_condition_token *comp)
+{
+ /*
+ * Are all members of the composite comparable to the token?
+ */
+ size_t i;
+ const struct ace_condition_composite *rc = &comp->data.composite;
+ size_t n = rc->n_members;
+
+ if ((comp->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED) &&
+ n > 1) {
+ /*
+ * all members are known to be the same type, so we
+ * can just check one.
+ */
+ n = 1;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (! tokens_are_comparable(NULL,
+ tok,
+ &rc->tokens[i])) {
+ DBG_NOTICE("token type %u != composite type %u\n",
+ tok->type, rc->tokens[i].type);
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static bool compare_composites(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+{
+ /*
+ * This is for comparing multivalued sets, which includes
+ * conditional ACE composites and claim sets. Because these
+ * are sets, there are no < and > operations, just equality or
+ * otherwise.
+ *
+ * Claims are true sets, while composites are multisets --
+ * duplicate values are allowed -- but these are reduced to
+ * sets in evaluation, and the number of duplicates has no
+ * effect in comparisons. Resource attribute ACEs live in an
+ * intermediate state -- they can contain duplicates on the
+ * wire and as ACE structures, but as soon as they are
+ * evaluated as claims their values must be unique. Windows
+ * will treat RA ACEs with duplicate values as not existing,
+ * rather than as UNKNOWN (This is significant for the Exists
+ * operator). Claims can have a case-sensitive flags set,
+ * meaning they must be compared case-sensitively.
+ *
+ * Some good news is that the LHS of a comparison must always
+ * be a claim. That means we can assume it has unique values
+ * when it comes to pairwise comparisons. Using the magic of
+ * flags, we try to check this only once per claim.
+ *
+ * Conditional ACE composites, which can have duplicates (and
+ * mixed types), can only be on the RHS.
+ *
+ * To summarise:
+ *
+ * {a, b} vs {a, b} equal
+ * { } vs { } equal
+ * {a, b} vs {b, a} equal
+ * {a, b} vs {a, c} not equal
+ * {a, b} vs {a, a, b} equal
+ * {b, a} vs {a, b, a} equal
+ * {a, b} vs {a, a, b, c} not equal
+ * {a, b, a} vs {a, b} should not happen, error
+ * {a, b, a} vs {a, b, a} should not happen, error
+ *
+ * mixed types:
+ * {1, 2} vs {1, "2"} error
+ * {1, "2"} vs {1, "2"} should not happen, error
+ *
+ * case sensitivity (*{ }* indicates case-sensitive flag):
+ *
+ * {"a", "b"} vs {"a", "B"} equal
+ * {"a", "b"} vs *{"a", "B"}* not equal
+ * *{"a", "b"}* vs {"a", "B"} not equal
+ * *{"a", "A"}* vs {"a", "A"} equal (if RHS is composite)
+ * {"a", "A"} vs *{"a", "A"}* impossible (LHS is not unique)
+ * *{"a"}* vs {"a", "A"} not equal
+ *
+ * The naive approach is of course O(n * m) with an additional O(n²)
+ * if the LHS values are not known to be unique (that is, in resource
+ * attribute claims). We want to avoid that with big sets.
+ */
+ const struct ace_condition_composite *lc = &lhs->data.composite;
+ const struct ace_condition_composite *rc = &rhs->data.composite;
+ bool ok;
+
+ if (!(lhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED)) {
+ /*
+ * The LHS needs to be a claim, and it should have gone
+ * through claim_v1_check_and_sort() to get here.
+ */
+ *cmp = -1;
+ return false;
+ }
+
+ /* if one or both are empty, the answer is easy */
+ if (lc->n_members == 0) {
+ if (rc->n_members == 0) {
+ *cmp = 0;
+ return true;
+ }
+ *cmp = -1;
+ return true;
+ }
+ if (rc->n_members == 0) {
+ *cmp = -1;
+ return true;
+ }
+
+ /*
+ * LHS must be a claim, so it must be unique, so if there are
+ * fewer members on the RHS, we know they can't be equal.
+ *
+ * If you think about it too much, you might think this is
+ * affected by case sensitivity, but it isn't. One side can be
+ * infected by case-sensitivity by the other, but that can't
+ * shrink the number of elements on the RHS -- it can only
+ * make a literal {"a", "A"} have effective length 2 rather
+ * than 1.
+ *
+ * On the other hand, if the RHS is case sensitive, it must be
+ * a claim and unique in its own terms, and its finer-grained
+ * distinctions can't collapse members of the case sensitive
+ * LHS.
+ */
+ if (lc->n_members > rc->n_members) {
+ *cmp = -1;
+ return composite_is_comparable(&lc->tokens[0], rhs);
+ }
+
+ /*
+ * It *could* be that RHS is also unique and we know it. In that
+ * case we can short circuit if RHS has more members. This is
+ * the case when both sides are claims.
+ *
+ * This is also not affected by case-senstivity.
+ */
+ if (lc->n_members < rc->n_members &&
+ (rhs->flags & CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED)) {
+ *cmp = -1;
+ return composite_is_comparable(&lc->tokens[0], rhs);
+ }
+
+ ok = compare_composites_via_sort(lhs, rhs, cmp);
+ if (! ok) {
+ return false;
+ }
+ return true;
+}
+
+
+static bool simple_relational_operator(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ int *cmp)
+
+{
+ if (lhs->type != rhs->type) {
+ if (! tokens_are_comparable(op, lhs, rhs)) {
+ return false;
+ }
+ }
+ switch (lhs->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ if (rhs->type == CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
+ return compare_bools(op, lhs, rhs, cmp);
+ }
+ return compare_ints(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_SAMBA_RESULT_BOOL:
+ return compare_bools(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ return compare_unicode(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ return compare_bytes(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_TOKEN_SID:
+ return compare_sids(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ return compare_composites(op, lhs, rhs, cmp);
+ case CONDITIONAL_ACE_SAMBA_RESULT_NULL:
+ /* leave the result unknown */
+ return false;
+ default:
+ DBG_ERR("did not expect ace type %u\n", lhs->type);
+ return false;
+ }
+
+ return false;
+}
+
+
+static bool find_in_composite(const struct ace_condition_token *tok,
+ struct ace_condition_composite candidates,
+ bool *answer)
+{
+ size_t i;
+ int cmp;
+ bool ok;
+ const struct ace_condition_token equals = {
+ .type = CONDITIONAL_ACE_TOKEN_EQUAL
+ };
+
+ *answer = false;
+
+ for (i = 0; i < candidates.n_members; i++) {
+ ok = simple_relational_operator(&equals,
+ tok,
+ &candidates.tokens[i],
+ &cmp);
+ if (! ok) {
+ return false;
+ }
+ if (cmp == 0) {
+ *answer = true;
+ return true;
+ }
+ }
+ return true;
+}
+
+
+static bool contains_operator(const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ bool *answer)
+{
+ size_t i;
+ bool ok;
+ int cmp;
+ const struct ace_condition_token equals = {
+ .type = CONDITIONAL_ACE_TOKEN_EQUAL
+ };
+
+ /*
+ * All the required objects must be identical to something in
+ * candidates. But what do we mean by *identical*? We'll use
+ * the equality operator to decide that.
+ *
+ * Both the lhs or rhs can be solitary objects or composites.
+ * This makes it a bit fiddlier.
+ *
+ * NOTE: this operator does not take advantage of the
+ * CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED flag. It could, but it
+ * doesn't.
+ */
+ if (lhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ struct ace_condition_composite candidates = lhs->data.composite;
+ struct ace_condition_composite required;
+ if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ return find_in_composite(rhs, candidates, answer);
+ }
+ required = rhs->data.composite;
+ if (required.n_members == 0) {
+ return false;
+ }
+ for (i = 0; i < required.n_members; i++) {
+ const struct ace_condition_token *t = &required.tokens[i];
+ ok = find_in_composite(t, candidates, answer);
+ if (! ok) {
+ return false;
+ }
+ if (! *answer) {
+ /*
+ * one required item was not there,
+ * *answer is false
+ */
+ return true;
+ }
+ }
+ /* all required items are there, *answer will be true */
+ return true;
+ }
+ /* LHS is a single item */
+ if (rhs->type == CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ /*
+ * There could be more than one RHS member that is
+ * equal to the single LHS value, so it doesn't help
+ * to compare lengths or anything.
+ */
+ struct ace_condition_composite required = rhs->data.composite;
+ if (required.n_members == 0) {
+ return false;
+ }
+ for (i = 0; i < required.n_members; i++) {
+ ok = simple_relational_operator(&equals,
+ lhs,
+ &required.tokens[i],
+ &cmp);
+ if (! ok) {
+ return false;
+ }
+ if (cmp != 0) {
+ /*
+ * one required item was not there,
+ * *answer is false
+ */
+ *answer = false;
+ return true;
+ }
+ }
+ *answer = true;
+ return true;
+ }
+ /* LHS and RHS are both single */
+ ok = simple_relational_operator(&equals,
+ lhs,
+ rhs,
+ &cmp);
+ if (! ok) {
+ return false;
+ }
+ *answer = (cmp == 0);
+ return true;
+}
+
+
+static bool any_of_operator(const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ bool *answer)
+{
+ size_t i;
+ bool ok;
+ int cmp;
+ const struct ace_condition_token equals = {
+ .type = CONDITIONAL_ACE_TOKEN_EQUAL
+ };
+
+ /*
+ * There has to be *some* overlap between the LHS and RHS.
+ * Both sides can be solitary objects or composites.
+ *
+ * We can exploit this symmetry.
+ */
+ if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ const struct ace_condition_token *tmp = lhs;
+ lhs = rhs;
+ rhs = tmp;
+ }
+ if (lhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ /* both singles */
+ ok = simple_relational_operator(&equals,
+ lhs,
+ rhs,
+ &cmp);
+ if (! ok) {
+ return false;
+ }
+ *answer = (cmp == 0);
+ return true;
+ }
+ if (rhs->type != CONDITIONAL_ACE_TOKEN_COMPOSITE) {
+ return find_in_composite(rhs, lhs->data.composite, answer);
+ }
+ /* both are composites */
+ if (lhs->data.composite.n_members == 0) {
+ return false;
+ }
+ for (i = 0; i < lhs->data.composite.n_members; i++) {
+ ok = find_in_composite(&lhs->data.composite.tokens[i],
+ rhs->data.composite,
+ answer);
+ if (! ok) {
+ return false;
+ }
+ if (*answer) {
+ /* We have found one match, which is enough. */
+ return true;
+ }
+ }
+ return true;
+}
+
+
+static bool composite_relational_operator(const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ struct ace_condition_token *result)
+{
+ bool ok, answer;
+ switch(op->type) {
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ ok = contains_operator(lhs, rhs, &answer);
+ break;
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ ok = any_of_operator(lhs, rhs, &answer);
+ break;
+ default:
+ return false;
+ }
+ if (!ok) {
+ return false;
+ }
+
+ /* negate the NOTs */
+ if (op->type == CONDITIONAL_ACE_TOKEN_NOT_CONTAINS ||
+ op->type == CONDITIONAL_ACE_TOKEN_NOT_ANY_OF)
+ {
+ answer = !answer;
+ }
+
+ if (answer) {
+ result->data.result.value = ACE_CONDITION_TRUE;
+ } else {
+ result->data.result.value = ACE_CONDITION_FALSE;
+ }
+ return true;
+}
+
+
+static bool relational_operator(
+ const struct security_token *token,
+ const struct ace_condition_token *op,
+ const struct ace_condition_token *lhs,
+ const struct ace_condition_token *rhs,
+ struct ace_condition_token *result)
+{
+ int cmp;
+ bool ok;
+ result->type = CONDITIONAL_ACE_SAMBA_RESULT_BOOL;
+ result->data.result.value = ACE_CONDITION_UNKNOWN;
+
+ if ((lhs->flags & CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR) == 0) {
+ /* LHS was not derived from an attribute */
+ return false;
+ }
+
+ /*
+ * This first nested switch is ensuring that >, >=, <, <= are
+ * not being tried on tokens that are not numbers, strings, or
+ * octet strings. Equality operators are available for all types.
+ */
+ switch (lhs->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ break;
+ default:
+ switch(op->type) {
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ return false;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * Dispatch according to operator type.
+ */
+ switch (op->type) {
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ ok = simple_relational_operator(op,
+ lhs,
+ rhs,
+ &cmp);
+ if (ok) {
+ ok = cmp_to_result(op, result, cmp);
+ }
+ return ok;
+
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ return composite_relational_operator(op,
+ lhs,
+ rhs,
+ result);
+ default:
+ return false;
+ }
+}
+
+
+int run_conditional_ace(TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ struct ace_condition_script *program,
+ const struct security_descriptor *sd)
+{
+ size_t i;
+ size_t depth = 0;
+ struct ace_condition_token *lhs = NULL;
+ struct ace_condition_token *rhs = NULL;
+ struct ace_condition_token result = {};
+ bool ok;
+
+ for (i = 0; i < program->length; i++) {
+ struct ace_condition_token *tok = &program->tokens[i];
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ case CONDITIONAL_ACE_TOKEN_SID:
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ /* just plonk these literals on the stack */
+ program->stack[depth] = *tok;
+ depth++;
+ break;
+
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ ok = token_claim_lookup(mem_ctx, token, tok, &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ ok = resource_claim_lookup(mem_ctx,
+ tok,
+ sd,
+ &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ if (depth == 0) {
+ goto error;
+ }
+ depth--;
+ lhs = &program->stack[depth];
+ ok = member_lookup(token, tok, lhs, &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+ /* binary relational operators */
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ if (depth < 2) {
+ goto error;
+ }
+ depth--;
+ rhs = &program->stack[depth];
+ depth--;
+ lhs = &program->stack[depth];
+ ok = relational_operator(token, tok, lhs, rhs, &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+ /* unary logical operators */
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ if (depth == 0) {
+ goto error;
+ }
+ depth--;
+ lhs = &program->stack[depth];
+ ok = unary_logic_operator(mem_ctx, token, tok, lhs, sd, &result);
+ if (!ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+ /* binary logical operators */
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ if (depth < 2) {
+ goto error;
+ }
+ depth--;
+ rhs = &program->stack[depth];
+ depth--;
+ lhs = &program->stack[depth];
+ ok = binary_logic_operator(token, tok, lhs, rhs, &result);
+ if (! ok) {
+ goto error;
+ }
+ program->stack[depth] = result;
+ depth++;
+ break;
+ default:
+ goto error;
+ }
+ }
+ /*
+ * The evaluation should have left a single result value (true, false,
+ * or unknown) on the stack. If not, the expression was malformed.
+ */
+ if (depth != 1) {
+ goto error;
+ }
+ result = program->stack[0];
+ if (result.type != CONDITIONAL_ACE_SAMBA_RESULT_BOOL) {
+ goto error;
+ }
+
+ return result.data.result.value;
+
+ error:
+ /*
+ * the result of an error is always UNKNOWN, which should be
+ * interpreted pessimistically, not allowing access.
+ */
+ return ACE_CONDITION_UNKNOWN;
+}
+
+
+/** access_check_conditional_ace()
+ *
+ * Run the conditional ACE from the blob form. Return false if it is
+ * not a valid conditional ACE, true if it is, even if there is some
+ * other error in running it. The *result parameter is set to
+ * ACE_CONDITION_FALSE, ACE_CONDITION_TRUE, or ACE_CONDITION_UNKNOWN.
+ *
+ * ACE_CONDITION_UNKNOWN should be treated pessimistically, as if it were
+ * TRUE for deny ACEs, and FALSE for allow ACEs.
+ *
+ * @param[in] ace - the ACE being processed.
+ * @param[in] token - the security token the ACE is processing.
+ * @param[out] result - a ternary result value.
+ *
+ * @return true if it is a valid conditional ACE.
+ */
+
+bool access_check_conditional_ace(const struct security_ace *ace,
+ const struct security_token *token,
+ const struct security_descriptor *sd,
+ int *result)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ struct ace_condition_script *program = NULL;
+ program = parse_conditional_ace(tmp_ctx, ace->coda.conditions);
+ if (program == NULL) {
+ *result = ACE_CONDITION_UNKNOWN;
+ TALLOC_FREE(tmp_ctx);
+ return false;
+ }
+
+ *result = run_conditional_ace(tmp_ctx, token, program, sd);
+
+ TALLOC_FREE(tmp_ctx);
+ return true;
+}
+
+
+bool conditional_ace_encode_binary(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program,
+ DATA_BLOB *dest)
+{
+ size_t i, j, alloc_size, required_size;
+ uint8_t *data = NULL;
+ uint8_t *new_data = NULL;
+ *dest = (DATA_BLOB){NULL, 0};
+
+ alloc_size = CONDITIONAL_ACE_MAX_LENGTH;
+ data = talloc_array(mem_ctx,
+ uint8_t,
+ alloc_size);
+ if (data == NULL) {
+ return false;
+ }
+
+ data[0] = 'a';
+ data[1] = 'r';
+ data[2] = 't';
+ data[3] = 'x';
+
+ j = 4;
+ for (i = 0; i < program->length; i++) {
+ struct ace_condition_token *tok = &program->tokens[i];
+ ssize_t consumed;
+ bool ok;
+ /*
+ * In all cases we write the token type byte.
+ */
+ data[j] = tok->type;
+ j++;
+ if (j >= alloc_size) {
+ DBG_ERR("program exceeds %zu bytes\n", alloc_size);
+ goto error;
+ }
+
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ /*
+ * All of these are simple operators that operate on
+ * the stack. We have already added the tok->type and
+ * there's nothing else to do.
+ */
+ continue;
+
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ ok = check_integer_range(tok);
+ if (! ok) {
+ goto error;
+ }
+ consumed = push_integer(data + j,
+ alloc_size - j,
+ &tok->data.int64);
+ break;
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ consumed = push_unicode(data + j,
+ alloc_size - j,
+ &tok->data.unicode);
+ break;
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ consumed = push_bytes(data + j,
+ alloc_size - j,
+ &tok->data.bytes);
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ consumed = push_sid(data + j,
+ alloc_size - j,
+ &tok->data.sid);
+ break;
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ consumed = push_composite(data + j,
+ alloc_size - j,
+ &tok->data.composite);
+ break;
+
+ default:
+ DBG_ERR("unknown token 0x%02x at position %zu\n",
+ tok->type, i);
+ goto error;
+ }
+ if (consumed == -1) {
+ DBG_ERR("program exceeds %zu bytes\n", alloc_size);
+ goto error;
+ }
+ j += consumed;
+ if (j >= alloc_size) {
+ DBG_ERR("program exceeds %zu bytes\n", alloc_size);
+ goto error;
+ }
+ }
+ /* align to a 4 byte boundary */
+ required_size = (j + 3) & ~((size_t)3);
+ if (required_size > alloc_size) {
+ DBG_ERR("program exceeds %zu bytes\n", alloc_size);
+ goto error;
+ }
+ while (j < required_size) {
+ data[j] = 0;
+ j++;
+ }
+ new_data = talloc_realloc(mem_ctx,
+ data,
+ uint8_t,
+ required_size);
+ if (new_data == NULL) {
+ goto error;
+ }
+ data = new_data;
+
+ (*dest).data = data;
+ (*dest).length = j;
+ return true;
+ error:
+ TALLOC_FREE(data);
+ return false;
+}
diff --git a/libcli/security/conditional_ace.h b/libcli/security/conditional_ace.h
new file mode 100644
index 0000000..e592056
--- /dev/null
+++ b/libcli/security/conditional_ace.h
@@ -0,0 +1,97 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright © Catalyst
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 _CONDITIONAL_ACE_H_
+#define _CONDITIONAL_ACE_H_
+
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+
+#include "librpc/gen_ndr/conditional_ace.h"
+
+
+struct ace_condition_script *parse_conditional_ace(TALLOC_CTX *mem_ctx,
+ DATA_BLOB data);
+
+int run_conditional_ace(TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ struct ace_condition_script *program,
+ const struct security_descriptor *sd);
+
+
+bool access_check_conditional_ace(const struct security_ace *ace,
+ const struct security_token *token,
+ const struct security_descriptor *sd,
+ int *result);
+
+bool conditional_ace_encode_binary(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program,
+ DATA_BLOB *dest);
+
+struct ace_condition_script * ace_conditions_compile_sddl(TALLOC_CTX *mem_ctx,
+ const enum ace_condition_flags ace_condition_flags,
+ const char *sddl,
+ const char **message,
+ size_t *message_offset,
+ size_t *consumed_length);
+
+char *debug_conditional_ace(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program);
+
+char *sddl_from_conditional_ace(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program);
+
+#define IS_INT_TOKEN(x) \
+ (((x)->type) == CONDITIONAL_ACE_TOKEN_INT64 || \
+ unlikely(((x)->type) == CONDITIONAL_ACE_TOKEN_INT32 || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_INT16 || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_INT8) \
+ )
+
+#define IS_BOOL_TOKEN(x) \
+ (((x)->type) == CONDITIONAL_ACE_SAMBA_RESULT_BOOL)
+
+#define IS_DERIVED_TOKEN(x) \
+ ((((x)->flags) & CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR) == 0)
+
+#define IS_LITERAL_TOKEN(x) \
+ ((IS_INT_TOKEN(x) || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_UNICODE || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_OCTET_STRING || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_SID || \
+ ((x)->type) == CONDITIONAL_ACE_TOKEN_COMPOSITE) && \
+ (! IS_DERIVED_TOKEN(x)))
+
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *parse_sddl_literal_as_claim(
+ TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *str);
+
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *sddl_decode_resource_attr (
+ TALLOC_CTX *mem_ctx,
+ const char *str,
+ size_t *length);
+
+char *sddl_resource_attr_from_claim(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim);
+
+
+#endif /*_CONDITIONAL_ACE_H_*/
diff --git a/libcli/security/create_descriptor.c b/libcli/security/create_descriptor.c
new file mode 100644
index 0000000..4db23be
--- /dev/null
+++ b/libcli/security/create_descriptor.c
@@ -0,0 +1,666 @@
+/*
+ Copyright (C) Nadezhda Ivanova 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/>.
+*/
+
+/*
+ * Name: create_descriptor
+ *
+ * Component: routines for calculating and creating security descriptors
+ * as described in MS-DTYP 2.5.3.x
+ *
+ * Description:
+ *
+ *
+ * Author: Nadezhda Ivanova
+ */
+#include "replace.h"
+#include "lib/util/debug.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+/* Todos:
+ * build the security token dacl as follows:
+ * SYSTEM: GA, OWNER: GA, LOGIN_SID:GW|GE
+ * Need session id information for the login SID. Probably
+ * the best place for this is during token creation
+ *
+ * Implement SD Invariants
+ * ACE sorting rules
+ * LDAP_SERVER_SD_FLAGS_OID control
+ * ADTS 7.1.3.3 needs to be clarified
+ */
+
+/* the mapping function for generic rights for DS.(GA,GR,GW,GX)
+ * The mapping function is passed as an argument to the
+ * descriptor calculating routine and depends on the security
+ * manager that calls the calculating routine.
+ * TODO: need similar mappings for the file system and
+ * registry security managers in order to make this code
+ * generic for all security managers
+ */
+
+uint32_t map_generic_rights_ds(uint32_t access_mask)
+{
+ if (access_mask & SEC_GENERIC_ALL) {
+ access_mask |= SEC_ADS_GENERIC_ALL;
+ access_mask &= ~SEC_GENERIC_ALL;
+ }
+
+ if (access_mask & SEC_GENERIC_EXECUTE) {
+ access_mask |= SEC_ADS_GENERIC_EXECUTE;
+ access_mask &= ~SEC_GENERIC_EXECUTE;
+ }
+
+ if (access_mask & SEC_GENERIC_WRITE) {
+ access_mask |= SEC_ADS_GENERIC_WRITE;
+ access_mask &= ~SEC_GENERIC_WRITE;
+ }
+
+ if (access_mask & SEC_GENERIC_READ) {
+ access_mask |= SEC_ADS_GENERIC_READ;
+ access_mask &= ~SEC_GENERIC_READ;
+ }
+
+ return access_mask;
+}
+
+/* Not sure what this has to be,
+* and it does not seem to have any influence */
+static bool object_in_list(const struct GUID *object_list, const struct GUID *object)
+{
+ size_t i;
+
+ if (object_list == NULL) {
+ return true;
+ }
+
+ if (GUID_all_zero(object)) {
+ return true;
+ }
+
+ for (i=0; ; i++) {
+ if (GUID_all_zero(&object_list[i])) {
+ return false;
+ }
+ if (!GUID_equal(&object_list[i], object)) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/* returns true if the ACE gontains generic information
+ * that needs to be processed additionally */
+
+static bool desc_ace_has_generic(const struct security_ace *ace)
+{
+ if (ace->access_mask & SEC_GENERIC_ALL || ace->access_mask & SEC_GENERIC_READ ||
+ ace->access_mask & SEC_GENERIC_WRITE || ace->access_mask & SEC_GENERIC_EXECUTE) {
+ return true;
+ }
+ if (dom_sid_equal(&ace->trustee, &global_sid_Creator_Owner) ||
+ dom_sid_equal(&ace->trustee, &global_sid_Creator_Group)) {
+ return true;
+ }
+ return false;
+}
+
+/* creates an ace in which the generic information is expanded */
+
+static void desc_expand_generic(struct security_ace *new_ace,
+ struct dom_sid *owner,
+ struct dom_sid *group)
+{
+ new_ace->access_mask = map_generic_rights_ds(new_ace->access_mask);
+ if (dom_sid_equal(&new_ace->trustee, &global_sid_Creator_Owner)) {
+ new_ace->trustee = *owner;
+ }
+ if (dom_sid_equal(&new_ace->trustee, &global_sid_Creator_Group)) {
+ new_ace->trustee = *group;
+ }
+ new_ace->flags = 0x0;
+}
+
+static struct security_acl *calculate_inherited_from_parent(TALLOC_CTX *mem_ctx,
+ struct security_acl *acl,
+ bool is_container,
+ struct dom_sid *owner,
+ struct dom_sid *group,
+ struct GUID *object_list)
+{
+ uint32_t i;
+ struct security_acl *tmp_acl = NULL;
+
+ if (!acl) {
+ return NULL;
+ }
+ tmp_acl = talloc_zero(mem_ctx, struct security_acl);
+ if (!tmp_acl) {
+ return NULL;
+ }
+
+ for (i=0; i < acl->num_aces; i++) {
+ const struct security_ace *ace = &acl->aces[i];
+ const struct GUID *inherited_object = NULL;
+ const struct GUID *inherited_property = NULL;
+ struct security_ace *tmp_ace = NULL;
+ bool applies = false;
+ bool inherited_only = false;
+ bool expand_ace = false;
+ bool expand_only = false;
+
+ if (is_container && (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+ applies = true;
+ } else if (!is_container && (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
+ applies = true;
+ }
+
+ if (!applies) {
+ /*
+ * If the ace doesn't apply to the
+ * current node, we should only keep
+ * it as SEC_ACE_FLAG_OBJECT_INHERIT
+ * on a container. We'll add
+ * SEC_ACE_FLAG_INHERITED_ACE
+ * and SEC_ACE_FLAG_INHERIT_ONLY below.
+ *
+ * Otherwise we should completely ignore it.
+ */
+ if (!(ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
+ continue;
+ }
+ }
+
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_ALLOWED_COMPOUND:
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT:
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT:
+ if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
+ inherited_property = &ace->object.object.type.type;
+ }
+ if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
+ inherited_object = &ace->object.object.inherited_type.inherited_type;
+ }
+
+ if (inherited_object != NULL && !object_in_list(object_list, inherited_object)) {
+ /*
+ * An explicit object class schemaId is given,
+ * but doesn't belong to the current object.
+ */
+ applies = false;
+ }
+
+ break;
+
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK:
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK:
+ break;
+ case SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE:
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK:
+ case SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT:
+ case SEC_ACE_TYPE_SYSTEM_MANDATORY_LABEL:
+ case SEC_ACE_TYPE_SYSTEM_SCOPED_POLICY_ID:
+ default:
+ DBG_WARNING("ACE type %d is not handled\n", ace->type);
+ TALLOC_FREE(tmp_acl);
+ return NULL;
+ }
+
+ if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ if (!applies) {
+ /*
+ * If the ACE doesn't apply to
+ * the current object, we should
+ * ignore it as it should not be
+ * inherited any further
+ */
+ continue;
+ }
+ /*
+ * We should only keep the expanded version
+ * of the ACE on the current object.
+ */
+ expand_ace = true;
+ expand_only = true;
+ } else if (applies) {
+ /*
+ * We check if should also add
+ * the expanded version of the ACE
+ * in addition, in case we should
+ * expand generic access bits or
+ * special sids.
+ *
+ * In that case we need to
+ * keep the original ACE with
+ * SEC_ACE_FLAG_INHERIT_ONLY.
+ */
+ expand_ace = desc_ace_has_generic(ace);
+ if (expand_ace) {
+ inherited_only = true;
+ }
+ } else {
+ /*
+ * If the ACE doesn't apply
+ * to the current object,
+ * we need to keep it with
+ * SEC_ACE_FLAG_INHERIT_ONLY
+ * in order to apply them to
+ * grandchildren
+ */
+ inherited_only = true;
+ }
+
+ if (expand_ace) {
+ tmp_acl->aces = talloc_realloc(tmp_acl,
+ tmp_acl->aces,
+ struct security_ace,
+ tmp_acl->num_aces+1);
+ if (tmp_acl->aces == NULL) {
+ TALLOC_FREE(tmp_acl);
+ return NULL;
+ }
+
+ tmp_ace = &tmp_acl->aces[tmp_acl->num_aces];
+ tmp_acl->num_aces++;
+
+ *tmp_ace = *ace;
+
+ /*
+ * Expand generic access bits as well as special
+ * sids.
+ */
+ desc_expand_generic(tmp_ace, owner, group);
+
+ /*
+ * Expanded ACEs are marked as inherited,
+ * but never inherited any further to
+ * grandchildren.
+ */
+ tmp_ace->flags |= SEC_ACE_FLAG_INHERITED_ACE;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_CONTAINER_INHERIT;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_OBJECT_INHERIT;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
+
+ /*
+ * Expanded ACEs never have an explicit
+ * object class schemaId, so clear it
+ * if present.
+ */
+ if (inherited_object != NULL) {
+ tmp_ace->object.object.flags &= ~SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT;
+ }
+
+ /*
+ * If the ACE had an explicit object class
+ * schemaId, but no attribute/propertySet
+ * we need to downgrade the _OBJECT variants
+ * to the normal ones.
+ */
+ if (inherited_property == NULL) {
+ switch (tmp_ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ case SEC_ACE_TYPE_ALLOWED_COMPOUND:
+ break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_ACCESS_DENIED;
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_SYSTEM_ALARM;
+ break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_SYSTEM_AUDIT;
+ break;
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK;
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK;
+ break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT:
+ tmp_ace->type = SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK;
+ break;
+ default:
+ /*
+ * SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT
+ * is reserved.
+ */
+ break;
+ }
+ }
+
+ if (expand_only) {
+ continue;
+ }
+ }
+
+ tmp_acl->aces = talloc_realloc(tmp_acl,
+ tmp_acl->aces,
+ struct security_ace,
+ tmp_acl->num_aces+1);
+ if (tmp_acl->aces == NULL) {
+ TALLOC_FREE(tmp_acl);
+ return NULL;
+ }
+
+ tmp_ace = &tmp_acl->aces[tmp_acl->num_aces];
+ tmp_acl->num_aces++;
+
+ *tmp_ace = *ace;
+ tmp_ace->flags |= SEC_ACE_FLAG_INHERITED_ACE;
+
+ if (inherited_only) {
+ tmp_ace->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ } else {
+ tmp_ace->flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
+ }
+
+ if (ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ tmp_ace->flags &= ~SEC_ACE_FLAG_CONTAINER_INHERIT;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_OBJECT_INHERIT;
+ tmp_ace->flags &= ~SEC_ACE_FLAG_NO_PROPAGATE_INHERIT;
+ }
+ }
+ if (tmp_acl->num_aces == 0) {
+ TALLOC_FREE(tmp_acl);
+ return NULL;
+ }
+ if (acl) {
+ tmp_acl->revision = acl->revision;
+ }
+ return tmp_acl;
+}
+
+static struct security_acl *process_user_acl(TALLOC_CTX *mem_ctx,
+ struct security_acl *acl,
+ bool is_container,
+ struct dom_sid *owner,
+ struct dom_sid *group,
+ struct GUID *object_list,
+ bool is_protected)
+{
+ uint32_t i;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ struct security_acl *tmp_acl = talloc_zero(tmp_ctx, struct security_acl);
+ struct security_acl *new_acl;
+
+ if (!acl)
+ return NULL;
+
+ if (!tmp_acl)
+ return NULL;
+
+ tmp_acl->revision = acl->revision;
+ DBG_DEBUG("acl revision %d\n", acl->revision);
+
+ for (i=0; i < acl->num_aces; i++){
+ struct security_ace *ace = &acl->aces[i];
+ /* Remove ID flags from user-provided ACEs
+ * if we break inheritance, ignore them otherwise */
+ if (ace->flags & SEC_ACE_FLAG_INHERITED_ACE) {
+ if (is_protected) {
+ ace->flags &= ~SEC_ACE_FLAG_INHERITED_ACE;
+ } else {
+ continue;
+ }
+ }
+
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY &&
+ !(ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT ||
+ ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT))
+ continue;
+
+ tmp_acl->aces = talloc_realloc(tmp_acl,
+ tmp_acl->aces,
+ struct security_ace,
+ tmp_acl->num_aces+1);
+ tmp_acl->aces[tmp_acl->num_aces] = *ace;
+ tmp_acl->num_aces++;
+ if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+ continue;
+ }
+ /* if the ACE contains CO, CG, GA, GE, GR or GW, and is inheritable
+ * it has to be expanded to two aces, the original as IO,
+ * and another one where these are translated */
+ if (desc_ace_has_generic(ace)) {
+ if (!(ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+ desc_expand_generic(&tmp_acl->aces[tmp_acl->num_aces-1],
+ owner,
+ group);
+ } else {
+ /*The original ACE becomes read only */
+ tmp_acl->aces[tmp_acl->num_aces-1].flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ tmp_acl->aces = talloc_realloc(tmp_acl, tmp_acl->aces,
+ struct security_ace,
+ tmp_acl->num_aces+1);
+ /* add a new ACE with expanded generic info */
+ tmp_acl->aces[tmp_acl->num_aces] = *ace;
+ desc_expand_generic(&tmp_acl->aces[tmp_acl->num_aces],
+ owner,
+ group);
+ tmp_acl->num_aces++;
+ }
+ }
+ }
+ new_acl = security_acl_dup(mem_ctx,tmp_acl);
+
+ if (new_acl)
+ new_acl->revision = acl->revision;
+
+ talloc_free(tmp_ctx);
+ return new_acl;
+}
+
+static void cr_descr_log_descriptor(struct security_descriptor *sd,
+ const char *message,
+ int level)
+{
+ if (sd) {
+ DEBUG(level,("%s: %s\n", message,
+ ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_descriptor,
+ "", sd)));
+ }
+ else {
+ DEBUG(level,("%s: NULL\n", message));
+ }
+}
+
+#if 0
+static void cr_descr_log_acl(struct security_acl *acl,
+ const char *message,
+ int level)
+{
+ if (acl) {
+ DEBUG(level,("%s: %s\n", message,
+ ndr_print_struct_string(0,(ndr_print_fn_t)ndr_print_security_acl,
+ "", acl)));
+ }
+ else {
+ DEBUG(level,("%s: NULL\n", message));
+ }
+}
+#endif
+
+static bool compute_acl(struct security_descriptor *parent_sd,
+ struct security_descriptor *creator_sd,
+ bool is_container,
+ uint32_t inherit_flags,
+ struct GUID *object_list,
+ uint32_t (*generic_map)(uint32_t access_mask),
+ struct security_token *token,
+ struct security_descriptor *new_sd) /* INOUT argument */
+{
+ struct security_acl *user_dacl, *user_sacl, *inherited_dacl, *inherited_sacl;
+ int level = 10;
+
+ if (!parent_sd || !(inherit_flags & SEC_DACL_AUTO_INHERIT)) {
+ inherited_dacl = NULL;
+ } else if (creator_sd && (creator_sd->type & SEC_DESC_DACL_PROTECTED)) {
+ inherited_dacl = NULL;
+ } else {
+ inherited_dacl = calculate_inherited_from_parent(new_sd,
+ parent_sd->dacl,
+ is_container,
+ new_sd->owner_sid,
+ new_sd->group_sid,
+ object_list);
+ }
+
+
+ if (!parent_sd || !(inherit_flags & SEC_SACL_AUTO_INHERIT)) {
+ inherited_sacl = NULL;
+ } else if (creator_sd && (creator_sd->type & SEC_DESC_SACL_PROTECTED)) {
+ inherited_sacl = NULL;
+ } else {
+ inherited_sacl = calculate_inherited_from_parent(new_sd,
+ parent_sd->sacl,
+ is_container,
+ new_sd->owner_sid,
+ new_sd->group_sid,
+ object_list);
+ }
+
+ if (!creator_sd || (inherit_flags & SEC_DEFAULT_DESCRIPTOR)) {
+ user_dacl = NULL;
+ user_sacl = NULL;
+ } else {
+ user_dacl = process_user_acl(new_sd,
+ creator_sd->dacl,
+ is_container,
+ new_sd->owner_sid,
+ new_sd->group_sid,
+ object_list,
+ creator_sd->type & SEC_DESC_DACL_PROTECTED);
+ user_sacl = process_user_acl(new_sd,
+ creator_sd->sacl,
+ is_container,
+ new_sd->owner_sid,
+ new_sd->group_sid,
+ object_list,
+ creator_sd->type & SEC_DESC_SACL_PROTECTED);
+ }
+ cr_descr_log_descriptor(parent_sd, __location__"parent_sd", level);
+ cr_descr_log_descriptor(creator_sd,__location__ "creator_sd", level);
+
+ new_sd->dacl = security_acl_concatenate(new_sd, user_dacl, inherited_dacl);
+ if (new_sd->dacl) {
+ new_sd->type |= SEC_DESC_DACL_PRESENT;
+ }
+ if (inherited_dacl) {
+ new_sd->type |= SEC_DESC_DACL_AUTO_INHERITED;
+ }
+
+ new_sd->sacl = security_acl_concatenate(new_sd, user_sacl, inherited_sacl);
+ if (new_sd->sacl) {
+ new_sd->type |= SEC_DESC_SACL_PRESENT;
+ }
+ if (inherited_sacl) {
+ new_sd->type |= SEC_DESC_SACL_AUTO_INHERITED;
+ }
+ /* This is a hack to handle the fact that
+ * apprantly any AI flag provided by the user is preserved */
+ if (creator_sd)
+ new_sd->type |= creator_sd->type;
+ cr_descr_log_descriptor(new_sd, __location__"final sd", level);
+ return true;
+}
+
+struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx,
+ struct security_descriptor *parent_sd,
+ struct security_descriptor *creator_sd,
+ bool is_container,
+ struct GUID *object_list,
+ uint32_t inherit_flags,
+ struct security_token *token,
+ struct dom_sid *default_owner, /* valid only for DS, NULL for the other RSs */
+ struct dom_sid *default_group, /* valid only for DS, NULL for the other RSs */
+ uint32_t (*generic_map)(uint32_t access_mask))
+{
+ struct security_descriptor *new_sd;
+ struct dom_sid *new_owner = NULL;
+ struct dom_sid *new_group = NULL;
+
+ new_sd = security_descriptor_initialise(mem_ctx);
+ if (!new_sd) {
+ return NULL;
+ }
+
+ if (!creator_sd || !creator_sd->owner_sid) {
+ if ((inherit_flags & SEC_OWNER_FROM_PARENT) && parent_sd) {
+ new_owner = parent_sd->owner_sid;
+ } else if (!default_owner) {
+ new_owner = &token->sids[PRIMARY_USER_SID_INDEX];
+ } else {
+ new_owner = default_owner;
+ new_sd->type |= SEC_DESC_OWNER_DEFAULTED;
+ }
+ } else {
+ new_owner = creator_sd->owner_sid;
+ }
+
+ if (!creator_sd || !creator_sd->group_sid){
+ if ((inherit_flags & SEC_GROUP_FROM_PARENT) && parent_sd) {
+ new_group = parent_sd->group_sid;
+ } else if (!default_group && token->num_sids > PRIMARY_GROUP_SID_INDEX) {
+ new_group = &token->sids[PRIMARY_GROUP_SID_INDEX];
+ } else if (!default_group) {
+ /* This will happen only for anonymous, which has no other groups */
+ new_group = &token->sids[PRIMARY_USER_SID_INDEX];
+ } else {
+ new_group = default_group;
+ new_sd->type |= SEC_DESC_GROUP_DEFAULTED;
+ }
+ } else {
+ new_group = creator_sd->group_sid;
+ }
+
+ new_sd->owner_sid = talloc_memdup(new_sd, new_owner, sizeof(struct dom_sid));
+ new_sd->group_sid = talloc_memdup(new_sd, new_group, sizeof(struct dom_sid));
+ if (!new_sd->owner_sid || !new_sd->group_sid){
+ talloc_free(new_sd);
+ return NULL;
+ }
+
+ if (!compute_acl(parent_sd, creator_sd,
+ is_container, inherit_flags, object_list,
+ generic_map,token,new_sd)){
+ talloc_free(new_sd);
+ return NULL;
+ }
+
+ return new_sd;
+}
diff --git a/libcli/security/display_sec.c b/libcli/security/display_sec.c
new file mode 100644
index 0000000..be89a33
--- /dev/null
+++ b/libcli/security/display_sec.c
@@ -0,0 +1,274 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 "librpc/ndr/libndr.h"
+#include "libcli/security/display_sec.h"
+
+/****************************************************************************
+convert a security permissions into a string
+****************************************************************************/
+
+char *get_sec_mask_str(TALLOC_CTX *ctx, uint32_t type)
+{
+ char *typestr = talloc_strdup(ctx, "");
+
+ if (type & SEC_GENERIC_ALL) {
+ talloc_asprintf_addbuf(&typestr, "Generic all access ");
+ }
+ if (type & SEC_GENERIC_EXECUTE) {
+ talloc_asprintf_addbuf(&typestr, "Generic execute access");
+ }
+ if (type & SEC_GENERIC_WRITE) {
+ talloc_asprintf_addbuf(&typestr, "Generic write access ");
+ }
+ if (type & SEC_GENERIC_READ) {
+ talloc_asprintf_addbuf(&typestr, "Generic read access ");
+ }
+ if (type & SEC_FLAG_MAXIMUM_ALLOWED) {
+ talloc_asprintf_addbuf(&typestr, "MAXIMUM_ALLOWED_ACCESS ");
+ }
+ if (type & SEC_FLAG_SYSTEM_SECURITY) {
+ talloc_asprintf_addbuf(&typestr, "SYSTEM_SECURITY_ACCESS ");
+ }
+ if (type & SEC_STD_SYNCHRONIZE) {
+ talloc_asprintf_addbuf(&typestr, "SYNCHRONIZE_ACCESS ");
+ }
+ if (type & SEC_STD_WRITE_OWNER) {
+ talloc_asprintf_addbuf(&typestr, "WRITE_OWNER_ACCESS ");
+ }
+ if (type & SEC_STD_WRITE_DAC) {
+ talloc_asprintf_addbuf(&typestr, "WRITE_DAC_ACCESS ");
+ }
+ if (type & SEC_STD_READ_CONTROL) {
+ talloc_asprintf_addbuf(&typestr, "READ_CONTROL_ACCESS ");
+ }
+ if (type & SEC_STD_DELETE) {
+ talloc_asprintf_addbuf(&typestr, "DELETE_ACCESS ");
+ }
+
+ printf("\t\tSpecific bits: 0x%lx\n", (unsigned long)type&SEC_MASK_SPECIFIC);
+
+ return typestr;
+}
+
+/****************************************************************************
+ display sec_access structure
+ ****************************************************************************/
+void display_sec_access(uint32_t *info)
+{
+ char *mask_str = get_sec_mask_str(NULL, *info);
+ printf("\t\tPermissions: 0x%x: %s\n", *info, mask_str ? mask_str : "");
+ talloc_free(mask_str);
+}
+
+/****************************************************************************
+ display sec_ace flags
+ ****************************************************************************/
+void display_sec_ace_flags(uint8_t flags)
+{
+ if (flags & SEC_ACE_FLAG_OBJECT_INHERIT)
+ printf("SEC_ACE_FLAG_OBJECT_INHERIT ");
+ if (flags & SEC_ACE_FLAG_CONTAINER_INHERIT)
+ printf(" SEC_ACE_FLAG_CONTAINER_INHERIT ");
+ if (flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)
+ printf("SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ");
+ if (flags & SEC_ACE_FLAG_INHERIT_ONLY)
+ printf("SEC_ACE_FLAG_INHERIT_ONLY ");
+ if (flags & SEC_ACE_FLAG_INHERITED_ACE)
+ printf("SEC_ACE_FLAG_INHERITED_ACE ");
+/* if (flags & SEC_ACE_FLAG_VALID_INHERIT)
+ printf("SEC_ACE_FLAG_VALID_INHERIT "); */
+ if (flags & SEC_ACE_FLAG_SUCCESSFUL_ACCESS)
+ printf("SEC_ACE_FLAG_SUCCESSFUL_ACCESS ");
+ if (flags & SEC_ACE_FLAG_FAILED_ACCESS)
+ printf("SEC_ACE_FLAG_FAILED_ACCESS ");
+
+ printf("\n");
+}
+
+/****************************************************************************
+ display sec_ace object
+ ****************************************************************************/
+static void disp_sec_ace_object(struct security_ace_object *object)
+{
+ char *str;
+ if (object->flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
+ str = GUID_string(NULL, &object->type.type);
+ if (str == NULL) return;
+ printf("Object type: SEC_ACE_OBJECT_TYPE_PRESENT\n");
+ printf("Object GUID: %s\n", str);
+ talloc_free(str);
+ }
+ if (object->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
+ str = GUID_string(NULL, &object->inherited_type.inherited_type);
+ if (str == NULL) return;
+ printf("Object type: SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT\n");
+ printf("Object GUID: %s\n", str);
+ talloc_free(str);
+ }
+}
+
+/****************************************************************************
+ display sec_ace structure
+ ****************************************************************************/
+void display_sec_ace(struct security_ace *ace)
+{
+ struct dom_sid_buf sid_str;
+
+ printf("\tACE\n\t\ttype: ");
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_ALLOWED:
+ printf("ACCESS ALLOWED");
+ break;
+ case SEC_ACE_TYPE_ACCESS_DENIED:
+ printf("ACCESS DENIED");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_AUDIT:
+ printf("SYSTEM AUDIT");
+ break;
+ case SEC_ACE_TYPE_SYSTEM_ALARM:
+ printf("SYSTEM ALARM");
+ break;
+#define ACE_CASE(x) case x: printf(#x); break
+ ACE_CASE(SEC_ACE_TYPE_ALLOWED_COMPOUND);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT);
+ ACE_CASE(SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT);
+#undef ACE_CASE
+ default:
+ printf("????");
+ break;
+ }
+
+ printf(" (%d) flags: 0x%02x ", ace->type, ace->flags);
+ display_sec_ace_flags(ace->flags);
+ display_sec_access(&ace->access_mask);
+ printf("\t\tSID: %s\n\n", dom_sid_str_buf(&ace->trustee, &sid_str));
+
+ if (sec_ace_object(ace->type)) {
+ disp_sec_ace_object(&ace->object.object);
+ }
+
+}
+
+/****************************************************************************
+ display sec_acl structure
+ ****************************************************************************/
+void display_sec_acl(struct security_acl *sec_acl)
+{
+ uint32_t i;
+
+ printf("\tACL\tNum ACEs:\t%u\trevision:\t%x\n",
+ sec_acl->num_aces, sec_acl->revision);
+ printf("\t---\n");
+
+ if (sec_acl->size != 0 && sec_acl->num_aces != 0) {
+ for (i = 0; i < sec_acl->num_aces; i++) {
+ display_sec_ace(&sec_acl->aces[i]);
+ }
+ }
+}
+
+void display_acl_type(uint16_t type)
+{
+ printf("type: 0x%04x: ", type);
+
+ if (type & SEC_DESC_OWNER_DEFAULTED) /* 0x0001 */
+ printf("SEC_DESC_OWNER_DEFAULTED ");
+ if (type & SEC_DESC_GROUP_DEFAULTED) /* 0x0002 */
+ printf("SEC_DESC_GROUP_DEFAULTED ");
+ if (type & SEC_DESC_DACL_PRESENT) /* 0x0004 */
+ printf("SEC_DESC_DACL_PRESENT ");
+ if (type & SEC_DESC_DACL_DEFAULTED) /* 0x0008 */
+ printf("SEC_DESC_DACL_DEFAULTED ");
+ if (type & SEC_DESC_SACL_PRESENT) /* 0x0010 */
+ printf("SEC_DESC_SACL_PRESENT ");
+ if (type & SEC_DESC_SACL_DEFAULTED) /* 0x0020 */
+ printf("SEC_DESC_SACL_DEFAULTED ");
+ if (type & SEC_DESC_DACL_TRUSTED) /* 0x0040 */
+ printf("SEC_DESC_DACL_TRUSTED ");
+ if (type & SEC_DESC_SERVER_SECURITY) /* 0x0080 */
+ printf("SEC_DESC_SERVER_SECURITY ");
+ if (type & SEC_DESC_DACL_AUTO_INHERIT_REQ) /* 0x0100 */
+ printf("SEC_DESC_DACL_AUTO_INHERIT_REQ ");
+ if (type & SEC_DESC_SACL_AUTO_INHERIT_REQ) /* 0x0200 */
+ printf("SEC_DESC_SACL_AUTO_INHERIT_REQ ");
+ if (type & SEC_DESC_DACL_AUTO_INHERITED) /* 0x0400 */
+ printf("SEC_DESC_DACL_AUTO_INHERITED ");
+ if (type & SEC_DESC_SACL_AUTO_INHERITED) /* 0x0800 */
+ printf("SEC_DESC_SACL_AUTO_INHERITED ");
+ if (type & SEC_DESC_DACL_PROTECTED) /* 0x1000 */
+ printf("SEC_DESC_DACL_PROTECTED ");
+ if (type & SEC_DESC_SACL_PROTECTED) /* 0x2000 */
+ printf("SEC_DESC_SACL_PROTECTED ");
+ if (type & SEC_DESC_RM_CONTROL_VALID) /* 0x4000 */
+ printf("SEC_DESC_RM_CONTROL_VALID ");
+ if (type & SEC_DESC_SELF_RELATIVE) /* 0x8000 */
+ printf("SEC_DESC_SELF_RELATIVE ");
+
+ printf("\n");
+}
+
+/****************************************************************************
+ display sec_desc structure
+ ****************************************************************************/
+void display_sec_desc(struct security_descriptor *sec)
+{
+ struct dom_sid_buf sid_str;
+
+ if (!sec) {
+ printf("NULL\n");
+ return;
+ }
+
+ printf("revision: %d\n", sec->revision);
+ display_acl_type(sec->type);
+
+ if (sec->sacl) {
+ printf("SACL\n");
+ display_sec_acl(sec->sacl);
+ }
+
+ if (sec->dacl) {
+ printf("DACL\n");
+ display_sec_acl(sec->dacl);
+ }
+
+ if (sec->owner_sid) {
+ printf("\tOwner SID:\t%s\n",
+ dom_sid_str_buf(sec->owner_sid, &sid_str));
+ }
+
+ if (sec->group_sid) {
+ printf("\tGroup SID:\t%s\n",
+ dom_sid_str_buf(sec->group_sid, &sid_str));
+ }
+}
diff --git a/libcli/security/display_sec.h b/libcli/security/display_sec.h
new file mode 100644
index 0000000..336e04c
--- /dev/null
+++ b/libcli/security/display_sec.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 _LIBCLI_SECURITY_DISPLAY_SEC_H
+#define _LIBCLI_SECURITY_DISPLAY_SEC_H
+
+/* The following definitions come from libcli/security/display_sec.c */
+
+char *get_sec_mask_str(TALLOC_CTX *ctx, uint32_t type);
+void display_sec_access(uint32_t *info);
+void display_sec_ace_flags(uint8_t flags);
+void display_sec_ace(struct security_ace *ace);
+void display_sec_acl(struct security_acl *sec_acl);
+void display_acl_type(uint16_t type);
+void display_sec_desc(struct security_descriptor *sec);
+
+#endif /* _LIBCLI_SECURITY_DISPLAY_SEC_H */
diff --git a/libcli/security/dom_sid.c b/libcli/security/dom_sid.c
new file mode 100644
index 0000000..eaece2a
--- /dev/null
+++ b/libcli/security/dom_sid.c
@@ -0,0 +1,582 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Stefan (metze) Metzmacher 2002-2004
+ Copyright (C) Andrew Tridgell 1992-2004
+ Copyright (C) Jeremy Allison 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/data_blob.h"
+#include "system/locale.h"
+#include "lib/util/debug.h"
+#include "lib/util/util.h"
+#include "librpc/gen_ndr/security.h"
+#include "dom_sid.h"
+#include "lib/util/smb_strtox.h"
+
+/*****************************************************************
+ Compare the auth portion of two sids.
+*****************************************************************/
+
+int dom_sid_compare_auth(const struct dom_sid *sid1,
+ const struct dom_sid *sid2)
+{
+ int i;
+
+ if (sid1 == sid2)
+ return 0;
+ if (!sid1)
+ return -1;
+ if (!sid2)
+ return 1;
+
+ if (sid1->sid_rev_num != sid2->sid_rev_num)
+ return sid1->sid_rev_num - sid2->sid_rev_num;
+
+ for (i = 0; i < 6; i++)
+ if (sid1->id_auth[i] != sid2->id_auth[i])
+ return sid1->id_auth[i] - sid2->id_auth[i];
+
+ return 0;
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+
+int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2)
+{
+ int i;
+
+ if (sid1 == sid2)
+ return 0;
+ if (!sid1)
+ return -1;
+ if (!sid2)
+ return 1;
+
+ /* Compare most likely different rids, first: i.e start at end */
+ if (sid1->num_auths != sid2->num_auths)
+ return sid1->num_auths - sid2->num_auths;
+
+ for (i = sid1->num_auths-1; i >= 0; --i) {
+ if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
+ return -1;
+ }
+ if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
+ return 1;
+ }
+ }
+
+ return dom_sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+ Compare two sids.
+*****************************************************************/
+
+bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2)
+{
+ return dom_sid_compare(sid1, sid2) == 0;
+}
+
+/*****************************************************************
+ Add a rid to the end of a sid
+*****************************************************************/
+
+bool sid_append_rid(struct dom_sid *sid, uint32_t rid)
+{
+ if (sid->num_auths < ARRAY_SIZE(sid->sub_auths)) {
+ sid->sub_auths[sid->num_auths++] = rid;
+ return true;
+ }
+ return false;
+}
+
+/*
+ See if 2 SIDs are in the same domain
+ this just compares the leading sub-auths
+*/
+int dom_sid_compare_domain(const struct dom_sid *sid1,
+ const struct dom_sid *sid2)
+{
+ int n, i;
+
+ n = MIN(sid1->num_auths, sid2->num_auths);
+
+ for (i = n-1; i >= 0; --i) {
+ if (sid1->sub_auths[i] < sid2->sub_auths[i]) {
+ return -1;
+ }
+ if (sid1->sub_auths[i] > sid2->sub_auths[i]) {
+ return 1;
+ }
+ }
+
+ return dom_sid_compare_auth(sid1, sid2);
+}
+
+/*****************************************************************
+ Convert a string to a SID. Returns True on success, False on fail.
+ Return the first character not parsed in endp.
+*****************************************************************/
+#define AUTHORITY_MASK (~(0xffffffffffffULL))
+
+bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
+ const char **endp)
+{
+ const char *p;
+ char *q = NULL;
+ char *end = NULL;
+ uint64_t conv;
+ int error = 0;
+
+ *sidout = (struct dom_sid) {};
+
+ if ((sidstr[0] != 'S' && sidstr[0] != 's') || sidstr[1] != '-') {
+ goto format_error;
+ }
+
+ /* Get the revision number. */
+ p = sidstr + 2;
+
+ if (!isdigit((unsigned char)*p)) {
+ goto format_error;
+ }
+
+ conv = smb_strtoul(p, &q, 10, &error, SMB_STR_STANDARD);
+ if (error != 0 || (*q != '-') || conv > UINT8_MAX || q - p > 4) {
+ goto format_error;
+ }
+ sidout->sid_rev_num = (uint8_t) conv;
+ q++;
+
+ if (!isdigit((unsigned char)*q)) {
+ goto format_error;
+ }
+ while (q[0] == '0' && isdigit((unsigned char)q[1])) {
+ /*
+ * strtoull will think this is octal, which is not how SIDs
+ * work! So let's walk along until there are no leading zeros
+ * (or a single zero).
+ */
+ q++;
+ }
+
+ /* get identauth */
+ conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
+ if (conv & AUTHORITY_MASK || error != 0) {
+ goto format_error;
+ }
+ if (conv >= (1ULL << 48) || end - q > 15) {
+ /*
+ * This identauth looks like a big number, but resolves to a
+ * small number after rounding.
+ */
+ goto format_error;
+ }
+
+ /* NOTE - the conv value is in big-endian format. */
+ sidout->id_auth[0] = (conv & 0xff0000000000ULL) >> 40;
+ sidout->id_auth[1] = (conv & 0x00ff00000000ULL) >> 32;
+ sidout->id_auth[2] = (conv & 0x0000ff000000ULL) >> 24;
+ sidout->id_auth[3] = (conv & 0x000000ff0000ULL) >> 16;
+ sidout->id_auth[4] = (conv & 0x00000000ff00ULL) >> 8;
+ sidout->id_auth[5] = (conv & 0x0000000000ffULL);
+
+ sidout->num_auths = 0;
+ q = end;
+ if (*q != '-') {
+ /* Just id_auth, no subauths */
+ goto done;
+ }
+
+ q++;
+
+ while (true) {
+ if (!isdigit((unsigned char)*q)) {
+ goto format_error;
+ }
+ while (q[0] == '0' && isdigit((unsigned char)q[1])) {
+ /*
+ * strtoull will think this is octal, which is not how
+ * SIDs work! So let's walk along until there are no
+ * leading zeros (or a single zero).
+ */
+ q++;
+ }
+ conv = smb_strtoull(q, &end, 0, &error, SMB_STR_STANDARD);
+ if (conv > UINT32_MAX || error != 0 || end - q > 12) {
+ /*
+ * This sub-auth is greater than 4294967295,
+ * and hence invalid. Windows will treat it as
+ * 4294967295, while we prefer to refuse (old
+ * versions of Samba will wrap, arriving at
+ * another number altogether).
+ */
+ DBG_NOTICE("bad sub-auth in %s\n", sidstr);
+ goto format_error;
+ }
+
+ if (!sid_append_rid(sidout, conv)) {
+ DEBUG(3, ("Too many sid auths in %s\n", sidstr));
+ return false;
+ }
+
+ q = end;
+ if (*q != '-') {
+ break;
+ }
+ q += 1;
+ }
+done:
+ if (endp != NULL) {
+ *endp = q;
+ }
+ return true;
+
+format_error:
+ DEBUG(3, ("string_to_sid: SID %s is not in a valid format\n", sidstr));
+ return false;
+}
+
+bool string_to_sid(struct dom_sid *sidout, const char *sidstr)
+{
+ return dom_sid_parse(sidstr, sidout);
+}
+
+bool dom_sid_parse(const char *sidstr, struct dom_sid *ret)
+{
+ return dom_sid_parse_endp(sidstr, ret, NULL);
+}
+
+/*
+ convert a string to a dom_sid, returning a talloc'd dom_sid
+*/
+struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr)
+{
+ struct dom_sid *ret;
+ ret = talloc(mem_ctx, struct dom_sid);
+ if (!ret) {
+ return NULL;
+ }
+ if (!dom_sid_parse(sidstr, ret)) {
+ talloc_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+/*
+ convert a string to a dom_sid, returning a talloc'd dom_sid
+*/
+struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid)
+{
+ char p[sid->length+1];
+ memcpy(p, sid->data, sid->length);
+ p[sid->length] = '\0';
+ return dom_sid_parse_talloc(mem_ctx, p);
+}
+
+/*
+ copy a dom_sid structure
+*/
+struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid)
+{
+ struct dom_sid *ret;
+
+ if (!dom_sid) {
+ return NULL;
+ }
+
+ ret = talloc(mem_ctx, struct dom_sid);
+ if (!ret) {
+ return NULL;
+ }
+ sid_copy(ret, dom_sid);
+
+ return ret;
+}
+
+/*
+ add a rid to a domain dom_sid to make a full dom_sid. This function
+ returns a new sid in the supplied memory context
+*/
+struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ uint32_t rid)
+{
+ struct dom_sid *sid;
+
+ sid = dom_sid_dup(mem_ctx, domain_sid);
+ if (!sid) return NULL;
+
+ if (!sid_append_rid(sid, rid)) {
+ talloc_free(sid);
+ return NULL;
+ }
+
+ return sid;
+}
+
+/*
+ Split up a SID into its domain and RID part
+*/
+NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **domain, uint32_t *rid)
+{
+ if (sid->num_auths == 0) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (domain) {
+ if (!(*domain = dom_sid_dup(mem_ctx, sid))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*domain)->num_auths -= 1;
+ }
+
+ if (rid) {
+ *rid = sid->sub_auths[sid->num_auths - 1];
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ return true if the 2nd sid is in the domain given by the first sid
+*/
+bool dom_sid_in_domain(const struct dom_sid *domain_sid,
+ const struct dom_sid *sid)
+{
+ int i;
+
+ if (!domain_sid || !sid) {
+ return false;
+ }
+
+ if (sid->num_auths < 2) {
+ return false;
+ }
+
+ if (domain_sid->num_auths != (sid->num_auths - 1)) {
+ return false;
+ }
+
+ for (i = domain_sid->num_auths-1; i >= 0; --i) {
+ if (domain_sid->sub_auths[i] != sid->sub_auths[i]) {
+ return false;
+ }
+ }
+
+ return dom_sid_compare_auth(domain_sid, sid) == 0;
+}
+
+bool dom_sid_has_account_domain(const struct dom_sid *sid)
+{
+ if (sid == NULL) {
+ return false;
+ }
+
+ if (sid->sid_rev_num != 1) {
+ return false;
+ }
+ if (sid->num_auths != 5) {
+ return false;
+ }
+ if (sid->id_auth[5] != 5) {
+ return false;
+ }
+ if (sid->id_auth[4] != 0) {
+ return false;
+ }
+ if (sid->id_auth[3] != 0) {
+ return false;
+ }
+ if (sid->id_auth[2] != 0) {
+ return false;
+ }
+ if (sid->id_auth[1] != 0) {
+ return false;
+ }
+ if (sid->id_auth[0] != 0) {
+ return false;
+ }
+ if (sid->sub_auths[0] != 21) {
+ return false;
+ }
+
+ return true;
+}
+
+bool dom_sid_is_valid_account_domain(const struct dom_sid *sid)
+{
+ /*
+ * We expect S-1-5-21-9-8-7, but we don't
+ * allow S-1-5-21-0-0-0 as this is used
+ * for claims and compound identities.
+ *
+ * With this structure:
+ *
+ * struct dom_sid {
+ * uint8_t sid_rev_num;
+ * int8_t num_auths; [range(0,15)]
+ * uint8_t id_auth[6];
+ * uint32_t sub_auths[15];
+ * }
+ *
+ * S-1-5-21-9-8-7 looks like this:
+ * {1, 4, {0,0,0,0,0,5}, {21,9,8,7,0,0,0,0,0,0,0,0,0,0,0}};
+ */
+ if (sid == NULL) {
+ return false;
+ }
+
+ if (sid->sid_rev_num != 1) {
+ return false;
+ }
+ if (sid->num_auths != 4) {
+ return false;
+ }
+ if (sid->id_auth[5] != 5) {
+ return false;
+ }
+ if (sid->id_auth[4] != 0) {
+ return false;
+ }
+ if (sid->id_auth[3] != 0) {
+ return false;
+ }
+ if (sid->id_auth[2] != 0) {
+ return false;
+ }
+ if (sid->id_auth[1] != 0) {
+ return false;
+ }
+ if (sid->id_auth[0] != 0) {
+ return false;
+ }
+ if (sid->sub_auths[0] != 21) {
+ return false;
+ }
+ if (sid->sub_auths[1] == 0) {
+ return false;
+ }
+ if (sid->sub_auths[2] == 0) {
+ return false;
+ }
+ if (sid->sub_auths[3] == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ Convert a dom_sid to a string, printing into a buffer. Return the
+ string length. If it overflows, return the string length that would
+ result (buflen needs to be +1 for the terminating 0).
+*/
+static int dom_sid_string_buf(const struct dom_sid *sid, char *buf, int buflen)
+{
+ int i, ofs, ret;
+ uint64_t ia;
+
+ if (!sid) {
+ return strlcpy(buf, "(NULL SID)", buflen);
+ }
+
+ ia = ((uint64_t)sid->id_auth[5]) +
+ ((uint64_t)sid->id_auth[4] << 8 ) +
+ ((uint64_t)sid->id_auth[3] << 16) +
+ ((uint64_t)sid->id_auth[2] << 24) +
+ ((uint64_t)sid->id_auth[1] << 32) +
+ ((uint64_t)sid->id_auth[0] << 40);
+
+ ret = snprintf(buf, buflen, "S-%"PRIu8"-", sid->sid_rev_num);
+ if (ret < 0) {
+ return ret;
+ }
+ ofs = ret;
+
+ if (ia >= UINT32_MAX) {
+ ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "0x%"PRIx64, ia);
+ } else {
+ ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "%"PRIu64, ia);
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ ofs += ret;
+
+ for (i = 0; i < sid->num_auths; i++) {
+ ret = snprintf(
+ buf+ofs,
+ MAX(buflen-ofs, 0),
+ "-%"PRIu32,
+ sid->sub_auths[i]);
+ if (ret < 0) {
+ return ret;
+ }
+ ofs += ret;
+ }
+ return ofs;
+}
+
+/*
+ convert a dom_sid to a string
+*/
+char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid)
+{
+ char buf[DOM_SID_STR_BUFLEN];
+ char *result;
+ int len;
+
+ len = dom_sid_string_buf(sid, buf, sizeof(buf));
+
+ if ((len < 0) || (len+1 > sizeof(buf))) {
+ return talloc_strdup(mem_ctx, "(SID ERR)");
+ }
+
+ /*
+ * Avoid calling strlen (via talloc_strdup), we already have
+ * the length
+ */
+ result = (char *)talloc_memdup(mem_ctx, buf, len+1);
+ if (result == NULL) {
+ return NULL;
+ }
+
+ /*
+ * beautify the talloc_report output
+ */
+ talloc_set_name_const(result, result);
+ return result;
+}
+
+char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst)
+{
+ int ret;
+ ret = dom_sid_string_buf(sid, dst->buf, sizeof(dst->buf));
+ if ((ret < 0) || (ret >= sizeof(dst->buf))) {
+ strlcpy(dst->buf, "(INVALID SID)", sizeof(dst->buf));
+ }
+ return dst->buf;
+}
diff --git a/libcli/security/dom_sid.h b/libcli/security/dom_sid.h
new file mode 100644
index 0000000..343001e
--- /dev/null
+++ b/libcli/security/dom_sid.h
@@ -0,0 +1,155 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) Stefan (metze) Metzmacher 2002-2004
+ Copyright (C) Andrew Tridgell 1992-2004
+ Copyright (C) Jeremy Allison 1999
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 _DOM_SID_H_
+#define _DOM_SID_H_
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+#include "librpc/gen_ndr/security.h"
+
+/* Some well-known SIDs */
+extern const struct dom_sid global_sid_World_Domain;
+extern const struct dom_sid global_sid_World;
+extern const struct dom_sid global_sid_Local_Authority;
+extern const struct dom_sid global_sid_Creator_Owner_Domain;
+extern const struct dom_sid global_sid_NT_Authority;
+extern const struct dom_sid global_sid_Enterprise_DCs;
+extern const struct dom_sid global_sid_System;
+extern const struct dom_sid global_sid_NULL;
+extern const struct dom_sid global_sid_Self;
+extern const struct dom_sid global_sid_Authenticated_Users;
+extern const struct dom_sid global_sid_Network;
+extern const struct dom_sid global_sid_Asserted_Identity;
+extern const struct dom_sid global_sid_Asserted_Identity_Service;
+extern const struct dom_sid global_sid_Asserted_Identity_Authentication_Authority;
+extern const struct dom_sid global_sid_Creator_Owner;
+extern const struct dom_sid global_sid_Creator_Group;
+extern const struct dom_sid global_sid_Owner_Rights;
+extern const struct dom_sid global_sid_Anonymous;
+extern const struct dom_sid global_sid_Compounded_Authentication;
+extern const struct dom_sid global_sid_Claims_Valid;
+extern const struct dom_sid global_sid_Builtin;
+extern const struct dom_sid global_sid_Builtin_Administrators;
+extern const struct dom_sid global_sid_Builtin_Users;
+extern const struct dom_sid global_sid_Builtin_Guests;
+extern const struct dom_sid global_sid_Builtin_Power_Users;
+extern const struct dom_sid global_sid_Builtin_Account_Operators;
+extern const struct dom_sid global_sid_Builtin_Server_Operators;
+extern const struct dom_sid global_sid_Builtin_Print_Operators;
+extern const struct dom_sid global_sid_Builtin_Backup_Operators;
+extern const struct dom_sid global_sid_Builtin_Replicator;
+extern const struct dom_sid global_sid_Builtin_PreWin2kAccess;
+extern const struct dom_sid global_sid_Unix_Users;
+extern const struct dom_sid global_sid_Unix_Groups;
+extern const struct dom_sid global_sid_Unix_NFS;
+extern const struct dom_sid global_sid_Unix_NFS_Users;
+extern const struct dom_sid global_sid_Unix_NFS_Groups;
+extern const struct dom_sid global_sid_Unix_NFS_Mode;
+extern const struct dom_sid global_sid_Unix_NFS_Other;
+extern const struct dom_sid global_sid_Samba_SMB3;
+
+extern const struct dom_sid global_sid_Samba_NPA_Flags;
+#define SAMBA_NPA_FLAGS_NEED_IDLE 1
+#define SAMBA_NPA_FLAGS_WINBIND_OFF 2
+
+struct auth_SidAttr;
+enum lsa_SidType;
+
+NTSTATUS dom_sid_lookup_predefined_name(const char *name,
+ const struct dom_sid **sid,
+ enum lsa_SidType *type,
+ const struct dom_sid **authority_sid,
+ const char **authority_name);
+NTSTATUS dom_sid_lookup_predefined_sid(const struct dom_sid *sid,
+ const char **name,
+ enum lsa_SidType *type,
+ const struct dom_sid **authority_sid,
+ const char **authority_name);
+bool dom_sid_lookup_is_predefined_domain(const char *domain);
+
+int dom_sid_compare_auth(const struct dom_sid *sid1,
+ const struct dom_sid *sid2);
+int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2);
+int dom_sid_compare_domain(const struct dom_sid *sid1,
+ const struct dom_sid *sid2);
+bool dom_sid_equal(const struct dom_sid *sid1, const struct dom_sid *sid2);
+bool sid_append_rid(struct dom_sid *sid, uint32_t rid);
+bool string_to_sid(struct dom_sid *sidout, const char *sidstr);
+bool dom_sid_parse_endp(const char *sidstr,struct dom_sid *sidout,
+ const char **endp);
+bool dom_sid_parse(const char *sidstr, struct dom_sid *ret);
+struct dom_sid *dom_sid_parse_talloc(TALLOC_CTX *mem_ctx, const char *sidstr);
+struct dom_sid *dom_sid_parse_length(TALLOC_CTX *mem_ctx, const DATA_BLOB *sid);
+struct dom_sid *dom_sid_dup(TALLOC_CTX *mem_ctx, const struct dom_sid *dom_sid);
+struct dom_sid *dom_sid_add_rid(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *domain_sid,
+ uint32_t rid);
+NTSTATUS dom_sid_split_rid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **domain, uint32_t *rid);
+bool dom_sid_in_domain(const struct dom_sid *domain_sid,
+ const struct dom_sid *sid);
+bool dom_sid_has_account_domain(const struct dom_sid *sid);
+bool dom_sid_is_valid_account_domain(const struct dom_sid *sid);
+
+#define DOM_SID_STR_BUFLEN (15*11+25)
+char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid);
+
+struct dom_sid_buf { char buf[DOM_SID_STR_BUFLEN]; };
+char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst);
+
+const char *sid_type_lookup(uint32_t sid_type);
+const struct security_token *get_system_token(void);
+bool sid_compose(struct dom_sid *dst, const struct dom_sid *domain_sid, uint32_t rid);
+bool sid_split_rid(struct dom_sid *sid, uint32_t *rid);
+bool sid_peek_rid(const struct dom_sid *sid, uint32_t *rid);
+bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid *sid, uint32_t *rid);
+void sid_copy(struct dom_sid *dst, const struct dom_sid *src);
+ssize_t sid_parse(const uint8_t *inbuf, size_t len, struct dom_sid *sid);
+NTSTATUS add_sid_to_array(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **sids, uint32_t *num);
+NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **sids, uint32_t *num_sids);
+NTSTATUS add_sid_to_array_attrs(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid, uint32_t attrs,
+ struct auth_SidAttr **sids, uint32_t *num);
+NTSTATUS add_sid_to_array_attrs_unique(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid, uint32_t attrs,
+ struct auth_SidAttr **sids, uint32_t *num_sids);
+void del_sid_from_array(const struct dom_sid *sid, struct dom_sid **sids,
+ uint32_t *num);
+bool add_rid_to_array_unique(TALLOC_CTX *mem_ctx,
+ uint32_t rid, uint32_t **pp_rids, size_t *p_num);
+bool is_null_sid(const struct dom_sid *sid);
+bool sids_contains_sid(const struct dom_sid *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid);
+bool sid_attrs_contains_sid(const struct auth_SidAttr *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid);
+bool sids_contains_sid_attrs(const struct auth_SidAttr *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid,
+ uint32_t attrs);
+
+#endif /*_DOM_SID_H_*/
diff --git a/libcli/security/object_tree.c b/libcli/security/object_tree.c
new file mode 100644
index 0000000..70b1ea0
--- /dev/null
+++ b/libcli/security/object_tree.c
@@ -0,0 +1,127 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security access checking routines
+
+ Copyright (C) Nadezhda Ivanova 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/>.
+*/
+
+/*
+ * Description: Contains data handler functions for
+ * the object tree that must be constructed to perform access checks.
+ * The object tree is an unbalanced tree of depth 3, indexed by
+ * object type guid. Perhaps a different data structure
+ * should be considered later to improve performance
+ *
+ * Author: Nadezhda Ivanova
+ */
+#include "replace.h"
+#include "libcli/security/security.h"
+#include "librpc/ndr/libndr.h"
+
+/* Adds a new node to the object tree. If attributeSecurityGUID is not zero and
+ * has already been added to the tree, the new node is added as a child of that node
+ * In all other cases as a child of the root
+ */
+
+bool insert_in_object_tree(TALLOC_CTX *mem_ctx,
+ const struct GUID *guid,
+ uint32_t init_access,
+ struct object_tree *root,
+ struct object_tree **new_node_out)
+{
+ struct object_tree *new_node;
+
+ if (!guid || GUID_all_zero(guid)){
+ return true;
+ }
+
+ if (!root) {
+ root = talloc_zero(mem_ctx, struct object_tree);
+ if (!root) {
+ return false;
+ }
+ new_node = root;
+ } else {
+ int i;
+
+ for (i = 0; i < root->num_of_children; i++) {
+ if (GUID_equal(&root->children[i].guid, guid)) {
+ new_node = &root->children[i];
+ new_node->remaining_access |= init_access;
+ *new_node_out = new_node;
+ return true;
+ }
+ }
+
+ root->children = talloc_realloc(mem_ctx, root->children,
+ struct object_tree,
+ root->num_of_children + 1);
+ if (!root->children) {
+ return false;
+ }
+ new_node = &root->children[root->num_of_children];
+ root->num_of_children++;
+ }
+
+ new_node->children = NULL;
+ new_node->guid = *guid;
+ new_node->remaining_access = init_access;
+ new_node->num_of_children = 0;
+
+ *new_node_out = new_node;
+ return true;
+}
+
+/* search by GUID */
+struct object_tree *get_object_tree_by_GUID(struct object_tree *root,
+ const struct GUID *guid)
+{
+ struct object_tree *result = NULL;
+ int i;
+
+ if (!root || GUID_equal(&root->guid, guid)) {
+ result = root;
+ return result;
+ }
+ for (i = 0; i < root->num_of_children; i++) {
+ if ((result = get_object_tree_by_GUID(&root->children[i], guid)))
+ break;
+ }
+ return result;
+}
+
+/**
+ * @brief Modify the tree to mark specified access rights as granted
+ *
+ * This function will modify the root and the child of the tree pointed by
+ * root, so that for each tree element the bits set in access_mask are
+ * marked as granted.
+ *
+ * @param[in] root An object_tree structure that we want to modify
+ *
+ * @param[in] access_mask A bitfield of access right that we want to mark as
+ * granted in the whole tree.
+ */
+void object_tree_modify_access(struct object_tree *root,
+ uint32_t access_mask)
+{
+ int i;
+ root->remaining_access &= ~access_mask;
+ for (i = 0; i < root->num_of_children; i++) {
+ object_tree_modify_access(&root->children[i], access_mask);
+ }
+}
diff --git a/libcli/security/privileges.c b/libcli/security/privileges.c
new file mode 100644
index 0000000..33debdc
--- /dev/null
+++ b/libcli/security/privileges.c
@@ -0,0 +1,498 @@
+/*
+ Unix SMB/CIFS implementation.
+ Privileges handling functions
+ Copyright (C) Jean François Micouleau 1998-2001
+ Copyright (C) Simo Sorce 2002-2003
+ Copyright (C) Gerald (Jerry) Carter 2005
+ Copyright (C) Michael Adam 2007
+ Copyright (C) Andrew Bartlett 2010
+ 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/>.
+*/
+
+/*
+ * Basic privileges functions (mask-operations and conversion
+ * functions between the different formats (se_priv, privset, luid)
+ * moved here * from lib/privileges.c to minimize linker deps.
+ *
+ * generally SID- and LUID-related code is left in lib/privileges.c
+ *
+ * some extra functions to hide privs array from lib/privileges.c
+ */
+
+#include "replace.h"
+#include "libcli/security/privileges.h"
+#include "libcli/security/privileges_private.h"
+#include "librpc/gen_ndr/security.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/debug.h"
+
+/* The use of strcasecmp here is safe, all the comparison strings are ASCII */
+#undef strcasecmp
+
+#define NUM_SHORT_LIST_PRIVS 9
+
+static const struct {
+ enum sec_privilege luid;
+ uint64_t privilege_mask;
+ const char *name;
+ const char *description;
+} privs[] = {
+
+ {SEC_PRIV_MACHINE_ACCOUNT, SEC_PRIV_MACHINE_ACCOUNT_BIT, "SeMachineAccountPrivilege", "Add machines to domain"},
+ {SEC_PRIV_TAKE_OWNERSHIP, SEC_PRIV_TAKE_OWNERSHIP_BIT, "SeTakeOwnershipPrivilege", "Take ownership of files or other objects"},
+ {SEC_PRIV_BACKUP, SEC_PRIV_BACKUP_BIT, "SeBackupPrivilege", "Back up files and directories"},
+ {SEC_PRIV_RESTORE, SEC_PRIV_RESTORE_BIT, "SeRestorePrivilege", "Restore files and directories"},
+ {SEC_PRIV_REMOTE_SHUTDOWN, SEC_PRIV_REMOTE_SHUTDOWN_BIT, "SeRemoteShutdownPrivilege", "Force shutdown from a remote system"},
+
+ {SEC_PRIV_PRINT_OPERATOR, SEC_PRIV_PRINT_OPERATOR_BIT, "SePrintOperatorPrivilege", "Manage printers"},
+ {SEC_PRIV_ADD_USERS, SEC_PRIV_ADD_USERS_BIT, "SeAddUsersPrivilege", "Add users and groups to the domain"},
+ {SEC_PRIV_DISK_OPERATOR, SEC_PRIV_DISK_OPERATOR_BIT, "SeDiskOperatorPrivilege", "Manage disk shares"},
+ {SEC_PRIV_SECURITY, SEC_PRIV_SECURITY_BIT, "SeSecurityPrivilege", "System security"},
+
+
+ /* The list from here on is not displayed in the code from
+ * source3, and is after index NUM_SHORT_LIST_PRIVS for that
+ * reason */
+
+ {SEC_PRIV_SYSTEMTIME,
+ SEC_PRIV_SYSTEMTIME_BIT,
+ "SeSystemtimePrivilege",
+ "Set the system clock"},
+
+ {SEC_PRIV_SHUTDOWN,
+ SEC_PRIV_SHUTDOWN_BIT,
+ "SeShutdownPrivilege",
+ "Shutdown the system"},
+
+ {SEC_PRIV_DEBUG,
+ SEC_PRIV_DEBUG_BIT,
+ "SeDebugPrivilege",
+ "Debug processes"},
+
+ {SEC_PRIV_SYSTEM_ENVIRONMENT,
+ SEC_PRIV_SYSTEM_ENVIRONMENT_BIT,
+ "SeSystemEnvironmentPrivilege",
+ "Modify system environment"},
+
+ {SEC_PRIV_SYSTEM_PROFILE,
+ SEC_PRIV_SYSTEM_PROFILE_BIT,
+ "SeSystemProfilePrivilege",
+ "Profile the system"},
+
+ {SEC_PRIV_PROFILE_SINGLE_PROCESS,
+ SEC_PRIV_PROFILE_SINGLE_PROCESS_BIT,
+ "SeProfileSingleProcessPrivilege",
+ "Profile one process"},
+
+ {SEC_PRIV_INCREASE_BASE_PRIORITY,
+ SEC_PRIV_INCREASE_BASE_PRIORITY_BIT,
+ "SeIncreaseBasePriorityPrivilege",
+ "Increase base priority"},
+
+ {SEC_PRIV_LOAD_DRIVER,
+ SEC_PRIV_LOAD_DRIVER_BIT,
+ "SeLoadDriverPrivilege",
+ "Load drivers"},
+
+ {SEC_PRIV_CREATE_PAGEFILE,
+ SEC_PRIV_CREATE_PAGEFILE_BIT,
+ "SeCreatePagefilePrivilege",
+ "Create page files"},
+
+ {SEC_PRIV_INCREASE_QUOTA,
+ SEC_PRIV_INCREASE_QUOTA_BIT,
+ "SeIncreaseQuotaPrivilege",
+ "Increase quota"},
+
+ {SEC_PRIV_CHANGE_NOTIFY,
+ SEC_PRIV_CHANGE_NOTIFY_BIT,
+ "SeChangeNotifyPrivilege",
+ "Register for change notify"},
+
+ {SEC_PRIV_UNDOCK,
+ SEC_PRIV_UNDOCK_BIT,
+ "SeUndockPrivilege",
+ "Undock devices"},
+
+ {SEC_PRIV_MANAGE_VOLUME,
+ SEC_PRIV_MANAGE_VOLUME_BIT,
+ "SeManageVolumePrivilege",
+ "Manage system volumes"},
+
+ {SEC_PRIV_IMPERSONATE,
+ SEC_PRIV_IMPERSONATE_BIT,
+ "SeImpersonatePrivilege",
+ "Impersonate users"},
+
+ {SEC_PRIV_CREATE_GLOBAL,
+ SEC_PRIV_CREATE_GLOBAL_BIT,
+ "SeCreateGlobalPrivilege",
+ "Create global"},
+
+ {SEC_PRIV_ENABLE_DELEGATION,
+ SEC_PRIV_ENABLE_DELEGATION_BIT,
+ "SeEnableDelegationPrivilege",
+ "Enable Delegation"},
+};
+
+/* These are rights, not privileges, and should not be confused. The
+ * names are very similar, and they are quite similar in behaviour,
+ * but they are not to be enumerated as a system-wide list or have an
+ * LUID value */
+static const struct {
+ uint32_t right_mask;
+ const char *name;
+ const char *description;
+} rights[] = {
+ {LSA_POLICY_MODE_INTERACTIVE,
+ "SeInteractiveLogonRight",
+ "Interactive logon"},
+
+ {LSA_POLICY_MODE_NETWORK,
+ "SeNetworkLogonRight",
+ "Network logon"},
+
+ {LSA_POLICY_MODE_REMOTE_INTERACTIVE,
+ "SeRemoteInteractiveLogonRight",
+ "Remote Interactive logon"}
+};
+
+/*
+ return a privilege mask given a privilege id
+*/
+uint64_t sec_privilege_mask(enum sec_privilege privilege)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(privs);i++) {
+ if (privs[i].luid == privilege) {
+ return privs[i].privilege_mask;
+ }
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ put all valid privileges into a mask
+****************************************************************************/
+
+void se_priv_put_all_privileges(uint64_t *privilege_mask)
+{
+ size_t i;
+
+ *privilege_mask = 0;
+ for ( i=0; i<ARRAY_SIZE(privs); i++ ) {
+ *privilege_mask |= privs[i].privilege_mask;
+ }
+}
+
+/*********************************************************************
+ Lookup the uint64_t bitmask value for a privilege name
+*********************************************************************/
+
+bool se_priv_from_name( const char *name, uint64_t *privilege_mask )
+{
+ size_t i;
+ for ( i=0; i<ARRAY_SIZE(privs); i++ ) {
+ if ( strequal( privs[i].name, name ) ) {
+ *privilege_mask = privs[i].privilege_mask;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const char* get_privilege_dispname( const char *name )
+{
+ size_t i;
+
+ if (!name) {
+ return NULL;
+ }
+
+ for ( i=0; i<ARRAY_SIZE(privs); i++ ) {
+ if ( strequal( privs[i].name, name ) ) {
+ return privs[i].description;
+ }
+ }
+
+ return NULL;
+}
+
+/*******************************************************************
+ return the number of elements in the 'short' privilege array (traditional source3 behaviour)
+*******************************************************************/
+
+int num_privileges_in_short_list( void )
+{
+ return NUM_SHORT_LIST_PRIVS;
+}
+
+/****************************************************************************
+ add a privilege to a privilege array
+ ****************************************************************************/
+
+static bool privilege_set_add(PRIVILEGE_SET *priv_set, struct lsa_LUIDAttribute set)
+{
+ struct lsa_LUIDAttribute *new_set;
+
+ /* we can allocate memory to add the new privilege */
+
+ new_set = talloc_realloc(priv_set->mem_ctx, priv_set->set, struct lsa_LUIDAttribute, priv_set->count + 1);
+ if ( !new_set ) {
+ DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
+ return false;
+ }
+
+ new_set[priv_set->count].luid.high = set.luid.high;
+ new_set[priv_set->count].luid.low = set.luid.low;
+ new_set[priv_set->count].attribute = set.attribute;
+
+ priv_set->count++;
+ priv_set->set = new_set;
+
+ return true;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t privilege_mask )
+{
+ size_t i;
+ struct lsa_LUIDAttribute luid;
+
+ luid.attribute = 0;
+ luid.luid.high = 0;
+
+ for ( i=0; i<ARRAY_SIZE(privs); i++ ) {
+ if ((privilege_mask & privs[i].privilege_mask) == 0)
+ continue;
+
+ luid.luid.high = 0;
+ luid.luid.low = privs[i].luid;
+
+ if ( !privilege_set_add( set, luid ) )
+ return false;
+ }
+
+ return true;
+}
+
+/*******************************************************************
+*******************************************************************/
+
+bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset )
+{
+ uint32_t i;
+
+ ZERO_STRUCTP( privilege_mask );
+
+ for ( i=0; i<privset->count; i++ ) {
+ uint64_t r;
+
+ /* sanity check for invalid privilege. we really
+ only care about the low 32 bits */
+
+ if ( privset->set[i].luid.high != 0 )
+ return false;
+
+ r = sec_privilege_mask(privset->set[i].luid.low);
+ if (r) {
+ *privilege_mask |= r;
+ }
+ }
+
+ return true;
+}
+
+/*
+ map a privilege id to the wire string constant
+*/
+const char *sec_privilege_name(enum sec_privilege privilege)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(privs);i++) {
+ if (privs[i].luid == privilege) {
+ return privs[i].name;
+ }
+ }
+ return NULL;
+}
+
+/*
+ map a privilege id to a privilege display name. Return NULL if not found
+
+ TODO: this should use language mappings
+*/
+const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(privs);i++) {
+ if (privs[i].luid == privilege) {
+ return privs[i].description;
+ }
+ }
+ return NULL;
+}
+
+/*
+ map a privilege name to a privilege id. Return SEC_PRIV_INVALID if not found
+*/
+enum sec_privilege sec_privilege_id(const char *name)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(privs);i++) {
+ if (strcasecmp(privs[i].name, name) == 0) {
+ return privs[i].luid;
+ }
+ }
+ return SEC_PRIV_INVALID;
+}
+
+/*
+ map a 'right' name to it's bitmap value. Return 0 if not found
+*/
+uint32_t sec_right_bit(const char *name)
+{
+ size_t i;
+ for (i=0;i<ARRAY_SIZE(rights);i++) {
+ if (strcasecmp(rights[i].name, name) == 0) {
+ return rights[i].right_mask;
+ }
+ }
+ return 0;
+}
+
+/*
+ assist in walking the table of privileges - return the LUID (low 32 bits) by index
+*/
+enum sec_privilege sec_privilege_from_index(int idx)
+{
+ if (idx >= 0 && (unsigned)idx<ARRAY_SIZE(privs)) {
+ return privs[idx].luid;
+ }
+ return SEC_PRIV_INVALID;
+}
+
+/*
+ assist in walking the table of privileges - return the string constant by index
+*/
+const char *sec_privilege_name_from_index(int idx)
+{
+ if (idx >= 0 && (unsigned)idx<ARRAY_SIZE(privs)) {
+ return privs[idx].name;
+ }
+ return NULL;
+}
+
+
+
+/*
+ return true if a security_token has a particular privilege bit set
+*/
+bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege)
+{
+ uint64_t mask;
+
+ if (!token) {
+ return false;
+ }
+
+ mask = sec_privilege_mask(privilege);
+ if (mask == 0) {
+ return false;
+ }
+
+ if (token->privilege_mask & mask) {
+ return true;
+ }
+ return false;
+}
+
+bool security_token_system_privilege(const struct security_token *token)
+{
+ if (token == NULL) {
+ return false;
+ }
+
+ if (token->privilege_mask == (uint64_t)~0) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ set a bit in the privilege mask
+*/
+void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege)
+{
+ /* Relies on the fact that an invalid privilege will return 0, so won't change this */
+ token->privilege_mask |= sec_privilege_mask(privilege);
+}
+
+/*
+ set a bit in the rights mask
+*/
+void security_token_set_right_bit(struct security_token *token, uint32_t right_bit)
+{
+ token->rights_mask |= right_bit;
+}
+
+char *security_token_debug_privileges(TALLOC_CTX *mem_ctx,
+ const struct security_token *token)
+{
+ char *s = NULL;
+
+ s = talloc_asprintf(mem_ctx,
+ " Privileges (0x%16" PRIX64 "):\n",
+ token->privilege_mask);
+
+ if (token->privilege_mask) {
+ size_t idx = 0;
+ size_t i = 0;
+ for (idx = 0; idx<ARRAY_SIZE(privs); idx++) {
+ if (token->privilege_mask & privs[idx].privilege_mask) {
+ talloc_asprintf_addbuf(
+ &s,
+ " Privilege[%3zu]: %s\n",
+ i++,
+ privs[idx].name);
+ }
+ }
+ }
+
+ talloc_asprintf_addbuf(&s,
+ " Rights (0x%16" PRIX32 "):\n",
+ token->rights_mask);
+
+ if (token->rights_mask) {
+ size_t idx = 0;
+ size_t i = 0;
+ for (idx = 0; idx<ARRAY_SIZE(rights); idx++) {
+ if (token->rights_mask & rights[idx].right_mask) {
+ talloc_asprintf_addbuf(&s,
+ " Right[%3zu]: %s\n",
+ i++,
+ rights[idx].name);
+ }
+ }
+ }
+
+ return s;
+}
diff --git a/libcli/security/privileges.h b/libcli/security/privileges.h
new file mode 100644
index 0000000..e9dab11
--- /dev/null
+++ b/libcli/security/privileges.h
@@ -0,0 +1,116 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ Copyright (C) Andrew Tridgell 1992-1997
+ Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+ Copyright (C) Paul Ashton 1997
+ Copyright (C) Simo Sorce 2003
+ Copyright (C) Gerald (Jerry) Carter 2005
+ 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/>.
+*/
+
+#ifndef PRIVILEGES_H
+#define PRIVILEGES_H
+
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "../librpc/gen_ndr/lsa.h"
+#include "../librpc/gen_ndr/security.h"
+
+/* common privilege bitmask defines */
+
+#define SE_ALL_PRIVS (uint64_t)-1
+
+/*
+ * These are used in Lsa replies (srv_lsa_nt.c)
+ */
+
+typedef struct {
+ TALLOC_CTX *mem_ctx;
+ bool ext_ctx;
+ uint32_t count;
+ uint32_t control;
+ struct lsa_LUIDAttribute *set;
+} PRIVILEGE_SET;
+
+const char* get_privilege_dispname( const char *name );
+
+/*******************************************************************
+ return the number of elements in the 'short' privilege array (traditional source3 behaviour)
+*******************************************************************/
+
+int num_privileges_in_short_list( void );
+
+/*
+ map a privilege id to the wire string constant
+*/
+const char *sec_privilege_name(enum sec_privilege privilege);
+
+/*
+ map a privilege id to a privilege display name. Return NULL if not found
+
+ TODO: this should use language mappings
+*/
+const char *sec_privilege_display_name(enum sec_privilege privilege, uint16_t *language);
+
+/*
+ map a privilege name to a privilege id. Return -1 if not found
+*/
+enum sec_privilege sec_privilege_id(const char *name);
+
+/*
+ map a 'right' name to it's bitmap value. Return 0 if not found
+*/
+uint32_t sec_right_bit(const char *name);
+
+/*
+ assist in walking the table of privileges - return the LUID (low 32 bits) by index
+*/
+enum sec_privilege sec_privilege_from_index(int idx);
+
+/*
+ assist in walking the table of privileges - return the string constant by index
+*/
+const char *sec_privilege_name_from_index(int idx);
+
+/*
+ return true if a security_token has a particular privilege bit set
+*/
+bool security_token_has_privilege(const struct security_token *token, enum sec_privilege privilege);
+
+
+/**
+ * @brief Check if the security token has system privileges.
+ *
+ * @param[in] token The token to check.
+ *
+ * @return True if the token has system privileges, false if not.
+ */
+bool security_token_system_privilege(const struct security_token *token);
+
+/*
+ set a bit in the privilege mask
+*/
+void security_token_set_privilege(struct security_token *token, enum sec_privilege privilege);
+/*
+ set a bit in the rights mask
+*/
+void security_token_set_right_bit(struct security_token *token, uint32_t right_bit);
+
+char *security_token_debug_privileges(TALLOC_CTX *mem_ctx,
+ const struct security_token *token);
+
+#endif /* PRIVILEGES_H */
diff --git a/libcli/security/privileges_private.h b/libcli/security/privileges_private.h
new file mode 100644
index 0000000..eec5ba3
--- /dev/null
+++ b/libcli/security/privileges_private.h
@@ -0,0 +1,41 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup
+ 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/>.
+*/
+
+/*********************************************************************
+ Lookup the privilege mask for a privilege name
+*********************************************************************/
+bool se_priv_from_name( const char *name, uint64_t *privilege_mask );
+
+/***************************************************************************
+ return a privilege mask given a privilege id
+****************************************************************************/
+uint64_t sec_privilege_mask(enum sec_privilege privilege);
+
+/***************************************************************************
+ put all privileges into a mask
+****************************************************************************/
+
+void se_priv_put_all_privileges(uint64_t *privilege_mask);
+
+/****************************************************************************
+ Convert PRIVILEGE_SET to a privilege bitmap and back again
+****************************************************************************/
+
+bool se_priv_to_privilege_set( PRIVILEGE_SET *set, uint64_t privilege_mask );
+bool privilege_set_to_se_priv( uint64_t *privilege_mask, struct lsa_PrivilegeSet *privset );
diff --git a/libcli/security/pysecurity.c b/libcli/security/pysecurity.c
new file mode 100644
index 0000000..037d43c
--- /dev/null
+++ b/libcli/security/pysecurity.c
@@ -0,0 +1,96 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 "lib/replace/system/python.h"
+#include "python/py3compat.h"
+#include "includes.h"
+#include "python/modules.h"
+#include "libcli/util/pyerrors.h"
+#include "libcli/security/security.h"
+#include "pytalloc.h"
+
+static PyObject *py_se_access_check(PyObject *module, PyObject *args, PyObject *kwargs)
+{
+ NTSTATUS nt_status;
+ const char * const kwnames[] = { "security_descriptor", "token", "access_desired", NULL };
+ PyObject *py_sec_desc = NULL;
+ PyObject *py_security_token = NULL;
+ struct security_descriptor *security_descriptor;
+ struct security_token *security_token;
+ unsigned int access_desired; /* This is an unsigned int, not uint32_t,
+ * because that's what we need for the
+ * python PyArg_ParseTupleAndKeywords */
+ uint32_t access_granted;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOI",
+ discard_const_p(char *, kwnames),
+ &py_sec_desc, &py_security_token, &access_desired)) {
+ return NULL;
+ }
+
+ security_descriptor = pytalloc_get_type(py_sec_desc, struct security_descriptor);
+ if (!security_descriptor) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected dcerpc.security.descriptor for security_descriptor argument got %s",
+ pytalloc_get_name(py_sec_desc));
+ return NULL;
+ }
+
+ security_token = pytalloc_get_type(py_security_token, struct security_token);
+ if (!security_token) {
+ PyErr_Format(PyExc_TypeError,
+ "Expected dcerpc.security.token for token argument, got %s",
+ pytalloc_get_name(py_sec_desc));
+ return NULL;
+ }
+
+ nt_status = se_access_check(security_descriptor, security_token, access_desired, &access_granted);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ PyErr_NTSTATUS_IS_ERR_RAISE(nt_status);
+ }
+
+ return PyLong_FromLong(access_granted);
+}
+
+static PyMethodDef py_security_methods[] = {
+ { "access_check", PY_DISCARD_FUNC_SIG(PyCFunction,
+ py_se_access_check),
+ METH_VARARGS|METH_KEYWORDS,
+ "access_check(security_descriptor, token, access_desired) -> access_granted. Raises NT_STATUS on error, including on access check failure, returns access granted bitmask"},
+ {0},
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "security",
+ .m_doc = "Security support.",
+ .m_size = -1,
+ .m_methods = py_security_methods,
+};
+
+MODULE_INIT_FUNC(security)
+{
+ PyObject *m;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ return m;
+}
diff --git a/libcli/security/sddl.c b/libcli/security/sddl.c
new file mode 100644
index 0000000..d1f7707
--- /dev/null
+++ b/libcli/security/sddl.c
@@ -0,0 +1,1341 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security descriptor description language functions
+
+ Copyright (C) Andrew Tridgell 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/debug.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "lib/util/smb_strtox.h"
+#include "libcli/security/sddl.h"
+#include "system/locale.h"
+#include "lib/util/util_str_hex.h"
+
+
+struct sddl_transition_state {
+ const struct dom_sid *machine_sid;
+ const struct dom_sid *domain_sid;
+ const struct dom_sid *forest_sid;
+};
+
+struct flag_map {
+ const char *name;
+ uint32_t flag;
+};
+
+static bool sddl_map_flag(
+ const struct flag_map *map,
+ const char *str,
+ size_t *plen,
+ uint32_t *pflag)
+{
+ while (map->name != NULL) {
+ size_t len = strlen(map->name);
+ int cmp = strncmp(map->name, str, len);
+
+ if (cmp == 0) {
+ *plen = len;
+ *pflag = map->flag;
+ return true;
+ }
+ map += 1;
+ }
+ return false;
+}
+
+/*
+ map a series of letter codes into a uint32_t
+*/
+static bool sddl_map_flags(const struct flag_map *map, const char *str,
+ uint32_t *pflags, size_t *plen,
+ bool unknown_flag_is_part_of_next_thing)
+{
+ const char *str0 = str;
+ if (plen != NULL) {
+ *plen = 0;
+ }
+ *pflags = 0;
+ while (str[0] != '\0' && isupper((unsigned char)str[0])) {
+ size_t len;
+ uint32_t flags;
+ bool found;
+
+ found = sddl_map_flag(map, str, &len, &flags);
+ if (!found) {
+ break;
+ }
+
+ *pflags |= flags;
+ if (plen != NULL) {
+ *plen += len;
+ }
+ str += len;
+ }
+ /*
+ * For ACL flags, unknown_flag_is_part_of_next_thing is set,
+ * and we expect some more stuff that isn't flags.
+ *
+ * For ACE flags, unknown_flag_is_part_of_next_thing is unset,
+ * and the flags have been tokenised into their own little
+ * string. We don't expect anything here, even whitespace.
+ */
+ if (*str == '\0' || unknown_flag_is_part_of_next_thing) {
+ return true;
+ }
+ DBG_WARNING("Unknown flag - '%s' in '%s'\n", str, str0);
+ return false;
+}
+
+
+/*
+ a mapping between the 2 letter SID codes and sid strings
+*/
+static const struct {
+ const char *code;
+ const char *sid;
+ uint32_t machine_rid;
+ uint32_t domain_rid;
+ uint32_t forest_rid;
+} sid_codes[] = {
+ { .code = "WD", .sid = SID_WORLD },
+
+ { .code = "CO", .sid = SID_CREATOR_OWNER },
+ { .code = "CG", .sid = SID_CREATOR_GROUP },
+ { .code = "OW", .sid = SID_OWNER_RIGHTS },
+
+ { .code = "NU", .sid = SID_NT_NETWORK },
+ { .code = "IU", .sid = SID_NT_INTERACTIVE },
+ { .code = "SU", .sid = SID_NT_SERVICE },
+ { .code = "AN", .sid = SID_NT_ANONYMOUS },
+ { .code = "ED", .sid = SID_NT_ENTERPRISE_DCS },
+ { .code = "PS", .sid = SID_NT_SELF },
+ { .code = "AU", .sid = SID_NT_AUTHENTICATED_USERS },
+ { .code = "RC", .sid = SID_NT_RESTRICTED },
+ { .code = "SY", .sid = SID_NT_SYSTEM },
+ { .code = "LS", .sid = SID_NT_LOCAL_SERVICE },
+ { .code = "NS", .sid = SID_NT_NETWORK_SERVICE },
+ { .code = "WR", .sid = SID_SECURITY_RESTRICTED_CODE },
+
+ { .code = "BA", .sid = SID_BUILTIN_ADMINISTRATORS },
+ { .code = "BU", .sid = SID_BUILTIN_USERS },
+ { .code = "BG", .sid = SID_BUILTIN_GUESTS },
+ { .code = "PU", .sid = SID_BUILTIN_POWER_USERS },
+ { .code = "AO", .sid = SID_BUILTIN_ACCOUNT_OPERATORS },
+ { .code = "SO", .sid = SID_BUILTIN_SERVER_OPERATORS },
+ { .code = "PO", .sid = SID_BUILTIN_PRINT_OPERATORS },
+ { .code = "BO", .sid = SID_BUILTIN_BACKUP_OPERATORS },
+ { .code = "RE", .sid = SID_BUILTIN_REPLICATOR },
+ { .code = "RU", .sid = SID_BUILTIN_PREW2K },
+ { .code = "RD", .sid = SID_BUILTIN_REMOTE_DESKTOP_USERS },
+ { .code = "NO", .sid = SID_BUILTIN_NETWORK_CONF_OPERATORS },
+
+ { .code = "MU", .sid = SID_BUILTIN_PERFMON_USERS },
+ { .code = "LU", .sid = SID_BUILTIN_PERFLOG_USERS },
+ { .code = "IS", .sid = SID_BUILTIN_IUSERS },
+ { .code = "CY", .sid = SID_BUILTIN_CRYPTO_OPERATORS },
+ { .code = "ER", .sid = SID_BUILTIN_EVENT_LOG_READERS },
+ { .code = "CD", .sid = SID_BUILTIN_CERT_SERV_DCOM_ACCESS },
+ { .code = "RA", .sid = SID_BUILTIN_RDS_REMOTE_ACCESS_SERVERS },
+ { .code = "ES", .sid = SID_BUILTIN_RDS_ENDPOINT_SERVERS },
+ { .code = "MS", .sid = SID_BUILTIN_RDS_MANAGEMENT_SERVERS },
+ { .code = "HA", .sid = SID_BUILTIN_HYPER_V_ADMINS },
+ { .code = "AA", .sid = SID_BUILTIN_ACCESS_CONTROL_ASSISTANCE_OPS },
+ { .code = "RM", .sid = SID_BUILTIN_REMOTE_MANAGEMENT_USERS },
+
+ { .code = "UD", .sid = SID_USER_MODE_DRIVERS },
+
+ { .code = "AC", .sid = SID_SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE },
+
+ { .code = "LW", .sid = SID_SECURITY_MANDATORY_LOW },
+ { .code = "ME", .sid = SID_SECURITY_MANDATORY_MEDIUM },
+ { .code = "MP", .sid = SID_SECURITY_MANDATORY_MEDIUM_PLUS },
+ { .code = "HI", .sid = SID_SECURITY_MANDATORY_HIGH },
+ { .code = "SI", .sid = SID_SECURITY_MANDATORY_SYSTEM },
+
+ { .code = "AS", .sid = SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY },
+ { .code = "SS", .sid = SID_SERVICE_ASSERTED_IDENTITY },
+
+ { .code = "RO", .forest_rid = DOMAIN_RID_ENTERPRISE_READONLY_DCS },
+
+ { .code = "LA", .machine_rid = DOMAIN_RID_ADMINISTRATOR },
+ { .code = "LG", .machine_rid = DOMAIN_RID_GUEST },
+
+ { .code = "DA", .domain_rid = DOMAIN_RID_ADMINS },
+ { .code = "DU", .domain_rid = DOMAIN_RID_USERS },
+ { .code = "DG", .domain_rid = DOMAIN_RID_GUESTS },
+ { .code = "DC", .domain_rid = DOMAIN_RID_DOMAIN_MEMBERS },
+ { .code = "DD", .domain_rid = DOMAIN_RID_DCS },
+ { .code = "CA", .domain_rid = DOMAIN_RID_CERT_ADMINS },
+ { .code = "SA", .forest_rid = DOMAIN_RID_SCHEMA_ADMINS },
+ { .code = "EA", .forest_rid = DOMAIN_RID_ENTERPRISE_ADMINS },
+ { .code = "PA", .domain_rid = DOMAIN_RID_POLICY_ADMINS },
+
+ { .code = "CN", .domain_rid = DOMAIN_RID_CLONEABLE_CONTROLLERS },
+
+ { .code = "AP", .domain_rid = DOMAIN_RID_PROTECTED_USERS },
+ { .code = "KA", .domain_rid = DOMAIN_RID_KEY_ADMINS },
+ { .code = "EK", .forest_rid = DOMAIN_RID_ENTERPRISE_KEY_ADMINS },
+
+ { .code = "RS", .domain_rid = DOMAIN_RID_RAS_SERVERS }
+};
+
+/*
+ decode a SID
+ It can either be a special 2 letter code, or in S-* format
+*/
+static struct dom_sid *sddl_transition_decode_sid(TALLOC_CTX *mem_ctx, const char **sddlp,
+ struct sddl_transition_state *state)
+{
+ const char *sddl = (*sddlp);
+ size_t i;
+
+ /* see if its in the numeric format */
+ if (strncasecmp(sddl, "S-", 2) == 0) {
+ struct dom_sid *sid = NULL;
+ char *sid_str = NULL;
+ const char *end = NULL;
+ bool ok;
+ size_t len = strspn(sddl + 2, "-0123456789ABCDEFabcdefxX") + 2;
+ if (len < 5) { /* S-1-x */
+ return NULL;
+ }
+ if (sddl[len - 1] == 'D' && sddl[len] == ':') {
+ /*
+ * we have run into the "D:" dacl marker, mistaking it
+ * for a hex digit. There is no other way for this
+ * pair to occur at the end of a SID in SDDL.
+ */
+ len--;
+ }
+
+ sid_str = talloc_strndup(mem_ctx, sddl, len);
+ if (sid_str == NULL) {
+ return NULL;
+ }
+ if (sid_str[0] == 's') {
+ /*
+ * In SDDL, but not in the dom_sid parsers, a
+ * lowercase "s-1-1-0" is accepted.
+ */
+ sid_str[0] = 'S';
+ }
+ sid = talloc(mem_ctx, struct dom_sid);
+ if (sid == NULL) {
+ TALLOC_FREE(sid_str);
+ return NULL;
+ };
+ ok = dom_sid_parse_endp(sid_str, sid, &end);
+ if (!ok) {
+ DBG_WARNING("could not parse SID '%s'\n", sid_str);
+ TALLOC_FREE(sid_str);
+ TALLOC_FREE(sid);
+ return NULL;
+ }
+ if (end - sid_str != len) {
+ DBG_WARNING("trailing junk after SID '%s'\n", sid_str);
+ TALLOC_FREE(sid_str);
+ TALLOC_FREE(sid);
+ return NULL;
+ }
+ TALLOC_FREE(sid_str);
+ (*sddlp) += len;
+ return sid;
+ }
+
+ /* now check for one of the special codes */
+ for (i=0;i<ARRAY_SIZE(sid_codes);i++) {
+ if (strncmp(sid_codes[i].code, sddl, 2) == 0) break;
+ }
+ if (i == ARRAY_SIZE(sid_codes)) {
+ DEBUG(1,("Unknown sddl sid code '%2.2s'\n", sddl));
+ return NULL;
+ }
+
+ (*sddlp) += 2;
+
+
+ if (sid_codes[i].machine_rid != 0) {
+ return dom_sid_add_rid(mem_ctx, state->machine_sid,
+ sid_codes[i].machine_rid);
+ }
+
+ if (sid_codes[i].domain_rid != 0) {
+ return dom_sid_add_rid(mem_ctx, state->domain_sid,
+ sid_codes[i].domain_rid);
+ }
+
+ if (sid_codes[i].forest_rid != 0) {
+ return dom_sid_add_rid(mem_ctx, state->forest_sid,
+ sid_codes[i].forest_rid);
+ }
+
+ return dom_sid_parse_talloc(mem_ctx, sid_codes[i].sid);
+}
+
+struct dom_sid *sddl_decode_sid(TALLOC_CTX *mem_ctx, const char **sddlp,
+ const struct dom_sid *domain_sid)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ return sddl_transition_decode_sid(mem_ctx, sddlp, &state);
+}
+
+
+static const struct flag_map ace_types[] = {
+ { "AU", SEC_ACE_TYPE_SYSTEM_AUDIT },
+ { "AL", SEC_ACE_TYPE_SYSTEM_ALARM },
+ { "OA", SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT },
+ { "OD", SEC_ACE_TYPE_ACCESS_DENIED_OBJECT },
+ { "OU", SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT },
+ { "OL", SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT },
+ { "A", SEC_ACE_TYPE_ACCESS_ALLOWED },
+ { "D", SEC_ACE_TYPE_ACCESS_DENIED },
+
+ { "XA", SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK },
+ { "XD", SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK },
+ { "ZA", SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT },
+ /*
+ * SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT exists but has
+ * no SDDL flag.
+ *
+ * ZA and XU are switched in [MS-DTYP] as of version 36.0,
+ * but this should be corrected in later versions.
+ */
+ { "XU", SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK },
+
+ { "RA", SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE },
+ { NULL, 0 }
+};
+
+static const struct flag_map ace_flags[] = {
+ { "OI", SEC_ACE_FLAG_OBJECT_INHERIT },
+ { "CI", SEC_ACE_FLAG_CONTAINER_INHERIT },
+ { "NP", SEC_ACE_FLAG_NO_PROPAGATE_INHERIT },
+ { "IO", SEC_ACE_FLAG_INHERIT_ONLY },
+ { "ID", SEC_ACE_FLAG_INHERITED_ACE },
+ { "SA", SEC_ACE_FLAG_SUCCESSFUL_ACCESS },
+ { "FA", SEC_ACE_FLAG_FAILED_ACCESS },
+ { NULL, 0 },
+};
+
+static const struct flag_map ace_access_mask[] = {
+ { "CC", SEC_ADS_CREATE_CHILD },
+ { "DC", SEC_ADS_DELETE_CHILD },
+ { "LC", SEC_ADS_LIST },
+ { "SW", SEC_ADS_SELF_WRITE },
+ { "RP", SEC_ADS_READ_PROP },
+ { "WP", SEC_ADS_WRITE_PROP },
+ { "DT", SEC_ADS_DELETE_TREE },
+ { "LO", SEC_ADS_LIST_OBJECT },
+ { "CR", SEC_ADS_CONTROL_ACCESS },
+ { "SD", SEC_STD_DELETE },
+ { "RC", SEC_STD_READ_CONTROL },
+ { "WD", SEC_STD_WRITE_DAC },
+ { "WO", SEC_STD_WRITE_OWNER },
+ { "GA", SEC_GENERIC_ALL },
+ { "GX", SEC_GENERIC_EXECUTE },
+ { "GW", SEC_GENERIC_WRITE },
+ { "GR", SEC_GENERIC_READ },
+ { NULL, 0 }
+};
+
+static const struct flag_map decode_ace_access_mask[] = {
+ { "FA", FILE_GENERIC_ALL },
+ { "FR", FILE_GENERIC_READ },
+ { "FW", FILE_GENERIC_WRITE },
+ { "FX", FILE_GENERIC_EXECUTE },
+ { NULL, 0 },
+};
+
+
+static char *sddl_match_file_rights(TALLOC_CTX *mem_ctx,
+ uint32_t flags)
+{
+ int i;
+
+ /* try to find an exact match */
+ for (i=0;decode_ace_access_mask[i].name;i++) {
+ if (decode_ace_access_mask[i].flag == flags) {
+ return talloc_strdup(mem_ctx,
+ decode_ace_access_mask[i].name);
+ }
+ }
+ return NULL;
+}
+
+static bool sddl_decode_access(const char *str, uint32_t *pmask)
+{
+ const char *str0 = str;
+ char *end = NULL;
+ uint32_t mask = 0;
+ unsigned long long numeric_mask;
+ int err;
+ /*
+ * The access mask can be a number or a series of flags.
+ *
+ * Canonically the number is expressed in hexadecimal (with 0x), but
+ * per MS-DTYP and Windows behaviour, octal and decimal numbers are
+ * also accepted.
+ *
+ * Windows has two behaviours we choose not to replicate:
+ *
+ * 1. numbers exceeding 0xffffffff are truncated at that point,
+ * turning on all access flags.
+ *
+ * 2. negative numbers are accepted, so e.g. -2 becomes 0xfffffffe.
+ */
+ numeric_mask = smb_strtoull(str, &end, 0, &err, SMB_STR_STANDARD);
+ if (err == 0) {
+ if (numeric_mask > UINT32_MAX) {
+ DBG_WARNING("Bad numeric flag value - %llu in %s\n",
+ numeric_mask, str0);
+ return false;
+ }
+ if (end - str > sizeof("037777777777")) {
+ /* here's the tricky thing: if a number is big
+ * enough to overflow the uint64, it might end
+ * up small enough to fit in the uint32, and
+ * we'd miss that it overflowed. So we count
+ * the digits -- any more than 12 (for
+ * "037777777777") is too long for 32 bits,
+ * and the shortest 64-bit wrapping string is
+ * 19 (for "0x1" + 16 zeros).
+ */
+ DBG_WARNING("Bad numeric flag value in '%s'\n", str0);
+ return false;
+ }
+ if (*end != '\0') {
+ DBG_WARNING("Bad characters in '%s'\n", str0);
+ return false;
+ }
+ *pmask = numeric_mask;
+ return true;
+ }
+ /* It's not a positive number, so we'll look for flags */
+
+ while ((str[0] != '\0') &&
+ (isupper((unsigned char)str[0]) || str[0] == ' ')) {
+ uint32_t flags = 0;
+ size_t len = 0;
+ bool found;
+ while (str[0] == ' ') {
+ /*
+ * Following Windows we accept spaces between flags
+ * but not after flags. Not tabs, though, never tabs.
+ */
+ str++;
+ if (str[0] == '\0') {
+ DBG_WARNING("trailing whitespace in flags "
+ "- '%s'\n", str0);
+ return false;
+ }
+ }
+ found = sddl_map_flag(
+ ace_access_mask, str, &len, &flags);
+ found |= sddl_map_flag(
+ decode_ace_access_mask, str, &len, &flags);
+ if (!found) {
+ DEBUG(1, ("Unknown flag - %s in %s\n", str, str0));
+ return false;
+ }
+ mask |= flags;
+ str += len;
+ }
+ if (*str != '\0') {
+ DBG_WARNING("Bad characters in '%s'\n", str0);
+ return false;
+ }
+ *pmask = mask;
+ return true;
+}
+
+
+static bool sddl_decode_guid(const char *str, struct GUID *guid)
+{
+ if (strlen(str) != 36) {
+ return false;
+ }
+ return parse_guid_string(str, guid);
+}
+
+
+
+static DATA_BLOB sddl_decode_conditions(TALLOC_CTX *mem_ctx,
+ const enum ace_condition_flags ace_condition_flags,
+ const char *conditions,
+ size_t *length,
+ const char **msg,
+ size_t *msg_offset)
+{
+ DATA_BLOB blob = {0};
+ struct ace_condition_script *script = NULL;
+ script = ace_conditions_compile_sddl(mem_ctx,
+ ace_condition_flags,
+ conditions,
+ msg,
+ msg_offset,
+ length);
+ if (script != NULL) {
+ bool ok = conditional_ace_encode_binary(mem_ctx,
+ script,
+ &blob);
+ if (! ok) {
+ DBG_ERR("could not blobify '%s'\n", conditions);
+ }
+ }
+ return blob;
+}
+
+
+/*
+ decode an ACE
+ return true on success, false on failure
+ note that this routine modifies the string
+*/
+static bool sddl_decode_ace(TALLOC_CTX *mem_ctx,
+ struct security_ace *ace,
+ const enum ace_condition_flags ace_condition_flags,
+ char **sddl_copy,
+ struct sddl_transition_state *state,
+ const char **msg, size_t *msg_offset)
+{
+ const char *tok[7];
+ const char *s;
+ uint32_t v;
+ struct dom_sid *sid;
+ bool ok;
+ size_t len;
+ size_t count = 0;
+ char *str = *sddl_copy;
+ bool has_extra_data = false;
+ ZERO_STRUCTP(ace);
+
+ *msg_offset = 1;
+ if (*str != '(') {
+ *msg = talloc_strdup(mem_ctx, "Not an ACE");
+ return false;
+ }
+ str++;
+ /*
+ * First we split apart the 6 (or 7) tokens.
+ *
+ * 0. ace type
+ * 1. ace flags
+ * 2. access mask
+ * 3. object guid
+ * 4. inherit guid
+ * 5. sid
+ *
+ * 6/extra_data rare optional extra data
+ */
+ tok[0] = str;
+ while (*str != '\0') {
+ if (*str == ';') {
+ *str = '\0';
+ str++;
+ count++;
+ tok[count] = str;
+ if (count == 6) {
+ /*
+ * this looks like a conditional ACE
+ * or resource ACE, but we can't say
+ * for sure until we look at the ACE
+ * type (tok[0]), after the loop.
+ */
+ has_extra_data = true;
+ break;
+ }
+ continue;
+ }
+ /*
+ * we are not expecting a ')' in the 6 sections of an
+ * ordinary ACE, except ending the last one.
+ */
+ if (*str == ')') {
+ count++;
+ *str = '\0';
+ str++;
+ break;
+ }
+ str++;
+ }
+ if (count != 6) {
+ /* we hit the '\0' or ')' before all of ';;;;;)' */
+ *msg = talloc_asprintf(mem_ctx,
+ "malformed ACE with only %zu ';'",
+ MIN(count - 1, count));
+ return false;
+ }
+
+ /* parse ace type */
+ ok = sddl_map_flag(ace_types, tok[0], &len, &v);
+ if (!ok) {
+ *msg = talloc_asprintf(mem_ctx,
+ "Unknown ACE type - %s", tok[0]);
+ return false;
+ }
+ if (tok[0][len] != '\0') {
+ *msg = talloc_asprintf(mem_ctx,
+ "Garbage after ACE type - %s", tok[0]);
+ return false;
+ }
+
+ ace->type = v;
+
+ /*
+ * Only callback and resource aces should have trailing data.
+ */
+ if (sec_ace_callback(ace->type)) {
+ if (! has_extra_data) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "callback ACE has no trailing data");
+ *msg_offset = str - *sddl_copy;
+ return false;
+ }
+ } else if (sec_ace_resource(ace->type)) {
+ if (! has_extra_data) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "resource attribute ACE has no trailing data");
+ *msg_offset = str - *sddl_copy;
+ return false;
+ }
+ } else if (has_extra_data) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "ACE has trailing section but is not a "
+ "callback or resource ACE");
+ *msg_offset = str - *sddl_copy;
+ return false;
+ }
+
+ /* ace flags */
+ if (!sddl_map_flags(ace_flags, tok[1], &v, NULL, false)) {
+ *msg = talloc_strdup(mem_ctx,
+ "could not parse flags");
+ *msg_offset = tok[1] - *sddl_copy;
+ return false;
+ }
+ ace->flags = v;
+
+ /* access mask */
+ ok = sddl_decode_access(tok[2], &ace->access_mask);
+ if (!ok) {
+ *msg = talloc_strdup(mem_ctx,
+ "could not parse access string");
+ *msg_offset = tok[2] - *sddl_copy;
+ return false;
+ }
+
+ /* object */
+ if (tok[3][0] != 0) {
+ ok = sddl_decode_guid(tok[3], &ace->object.object.type.type);
+ if (!ok) {
+ *msg = talloc_strdup(mem_ctx,
+ "could not parse object GUID");
+ *msg_offset = tok[3] - *sddl_copy;
+ return false;
+ }
+ ace->object.object.flags |= SEC_ACE_OBJECT_TYPE_PRESENT;
+ }
+
+ /* inherit object */
+ if (tok[4][0] != 0) {
+ ok = sddl_decode_guid(tok[4],
+ &ace->object.object.inherited_type.inherited_type);
+ if (!ok) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "could not parse inherited object GUID");
+ *msg_offset = tok[4] - *sddl_copy;
+ return false;
+ }
+ ace->object.object.flags |= SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT;
+ }
+
+ /* trustee */
+ s = tok[5];
+ sid = sddl_transition_decode_sid(mem_ctx, &s, state);
+ if (sid == NULL) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "could not parse trustee SID");
+ *msg_offset = tok[5] - *sddl_copy;
+ return false;
+ }
+ ace->trustee = *sid;
+ talloc_free(sid);
+ if (*s != '\0') {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "garbage after trustee SID");
+ *msg_offset = s - *sddl_copy;
+ return false;
+ }
+
+ if (sec_ace_callback(ace->type)) {
+ /*
+ * This is either a conditional ACE or some unknown
+ * type of callback ACE that will be rejected by the
+ * conditional ACE compiler.
+ */
+ size_t length;
+ DATA_BLOB conditions = {0};
+ s = tok[6];
+
+ conditions = sddl_decode_conditions(mem_ctx,
+ ace_condition_flags,
+ s,
+ &length,
+ msg,
+ msg_offset);
+ if (conditions.data == NULL) {
+ DBG_NOTICE("Conditional ACE compilation failure at %zu: %s\n",
+ *msg_offset, *msg);
+ *msg_offset += s - *sddl_copy;
+ return false;
+ }
+ ace->coda.conditions = conditions;
+
+ /*
+ * We have found the end of the conditions, and the
+ * next character should be the ')' to end the ACE.
+ */
+ if (s[length] != ')') {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "Conditional ACE has trailing bytes"
+ " or lacks ')'");
+ *msg_offset = s + length - *sddl_copy;
+ return false;
+ }
+ str = discard_const_p(char, s + length + 1);
+ } else if (sec_ace_resource(ace->type)) {
+ size_t length;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
+
+ if (! dom_sid_equal(&ace->trustee, &global_sid_World)) {
+ /* these are just the rules */
+ *msg = talloc_strdup(
+ mem_ctx,
+ "Resource Attribute ACE trustee must be "
+ "'S-1-1-0' or 'WD'.");
+ *msg_offset = tok[5] - *sddl_copy;
+ return false;
+ }
+
+ s = tok[6];
+ claim = sddl_decode_resource_attr(mem_ctx, s, &length);
+ if (claim == NULL) {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "Resource Attribute ACE parse failure");
+ *msg_offset = s - *sddl_copy;
+ return false;
+ }
+ ace->coda.claim = *claim;
+
+ /*
+ * We want a ')' to end the ACE.
+ */
+ if (s[length] != ')') {
+ *msg = talloc_strdup(
+ mem_ctx,
+ "Resource Attribute ACE has trailing bytes"
+ " or lacks ')'");
+ *msg_offset = s + length - *sddl_copy;
+ return false;
+ }
+ str = discard_const_p(char, s + length + 1);
+ }
+
+ *sddl_copy = str;
+ return true;
+}
+
+static const struct flag_map acl_flags[] = {
+ { "P", SEC_DESC_DACL_PROTECTED },
+ { "AR", SEC_DESC_DACL_AUTO_INHERIT_REQ },
+ { "AI", SEC_DESC_DACL_AUTO_INHERITED },
+ { NULL, 0 }
+};
+
+/*
+ decode an ACL
+*/
+static struct security_acl *sddl_decode_acl(struct security_descriptor *sd,
+ const enum ace_condition_flags ace_condition_flags,
+ const char **sddlp, uint32_t *flags,
+ struct sddl_transition_state *state,
+ const char **msg, size_t *msg_offset)
+{
+ const char *sddl = *sddlp;
+ char *sddl_copy = NULL;
+ char *aces_start = NULL;
+ struct security_acl *acl;
+ size_t len;
+ *flags = 0;
+
+ acl = talloc_zero(sd, struct security_acl);
+ if (acl == NULL) {
+ return NULL;
+ }
+ acl->revision = SECURITY_ACL_REVISION_ADS;
+
+ if (isupper((unsigned char)sddl[0]) && sddl[1] == ':') {
+ /* its an empty ACL */
+ return acl;
+ }
+
+ /* work out the ACL flags */
+ if (!sddl_map_flags(acl_flags, sddl, flags, &len, true)) {
+ *msg = talloc_strdup(sd, "bad ACL flags");
+ *msg_offset = 0;
+ talloc_free(acl);
+ return NULL;
+ }
+ sddl += len;
+
+ if (sddl[0] != '(') {
+ /*
+ * it is empty apart from the flags
+ * (or the flags are bad, and we will find out when
+ * we try to parse the next bit as a top-level fragment)
+ */
+ *sddlp = sddl;
+ return acl;
+ }
+
+ /*
+ * now the ACEs
+ *
+ * For this we make a copy of the rest of the SDDL, which the ACE
+ * tokeniser will mutilate by putting '\0' where it finds ';'.
+ *
+ * We need to copy the rest of the SDDL string because it is not
+ * possible in general to find where an ACL ends if there are
+ * conditional ACEs.
+ */
+
+ sddl_copy = talloc_strdup(acl, sddl);
+ if (sddl_copy == NULL) {
+ TALLOC_FREE(acl);
+ return NULL;
+ }
+ aces_start = sddl_copy;
+
+ while (*sddl_copy == '(') {
+ bool ok;
+ if (acl->num_aces > UINT16_MAX / 16) {
+ /*
+ * We can't fit this many ACEs in a wire ACL
+ * which has a 16 bit size field (and 16 is
+ * the minimal size of an ACE with no subauths).
+ */
+ talloc_free(acl);
+ return NULL;
+ }
+
+ acl->aces = talloc_realloc(acl, acl->aces, struct security_ace,
+ acl->num_aces+1);
+ if (acl->aces == NULL) {
+ talloc_free(acl);
+ return NULL;
+ }
+ ok = sddl_decode_ace(acl->aces, &acl->aces[acl->num_aces],
+ ace_condition_flags,
+ &sddl_copy, state, msg, msg_offset);
+ if (!ok) {
+ *msg_offset += sddl_copy - aces_start;
+ talloc_steal(sd, *msg);
+ talloc_free(acl);
+ return NULL;
+ }
+ acl->num_aces++;
+ }
+ sddl += sddl_copy - aces_start;
+ TALLOC_FREE(aces_start);
+ (*sddlp) = sddl;
+ return acl;
+}
+
+/*
+ * Decode a security descriptor in SDDL format, catching compilation
+ * error messages, if any.
+ *
+ * The message will be a direct talloc child of mem_ctx or NULL.
+ */
+struct security_descriptor *sddl_decode_err_msg(TALLOC_CTX *mem_ctx, const char *sddl,
+ const struct dom_sid *domain_sid,
+ const enum ace_condition_flags ace_condition_flags,
+ const char **msg, size_t *msg_offset)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ const char *start = sddl;
+ struct security_descriptor *sd = NULL;
+
+ if (msg == NULL || msg_offset == NULL) {
+ DBG_ERR("Programmer misbehaviour: use sddl_decode() "
+ "or provide msg pointers.\n");
+ return NULL;
+ }
+ *msg = NULL;
+ *msg_offset = 0;
+
+ sd = talloc_zero(mem_ctx, struct security_descriptor);
+ if (sd == NULL) {
+ return NULL;
+ }
+ sd->revision = SECURITY_DESCRIPTOR_REVISION_1;
+ sd->type = SEC_DESC_SELF_RELATIVE;
+
+ while (*sddl) {
+ uint32_t flags;
+ char c = sddl[0];
+ if (sddl[1] != ':') {
+ *msg = talloc_strdup(mem_ctx,
+ "expected '[OGDS]:' section start "
+ "(or the previous section ended prematurely)");
+ goto failed;
+ }
+ sddl += 2;
+ switch (c) {
+ case 'D':
+ if (sd->dacl != NULL) goto failed;
+ sd->dacl = sddl_decode_acl(sd, ace_condition_flags, &sddl, &flags, &state, msg, msg_offset);
+ if (sd->dacl == NULL) goto failed;
+ sd->type |= flags | SEC_DESC_DACL_PRESENT;
+ break;
+ case 'S':
+ if (sd->sacl != NULL) goto failed;
+ sd->sacl = sddl_decode_acl(sd, ace_condition_flags, &sddl, &flags, &state, msg, msg_offset);
+ if (sd->sacl == NULL) goto failed;
+ /* this relies on the SEC_DESC_SACL_* flags being
+ 1 bit shifted from the SEC_DESC_DACL_* flags */
+ sd->type |= (flags<<1) | SEC_DESC_SACL_PRESENT;
+ break;
+ case 'O':
+ if (sd->owner_sid != NULL) goto failed;
+ sd->owner_sid = sddl_transition_decode_sid(sd, &sddl, &state);
+ if (sd->owner_sid == NULL) goto failed;
+ break;
+ case 'G':
+ if (sd->group_sid != NULL) goto failed;
+ sd->group_sid = sddl_transition_decode_sid(sd, &sddl, &state);
+ if (sd->group_sid == NULL) goto failed;
+ break;
+ default:
+ *msg = talloc_strdup(mem_ctx, "unexpected character (expected [OGDS])");
+ goto failed;
+ }
+ }
+ return sd;
+failed:
+ if (*msg != NULL) {
+ *msg = talloc_steal(mem_ctx, *msg);
+ }
+ /*
+ * The actual message (*msg) might still be NULL, but the
+ * offset at least provides a clue.
+ */
+ *msg_offset += sddl - start;
+
+ if (*msg_offset > strlen(sddl)) {
+ /*
+ * It's not that we *don't* trust our pointer difference
+ * arithmetic, just that we *shouldn't*. Let's render it
+ * harmless, before Python tries printing 18 quadrillion
+ * spaces.
+ */
+ DBG_WARNING("sddl error message offset %zu is too big\n",
+ *msg_offset);
+ *msg_offset = 0;
+ }
+ DEBUG(2,("Badly formatted SDDL '%s'\n", sddl));
+ talloc_free(sd);
+ return NULL;
+}
+
+
+/*
+ decode a security descriptor in SDDL format
+*/
+struct security_descriptor *sddl_decode(TALLOC_CTX *mem_ctx, const char *sddl,
+ const struct dom_sid *domain_sid)
+{
+ const char *msg = NULL;
+ size_t msg_offset = 0;
+ struct security_descriptor *sd = sddl_decode_err_msg(mem_ctx,
+ sddl,
+ domain_sid,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ &msg,
+ &msg_offset);
+ if (sd == NULL) {
+ DBG_NOTICE("could not decode '%s'\n", sddl);
+ if (msg != NULL) {
+ DBG_NOTICE(" %*c\n",
+ (int)msg_offset, '^');
+ DBG_NOTICE("error '%s'\n", msg);
+ talloc_free(discard_const(msg));
+ }
+ }
+ return sd;
+}
+
+/*
+ turn a set of flags into a string
+*/
+static char *sddl_flags_to_string(TALLOC_CTX *mem_ctx, const struct flag_map *map,
+ uint32_t flags, bool check_all)
+{
+ int i;
+ char *s;
+
+ /* try to find an exact match */
+ for (i=0;map[i].name;i++) {
+ if (map[i].flag == flags) {
+ return talloc_strdup(mem_ctx, map[i].name);
+ }
+ }
+
+ s = talloc_strdup(mem_ctx, "");
+
+ /* now by bits */
+ for (i=0;map[i].name;i++) {
+ if ((flags & map[i].flag) != 0) {
+ s = talloc_asprintf_append_buffer(s, "%s", map[i].name);
+ if (s == NULL) goto failed;
+ flags &= ~map[i].flag;
+ }
+ }
+
+ if (check_all && flags != 0) {
+ goto failed;
+ }
+
+ return s;
+
+failed:
+ talloc_free(s);
+ return NULL;
+}
+
+/*
+ encode a sid in SDDL format
+*/
+static char *sddl_transition_encode_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct sddl_transition_state *state)
+{
+ bool in_machine = dom_sid_in_domain(state->machine_sid, sid);
+ bool in_domain = dom_sid_in_domain(state->domain_sid, sid);
+ bool in_forest = dom_sid_in_domain(state->forest_sid, sid);
+ struct dom_sid_buf buf;
+ const char *sidstr = dom_sid_str_buf(sid, &buf);
+ uint32_t rid = 0;
+ size_t i;
+
+ if (sid->num_auths > 1) {
+ rid = sid->sub_auths[sid->num_auths-1];
+ }
+
+ for (i=0;i<ARRAY_SIZE(sid_codes);i++) {
+ /* seen if its a well known sid */
+ if (sid_codes[i].sid != NULL) {
+ int cmp;
+
+ cmp = strcmp(sidstr, sid_codes[i].sid);
+ if (cmp != 0) {
+ continue;
+ }
+
+ return talloc_strdup(mem_ctx, sid_codes[i].code);
+ }
+
+ if (rid == 0) {
+ continue;
+ }
+
+ if (in_machine && sid_codes[i].machine_rid == rid) {
+ return talloc_strdup(mem_ctx, sid_codes[i].code);
+ }
+ if (in_domain && sid_codes[i].domain_rid == rid) {
+ return talloc_strdup(mem_ctx, sid_codes[i].code);
+ }
+ if (in_forest && sid_codes[i].forest_rid == rid) {
+ return talloc_strdup(mem_ctx, sid_codes[i].code);
+ }
+ }
+
+ return talloc_strdup(mem_ctx, sidstr);
+}
+
+char *sddl_encode_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ const struct dom_sid *domain_sid)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ return sddl_transition_encode_sid(mem_ctx, sid, &state);
+}
+
+
+
+/*
+ encode an ACE in SDDL format
+*/
+static char *sddl_transition_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
+ struct sddl_transition_state *state)
+{
+ char *sddl = NULL;
+ TALLOC_CTX *tmp_ctx;
+ struct GUID_txt_buf object_buf, iobject_buf;
+ const char *sddl_type="", *sddl_flags="", *sddl_mask="",
+ *sddl_object="", *sddl_iobject="", *sddl_trustee="";
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ DEBUG(0, ("talloc_new failed\n"));
+ return NULL;
+ }
+
+ sddl_type = sddl_flags_to_string(tmp_ctx, ace_types, ace->type, true);
+ if (sddl_type == NULL) {
+ goto failed;
+ }
+
+ sddl_flags = sddl_flags_to_string(tmp_ctx, ace_flags, ace->flags,
+ true);
+ if (sddl_flags == NULL) {
+ goto failed;
+ }
+
+ sddl_mask = sddl_flags_to_string(tmp_ctx, ace_access_mask,
+ ace->access_mask, true);
+ if (sddl_mask == NULL) {
+ sddl_mask = sddl_match_file_rights(tmp_ctx,
+ ace->access_mask);
+ if (sddl_mask == NULL) {
+ sddl_mask = talloc_asprintf(tmp_ctx, "0x%x",
+ ace->access_mask);
+ }
+ if (sddl_mask == NULL) {
+ goto failed;
+ }
+ }
+
+ if (sec_ace_object(ace->type)) {
+ const struct security_ace_object *object = &ace->object.object;
+
+ if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
+ sddl_object = GUID_buf_string(
+ &object->type.type, &object_buf);
+ }
+
+ if (ace->object.object.flags &
+ SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
+ sddl_iobject = GUID_buf_string(
+ &object->inherited_type.inherited_type,
+ &iobject_buf);
+ }
+ }
+ sddl_trustee = sddl_transition_encode_sid(tmp_ctx, &ace->trustee, state);
+ if (sddl_trustee == NULL) {
+ goto failed;
+ }
+
+ if (sec_ace_callback(ace->type)) {
+ /* encode the conditional part */
+ struct ace_condition_script *s = NULL;
+ const char *sddl_conditions = NULL;
+
+ s = parse_conditional_ace(tmp_ctx, ace->coda.conditions);
+
+ if (s == NULL) {
+ goto failed;
+ }
+
+ sddl_conditions = sddl_from_conditional_ace(tmp_ctx, s);
+ if (sddl_conditions == NULL) {
+ goto failed;
+ }
+
+ sddl = talloc_asprintf(mem_ctx, "%s;%s;%s;%s;%s;%s;%s",
+ sddl_type, sddl_flags, sddl_mask,
+ sddl_object, sddl_iobject,
+ sddl_trustee, sddl_conditions);
+ } else if (sec_ace_resource(ace->type)) {
+ /* encode the resource part */
+ const char *coda = NULL;
+ coda = sddl_resource_attr_from_claim(tmp_ctx,
+ &ace->coda.claim);
+
+ if (coda == NULL) {
+ DBG_WARNING("resource ACE has invalid claim\n");
+ goto failed;
+ }
+ sddl = talloc_asprintf(mem_ctx, "%s;%s;%s;%s;%s;%s;%s",
+ sddl_type, sddl_flags, sddl_mask,
+ sddl_object, sddl_iobject,
+ sddl_trustee, coda);
+ } else {
+ sddl = talloc_asprintf(mem_ctx, "%s;%s;%s;%s;%s;%s",
+ sddl_type, sddl_flags, sddl_mask,
+ sddl_object, sddl_iobject, sddl_trustee);
+ }
+failed:
+ talloc_free(tmp_ctx);
+ return sddl;
+}
+
+char *sddl_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
+ const struct dom_sid *domain_sid)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ return sddl_transition_encode_ace(mem_ctx, ace, &state);
+}
+
+/*
+ encode an ACL in SDDL format
+*/
+static char *sddl_encode_acl(TALLOC_CTX *mem_ctx, const struct security_acl *acl,
+ uint32_t flags, struct sddl_transition_state *state)
+{
+ char *sddl;
+ uint32_t i;
+
+ /* add any ACL flags */
+ sddl = sddl_flags_to_string(mem_ctx, acl_flags, flags, false);
+ if (sddl == NULL) goto failed;
+
+ /* now the ACEs, encoded in braces */
+ for (i=0;i<acl->num_aces;i++) {
+ char *ace = sddl_transition_encode_ace(sddl, &acl->aces[i], state);
+ if (ace == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "(%s)", ace);
+ if (sddl == NULL) goto failed;
+ talloc_free(ace);
+ }
+
+ return sddl;
+
+failed:
+ talloc_free(sddl);
+ return NULL;
+}
+
+
+/*
+ encode a security descriptor to SDDL format
+*/
+char *sddl_encode(TALLOC_CTX *mem_ctx, const struct security_descriptor *sd,
+ const struct dom_sid *domain_sid)
+{
+ struct sddl_transition_state state = {
+ /*
+ * TODO: verify .machine_rid values really belong
+ * to the machine_sid on a member, once
+ * we pass machine_sid from the caller...
+ */
+ .machine_sid = domain_sid,
+ .domain_sid = domain_sid,
+ .forest_sid = domain_sid,
+ };
+ char *sddl;
+ TALLOC_CTX *tmp_ctx;
+
+ /* start with a blank string */
+ sddl = talloc_strdup(mem_ctx, "");
+ if (sddl == NULL) goto failed;
+
+ tmp_ctx = talloc_new(sddl);
+ if (tmp_ctx == NULL) {
+ goto failed;
+ }
+
+ if (sd->owner_sid != NULL) {
+ char *sid = sddl_transition_encode_sid(tmp_ctx, sd->owner_sid, &state);
+ if (sid == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "O:%s", sid);
+ if (sddl == NULL) goto failed;
+ }
+
+ if (sd->group_sid != NULL) {
+ char *sid = sddl_transition_encode_sid(tmp_ctx, sd->group_sid, &state);
+ if (sid == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "G:%s", sid);
+ if (sddl == NULL) goto failed;
+ }
+
+ if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl != NULL) {
+ char *acl = sddl_encode_acl(tmp_ctx, sd->dacl, sd->type, &state);
+ if (acl == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "D:%s", acl);
+ if (sddl == NULL) goto failed;
+ }
+
+ if ((sd->type & SEC_DESC_SACL_PRESENT) && sd->sacl != NULL) {
+ char *acl = sddl_encode_acl(tmp_ctx, sd->sacl, sd->type>>1, &state);
+ if (acl == NULL) goto failed;
+ sddl = talloc_asprintf_append_buffer(sddl, "S:%s", acl);
+ if (sddl == NULL) goto failed;
+ }
+
+ talloc_free(tmp_ctx);
+ return sddl;
+
+failed:
+ talloc_free(sddl);
+ return NULL;
+}
diff --git a/libcli/security/sddl.h b/libcli/security/sddl.h
new file mode 100644
index 0000000..03c8a27
--- /dev/null
+++ b/libcli/security/sddl.h
@@ -0,0 +1,47 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) 2009 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/>.
+*/
+
+#ifndef __SDDL_H__
+#define __SDDL_H__
+
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "librpc/gen_ndr/security.h"
+
+struct security_descriptor *sddl_decode(TALLOC_CTX *mem_ctx, const char *sddl,
+ const struct dom_sid *domain_sid);
+struct security_descriptor *sddl_decode_err_msg(TALLOC_CTX *mem_ctx, const char *sddl,
+ const struct dom_sid *domain_sid,
+ const enum ace_condition_flags ace_condition_flags,
+ const char **msg, size_t *msg_offset);
+char *sddl_encode(TALLOC_CTX *mem_ctx, const struct security_descriptor *sd,
+ const struct dom_sid *domain_sid);
+char *sddl_encode_ace(TALLOC_CTX *mem_ctx, const struct security_ace *ace,
+ const struct dom_sid *domain_sid);
+
+struct dom_sid *sddl_decode_sid(TALLOC_CTX *mem_ctx, const char **sddlp,
+ const struct dom_sid *domain_sid);
+
+char *sddl_encode_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ const struct dom_sid *domain_sid);
+
+#endif /* __SDDL_H__ */
diff --git a/libcli/security/sddl_conditional_ace.c b/libcli/security/sddl_conditional_ace.c
new file mode 100644
index 0000000..e9d83b7
--- /dev/null
+++ b/libcli/security/sddl_conditional_ace.c
@@ -0,0 +1,3476 @@
+/*
+ * Unix SMB implementation.
+ * Functions for understanding conditional ACEs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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_security.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+#include "lib/util/tsort.h"
+#include "lib/util/bytearray.h"
+
+
+/* We're only dealing with utf-8 here. Honestly. */
+#undef strncasecmp
+
+
+#define SDDL_FLAG_EXPECTING_UNARY_OP 1
+#define SDDL_FLAG_EXPECTING_BINARY_OP 2
+#define SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP 4
+#define SDDL_FLAG_EXPECTING_LOCAL_ATTR 8
+#define SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR 16
+#define SDDL_FLAG_EXPECTING_LITERAL 32
+#define SDDL_FLAG_EXPECTING_PAREN 64
+#define SDDL_FLAG_EXPECTING_PAREN_LITERAL 128
+#define SDDL_FLAG_NOT_EXPECTING_END_PAREN 256
+
+#define SDDL_FLAG_DEVICE 512
+
+#define SDDL_FLAG_IS_UNARY_OP (1 << 20)
+#define SDDL_FLAG_IS_BINARY_OP (1 << 21)
+
+
+#define SDDL_FLAGS_EXPR_START (SDDL_FLAG_EXPECTING_UNARY_OP | \
+ SDDL_FLAG_EXPECTING_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_PAREN)
+
+#define SDDL_FLAGS_MEMBER_OP (SDDL_FLAG_EXPECTING_LITERAL | \
+ SDDL_FLAG_EXPECTING_PAREN_LITERAL | \
+ SDDL_FLAG_IS_UNARY_OP)
+
+#define SDDL_FLAGS_RELATIONAL_OP (SDDL_FLAG_EXPECTING_LITERAL | \
+ SDDL_FLAG_EXPECTING_PAREN_LITERAL | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_IS_BINARY_OP)
+
+#define SDDL_FLAGS_CONTAINS_OP (SDDL_FLAG_EXPECTING_LITERAL | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_IS_BINARY_OP)
+
+#define SDDL_FLAGS_EXISTS_OP (SDDL_FLAG_EXPECTING_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_IS_UNARY_OP)
+
+#define SDDL_FLAGS_LOGIC_OP (SDDL_FLAG_EXPECTING_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR | \
+ SDDL_FLAG_EXPECTING_PAREN | \
+ SDDL_FLAG_EXPECTING_UNARY_OP | \
+ SDDL_FLAG_IS_BINARY_OP)
+
+#define SDDL_FLAGS_ATTRIBUTE (SDDL_FLAG_EXPECTING_BINARY_OP | \
+ SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP)
+
+#define SDDL_FLAGS_LITERAL SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP
+
+#define SDDL_FLAGS_PAREN_END (SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP | \
+ SDDL_FLAG_EXPECTING_BINARY_OP)
+
+enum {
+ SDDL_NOT_AN_OP = 0,
+ SDDL_PRECEDENCE_EXISTS,
+ SDDL_PRECEDENCE_COMMON,
+ SDDL_PRECEDENCE_NOT,
+ SDDL_PRECEDENCE_AND,
+ SDDL_PRECEDENCE_OR,
+ SDDL_PRECEDENCE_PAREN_END,
+ SDDL_PRECEDENCE_PAREN_START,
+};
+
+struct ace_condition_sddl_compiler_context {
+ TALLOC_CTX *mem_ctx;
+ const uint8_t *sddl;
+ uint32_t length;
+ uint32_t offset;
+ uint32_t stack_depth;
+ uint32_t max_program_length;
+ uint32_t approx_size;
+ struct ace_condition_script *program;
+ struct ace_condition_token *stack;
+ struct ace_condition_token *target;
+ uint32_t *target_len;
+ const char *message;
+ uint32_t message_offset;
+ struct dom_sid *domain_sid;
+ uint32_t state;
+ uint8_t last_token_type;
+ bool allow_device;
+};
+
+struct sddl_data {
+ const char *name;
+ uint32_t flags;
+ uint8_t op_precedence;
+ uint8_t nargs;
+};
+
+static const struct sddl_data sddl_strings[256] = {
+ /* operators */
+ [CONDITIONAL_ACE_TOKEN_MEMBER_OF] = {
+ "Member_of",
+ SDDL_FLAGS_MEMBER_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF] = {
+ "Device_Member_of",
+ SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY] = {
+ /* [MS-DTYP] says "_Any", but windows prefers '_any' */
+ "Member_of_any",
+ SDDL_FLAGS_MEMBER_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY] = {
+ "Device_Member_of_Any",
+ SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF] = {
+ "Not_Member_of",
+ SDDL_FLAGS_MEMBER_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF] = {
+ "Not_Device_Member_of",
+ SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY] = {
+ "Not_Member_of_Any",
+ SDDL_FLAGS_MEMBER_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY] = {
+ "Not_Device_Member_of_Any",
+ SDDL_FLAGS_MEMBER_OP|SDDL_FLAG_DEVICE,
+ SDDL_PRECEDENCE_COMMON,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_EQUAL] = {
+ "==",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_EQUAL] = {
+ "!=",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_LESS_THAN] = {
+ "<",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL] = {
+ "<=",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_GREATER_THAN] = {
+ ">",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL] = {
+ ">=",
+ SDDL_FLAGS_RELATIONAL_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_CONTAINS] = {
+ "Contains",
+ SDDL_FLAGS_CONTAINS_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_ANY_OF] = {
+ "Any_of",
+ SDDL_FLAGS_CONTAINS_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_CONTAINS] = {
+ "Not_Contains",
+ SDDL_FLAGS_CONTAINS_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_ANY_OF] = {
+ "Not_Any_of",
+ SDDL_FLAGS_CONTAINS_OP,
+ SDDL_PRECEDENCE_COMMON,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_AND] = {
+ "&&",
+ SDDL_FLAGS_LOGIC_OP,
+ SDDL_PRECEDENCE_AND,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_OR] = {
+ "||",
+ SDDL_FLAGS_LOGIC_OP,
+ SDDL_PRECEDENCE_OR,
+ 2
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT] = {
+ "!",
+ (SDDL_FLAG_EXPECTING_PAREN |
+ SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR |
+ SDDL_FLAG_IS_UNARY_OP),
+ SDDL_PRECEDENCE_NOT,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_EXISTS] = {
+ "Exists",
+ SDDL_FLAGS_EXISTS_OP,
+ SDDL_PRECEDENCE_EXISTS,
+ 1
+ },
+ [CONDITIONAL_ACE_TOKEN_NOT_EXISTS] = {
+ "Not_Exists",
+ SDDL_FLAGS_EXISTS_OP,
+ SDDL_PRECEDENCE_EXISTS,
+ 1
+ },
+ /* pseudo-operator pseudo-tokens */
+ [CONDITIONAL_ACE_SAMBA_SDDL_PAREN] = {
+ "(",
+ 0,
+ SDDL_PRECEDENCE_PAREN_START,
+ 0
+ },
+ [CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END] = {
+ ")",
+ SDDL_FLAGS_PAREN_END,
+ SDDL_PRECEDENCE_PAREN_END,
+ 0
+ },
+
+ /*
+ * non-operators.
+ * The names here are only used for error messages.
+ *
+ * some of them will never actually be encountered (e.g. 8-bit
+ * integers).
+ */
+ [CONDITIONAL_ACE_TOKEN_INT8] = {
+ .name = "8-bit integer",
+ .flags = SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_INT16] = {
+ "16-bit integer",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_INT32] = {
+ "32-bit integer",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_INT64] = {
+ "64-bit integer",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+
+ [CONDITIONAL_ACE_TOKEN_UNICODE] = {
+ "unicode",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_OCTET_STRING] = {
+ "byte string",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_COMPOSITE] = {
+ "composite list",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_TOKEN_SID] = {
+ "SID",
+ SDDL_FLAGS_LITERAL,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_LOCAL_ATTRIBUTE] = {
+ "local attribute",
+ SDDL_FLAGS_ATTRIBUTE,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_USER_ATTRIBUTE] = {
+ "user attribute",
+ SDDL_FLAGS_ATTRIBUTE,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_RESOURCE_ATTRIBUTE] = {
+ "resource attribute",
+ SDDL_FLAGS_ATTRIBUTE,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_DEVICE_ATTRIBUTE] = {
+ "device attribute",
+ SDDL_FLAGS_ATTRIBUTE|SDDL_FLAG_DEVICE,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_SAMBA_RESULT_BOOL] = {
+ "boolean result",
+ 0,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_SAMBA_RESULT_NULL] = {
+ "null result",
+ 0,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+ [CONDITIONAL_ACE_SAMBA_RESULT_ERROR] = {
+ "error result",
+ 0,
+ SDDL_NOT_AN_OP,
+ 0
+ },
+};
+
+struct sddl_attr_type{
+ const char *name;
+ uint8_t code;
+};
+
+/*
+ * These are the prefixes for non-local attribute types. [MS-DTYP]
+ * styles them in title case ("@User."), but Windows itself seems to
+ * prefer all-caps, so that is how we render them.
+ */
+static const struct sddl_attr_type sddl_attr_types[] = {
+ {"USER.", CONDITIONAL_ACE_USER_ATTRIBUTE},
+ {"RESOURCE.", CONDITIONAL_ACE_RESOURCE_ATTRIBUTE},
+ {"DEVICE.", CONDITIONAL_ACE_DEVICE_ATTRIBUTE},
+};
+
+
+struct sddl_write_context {
+ TALLOC_CTX *mem_ctx;
+ char *sddl;
+ size_t len;
+ size_t alloc_len;
+};
+
+static bool sddl_write(struct sddl_write_context *ctx,
+ const char *s)
+{
+ size_t len = strlen(s);
+ if (ctx->alloc_len - ctx->len <= len ||
+ ctx->sddl == NULL) {
+ size_t old = ctx->alloc_len;
+ ctx->alloc_len = old + MAX(old / 2, len + 50);
+ if (ctx->alloc_len <= old ||
+ ctx->alloc_len - ctx->len <= len) {
+ return false;
+ }
+ ctx->sddl = talloc_realloc(ctx->mem_ctx, ctx->sddl,
+ char, ctx->alloc_len);
+
+ if (ctx->sddl == NULL) {
+ return false;
+ }
+ }
+ memcpy(ctx->sddl + ctx->len, s, len);
+ ctx->len += len;
+ ctx->sddl[ctx->len] = 0;
+ return true;
+}
+
+/*
+ * This is a helper function to create a representation of a
+ * conditional ACE. This is not SDDL, more like a disassembly,
+ * but it uses some of the same tables.
+ */
+char *debug_conditional_ace(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program)
+{
+ size_t i;
+ size_t depth = 0;
+ char stack[] = " ";
+ char line[120];
+ struct sddl_write_context ctx = {
+ .mem_ctx = mem_ctx
+ };
+
+ for (i = 0; i < program->length; i++) {
+ struct ace_condition_token *tok = &program->tokens[i];
+ struct sddl_data s = sddl_strings[tok->type];
+ char hex[21];
+ char *utf8 = NULL;
+ int utf8_len;
+ char type;
+ char nom[40];
+ snprintf(nom, sizeof(nom), "\033[1;33m%20s\033[0m", s.name);
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ if (tok->data.int64.sign > 3 ||
+ tok->data.int64.base > 3) {
+ goto error;
+ }
+ snprintf(line, sizeof(line),
+ "%s %"PRIi64" %c%c\n",
+ nom,
+ tok->data.int64.value,
+ "?+-_"[tok->data.int64.sign],
+ "?odh"[tok->data.int64.base]
+ );
+ type = 'i';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ snprintf(line, sizeof(line),
+ "%s bool\n",
+ nom
+ );
+ type = 'b';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ snprintf(line, sizeof(line),
+ "%s bool\n",
+ nom
+ );
+ type = 'b';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ snprintf(line, sizeof(line),
+ "%s bool\n",
+ nom
+ );
+ type = 'b';
+ break;
+
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ snprintf(line, sizeof(line),
+ "%s.%s (any type)\n",
+ nom,
+ tok->data.unicode.value
+ );
+ type = '?';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ snprintf(line, sizeof(line),
+ "%s.%s (any type)\n",
+ nom,
+ tok->data.unicode.value
+ );
+ type = 'u';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ utf8_len = MIN(tok->data.bytes.length, 9);
+ hex_encode_buf(hex, tok->data.bytes.data, utf8_len);
+
+ snprintf(line, sizeof(line),
+ "%s %.*s (%d)\n",
+ nom, utf8_len * 2, hex, utf8_len);
+ type = 'o';
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ utf8 = sddl_encode_sid(mem_ctx,
+ &tok->data.sid.sid,
+ NULL);
+ snprintf(line, sizeof(line),
+ "%s (%s)\n",
+ nom, utf8);
+ type = 'S';
+ break;
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ snprintf(line, sizeof(line),
+ "%s %"PRIu32" direct members\n",
+ nom, tok->data.composite.n_members);
+ type = 'C';
+ break;
+
+ case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
+ snprintf(line, sizeof(line),
+ "%s\n", nom);
+ type = '0';
+ break;
+ default:
+ snprintf(line, sizeof(line),
+ "unknown opcode %#02x\n", tok->type);
+ type = '!';
+ break;
+ }
+
+ if (s.nargs > depth) {
+ snprintf(nom, sizeof(nom),
+ "UNDER: -%zu", s.nargs - depth);
+ depth = 0;
+ sddl_write(&ctx, nom);
+ } else if (depth >= strlen(stack)) {
+ snprintf(nom, sizeof(nom),
+ "depth %zu", s.nargs - depth);
+ depth -= (s.nargs - 1);
+ sddl_write(&ctx, nom);
+ } else {
+ depth -= s.nargs;
+ stack[depth] = type;
+ depth++;
+ if (depth < strlen(stack)) {
+ stack[depth] = ' ';
+ }
+ sddl_write(&ctx, stack);
+ }
+ sddl_write(&ctx, line);
+ }
+ if (depth == 1 && stack[0] == 'b') {
+ snprintf(line, sizeof(line),
+ "\033[1;32mGOOD: finishes on a single bool\033[0m\n");
+ } else {
+ snprintf(line, sizeof(line),
+ "\033[1;31mBAD: should finish with a bool\033[0m\n");
+ }
+ sddl_write(&ctx, line);
+ return ctx.sddl;
+
+ error:
+ TALLOC_FREE(ctx.sddl);
+ return NULL;
+}
+
+
+struct sddl_node {
+ struct ace_condition_token *tok;
+ struct sddl_node *lhs;
+ struct sddl_node *rhs;
+ bool wants_parens;
+};
+
+static bool sddl_write_int(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ int64_t v = tok->data.int64.value;
+ uint8_t sign = tok->data.int64.sign;
+ uint8_t base = tok->data.int64.base;
+ char buf[26]; /* oct(1<<63) + sign + \0 */
+ char sign_char;
+ if (sign > CONDITIONAL_ACE_INT_SIGN_NONE ||
+ base > CONDITIONAL_ACE_INT_BASE_16) {
+ return false;
+ }
+
+ /*
+ * we have 9 combinations of base/sign (+ some invalid combinations of
+ * actual sign vs claimed sign).
+ */
+ if (sign == CONDITIONAL_ACE_INT_SIGN_NONE) {
+ /* octal and hex will end up unsigned! */
+ if (base == CONDITIONAL_ACE_INT_BASE_8) {
+ snprintf(buf, sizeof(buf), "0%"PRIo64, v);
+ } else if (base == CONDITIONAL_ACE_INT_BASE_10) {
+ snprintf(buf, sizeof(buf), "%"PRId64, v);
+ } else {
+ snprintf(buf, sizeof(buf), "0x%"PRIx64, v);
+ }
+ return sddl_write(ctx, buf);
+ }
+ if (sign == CONDITIONAL_ACE_INT_SIGN_POSITIVE && v < 0) {
+ return false;
+ }
+ if (sign == CONDITIONAL_ACE_INT_SIGN_NEGATIVE && v > 0) {
+ /* note we allow "-0", because we will parse it. */
+ return false;
+ }
+ sign_char = (sign == CONDITIONAL_ACE_INT_SIGN_NEGATIVE) ? '-' : '+';
+ /*
+ * We can use "%+ld" for the decimal sign (except -0), but
+ * "%+lx" and "%+lo" are invalid because %o and %x are
+ * unsigned.
+ */
+ if (base == CONDITIONAL_ACE_INT_BASE_10) {
+ if (v == 0) {
+ snprintf(buf, sizeof(buf), "%c0", sign_char);
+ } else {
+ snprintf(buf, sizeof(buf), "%+"PRId64, v);
+ }
+ return sddl_write(ctx, buf);
+ }
+
+ if (v == INT64_MIN) {
+ /*
+ * llabs(INT64_MIN) will be undefined.
+ * The lengths we must go to to round trip!
+ */
+ if (base == CONDITIONAL_ACE_INT_BASE_8) {
+ return sddl_write(ctx, "-01000000000000000000000");
+ }
+ return sddl_write(ctx, "-0x8000000000000000");
+ }
+
+ if (base == CONDITIONAL_ACE_INT_BASE_8) {
+ snprintf(buf, sizeof(buf), "%c0%llo", sign_char, llabs(v));
+ } else {
+ snprintf(buf, sizeof(buf), "%c0x%llx", sign_char, llabs(v));
+ }
+ return sddl_write(ctx, buf);
+}
+
+
+static bool sddl_should_escape_utf16(uint16_t c)
+{
+ if (c <= ' ' || c > 126) {
+ return true;
+ }
+
+ switch (c) {
+ case '!':
+ case '"':
+ case '&':
+ case '(':
+ case ')':
+ case '<':
+ case '=':
+ case '>':
+ case '|':
+ case '%':
+ return true;
+ }
+
+ return false;
+}
+
+static bool sddl_encode_attr_name(TALLOC_CTX *mem_ctx,
+ const char *src,
+ char **dest,
+ size_t *dest_len)
+{
+ size_t i, j;
+ bool ok;
+ uint16_t *utf16 = NULL;
+ char *escaped = NULL;
+ size_t utf16_byte_len;
+ size_t utf16_len;
+ size_t src_len = strlen(src);
+ size_t escapees;
+ size_t required;
+ *dest = NULL;
+
+ /*
+ * Writing the string escapes can only really happen in
+ * utf-16.
+ */
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF8, CH_UTF16LE,
+ src, src_len,
+ &utf16, &utf16_byte_len);
+ if (!ok) {
+ return false;
+ }
+ utf16_len = utf16_byte_len / 2;
+
+ escapees = 0;
+ for (i = 0; i < utf16_len; i++) {
+ uint16_t c = utf16[i];
+ if (sddl_should_escape_utf16(c)) {
+ escapees++;
+ }
+ if (c == 0) {
+ /* we can't have '\0' (or "%0000") in a name. */
+ TALLOC_FREE(utf16);
+ return false;
+ }
+ }
+
+ required = src_len + escapees * 5;
+ escaped = talloc_size(mem_ctx, required + 1);
+ if (escaped == NULL) {
+ TALLOC_FREE(utf16);
+ return false;
+ }
+
+ if (escapees == 0) {
+ /* there is nothing to escape: the original string is fine */
+ memcpy(escaped, src, src_len);
+ escaped[src_len] = '\0';
+ *dest = escaped;
+ *dest_len = src_len;
+ TALLOC_FREE(utf16);
+ return true;
+ }
+
+ for (i = 0, j = 0; i < utf16_len && j < required; i++) {
+ uint16_t c = utf16[i];
+ if (sddl_should_escape_utf16(c)) {
+ if (j + 5 >= required) {
+ TALLOC_FREE(escaped);
+ TALLOC_FREE(utf16);
+ return false;
+ }
+ snprintf(escaped + j, 6, "%%%04x", c);
+ j += 5;
+ } else {
+ escaped[j] = c;
+ j++;
+ }
+ }
+ escaped[j] = '\0';
+
+ *dest = escaped;
+ *dest_len = j;
+
+ TALLOC_FREE(utf16);
+ return true;
+}
+
+static bool sddl_write_attr(struct sddl_write_context *ctx,
+ struct ace_condition_token *tok)
+{
+ char *name = NULL;
+ size_t name_len;
+ size_t i;
+ bool ok = sddl_encode_attr_name(ctx->mem_ctx,
+ tok->data.local_attr.value,
+ &name, &name_len);
+ if (!ok) {
+ return false;
+ }
+ for (i = 0; i < ARRAY_SIZE(sddl_attr_types); i++) {
+ struct sddl_attr_type x = sddl_attr_types[i];
+ if (x.code == tok->type) {
+ ok = sddl_write(ctx, "@");
+ if (! ok) {
+ return false;
+ }
+ ok = sddl_write(ctx, x.name);
+ if (! ok) {
+ return false;
+ }
+ break;
+ }
+ }
+
+ ok = sddl_write(ctx, name);
+ talloc_free(name);
+ return ok;
+}
+
+
+static bool sddl_write_unicode(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ char *quoted = NULL;
+ bool ok;
+ /*
+ * We rely on tok->data.unicode.value being
+ * nul-terminated.
+ */
+ if (strchr(tok->data.unicode.value, '"') != NULL) {
+ /*
+ * There is a double quote in this string, but SDDL
+ * has no mechanism for escaping these (or anything
+ * else) in unicode strings.
+ *
+ * The only thing to do is fail.
+ *
+ * This cannot happen with an ACE created from SDDL,
+ * because the same no-escapes rule applies on the way
+ * in.
+ */
+ return false;
+ }
+
+ quoted = talloc_asprintf(ctx->mem_ctx, "\"%s\"",
+ tok->data.unicode.value);
+ if (quoted == NULL) {
+ return false;
+ }
+ ok = sddl_write(ctx, quoted);
+ TALLOC_FREE(quoted);
+ return ok;
+}
+
+static bool sddl_write_octet_string(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ bool ok;
+ char *hex = hex_encode_talloc(ctx->mem_ctx,
+ tok->data.bytes.data,
+ tok->data.bytes.length);
+ ok = sddl_write(ctx, "#");
+ if (!ok) {
+ return false;
+ }
+ ok = sddl_write(ctx, hex);
+ talloc_free(hex);
+ return ok;
+}
+
+/*
+ * For octet strings, the Resource attribute ACE SDDL differs from conditional
+ * ACE SDDL, lacking the leading '#'.
+ */
+static bool sddl_write_ra_octet_string(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ bool ok;
+ char *hex = hex_encode_talloc(ctx->mem_ctx,
+ tok->data.bytes.data,
+ tok->data.bytes.length);
+ ok = sddl_write(ctx, hex);
+ talloc_free(hex);
+ return ok;
+}
+
+
+static bool sddl_write_sid(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ bool ok;
+ char *sddl = NULL;
+ char *sid = sddl_encode_sid(ctx->mem_ctx,
+ &tok->data.sid.sid,
+ NULL);
+ if (sid == NULL) {
+ return false;
+ }
+ sddl = talloc_asprintf(ctx->mem_ctx, "SID(%s)", sid);
+ if (sddl == NULL) {
+ talloc_free(sid);
+ return false;
+ }
+ ok = sddl_write(ctx, sddl);
+ talloc_free(sid);
+ talloc_free(sddl);
+ return ok;
+}
+
+static bool sddl_write_composite(struct sddl_write_context *ctx,
+ struct ace_condition_token *tok)
+{
+ /*
+ * Looks like {1, 2, 3, "four", {"woah, nesting", {6}}, SID(BA)}.
+ */
+ struct ace_condition_composite *c = &tok->data.composite;
+ uint32_t i;
+ bool ok;
+ ok = sddl_write(ctx, "{");
+ if (!ok) {
+ return false;
+ }
+ for (i = 0; i < c->n_members; i++) {
+ struct ace_condition_token *t = &c->tokens[i];
+ if (i > 0) {
+ ok = sddl_write(ctx, ", ");
+ if (!ok) {
+ return false;
+ }
+ }
+ switch (t->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ ok = sddl_write_int(ctx, t);
+ break;
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ ok = sddl_write_unicode(ctx, t);
+ break;
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ ok = sddl_write_octet_string(ctx, t);
+ break;
+ case CONDITIONAL_ACE_TOKEN_SID:
+ ok = sddl_write_sid(ctx, t);
+ break;
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ return false;
+ default:
+ return false;
+ }
+ if (!ok) {
+ return false;
+ }
+ }
+ ok = sddl_write(ctx, "}");
+ return ok;
+}
+
+static bool sddl_write_node(struct sddl_write_context *ctx,
+ struct sddl_node *node)
+{
+ struct ace_condition_token *tok = node->tok;
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT8:
+ case CONDITIONAL_ACE_TOKEN_INT16:
+ case CONDITIONAL_ACE_TOKEN_INT32:
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ return sddl_write_int(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY:
+ case CONDITIONAL_ACE_TOKEN_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_NOT_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_LESS_THAN:
+ case CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_GREATER_THAN:
+ case CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL:
+ case CONDITIONAL_ACE_TOKEN_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_NOT_CONTAINS:
+ case CONDITIONAL_ACE_TOKEN_NOT_ANY_OF:
+ case CONDITIONAL_ACE_TOKEN_AND:
+ case CONDITIONAL_ACE_TOKEN_OR:
+ case CONDITIONAL_ACE_TOKEN_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT_EXISTS:
+ case CONDITIONAL_ACE_TOKEN_NOT:
+ return sddl_write(ctx, sddl_strings[tok->type].name);
+
+ case CONDITIONAL_ACE_LOCAL_ATTRIBUTE:
+ case CONDITIONAL_ACE_USER_ATTRIBUTE:
+ case CONDITIONAL_ACE_RESOURCE_ATTRIBUTE:
+ case CONDITIONAL_ACE_DEVICE_ATTRIBUTE:
+ return sddl_write_attr(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ return sddl_write_unicode(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ return sddl_write_octet_string(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ return sddl_write_sid(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ return sddl_write_composite(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING:
+ /*
+ * This is only expected at the very end, which we
+ * can't (and don't need to) check here, but we can at
+ * least ensure it's the end of a sub-expression.
+ */
+ return (node->rhs == NULL);
+ default:
+ return false;
+ }
+ /* not expecting to get here */
+ return false;
+}
+
+
+static inline bool sddl_wants_outer_parens(struct sddl_node *node)
+{
+ /*
+ * Binary ops (having a LHS) are always parenthesised "(a == 2)"
+ *
+ * Member-of ops are too, for some reason.
+ */
+ return (node->lhs != NULL ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_MEMBER_OF ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY ||
+ node->tok->type == CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY);
+}
+
+
+static inline bool sddl_wants_inner_parens(struct sddl_node *node,
+ struct sddl_node *child)
+{
+ /*
+ * logical operators are serialised with parentheses around their
+ * arguments (for NOT it is obligatory).
+ */
+ if (node->tok->type != CONDITIONAL_ACE_TOKEN_NOT &&
+ node->tok->type != CONDITIONAL_ACE_TOKEN_AND &&
+ node->tok->type != CONDITIONAL_ACE_TOKEN_OR) {
+ return false;
+ }
+ if (sddl_wants_outer_parens(child)) {
+ return false;
+ }
+ return true;
+}
+
+
+static void sddl_tree_resolve_parens(struct sddl_node *node)
+{
+ if (sddl_wants_outer_parens(node)) {
+ node->wants_parens = true;
+ }
+ if (node->lhs != NULL) {
+ bool p = sddl_wants_inner_parens(node, node->lhs);
+ node->lhs->wants_parens = p;
+ sddl_tree_resolve_parens(node->lhs);
+ }
+ if (node->rhs != NULL) {
+ bool p = sddl_wants_inner_parens(node, node->rhs);
+ node->rhs->wants_parens = p;
+ sddl_tree_resolve_parens(node->rhs);
+ }
+}
+
+static bool sddl_tree_to_sddl(struct sddl_write_context *ctx,
+ struct sddl_node *node)
+{
+ bool ok;
+ if (node->wants_parens) {
+ ok = sddl_write(ctx, "(");
+ if (! ok) {
+ return false;
+ }
+ }
+
+ if (node->lhs != NULL) {
+ ok = sddl_tree_to_sddl(ctx, node->lhs);
+ if (! ok) {
+ return false;
+ }
+ ok = sddl_write(ctx, " ");
+ if (!ok) {
+ return false;
+ }
+ }
+
+ ok = sddl_write_node(ctx, node);
+ if (!ok) {
+ return false;
+ }
+ if (node->rhs != NULL) {
+ /* NOT is a special case: "!(x)", not "! (x)" */
+ if (node->tok->type != CONDITIONAL_ACE_TOKEN_NOT) {
+ ok = sddl_write(ctx, " ");
+ if (!ok) {
+ return false;
+ }
+ }
+
+ ok = sddl_tree_to_sddl(ctx, node->rhs);
+ if (! ok) {
+ return false;
+ }
+ }
+ if (node->wants_parens) {
+ ok = sddl_write(ctx, ")");
+ if (!ok) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * Convert conditional ACE conditions into SDDL conditions.
+ *
+ * @param mem_ctx
+ * @param program
+ * @return a string or NULL on error.
+ */
+char *sddl_from_conditional_ace(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program)
+{
+ size_t i;
+ char *sddl = NULL;
+ struct sddl_node *nodes = NULL;
+ struct sddl_node **trees = NULL;
+ size_t n_trees = 0;
+ struct ace_condition_token *tok = NULL;
+ struct sddl_data s;
+ bool ok;
+ struct sddl_write_context ctx = {
+ .mem_ctx = mem_ctx
+ };
+
+ if (program->length == 0) {
+ /*
+ * The empty program is a special case.
+ */
+ return talloc_strdup(mem_ctx, "()");
+ }
+ nodes = talloc_zero_array(mem_ctx,
+ struct sddl_node,
+ program->length);
+ if (nodes == NULL) {
+ talloc_free(sddl);
+ return NULL;
+ }
+ trees = talloc_array(mem_ctx,
+ struct sddl_node*,
+ program->length);
+ if (trees == NULL) {
+ talloc_free(sddl);
+ talloc_free(nodes);
+ return NULL;
+ }
+
+ /*
+ * This loop constructs a tree, which we then traverse to get the
+ * SDDL. Consider this transformation:
+ *
+ * {A, B, ==, C, D, ==, &&} => "((A == B) && (C == D))"
+ *
+ * We keep an array of sub-trees, and add to it in sequence. When the
+ * thing we're adding takes arguments, we pop those off the tree list.
+ * So it would go through this sequence:
+ *
+ * len items
+ * 1: A
+ * 2: A, B
+ * 1: ==(A, B)
+ * 2: ==(A, B), C
+ * 3: ==(A, B), C, D
+ * 2: ==(A, B), ==(C, D)
+ * 1 &&(==(A, B), ==(C, D))
+ *
+ * Without building a tree it would be difficult to know how many
+ * parentheses to put before A.
+ *
+ * (A == B == C) should become
+ * {A B == C ==} which should be the same as
+ * ((A == B) == C)
+ */
+
+ for (i = 0; i < program->length; i++) {
+ tok = &program->tokens[i];
+ s = sddl_strings[tok->type];
+ nodes[i].tok = tok;
+ if (s.nargs > n_trees) {
+ goto error;
+ }
+ if (s.nargs >= 1) {
+ /*
+ * Read this note if you're trying to follow
+ * [MS-DTYP]. MS-DTYP uses 'LHS' to describe the
+ * operand of unary operators even though they are
+ * always displayed on the right of the operator. It
+ * makes everything much simpler to use rhs
+ * instead.
+ */
+ n_trees--;
+ nodes[i].rhs = trees[n_trees];
+
+ if (s.nargs == 2) {
+ n_trees--;
+ nodes[i].lhs = trees[n_trees];
+ }
+ }
+ trees[n_trees] = &nodes[i];
+ n_trees++;
+ }
+
+ if (n_trees != 1) {
+ goto error;
+ }
+
+ /*
+ * First we walk the tree to work out where to put parentheses (to
+ * match the canonical Windows representation).
+ *
+ * Doing it in the same traverse as the writing would be possible but
+ * trickier to get right.
+ */
+ sddl_tree_resolve_parens(trees[0]);
+ trees[0]->wants_parens = true;
+
+ /*
+ * Clamber over the tree, writing the string.
+ */
+ ok = sddl_tree_to_sddl(&ctx, trees[0]);
+
+ if (! ok) {
+ goto error;
+ }
+
+ talloc_free(trees);
+ talloc_free(nodes);
+ return ctx.sddl;
+
+ error:
+ talloc_free(sddl);
+ talloc_free(trees);
+ talloc_free(nodes);
+ return NULL;
+}
+
+
+
+static void comp_error(struct ace_condition_sddl_compiler_context *comp,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+
+static void comp_error(struct ace_condition_sddl_compiler_context *comp,
+ const char *fmt, ...)
+{
+ char *msg = NULL;
+ va_list ap;
+ va_start(ap, fmt);
+ msg = talloc_vasprintf(comp->mem_ctx, fmt, ap);
+ va_end(ap);
+ if (msg == NULL) {
+ goto fail;
+ }
+
+ if (comp->message == NULL) {
+ /*
+ * Previously unset message; prepend the position.
+ *
+ * This is the common case.
+ */
+ comp->message_offset = comp->offset;
+ comp->message = msg;
+ return;
+ }
+ /*
+ * There's a message already so we'll try to append.
+ * This is unlikely to happen.
+ */
+ comp->message = talloc_asprintf(comp->mem_ctx,
+ "%s AND THEN %s",
+ comp->message,
+ msg);
+ TALLOC_FREE(msg);
+ if (comp->message == NULL) {
+ goto fail;
+ }
+ DBG_NOTICE("%s\n", comp->message);
+ return;
+fail:
+ comp->message = talloc_strdup(comp->mem_ctx,
+ "failed to set error message");
+ DBG_WARNING("%s\n", comp->message);
+}
+
+
+
+
+/*
+conditional-ace = "(" conditional-ace-type ";" [ace-flag-string] ";" ace-rights
+";" [object- guid] ";" [inherit-object-guid] ";" sid-string ";" "(" cond-expr
+")" ")"
+
+wspace = 1*(%x09-0D / %x20)
+
+literal-SID = "SID(" sid-string ")"
+
+term = [wspace] (memberof-op / exists-op / rel-op / contains-op / anyof-op /
+attr-name / rel- op2) [wspace]
+
+cond-expr = term / term [wspace] ("||" / "&&" ) [wspace] cond-expr / (["!"]
+[wspace] "(" cond-expr ")")
+
+memberof-op = ( "Member_of" / "Not_Member_of" / "Member_of_Any" /
+"Not_Member_of_Any" / "Device_Member_of" / "Device_Member_of_Any" /
+"Not_Device_Member_of" / "Not_Device_Member_of_Any" ) wspace sid-array
+
+exists-op = ( "Exists" / "Not_Exists") wspace attr-name
+
+rel-op = attr-name [wspace] ("<" / "<=" / ">" / ">=") [wspace] (attr-name2 /
+value) ; only scalars
+
+rel-op2 = attr-name [wspace] ("==" / "!=") [wspace] ( attr-name2 / value-array )
+; scalar or list
+
+contains-op = attr-name wspace ("Contains" / "Not_Contains") wspace (attr-name2
+/ value- array)
+
+anyof-op = attr-name wspace ("Any_of" / "Not_Any_of") wspace (attr-name2 /
+value-array)
+
+
+attr-name1 = attr-char1 *(attr-char1 / "@")
+
+attr-char1 = 1*(ALPHA / DIGIT / ":" / "." / "/" / "_")
+
+
+
+attr-name2 = ("@user." / "@device." / "@resource.") 1*attr-char2
+; new prefixed name form
+attr-char2 = attr-char1 / lit-char
+attr-name = attr-name1 / attr-name2
+ */
+
+
+
+static inline bool is_wspace(uint8_t c)
+{
+ /* wspace := %x09-0D | %x20 */
+ return (c == ' ' || c == '\x09' || c == '\x0A' ||
+ c == '\x0B' || c == '\x0C' || c == '\x0D');
+}
+
+static inline bool is_attr_char1(uint8_t c)
+{
+ /*
+ * attr-char1 = 1*(ALPHA / DIGIT / ":" / "." / "/" / "_")
+ * (ALPHA and DIGIT being ASCII only).
+ *
+ * These are used for local attributes, which we don't really
+ * expect to see in Samba AD.
+ *
+ * One example is "WIN://SYSAPPID", which is used in conditional ACEs
+ * that seem to relate to software installers; another is
+ * "APPID://PATH", used by Windows Applocker.
+ */
+ return (((c >= 'a') && (c <= 'z')) ||
+ ((c >= 'A') && (c <= 'Z')) ||
+ ((c >= '0') && (c <= '9')) ||
+ c == ':' || c == '.' || c == '/' || c == '_');
+}
+
+
+static ssize_t read_attr2_string(
+ struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_unicode *dest)
+{
+ /*
+ * our SDDL is utf-8, but we need to convert to utf-16 and
+ * parse the escapes, then back to utf-8, because that's how
+ * the claims will appear.
+ *
+ * attr_char2 is used for attribute names that follow "@Class."
+ * specifiers. They can consume 5 characters to specify a single code
+ * unit, using "%1234" style escapes. Certain characters must be
+ * encoded this way, while others must be literal values. Because the
+ * %1234 refers to a utf-16 code unit, we really need to do the work
+ * in that codespace.
+ */
+ bool ok;
+ uint16_t *utf16 = NULL;
+ size_t utf16_byte_len;
+ size_t utf16_chars;
+ size_t utf8_len;
+ size_t src_len;
+ ssize_t i, j;
+ ssize_t max_len = comp->length - comp->offset;
+ const uint8_t *src = comp->sddl + comp->offset;
+
+ for (i = 0; i < max_len; i++) {
+ uint8_t c = src[i];
+ /*
+ * A double‐byte that must be escaped but isn't tells us that
+ * the attribute name has ended.
+ *
+ * The exception is '%', which must also be escaped
+ * (as "%0025"), but is obviously still expected in
+ * the escaped string.
+ */
+ if (strchr("!&()><=| \"", c) != NULL || is_wspace(c)) {
+ break;
+ }
+ }
+ if (i == max_len) {
+ /* too long, because we need at least one ')' */
+ comp_error(comp, "interminable attribute name");
+ return -1;
+ }
+ if (i == 0) {
+ /* too short! like "User.>= 4" */
+ comp_error(comp, "empty attribute name");
+ return -1;
+ }
+
+ if (unlikely(i > CONDITIONAL_ACE_MAX_LENGTH)) {
+ /*
+ * This is imprecise; the limit for the whole ACL is 64k.
+ * However there could be many escapes in the SDDL name which
+ * would reduce down to single utf16 code units in the
+ * compiled string.
+ */
+ comp_error(comp, "attribute is way too long (%zu)", i);
+ return -1;
+ }
+
+ src_len = i;
+
+ ok = convert_string_talloc(comp->mem_ctx,
+ CH_UTF8, CH_UTF16LE,
+ src, src_len,
+ &utf16, &utf16_byte_len);
+ if (!ok) {
+ comp_error(comp, "could not convert to utf-16");
+ return -1;
+ }
+ /*
+ * utf16_byte_len is in bytes, we want to count uint16s.
+ */
+ utf16_chars = utf16_byte_len / 2;
+
+ /* now the escapes. */
+ for (i = 0, j = 0;
+ j < utf16_chars && i < utf16_chars;
+ j++) {
+ uint16_t c = utf16[i];
+ if (c == '%') {
+ uint16_t v = 0;
+ size_t end = i + 5;
+ /*
+ * we need to read 4 hex characters.
+ * hex_byte() won't help because that is 8-bit.
+ */
+ if (end > utf16_chars) {
+ comp_error(comp,
+ "insufficient room for %% escape");
+ talloc_free(utf16);
+ return -1;
+ }
+ for (i++; i < end; i++) {
+ v <<= 4;
+ c = utf16[i];
+ if (c >= '0' && c <= '9') {
+ v += c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ v += c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'f') {
+ v += c - 'a' + 10;
+ } else {
+ comp_error(comp, "invalid %% escape");
+ talloc_free(utf16);
+ return -1;
+ }
+ }
+ /*
+ * from MS-DTYP 2.5.1.1 Syntax (text, not ABNF), some
+ * characters must be literals, not escaped.
+ */
+ if ((v >= '0' && v <= '9') ||
+ (v >= 'A' && v <= 'Z') ||
+ (v >= 'a' && v <= 'z') ||
+ (v < 127 &&
+ strchr("#$'*+-;?@[\\]^_`{}~:/.", v) != NULL)) {
+ comp_error(comp, "invalid %% escape: "
+ "'%%%04x' should be literal '%c'",
+ v, v);
+ talloc_free(utf16);
+ return -1;
+ }
+ utf16[j] = v;
+ continue;
+ }
+ /*
+ * Note the characters "!&()><=|% \"" must be escaped per
+ * [MS-DTYP], but as we found the bounds of this string using
+ * those in utf-8 at the top of this function, we are not
+ * going to find them in the utf-16 now.
+ *
+ * Also, per [MS-DTYP], un-escaped whitespace is allowed, but
+ * effectively disallowed by Samba.
+ */
+ utf16[j] = utf16[i];
+ i++;
+ }
+
+ ok = convert_string_talloc(comp->mem_ctx,
+ CH_UTF16LE, CH_UTF8,
+ utf16, j * 2,
+ &dest->value, &utf8_len);
+ TALLOC_FREE(utf16);
+ if (!ok) {
+ comp_error(comp, "could not convert to utf-16");
+ return -1;
+ }
+
+ /* returning bytes consumed, not necessarily the length of token */
+ return src_len;
+}
+
+
+
+static bool eat_whitespace(struct ace_condition_sddl_compiler_context *comp,
+ bool trailing)
+{
+ /*
+ * Advance the offset to the first non-whitespace character.
+ *
+ * If trailing is false, there has to be something before the end of
+ * the string.
+ */
+ while (comp->offset < comp->length) {
+ if (! is_wspace(comp->sddl[comp->offset])) {
+ break;
+ }
+ comp->offset++;
+ }
+ if ((!trailing) && comp->offset == comp->length) {
+ comp_error(comp, "input ends unexpectedly");
+ return false;
+ }
+ return true;
+}
+
+static bool pop_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token *token);
+
+static bool write_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token token);
+
+static bool pop_write_sddl_token(
+ struct ace_condition_sddl_compiler_context *comp);
+
+
+static bool flush_stack_tokens(struct ace_condition_sddl_compiler_context *comp,
+ uint8_t type)
+{
+ bool ok;
+ uint8_t precedence = sddl_strings[type].op_precedence;
+ if (precedence == SDDL_PRECEDENCE_PAREN_START) {
+ /* paren has a special role */
+ return true;
+ }
+ /*
+ * Any operators on the top of the stack that have a "higher"
+ * precedence (tighter binding) to this one get popped off and written
+ * to the output. "higher" is in quotes because it means lower enum
+ * value.
+ *
+ * This works for binary operators, for example, with "(a == b == c)"
+ * (which is equivalent to "((a == b) == c)" via the left-to-right
+ * rule), we have:
+ * TOKEN dest PROGRAM STACK
+ * (
+ * a p
+ * == s a
+ * b p a ==
+ * == s a b ==
+ * flush stack
+ * s->p a b == ==
+ * c p a b ==
+ * ) a b == c ==
+ * flush stack
+ * a b == c ==
+ *
+ * but it is not right for unary operators, as in "(!(!(Exists
+ * a)))". As it turns out though, >= works for the unary
+ * operators and syntactic rules we have.
+ */
+ while (comp->stack_depth > 0) {
+ struct ace_condition_token *op =
+ &comp->stack[comp->stack_depth - 1];
+ if(sddl_strings[op->type].op_precedence > precedence) {
+ break;
+ }
+ if(sddl_strings[op->type].op_precedence == precedence &&
+ sddl_strings[op->type].flags & SDDL_FLAG_IS_UNARY_OP) {
+ break;
+ }
+
+ ok = pop_write_sddl_token(comp);
+ if (! ok) {
+ comp_error(comp,
+ "could not flush '%s' to program",
+ sddl_strings[op->type].name);
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool push_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token token)
+{
+ if (comp->stack_depth >= CONDITIONAL_ACE_MAX_TOKENS - 1) {
+ comp_error(comp, "excessive recursion");
+ return false;
+ }
+ if (sddl_strings[token.type].op_precedence == SDDL_NOT_AN_OP) {
+ comp_error(comp,
+ "wrong kind of token for the SDDL stack: %s",
+ sddl_strings[token.type].name);
+ return false;
+ }
+ /*
+ * Any operators on the top of the stack that have a "greater" or
+ * equal precedence to this one get popped off and written to the
+ * output.
+ */
+ flush_stack_tokens(comp, token.type);
+
+ token.data.op.sddl_position = comp->offset;
+
+ comp->stack[comp->stack_depth] = token;
+ comp->stack_depth++;
+ if (token.type != CONDITIONAL_ACE_SAMBA_SDDL_PAREN) {
+ comp->last_token_type = token.type;
+ }
+ return true;
+}
+
+static bool pop_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token *token)
+{
+ if (comp->stack_depth == 0) {
+ comp_error(comp, "misbalanced expression");
+ return false;
+ }
+ comp->stack_depth--;
+ *token = comp->stack[comp->stack_depth];
+ return true;
+}
+
+
+static bool write_sddl_token(struct ace_condition_sddl_compiler_context *comp,
+ struct ace_condition_token token)
+{
+ /*
+ * This is adding a token to the program. Normally it will be to the
+ * main program list, but if we are constructing a composite list, then
+ * will be redirected there (via comp->target).
+ *
+ * We also conservatively track the overall size, so we don't waste
+ * time compiling something that is way too big.
+ */
+ DBG_INFO("writing %"PRIu32" %x %s\n",
+ *comp->target_len,
+ token.type,
+ sddl_strings[token.type].name);
+ comp->approx_size++;
+ if (comp->approx_size > CONDITIONAL_ACE_MAX_TOKENS) {
+ comp_error(comp, "program is too long "
+ "(over %d tokens)",
+ CONDITIONAL_ACE_MAX_TOKENS);
+ return false;
+ }
+ if (token.type != CONDITIONAL_ACE_SAMBA_SDDL_PAREN) {
+ comp->last_token_type = token.type;
+ }
+ comp->target[*comp->target_len] = token;
+ (*comp->target_len)++;
+ return true;
+}
+
+static bool pop_write_sddl_token(
+ struct ace_condition_sddl_compiler_context *comp)
+{
+ bool ok;
+ struct ace_condition_token token = {};
+ ok = pop_sddl_token(comp, &token);
+ if (!ok) {
+ comp_error(comp, "could not pop from op stack");
+ return false;
+ }
+ if (comp->target != comp->program->tokens) {
+ comp_error(comp, "compiler is seriously confused");
+ return false;
+ }
+
+ ok = write_sddl_token(comp, token);
+ if (!ok) {
+ comp_error(comp,
+ "could not write '%s' to program",
+ sddl_strings[token.type].name);
+ return false;
+ }
+ DBG_INFO(" written '%s'\n", sddl_strings[token.type].name);
+ return true;
+}
+
+
+
+static bool parse_expression(struct ace_condition_sddl_compiler_context *comp);
+static bool parse_composite(struct ace_condition_sddl_compiler_context *comp);
+
+
+
+
+static bool parse_oppy_op(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * These ones look like operators and are operators.
+ */
+ bool ok;
+ struct ace_condition_token token = {};
+ uint8_t c, d;
+ uint32_t flag = SDDL_FLAG_EXPECTING_BINARY_OP;
+
+ if (comp->offset + 1 >= comp->length) {
+ comp_error(comp, "syntax error");
+ return false;
+ }
+
+ token.data.sddl_op.start = comp->offset;
+
+ /*
+ * These are all one or two characters long, and we always have room
+ * to peek ahead.
+ */
+ c = comp->sddl[comp->offset];
+ d = comp->sddl[comp->offset + 1];
+
+ if (c == '!') {
+ if (d == '=') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_NOT_EQUAL;
+
+ } else {
+ token.type = CONDITIONAL_ACE_TOKEN_NOT;
+ flag = SDDL_FLAG_EXPECTING_UNARY_OP;
+ }
+ } else if (c == '=' && d == '=') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_EQUAL;
+ } else if (c == '>') {
+ if (d == '=') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL;
+
+ } else {
+ token.type = CONDITIONAL_ACE_TOKEN_GREATER_THAN;
+ }
+ } else if (c == '<') {
+ if (d == '=') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL;
+
+ } else {
+ token.type = CONDITIONAL_ACE_TOKEN_LESS_THAN;
+ }
+ } else if (c == '&' && d == '&') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_AND;
+ flag = SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP;
+ } else if (c == '|' && d == '|') {
+ comp->offset++;
+ token.type = CONDITIONAL_ACE_TOKEN_OR;
+ flag = SDDL_FLAG_EXPECTING_BINARY_LOGIC_OP;
+ } else {
+ comp_error(comp, "unknown operator");
+ return false;
+ }
+
+ if ((comp->state & flag) == 0) {
+ comp_error(comp, "unexpected operator");
+ return false;
+ }
+
+ comp->offset++;
+
+ ok = push_sddl_token(comp, token);
+ if (!ok) {
+ return false;
+ }
+
+ ok = eat_whitespace(comp, true);
+ return ok;
+}
+
+static bool parse_unicode(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This looks like "hello" (including the double quotes).
+ *
+ * Fortunately (for now), there is no mechanism for escaping
+ * double quotes in conditional ace strings, so we can simply
+ * look for the second quote without worrying about things
+ * like «\\\"».
+ */
+ struct ace_condition_token token = {};
+ char *s = NULL;
+ const uint8_t *src = NULL;
+ char *utf16 = NULL;
+ size_t len, max_len;
+ bool ok;
+ if (comp->sddl[comp->offset] != '"') {
+ comp_error(comp, "was expecting '\"' for Unicode string");
+ return false;
+ }
+ comp->offset++;
+ src = comp->sddl + comp->offset;
+ max_len = comp->length - comp->offset;
+ /* strnchr */
+ for (len = 0; len < max_len; len++) {
+ if (src[len] == '"') {
+ break;
+ }
+ }
+ if (len == max_len) {
+ comp_error(comp, "unterminated unicode string");
+ return false;
+ }
+
+ /*
+ * Look, this is wasteful, but it probably doesn't matter. We want to
+ * check that the string we're putting into the descriptor is valid,
+ * or we'll see errors down the track.
+ */
+ ok = convert_string_talloc(comp->mem_ctx,
+ CH_UTF8, CH_UTF16LE,
+ src, len,
+ &utf16, NULL);
+ if (!ok) {
+ comp_error(comp, "not valid unicode");
+ return false;
+ }
+ TALLOC_FREE(utf16);
+
+ s = talloc_array_size(comp->mem_ctx, 1, len + 1);
+ if (s == NULL) {
+ comp_error(comp, "allocation error");
+ return false;
+ }
+ memcpy(s, src, len);
+ s[len] = 0;
+ comp->offset += len + 1; /* +1 for the final quote */
+ token.type = CONDITIONAL_ACE_TOKEN_UNICODE;
+ token.data.unicode.value = s;
+
+ return write_sddl_token(comp, token);
+}
+
+
+static bool parse_octet_string(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This looks like '#hhhh...', where each 'hh' is hex for a byte, with
+ * the weird and annoying complication that '#' can be used to mean
+ * '0'.
+ */
+ struct ace_condition_token token = {};
+ size_t length, i;
+
+ if (comp->sddl[comp->offset] != '#') {
+ comp_error(comp, "was expecting '#' for octet string");
+ return false;
+ }
+ comp->offset++;
+ length = strspn((const char*)(comp->sddl + comp->offset),
+ "#0123456789abcdefABCDEF");
+
+ if (length & 1) {
+ comp_error(comp, "octet string has odd number of hex digits");
+ return false;
+ }
+
+ length /= 2;
+
+ token.data.bytes = data_blob_talloc_zero(comp->mem_ctx, length);
+ token.type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
+
+ for (i = 0; i < length; i++) {
+ /*
+ * Why not just strhex_to_str()?
+ *
+ * Because we need to treat '#' as '0' in octet string values,
+ * so all of the following are the same
+ * (equaling {0x10, 0x20, 0x30, 0x0}).
+ *
+ * #10203000
+ * #10203###
+ * #1#2#3###
+ * #10203#00
+ */
+ bool ok;
+ char pair[2];
+ size_t j = comp->offset + i * 2;
+ pair[0] = (comp->sddl[j] == '#') ? '0' : comp->sddl[j];
+ pair[1] = (comp->sddl[j + 1] == '#') ? '0' : comp->sddl[j + 1];
+
+ ok = hex_byte(pair, &token.data.bytes.data[i]);
+ if (!ok) {
+ talloc_free(token.data.bytes.data);
+ comp_error(comp, "inexplicable error in octet string");
+ return false;
+ }
+ }
+ comp->offset += length * 2;
+ return write_sddl_token(comp, token);
+}
+
+
+static bool parse_ra_octet_string(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * Resource attribute octet strings resemble conditional ace octet
+ * strings, but have some important differences:
+ *
+ * 1. The '#' at the start is optional, and if present is
+ * counted as a zero.
+ *
+ * 2. An odd number of characters is implicitly left-padded with a zero.
+ *
+ * That is, "abc" means "0abc", "#12" means "0012", "f##"
+ * means "0f00", and "##" means 00.
+ */
+ struct ace_condition_token token = {};
+ size_t string_length, bytes_length, i, j;
+ bool ok;
+ char pair[2];
+
+ string_length = strspn((const char*)(comp->sddl + comp->offset),
+ "#0123456789abcdefABCDEF");
+
+ bytes_length = (string_length + 1) / 2;
+
+ if (bytes_length == 0) {
+ comp_error(comp, "zero length octet bytes");
+ return false;
+ }
+
+ token.data.bytes = data_blob_talloc_zero(comp->mem_ctx, bytes_length);
+ if (token.data.bytes.data == NULL) {
+ return false;
+ }
+ token.type = CONDITIONAL_ACE_TOKEN_OCTET_STRING;
+
+ j = comp->offset;
+ i = 0;
+ if (string_length & 1) {
+ /*
+ * An odd number of characters means the first
+ * character gains an implicit 0 for the high nybble.
+ */
+ pair[0] = 0;
+ pair[1] = (comp->sddl[0] == '#') ? '0' : comp->sddl[0];
+
+ ok = hex_byte(pair, &token.data.bytes.data[i]);
+ if (!ok) {
+ goto fail;
+ }
+ j++;
+ i++;
+ }
+
+ for (; i < bytes_length; i++) {
+ /*
+ * Why not just strhex_to_str() ?
+ *
+ * Because we need to treat '#' as '0' in octet string values.
+ */
+ if (comp->length - j < 2) {
+ goto fail;
+ }
+
+ pair[0] = (comp->sddl[j] == '#') ? '0' : comp->sddl[j];
+ pair[1] = (comp->sddl[j + 1] == '#') ? '0' : comp->sddl[j + 1];
+
+ ok = hex_byte(pair, &token.data.bytes.data[i]);
+ if (!ok) {
+ goto fail;
+ }
+ j += 2;
+ }
+ comp->offset = j;
+ return write_sddl_token(comp, token);
+
+fail:
+ comp_error(comp, "inexplicable error in octet string");
+ talloc_free(token.data.bytes.data);
+ return false;
+}
+
+
+static bool parse_sid(struct ace_condition_sddl_compiler_context *comp)
+{
+ struct dom_sid *sid = NULL;
+ const uint8_t *sidstr = NULL;
+ struct ace_condition_token token = {};
+ size_t end;
+ if (comp->length - comp->offset < 7) {
+ /* minimum: "SID(AA)" */
+ comp_error(comp, "no room for a complete SID");
+ return false;
+ }
+ /* conditional ACE SID string */
+ if (comp->sddl[comp->offset ] != 'S' ||
+ comp->sddl[comp->offset + 1] != 'I' ||
+ comp->sddl[comp->offset + 2] != 'D' ||
+ comp->sddl[comp->offset + 3] != '(') {
+ comp_error(comp, "malformed SID() constructor");
+ return false;
+ } else {
+ comp->offset += 4;
+ }
+
+ sidstr = comp->sddl + comp->offset;
+
+ sid = sddl_decode_sid(comp->mem_ctx,
+ (const char **)&sidstr,
+ comp->domain_sid);
+
+ if (sid == NULL) {
+ comp_error(comp, "could not parse SID");
+ return false;
+ }
+ end = sidstr - comp->sddl;
+ if (end >= comp->length || end < comp->offset) {
+ comp_error(comp, "apparent overflow in SID parsing");
+ return false;
+ }
+ comp->offset = end;
+ /*
+ * offset is now at the end of the SID, but we need to account
+ * for the ')'.
+ */
+ if (comp->sddl[comp->offset] != ')') {
+ comp_error(comp, "expected ')' to follow SID");
+ return false;
+ }
+ comp->offset++;
+
+ token.type = CONDITIONAL_ACE_TOKEN_SID;
+ token.data.sid.sid = *sid;
+ return write_sddl_token(comp, token);
+}
+
+
+
+static bool parse_ra_sid(struct ace_condition_sddl_compiler_context *comp)
+{
+ struct dom_sid *sid = NULL;
+ const uint8_t *sidstr = NULL;
+ struct ace_condition_token token = {};
+ size_t end;
+
+ if ((comp->state & SDDL_FLAG_EXPECTING_LITERAL) == 0) {
+ comp_error(comp, "did not expect a SID here");
+ return false;
+ }
+ /*
+ * Here we are parsing a resource attribute ACE which doesn't
+ * have the SID() wrapper around the SID string (unlike a
+ * conditional ACE).
+ *
+ * The resource ACE doesn't need this because there is no
+ * ambiguity with local attribute names, besides which the
+ * type has already been specified earlier in the ACE.
+ */
+ if (comp->length - comp->offset < 2){
+ comp_error(comp, "no room for a complete SID");
+ return false;
+ }
+
+ sidstr = comp->sddl + comp->offset;
+
+ sid = sddl_decode_sid(comp->mem_ctx,
+ (const char **)&sidstr,
+ comp->domain_sid);
+
+ if (sid == NULL) {
+ comp_error(comp, "could not parse SID");
+ return false;
+ }
+ end = sidstr - comp->sddl;
+ if (end >= comp->length || end < comp->offset) {
+ comp_error(comp, "apparent overflow in SID parsing");
+ return false;
+ }
+ comp->offset = end;
+ token.type = CONDITIONAL_ACE_TOKEN_SID;
+ token.data.sid.sid = *sid;
+ return write_sddl_token(comp, token);
+}
+
+
+static bool parse_int(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This one is relatively simple. strtoll() does the work.
+ */
+ long long v;
+ struct ace_condition_token token = {};
+ const char *start = (const char *)comp->sddl + comp->offset;
+ char *end = NULL;
+ const char *first_digit = start;
+ size_t len;
+ errno = 0;
+ v = strtoll(start, &end, 0);
+ if (errno != 0) {
+ comp_error(comp, "bad integer: %s", strerror(errno));
+ return false;
+ }
+ len = end - start;
+
+ if (len == 0) {
+ comp_error(comp, "unexpected non-integer");
+ return false;
+ }
+ if (comp->offset + len > comp->length) {
+ comp_error(comp, "impossible integer length: %zu!", len);
+ return false;
+ }
+
+ comp->offset += len;
+
+ /*
+ * Record the base and sign, which are used for recreating the SDDL.
+ *
+ * 'Sign' indicates whether there is a '+' or '-' sign. Base indicates
+ * whether the number was in hex, octal, or decimal. These make no
+ * difference to the evaluation of the ACE, just the display.
+ *
+ * This would not work reliably if eat_whitespace() is not called
+ * before parse_int(), but a) we know it is, and b) we don't *really*
+ * care if we lose these display hints.
+ */
+ if (*start == '-') {
+ token.data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NEGATIVE;
+ first_digit++;
+ } else if (*start == '+') {
+ token.data.int64.sign = CONDITIONAL_ACE_INT_SIGN_POSITIVE;
+ first_digit++;
+ } else {
+ token.data.int64.sign = CONDITIONAL_ACE_INT_SIGN_NONE;
+ }
+ if (*first_digit == '0' && (end - first_digit) > 1) {
+ if ((end - first_digit > 2) &&
+ (first_digit[1] == 'x' ||
+ first_digit[1] == 'X')) {
+ token.data.int64.base = CONDITIONAL_ACE_INT_BASE_16;
+ } else {
+ token.data.int64.base = CONDITIONAL_ACE_INT_BASE_8;
+ }
+ } else {
+ token.data.int64.base = CONDITIONAL_ACE_INT_BASE_10;
+ }
+
+ token.data.int64.value = v;
+ token.type = CONDITIONAL_ACE_TOKEN_INT64;
+ return write_sddl_token(comp, token);
+}
+
+
+static bool parse_uint(struct ace_condition_sddl_compiler_context *comp)
+{
+ struct ace_condition_token *tok = NULL;
+ bool ok = parse_int(comp);
+ if (ok == false) {
+ return false;
+ }
+ /*
+ * check that the token's value is positive.
+ */
+ if (comp->target_len == 0) {
+ return false;
+ }
+ tok = &comp->target[*comp->target_len - 1];
+ if (tok->type != CONDITIONAL_ACE_TOKEN_INT64) {
+ return false;
+ }
+ if (tok->data.int64.value < 0) {
+ comp_error(comp, "invalid resource ACE value for unsigned TU claim");
+ return false;
+ }
+ return true;
+}
+
+
+static bool parse_bool(struct ace_condition_sddl_compiler_context *comp)
+{
+ struct ace_condition_token *tok = NULL;
+ bool ok = parse_int(comp);
+ if (ok == false || comp->target_len == 0) {
+ return false;
+ }
+ /*
+ * check that the token is 0 or 1.
+ */
+ tok = &comp->target[*comp->target_len - 1];
+ if (tok->type != CONDITIONAL_ACE_TOKEN_INT64) {
+ return false;
+ }
+ if (tok->data.int64.value != 0 && tok->data.int64.value != 1) {
+ comp_error(comp, "invalid resource ACE Boolean value");
+ return false;
+ }
+ return true;
+}
+
+
+static bool could_be_an_int(struct ace_condition_sddl_compiler_context *comp)
+{
+ const char *start = (const char*)(comp->sddl + comp->offset);
+ char* end = NULL;
+
+ if ((comp->state & SDDL_FLAG_EXPECTING_LITERAL) == 0) {
+ return false;
+ }
+
+ errno = 0;
+ /*
+ * See, we don't care about the strtoll return value, only
+ * whether it succeeds or not and what it finds at the end. If
+ * it succeeds, parse_int() will do it again for the value.
+ *
+ * Note that an out of range int will raise ERANGE (probably
+ * 34), so it will be read as a local attribute.
+ */
+ strtoll(start, &end, 0);
+ if (errno != 0 ||
+ end == start ||
+ end >= (const char*)comp->sddl + comp->length) {
+ return false;
+ }
+ /*
+ * We know *some* characters form an int, but if we run right
+ * into other attr1 characters (basically, letters), we won't
+ * count it as an int.
+ *
+ * For example, the "17" in "17p" is not an int. The "17" in
+ * "17||" is.
+ */
+ if (is_attr_char1(*end)) {
+ return false;
+ }
+ return true;
+}
+
+
+static bool parse_word(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * Sometimes a bare word must be a local attribute, while in other
+ * cases it could also be a member-of or exists operator. Sometimes it
+ * could actually be a SID, which we discover when we've read as far
+ * as "SID(". Sometimes it might be a literal integer (attribute
+ * names can also consist entirely of digits).
+ *
+ * When it is an operator name, we have the complication that a match
+ * does not necessarily end the token. Consider "Member_of_Any" which
+ * contains the operator "Member_of". According to [MS-DTYP], a space
+ * is not necessary between the operator and the next token, but it
+ * does seem to be required for Windows 2022.
+ *
+ * Also, "Member_of" et. al. *could* be valid local attributes, which
+ * would make "(Member_of == 123)" a valid expression that we will
+ * fail to parse. This is not much of an issue for Samba AD where
+ * local attributes are not used.
+ *
+ * Operators are matched case-insensitively.
+ *
+ * There's another kind of attribute that starts with a '@', which we
+ * deal with in parse_attr2(). Those ones have full unicode glory;
+ * these ones are ASCII only.
+ */
+ size_t i, j, k;
+ bool ok;
+ uint8_t candidates[8];
+ size_t n_candidates = 0;
+ struct ace_condition_token token = {};
+ bool expecting_unary = comp->state & SDDL_FLAG_EXPECTING_UNARY_OP;
+ bool expecting_binary = comp->state & SDDL_FLAG_EXPECTING_BINARY_OP;
+ bool expecting_attr = comp->state & SDDL_FLAG_EXPECTING_LOCAL_ATTR;
+ bool expecting_literal = comp->state & SDDL_FLAG_EXPECTING_LITERAL;
+ const uint8_t *start = comp->sddl + comp->offset;
+ uint8_t c = start[0];
+ char *s = NULL;
+ if (! is_attr_char1(*start)) {
+ /* we shouldn't get here, because we peeked first */
+ return false;
+ }
+
+ /*
+ * We'll look for a SID first, because it simplifies the rest.
+ */
+ if (expecting_literal &&
+ comp->offset + 4 < comp->length &&
+ start[0] == 'S' &&
+ start[1] == 'I' &&
+ start[2] == 'D' &&
+ start[3] == '(') {
+ /* actually, we are parsing a SID. */
+ return parse_sid(comp);
+ }
+
+ if (expecting_binary || expecting_unary) {
+ /*
+ * Collect up the operators that can possibly be used
+ * here, including only those that start with the
+ * current letter and have the right arity/syntax.
+ *
+ * We don't expect more than 5 (for 'N', beginning the
+ * "Not_..." unary ops), and we'll winnow them down as
+ * we progress through the word.
+ */
+ int uc = toupper(c);
+ for (i = 0; i < 256; i++) {
+ const struct sddl_data *d = &sddl_strings[i];
+ if (sddl_strings[i].op_precedence != SDDL_NOT_AN_OP &&
+ uc == toupper((unsigned char)d->name[0])) {
+ if (d->flags & SDDL_FLAG_IS_UNARY_OP) {
+ if (!expecting_unary) {
+ continue;
+ }
+ } else if (!expecting_binary) {
+ continue;
+ }
+ candidates[n_candidates] = i;
+ n_candidates++;
+ if (n_candidates == ARRAY_SIZE(candidates)) {
+ /* impossible, really. */
+ return false;
+ }
+ }
+ }
+ } else if (could_be_an_int(comp)) {
+ /*
+ * if looks like an integer, and we expect an integer, it is
+ * an integer. If we don't expect an integer, it is a local
+ * attribute with a STUPID NAME. Or an error.
+ */
+ return parse_int(comp);
+ } else if (! expecting_attr) {
+ comp_error(comp, "did not expect this word here");
+ return false;
+ }
+
+ i = 1;
+ while (comp->offset + i < comp->length) {
+ c = start[i];
+ if (! is_attr_char1(c)) {
+ break;
+ }
+ if (n_candidates != 0) {
+ /*
+ * Filter out candidate operators that no longer
+ * match.
+ */
+ int uc = toupper(c);
+ k = 0;
+ for (j = 0; j < n_candidates; j++) {
+ size_t o = candidates[j];
+ uint8_t c2 = sddl_strings[o].name[i];
+ if (uc == toupper(c2)) {
+ candidates[k] = candidates[j];
+ k++;
+ }
+ }
+ n_candidates = k;
+ }
+ i++;
+ }
+
+ /*
+ * We have finished and there is a complete word. If it could be an
+ * operator we'll assume it is one.
+ *
+ * A complication is we could have matched more than one operator, for
+ * example "Member_of" and "Member_of_Any", so we have to look through
+ * the list of candidates for the one that ends.
+ */
+ if (n_candidates != 0) {
+ for (j = 0; j < n_candidates; j++) {
+ size_t o = candidates[j];
+ if (sddl_strings[o].name[i] == '\0') {
+ /* it is this one */
+
+ if (!comp->allow_device &&
+ (sddl_strings[o].flags & SDDL_FLAG_DEVICE))
+ {
+ comp_error(
+ comp,
+ "a device‐relative expression "
+ "will never evaluate to true "
+ "in this context (did you "
+ "intend a user‐relative "
+ "expression?)");
+ return false;
+ }
+
+ token.type = o;
+ token.data.sddl_op.start = comp->offset;
+ comp->offset += i;
+ ok = push_sddl_token(comp, token);
+ return ok;
+ }
+ }
+ }
+ /*
+ * if looks like an integer, and we expect an integer, it is
+ * an integer. If we don't expect an integer, it is a local
+ * attribute with a STUPID NAME.
+ */
+ if (could_be_an_int(comp)) {
+ return parse_int(comp);
+ }
+
+ if (! expecting_attr) {
+ comp_error(comp, "word makes no sense here");
+ return false;
+ }
+ /* it's definitely an attribute name */
+ token.type = CONDITIONAL_ACE_LOCAL_ATTRIBUTE;
+ if (comp->offset + i >= comp->length) {
+ comp_error(comp, "missing trailing ')'?");
+ return false;
+ }
+
+ s = talloc_memdup(comp->mem_ctx, start, i + 1);
+ if (s == NULL) {
+ comp_error(comp, "allocation error");
+ return false;
+ }
+ s[i] = 0;
+ token.data.local_attr.value = s;
+ comp->offset += i;
+ return write_sddl_token(comp, token);
+}
+
+static bool parse_attr2(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * Attributes in the form @class.attr
+ *
+ * class can be "User", "Device", or "Resource", case insensitive.
+ */
+ size_t i;
+ bool ok;
+ size_t len;
+ struct ace_condition_token token = {};
+
+ if ((comp->state & SDDL_FLAG_EXPECTING_NON_LOCAL_ATTR) == 0) {
+ comp_error(comp, "did not expect @attr here");
+ return false;
+ }
+ if (comp->sddl[comp->offset] != '@') {
+ comp_error(comp, "Expected '@'");
+ return false;
+ }
+ comp->offset++;
+
+ for (i = 0; i < ARRAY_SIZE(sddl_attr_types); i++) {
+ int ret;
+ size_t attr_len = strlen(sddl_attr_types[i].name);
+ if (attr_len >= comp->length - comp->offset) {
+ continue;
+ }
+ ret = strncasecmp(sddl_attr_types[i].name,
+ (const char *) (comp->sddl + comp->offset),
+ attr_len);
+ if (ret == 0) {
+ const uint8_t code = sddl_attr_types[i].code;
+
+ if (!comp->allow_device &&
+ (sddl_strings[code].flags & SDDL_FLAG_DEVICE))
+ {
+ comp_error(comp,
+ "a device attribute is not "
+ "applicable in this context (did "
+ "you intend a user attribute?)");
+ return false;
+ }
+
+ token.type = code;
+ comp->offset += attr_len;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(sddl_attr_types)) {
+ comp_error(comp, "unknown attribute class");
+ return false;
+ }
+
+ /*
+ * Now we are past the class and the '.', and into the
+ * attribute name. The attribute name can be almost
+ * anything, but some characters need to be escaped.
+ */
+
+ len = read_attr2_string(comp, &token.data.unicode);
+ if (len == -1) {
+ /* read_attr2_string has set a message */
+ return false;
+ }
+ ok = write_sddl_token(comp, token);
+ if (! ok) {
+ return false;
+ }
+ comp->offset += len;
+ ok = eat_whitespace(comp, false);
+ return ok;
+}
+
+static bool parse_literal(struct ace_condition_sddl_compiler_context *comp,
+ bool in_composite)
+{
+ uint8_t c = comp->sddl[comp->offset];
+ if (!(comp->state & SDDL_FLAG_EXPECTING_LITERAL)) {
+ comp_error(comp, "did not expect to be parsing a literal now");
+ return false;
+ }
+ switch(c) {
+ case '#':
+ return parse_octet_string(comp);
+ case '"':
+ return parse_unicode(comp);
+ case 'S':
+ return parse_sid(comp);
+ case '{':
+ if (in_composite) {
+ /* nested composites are not supported */
+ return false;
+ } else {
+ return parse_composite(comp);
+ }
+ default:
+ if (strchr("1234567890-+", c) != NULL) {
+ return parse_int(comp);
+ }
+ }
+ if (c > 31 && c < 127) {
+ comp_error(comp,
+ "unexpected byte 0x%02x '%c' parsing literal", c, c);
+ } else {
+ comp_error(comp, "unexpected byte 0x%02x parsing literal", c);
+ }
+ return false;
+}
+
+
+static bool parse_composite(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This jumps into a different parser, expecting a comma separated
+ * list of literal values, which might include nested literal
+ * composites.
+ *
+ * To handle the nesting, we redirect the pointers that determine
+ * where write_sddl_token() writes.
+ */
+ bool ok;
+ bool first = true;
+ struct ace_condition_token token = {
+ .type = CONDITIONAL_ACE_TOKEN_COMPOSITE
+ };
+ uint32_t start = comp->offset;
+ size_t alloc_size;
+ struct ace_condition_token *old_target = comp->target;
+ uint32_t *old_target_len = comp->target_len;
+
+ if (comp->sddl[start] != '{') {
+ comp_error(comp, "expected '{' for composite list");
+ return false;
+ }
+ if (!(comp->state & SDDL_FLAG_EXPECTING_LITERAL)) {
+ comp_error(comp, "did not expect '{' for composite list");
+ return false;
+ }
+ comp->offset++; /* past '{' */
+
+ /*
+ * the worst case is one token for every two bytes: {1,1,1}, and we
+ * allocate for that (counting commas and finding '}' gets hard because
+ * string literals).
+ */
+ alloc_size = MIN((comp->length - start) / 2 + 1,
+ CONDITIONAL_ACE_MAX_LENGTH);
+
+ token.data.composite.tokens = talloc_array(
+ comp->mem_ctx,
+ struct ace_condition_token,
+ alloc_size);
+ if (token.data.composite.tokens == NULL) {
+ comp_error(comp, "allocation failure");
+ return false;
+ }
+
+ comp->target = token.data.composite.tokens;
+ comp->target_len = &token.data.composite.n_members;
+
+ /*
+ * in this loop we are looking for:
+ *
+ * a) possible whitespace.
+ * b) a comma (or terminating '}')
+ * c) more possible whitespace
+ * d) a literal
+ *
+ * Failures use a goto to reset comp->target, just in case we ever try
+ * continuing after error.
+ */
+ while (comp->offset < comp->length) {
+ uint8_t c;
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ goto fail;
+ }
+ c = comp->sddl[comp->offset];
+ if (c == '}') {
+ comp->offset++;
+ break;
+ }
+ if (!first) {
+ if (c != ',') {
+ comp_error(comp,
+ "malformed composite (expected comma)");
+ goto fail;
+ }
+ comp->offset++;
+
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ goto fail;
+ }
+ }
+ first = false;
+ if (*comp->target_len >= alloc_size) {
+ comp_error(comp,
+ "Too many tokens in composite "
+ "(>= %"PRIu32" tokens)",
+ *comp->target_len);
+ goto fail;
+ }
+ ok = parse_literal(comp, true);
+ if (!ok) {
+ goto fail;
+ }
+ }
+ comp->target = old_target;
+ comp->target_len = old_target_len;
+ write_sddl_token(comp, token);
+ return true;
+fail:
+ talloc_free(token.data.composite.tokens);
+ comp->target = old_target;
+ comp->target_len = old_target_len;
+ return false;
+}
+
+
+static bool parse_paren_literal(struct ace_condition_sddl_compiler_context *comp)
+{
+ bool ok;
+ if (comp->sddl[comp->offset] != '(') {
+ comp_error(comp, "expected '('");
+ return false;
+ }
+ comp->offset++;
+ ok = parse_literal(comp, false);
+ if (!ok) {
+ return false;
+ }
+ if (comp->sddl[comp->offset] != ')') {
+ comp_error(comp, "expected ')'");
+ return false;
+ }
+ comp->offset++;
+ return true;
+}
+
+static bool parse_expression(struct ace_condition_sddl_compiler_context *comp)
+{
+ /*
+ * This expects a parenthesised expression.
+ */
+ bool ok;
+ struct ace_condition_token token = {};
+ uint32_t start = comp->offset;
+
+ if (comp->state & SDDL_FLAG_EXPECTING_PAREN_LITERAL) {
+ /*
+ * Syntactically we allow parentheses to wrap a
+ * literal value after a Member_of or >= op, but we
+ * want to remember that it just wants a single
+ * literal, not a general expression.
+ */
+ return parse_paren_literal(comp);
+ }
+
+ if (comp->sddl[start] != '(') {
+ comp_error(comp, "expected '('");
+ return false;
+ }
+
+ if (!(comp->state & SDDL_FLAG_EXPECTING_PAREN)) {
+ comp_error(comp, "did not expect '('");
+ return false;
+ }
+
+ token.type = CONDITIONAL_ACE_SAMBA_SDDL_PAREN;
+ token.data.sddl_op.start = start;
+ ok = push_sddl_token(comp, token);
+ if (!ok) {
+ return false;
+ }
+ comp->offset++; /* over the '(' */
+ comp->state = SDDL_FLAGS_EXPR_START;
+ DBG_INFO("%3"PRIu32": (\n", comp->offset);
+
+ comp->state |= SDDL_FLAG_NOT_EXPECTING_END_PAREN;
+
+ while (comp->offset < comp->length) {
+ uint8_t c;
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ return false;
+ }
+ c = comp->sddl[comp->offset];
+ if (c == '(') {
+ ok = parse_expression(comp);
+ } else if (c == ')') {
+ if (comp->state & (SDDL_FLAG_IS_BINARY_OP |
+ SDDL_FLAG_IS_UNARY_OP)) {
+ /*
+ * You can't have "(a ==)" or "(!)"
+ */
+ comp_error(comp,
+ "operator lacks right hand argument");
+ return false;
+ }
+ if (comp->state & SDDL_FLAG_NOT_EXPECTING_END_PAREN) {
+ /*
+ * You can't have "( )"
+ */
+ comp_error(comp, "empty expression");
+ return false;
+ }
+ break;
+ } else if (c == '@') {
+ ok = parse_attr2(comp);
+ } else if (strchr("!<>=&|", c)) {
+ ok = parse_oppy_op(comp);
+ } else if (is_attr_char1(c)) {
+ ok = parse_word(comp);
+ } else if (comp->state & SDDL_FLAG_EXPECTING_LITERAL) {
+ ok = parse_literal(comp, false);
+ } else {
+ if (c > 31 && c < 127) {
+ comp_error(comp,
+ "unexpected byte 0x%02x '%c'", c, c);
+ } else {
+ comp_error(comp, "unexpected byte 0x%02x", c);
+ }
+ ok = false;
+ }
+
+ if (! ok) {
+ return false;
+ }
+ /*
+ * what did we just find? Set what we expect accordingly.
+ */
+ comp->state = sddl_strings[comp->last_token_type].flags;
+ DBG_INFO("%3"PRIu32": %s\n",
+ comp->offset,
+ sddl_strings[comp->last_token_type].name);
+ }
+ ok = eat_whitespace(comp, false);
+ if (!ok) {
+ return false;
+ }
+
+ if (comp->sddl[comp->offset] != ')') {
+ comp_error(comp, "expected ')' to match '(' at %"PRIu32, start);
+ return false;
+ }
+ /*
+ * we won't comp->offset++ until after these other error checks, so
+ * that their messages have consistent locations.
+ */
+ ok = flush_stack_tokens(comp, CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END);
+ if (!ok) {
+ return false;
+ }
+ if (comp->stack_depth == 0) {
+ comp_error(comp, "mysterious nesting error between %"
+ PRIu32" and here",
+ start);
+ return false;
+ }
+ token = comp->stack[comp->stack_depth - 1];
+ if (token.type != CONDITIONAL_ACE_SAMBA_SDDL_PAREN) {
+ comp_error(comp, "nesting error between %"PRIu32" and here",
+ start);
+ return false;
+ }
+ if (token.data.sddl_op.start != start) {
+ comp_error(comp, "')' should match '(' at %"PRIu32
+ ", not %"PRIu32,
+ token.data.sddl_op.start, start);
+ return false;
+ }
+ comp->stack_depth--;
+ DBG_INFO("%3"PRIu32": )\n", comp->offset);
+
+ comp->offset++; /* for the ')' */
+ comp->last_token_type = CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END;
+ comp->state = sddl_strings[comp->last_token_type].flags;
+
+ ok = eat_whitespace(comp, true);
+ return ok;
+}
+
+
+
+static bool init_compiler_context(
+ TALLOC_CTX *mem_ctx,
+ struct ace_condition_sddl_compiler_context *comp,
+ const enum ace_condition_flags ace_condition_flags,
+ const char *sddl,
+ size_t max_length,
+ size_t max_stack)
+{
+ struct ace_condition_script *program = NULL;
+
+ comp->sddl = (const uint8_t*)sddl;
+ comp->mem_ctx = mem_ctx;
+
+ program = talloc_zero(mem_ctx, struct ace_condition_script);
+ if (program == NULL) {
+ return false;
+ }
+ /*
+ * For the moment, we allocate for the worst case up front.
+ */
+ program->tokens = talloc_array(program,
+ struct ace_condition_token,
+ max_length);
+ if (program->tokens == NULL) {
+ TALLOC_FREE(program);
+ return false;
+ }
+ program->stack = talloc_array(program,
+ struct ace_condition_token,
+ max_stack + 1);
+ if (program->stack == NULL) {
+ TALLOC_FREE(program);
+ return false;
+ }
+ comp->program = program;
+ /* we can borrow the program stack for the operator stack */
+ comp->stack = program->stack;
+ comp->target = program->tokens;
+ comp->target_len = &program->length;
+ comp->length = strlen(sddl);
+ comp->state = SDDL_FLAG_EXPECTING_PAREN;
+ comp->allow_device = ace_condition_flags & ACE_CONDITION_FLAG_ALLOW_DEVICE;
+ return true;
+}
+
+/*
+ * Compile SDDL conditional ACE conditions.
+ *
+ * @param mem_ctx
+ * @param sddl - the string to be parsed
+ * @param ace_condition_flags - flags controlling compiler behaviour
+ * @param message - on error, a pointer to a compiler message
+ * @param message_offset - where the error occurred
+ * @param consumed_length - how much of the SDDL was used
+ * @return a struct ace_condition_script (or NULL).
+ */
+struct ace_condition_script * ace_conditions_compile_sddl(
+ TALLOC_CTX *mem_ctx,
+ const enum ace_condition_flags ace_condition_flags,
+ const char *sddl,
+ const char **message,
+ size_t *message_offset,
+ size_t *consumed_length)
+{
+ bool ok;
+ struct ace_condition_sddl_compiler_context comp = {};
+
+ *message = NULL;
+ *message_offset = 0;
+
+ ok = init_compiler_context(mem_ctx,
+ &comp,
+ ace_condition_flags,
+ sddl,
+ CONDITIONAL_ACE_MAX_LENGTH,
+ CONDITIONAL_ACE_MAX_TOKENS);
+ if (!ok) {
+ return NULL;
+ }
+
+ ok = parse_expression(&comp);
+ if (!ok) {
+ goto error;
+ }
+ if (comp.stack_depth != 0) {
+ comp_error(&comp, "incomplete expression");
+ goto error;
+ }
+ if (consumed_length != NULL) {
+ *consumed_length = comp.offset;
+ }
+ *message = comp.message;
+ *message_offset = comp.message_offset;
+ return comp.program;
+ error:
+ *message = comp.message;
+ *message_offset = comp.message_offset;
+ TALLOC_FREE(comp.program);
+ return NULL;
+}
+
+
+
+static bool parse_resource_attr_list(
+ struct ace_condition_sddl_compiler_context *comp,
+ char attr_type_char)
+{
+ /*
+ * This is a bit like parse_composite() above, but with the following
+ * differences:
+ *
+ * - it doesn't want '{...}' around the list.
+ * - if there is just one value, it is not a composite
+ * - all the values must be the expected type.
+ * - there is no nesting.
+ * - SIDs are not written with SID(...) around them.
+ */
+ bool ok;
+ bool first = true;
+ struct ace_condition_token composite = {
+ .type = CONDITIONAL_ACE_TOKEN_COMPOSITE
+ };
+ uint32_t start = comp->offset;
+ size_t alloc_size;
+ struct ace_condition_token *old_target = comp->target;
+ uint32_t *old_target_len = comp->target_len;
+
+ comp->state = SDDL_FLAG_EXPECTING_LITERAL;
+
+ /*
+ * the worst case is one token for every two bytes: {1,1,1}, and we
+ * allocate for that (counting commas and finding '}' gets hard because
+ * string literals).
+ */
+ alloc_size = MIN((comp->length - start) / 2 + 1,
+ CONDITIONAL_ACE_MAX_LENGTH);
+
+ composite.data.composite.tokens = talloc_array(
+ comp->mem_ctx,
+ struct ace_condition_token,
+ alloc_size);
+ if (composite.data.composite.tokens == NULL) {
+ comp_error(comp, "allocation failure");
+ return false;
+ }
+
+ comp->target = composite.data.composite.tokens;
+ comp->target_len = &composite.data.composite.n_members;
+
+ /*
+ * in this loop we are looking for:
+ *
+ * a) possible whitespace.
+ * b) a comma (or terminating ')')
+ * c) more possible whitespace
+ * d) a literal, of the right type (checked after)
+ *
+ * Failures use a goto to reset comp->target, just in case we ever try
+ * continuing after error.
+ */
+ while (comp->offset < comp->length) {
+ uint8_t c;
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ goto fail;
+ }
+ c = comp->sddl[comp->offset];
+ if (c == ')') {
+ break;
+ }
+ if (!first) {
+ if (c != ',') {
+ comp_error(comp,
+ "malformed resource attribute ACE "
+ "(expected comma)");
+ goto fail;
+ }
+ comp->offset++;
+
+ ok = eat_whitespace(comp, false);
+ if (! ok) {
+ goto fail;
+ }
+ }
+ first = false;
+ if (*comp->target_len >= alloc_size) {
+ comp_error(comp,
+ "Too many tokens in resource attribute ACE "
+ "(>= %"PRIu32" tokens)",
+ *comp->target_len);
+ goto fail;
+ }
+ switch(attr_type_char) {
+ case 'X':
+ ok = parse_ra_octet_string(comp);
+ break;
+ case 'S':
+ ok = parse_unicode(comp);
+ break;
+ case 'U':
+ ok = parse_uint(comp);
+ break;
+ case 'B':
+ ok = parse_bool(comp);
+ break;
+ case 'I':
+ ok = parse_int(comp);
+ break;
+ case 'D':
+ ok = parse_ra_sid(comp);
+ break;
+ default:
+ /* it's a mystery we got this far */
+ comp_error(comp,
+ "unknown attribute type T%c",
+ attr_type_char);
+ goto fail;
+ }
+ if (!ok) {
+ goto fail;
+ }
+
+ if (*comp->target_len == 0) {
+ goto fail;
+ }
+ }
+ comp->target = old_target;
+ comp->target_len = old_target_len;
+
+ /*
+ * If we only ended up collecting one token into the composite, we
+ * write that instead.
+ */
+ if (composite.data.composite.n_members == 1) {
+ ok = write_sddl_token(comp, composite.data.composite.tokens[0]);
+ talloc_free(composite.data.composite.tokens);
+ } else {
+ ok = write_sddl_token(comp, composite);
+ }
+ if (! ok) {
+ goto fail;
+ }
+
+ return true;
+fail:
+ comp->target = old_target;
+ comp->target_len = old_target_len;
+ TALLOC_FREE(composite.data.composite.tokens);
+ return false;
+}
+
+
+
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *sddl_decode_resource_attr (
+ TALLOC_CTX *mem_ctx,
+ const char *str,
+ size_t *length)
+{
+ /*
+ * Resource attribute ACEs define claims in object SACLs. They look like
+ *
+ * "(RA; «flags» ;;;;WD;( «attribute-data» ))"
+ *
+ * attribute-data = DQUOTE 1*attr-char2 DQUOTE "," \
+ * ( TI-attr / TU-attr / TS-attr / TD-attr / TX-attr / TB-attr )
+ * TI-attr = "TI" "," attr-flags *("," int-64)
+ * TU-attr = "TU" "," attr-flags *("," uint-64)
+ * TS-attr = "TS" "," attr-flags *("," char-string)
+ * TD-attr = "TD" "," attr-flags *("," sid-string)
+ * TX-attr = "TX" "," attr-flags *("," octet-string)
+ * TB-attr = "TB" "," attr-flags *("," ( "0" / "1" ) )
+ *
+ * and the data types are *mostly* parsed in the SDDL way,
+ * though there are significant differences for octet-strings.
+ *
+ * At this point we only have the "(«attribute-data»)".
+ *
+ * What we do is set up a conditional ACE compiler to be expecting a
+ * literal, and ask it to parse the strings between the commas. It's a
+ * hack.
+ */
+ bool ok;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
+ struct ace_condition_sddl_compiler_context comp = {};
+ char attr_type;
+ struct ace_condition_token *tok;
+ uint32_t flags;
+ size_t len;
+ struct ace_condition_unicode attr_name = {};
+
+ ok = init_compiler_context(mem_ctx,
+ &comp,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ str,
+ 3,
+ 3);
+ if (!ok) {
+ return NULL;
+ }
+ if (comp.length < 6 || comp.length > CONDITIONAL_ACE_MAX_LENGTH) {
+ DBG_WARNING("invalid resource attribute: '%s'\n", str);
+ goto error;
+ }
+ /*
+ * Resource attribute ACEs list SIDs in a bare form "S-1-2-3", while
+ * conditional ACEs use a wrapper syntax "SID(S-1-2-3)". As almost
+ * everything is the same, we are reusing the conditional ACE parser,
+ * with a flag set to tell the SID parser which form to expect.
+ */
+
+ /* Most examples on the web have leading whitespace */
+ ok = eat_whitespace(&comp, false);
+ if (!ok) {
+ return NULL;
+ }
+ if (comp.sddl[comp.offset] != '(' ||
+ comp.sddl[comp.offset + 1] != '"') {
+ DBG_WARNING("invalid resource attribute -- expected '(\"'\n");
+ goto error;
+ }
+ comp.offset += 2;
+
+ /*
+ * Read the name. Here we are not reading a token into comp->program,
+ * just into a unicode blob.
+ */
+ len = read_attr2_string(&comp, &attr_name);
+
+ if (len == -1) {
+ DBG_WARNING("invalid resource attr name: %s\n", str);
+ goto error;
+ }
+ comp.offset += len;
+
+ ok = eat_whitespace(&comp, false);
+ if (comp.offset + 6 > comp.length) {
+ DBG_WARNING("invalid resource attribute (too short): '%s'\n",
+ str);
+ goto error;
+ }
+ /*
+ * now we have the name. Next comes '",«T[IUSDXB]»,' followed
+ * by the flags, which are a 32 bit number.
+ */
+ if (comp.sddl[comp.offset] != '"' ||
+ comp.sddl[comp.offset + 1] != ','||
+ comp.sddl[comp.offset + 2] != 'T') {
+ DBG_WARNING("expected '\",T[IUSDXB]' after attr name\n");
+ goto error;
+ }
+ attr_type = comp.sddl[comp.offset + 3];
+
+ if (comp.sddl[comp.offset + 4] != ',') {
+ DBG_WARNING("expected ',' after attr type\n");
+ goto error;
+ }
+ comp.offset += 5;
+ comp.state = SDDL_FLAG_EXPECTING_LITERAL;
+ ok = parse_literal(&comp, false);
+ if (!ok ||
+ comp.program->length != 1) {
+ DBG_WARNING("invalid attr flags: %s\n", str);
+ goto error;
+ }
+
+ tok = &comp.program->tokens[0];
+ if (tok->type != CONDITIONAL_ACE_TOKEN_INT64 ||
+ tok->data.int64.value < 0 ||
+ tok->data.int64.value > UINT32_MAX) {
+ DBG_WARNING("invalid attr flags (want 32 bit int): %s\n", str);
+ goto error;
+ }
+ flags = tok->data.int64.value;
+ if (flags & 0xff00) {
+ DBG_WARNING("invalid attr flags, "
+ "stepping on reserved 0xff00 range: %s\n",
+ str);
+ goto error;
+ }
+ if (comp.offset + 3 > comp.length) {
+ DBG_WARNING("invalid resource attribute (too short): '%s'\n",
+ str);
+ goto error;
+ }
+ if (comp.sddl[comp.offset] != ',') {
+ DBG_WARNING("invalid resource attribute ace\n");
+ goto error;
+ }
+ comp.offset++;
+
+ ok = parse_resource_attr_list(&comp, attr_type);
+ if (!ok || comp.program->length != 2) {
+ DBG_WARNING("invalid attribute type or value: T%c, %s\n",
+ attr_type, str);
+ goto error;
+ }
+ if (comp.sddl[comp.offset] != ')') {
+ DBG_WARNING("expected trailing ')'\n");
+ goto error;
+ }
+ comp.offset++;
+ *length = comp.offset;
+
+ ok = ace_token_to_claim_v1(mem_ctx,
+ attr_name.value,
+ &comp.program->tokens[1],
+ &claim,
+ flags);
+ if (!ok) {
+ goto error;
+ }
+ TALLOC_FREE(comp.program);
+ return claim;
+ error:
+ TALLOC_FREE(comp.program);
+ return NULL;
+}
+
+
+static bool write_resource_attr_from_token(struct sddl_write_context *ctx,
+ const struct ace_condition_token *tok)
+{
+ /*
+ * this is a helper for sddl_resource_attr_from_claim(),
+ * recursing into composites if necessary.
+ */
+ bool ok;
+ char *sid = NULL;
+ size_t i;
+ const struct ace_condition_composite *c = NULL;
+ switch (tok->type) {
+ case CONDITIONAL_ACE_TOKEN_INT64:
+ /*
+ * Note that this includes uint and bool claim types,
+ * but we don't check the validity of the ranges (0|1
+ * and >=0, respectively), rather we trust the claim
+ * to be self-consistent in this regard. Going the
+ * other way, string-to-claim, we do check.
+ */
+ return sddl_write_int(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_UNICODE:
+ return sddl_write_unicode(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_SID:
+ /* unlike conditional ACE, SID does not have a "SID()" wrapper. */
+ sid = sddl_encode_sid(ctx->mem_ctx, &tok->data.sid.sid, NULL);
+ if (sid == NULL) {
+ return false;
+ }
+ return sddl_write(ctx, sid);
+
+ case CONDITIONAL_ACE_TOKEN_OCTET_STRING:
+ return sddl_write_ra_octet_string(ctx, tok);
+
+ case CONDITIONAL_ACE_TOKEN_COMPOSITE:
+ /*
+ * write each token, separated by commas. If there
+ * were nested composites, this would flatten them,
+ * but that isn't really possible because the token we
+ * are dealing with came from a claim, which has no
+ * facility for nesting.
+ */
+ c = &tok->data.composite;
+ for(i = 0; i < c->n_members; i++) {
+ ok = write_resource_attr_from_token(ctx, &c->tokens[i]);
+ if (!ok) {
+ return false;
+ }
+ if (i != c->n_members - 1) {
+ ok = sddl_write(ctx, ",");
+ if (!ok) {
+ return false;
+ }
+ }
+ }
+ return true;
+ default:
+ /* We really really don't expect to get here */
+ return false;
+ }
+}
+
+char *sddl_resource_attr_from_claim(
+ TALLOC_CTX *mem_ctx,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim)
+{
+ char *s = NULL;
+ char attr_type;
+ bool ok;
+ struct ace_condition_token tok = {};
+ struct sddl_write_context ctx = {};
+ TALLOC_CTX *tmp_ctx = NULL;
+ char *name = NULL;
+ size_t name_len;
+
+ switch(claim->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ attr_type = 'I';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ attr_type = 'U';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ attr_type = 'S';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ attr_type = 'D';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
+ attr_type = 'B';
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ attr_type = 'X';
+ break;
+ default:
+ return NULL;
+ }
+
+ tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return NULL;
+ }
+ ctx.mem_ctx = tmp_ctx;
+
+ ok = claim_v1_to_ace_composite_unchecked(tmp_ctx, claim, &tok);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NULL;
+ }
+
+ /* this will construct the proper string in ctx.sddl */
+ ok = write_resource_attr_from_token(&ctx, &tok);
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NULL;
+ }
+
+ /* escape the claim name */
+ ok = sddl_encode_attr_name(tmp_ctx,
+ claim->name,
+ &name, &name_len);
+
+ if (!ok) {
+ TALLOC_FREE(tmp_ctx);
+ return NULL;
+ }
+
+ s = talloc_asprintf(mem_ctx,
+ "(\"%s\",T%c,0x%x,%s)",
+ name,
+ attr_type,
+ claim->flags,
+ ctx.sddl);
+ TALLOC_FREE(tmp_ctx);
+ return s;
+}
+
+
+struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *parse_sddl_literal_as_claim(
+ TALLOC_CTX *mem_ctx,
+ const char *name,
+ const char *str)
+{
+ /*
+ * For testing purposes (and possibly for client tools), we
+ * want to be able to create claim literals, and we might as
+ * well use the SDDL syntax. So we pretend to be parsing SDDL
+ * for one literal.
+ */
+ bool ok;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
+ struct ace_condition_sddl_compiler_context comp = {};
+
+ ok = init_compiler_context(mem_ctx,
+ &comp,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ str,
+ 2,
+ 2);
+ if (!ok) {
+ return NULL;
+ }
+
+ comp.state = SDDL_FLAG_EXPECTING_LITERAL;
+ ok = parse_literal(&comp, false);
+
+ if (!ok) {
+ goto error;
+ }
+ if (comp.program->length != 1) {
+ goto error;
+ }
+
+ ok = ace_token_to_claim_v1(mem_ctx,
+ name,
+ &comp.program->tokens[0],
+ &claim,
+ 0);
+ if (!ok) {
+ goto error;
+ }
+ TALLOC_FREE(comp.program);
+ return claim;
+ error:
+ TALLOC_FREE(comp.program);
+ return NULL;
+}
diff --git a/libcli/security/secace.c b/libcli/security/secace.c
new file mode 100644
index 0000000..22bf217
--- /dev/null
+++ b/libcli/security/secace.c
@@ -0,0 +1,204 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * struct security_ace handling functions
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 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 "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "lib/util/tsort.h"
+
+/**
+ * Check if ACE has OBJECT type.
+ */
+bool sec_ace_object(uint8_t type)
+{
+ if (type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT) {
+ /*
+ * MS-DTYP has a reserved value for
+ * SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT, but we
+ * don't assume that it will be an object ACE just
+ * because it sounds like one.
+ */
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Check if ACE is a CALLBACK type, which means it will have a blob of data at
+ * the end.
+ */
+bool sec_ace_callback(uint8_t type)
+{
+ if (type == SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK ||
+ type == SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT ||
+ type == SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK ||
+ type == SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT) {
+ /*
+ * While SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK and
+ * SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT sound like
+ * callback types, they are reserved values in MS-DTYP,
+ * and their eventual use is not defined.
+ */
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Check if an ACE type is resource attribute, which means it will
+ * have a blob of data at the end defining an attribute on the object.
+ * Resource attribute ACEs should only occur in SACLs.
+ */
+bool sec_ace_resource(uint8_t type)
+{
+ return type == SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE;
+}
+
+bool sec_ace_has_extra_blob(uint8_t type)
+{
+ return sec_ace_callback(type) || sec_ace_resource(type);
+}
+
+
+/*******************************************************************
+ Sets up a struct security_ace structure.
+********************************************************************/
+
+void init_sec_ace(struct security_ace *t, const struct dom_sid *sid, enum security_ace_type type,
+ uint32_t mask, uint8_t flag)
+{
+ t->type = type;
+ t->flags = flag;
+ t->size = ndr_size_dom_sid(sid, 0) + 8;
+ t->access_mask = mask;
+
+ t->trustee = *sid;
+ t->coda.ignored.data = NULL;
+ t->coda.ignored.length = 0;
+}
+
+int nt_ace_inherit_comp(const struct security_ace *a1, const struct security_ace *a2)
+{
+ int a1_inh = a1->flags & SEC_ACE_FLAG_INHERITED_ACE;
+ int a2_inh = a2->flags & SEC_ACE_FLAG_INHERITED_ACE;
+
+ if (a1_inh == a2_inh)
+ return 0;
+
+ if (!a1_inh && a2_inh)
+ return -1;
+ return 1;
+}
+
+/*******************************************************************
+ Comparison function to apply the order explained below in a group.
+*******************************************************************/
+
+int nt_ace_canon_comp( const struct security_ace *a1, const struct security_ace *a2)
+{
+ if ((a1->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
+ (a2->type != SEC_ACE_TYPE_ACCESS_DENIED))
+ return -1;
+
+ if ((a2->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
+ (a1->type != SEC_ACE_TYPE_ACCESS_DENIED))
+ return 1;
+
+ /* Both access denied or access allowed. */
+
+ /* 1. ACEs that apply to the object itself */
+
+ if (!(a1->flags & SEC_ACE_FLAG_INHERIT_ONLY) &&
+ (a2->flags & SEC_ACE_FLAG_INHERIT_ONLY))
+ return -1;
+ else if (!(a2->flags & SEC_ACE_FLAG_INHERIT_ONLY) &&
+ (a1->flags & SEC_ACE_FLAG_INHERIT_ONLY))
+ return 1;
+
+ /* 2. ACEs that apply to a subobject of the object, such as
+ * a property set or property. */
+
+ if (a1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT) &&
+ !(a2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)))
+ return -1;
+ else if (a2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT) &&
+ !(a1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT)))
+ return 1;
+
+ return 0;
+}
+
+/*******************************************************************
+ Functions to convert a SEC_DESC ACE DACL list into canonical order.
+ JRA.
+
+--- from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/order_of_aces_in_a_dacl.asp
+
+The following describes the preferred order:
+
+ To ensure that noninherited ACEs have precedence over inherited ACEs,
+ place all noninherited ACEs in a group before any inherited ACEs.
+ This ordering ensures, for example, that a noninherited access-denied ACE
+ is enforced regardless of any inherited ACE that allows access.
+
+ Within the groups of noninherited ACEs and inherited ACEs, order ACEs according to ACE type, as the following shows:
+ 1. Access-denied ACEs that apply to the object itself
+ 2. Access-denied ACEs that apply to a subobject of the object, such as a property set or property
+ 3. Access-allowed ACEs that apply to the object itself
+ 4. Access-allowed ACEs that apply to a subobject of the object"
+
+********************************************************************/
+
+void dacl_sort_into_canonical_order(struct security_ace *srclist, unsigned int num_aces)
+{
+ unsigned int i;
+
+ if (!srclist || num_aces == 0)
+ return;
+
+ /* Sort so that non-inherited ACE's come first. */
+ TYPESAFE_QSORT(srclist, num_aces, nt_ace_inherit_comp);
+
+ /* Find the boundary between non-inherited ACEs. */
+ for (i = 0; i < num_aces; i++ ) {
+ struct security_ace *curr_ace = &srclist[i];
+
+ if (curr_ace->flags & SEC_ACE_FLAG_INHERITED_ACE)
+ break;
+ }
+
+ /* i now points at entry number of the first inherited ACE. */
+
+ /* Sort the non-inherited ACEs. */
+ TYPESAFE_QSORT(srclist, i, nt_ace_canon_comp);
+
+ /* Now sort the inherited ACEs. */
+ TYPESAFE_QSORT(&srclist[i], num_aces - i, nt_ace_canon_comp);
+}
diff --git a/libcli/security/secace.h b/libcli/security/secace.h
new file mode 100644
index 0000000..879c711
--- /dev/null
+++ b/libcli/security/secace.h
@@ -0,0 +1,40 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) 2009 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/>.
+*/
+
+#ifndef _ACE_H_
+#define _ACE_H_
+
+#include "librpc/gen_ndr/security.h"
+#include "librpc/ndr/libndr.h"
+
+bool sec_ace_object(uint8_t type);
+size_t ndr_subcontext_size_of_ace_coda(const struct security_ace *ace, size_t ace_size, libndr_flags flags);
+bool sec_ace_callback(uint8_t type);
+bool sec_ace_resource(uint8_t type);
+bool sec_ace_has_extra_blob(uint8_t type);
+
+void init_sec_ace(struct security_ace *t, const struct dom_sid *sid, enum security_ace_type type,
+ uint32_t mask, uint8_t flag);
+int nt_ace_inherit_comp( const struct security_ace *a1, const struct security_ace *a2);
+int nt_ace_canon_comp( const struct security_ace *a1, const struct security_ace *a2);
+void dacl_sort_into_canonical_order(struct security_ace *srclist, unsigned int num_aces);
+
+#endif /*_ACE_H_*/
+
diff --git a/libcli/security/secacl.c b/libcli/security/secacl.c
new file mode 100644
index 0000000..6c92a2e
--- /dev/null
+++ b/libcli/security/secacl.c
@@ -0,0 +1,75 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_ACL handling routines
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 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 "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/secace.h"
+#include "libcli/security/secacl.h"
+
+#define SEC_ACL_HEADER_SIZE (2 * sizeof(uint16_t) + sizeof(uint32_t))
+
+/*******************************************************************
+ Create a SEC_ACL structure.
+********************************************************************/
+
+struct security_acl *make_sec_acl(
+ TALLOC_CTX *ctx,
+ enum security_acl_revision revision,
+ int num_aces,
+ const struct security_ace *ace_list)
+{
+ struct security_acl *dst;
+ int i;
+
+ dst = talloc(ctx, struct security_acl);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ dst->revision = revision;
+ dst->num_aces = num_aces;
+ dst->size = SEC_ACL_HEADER_SIZE;
+ dst->aces = NULL;
+
+ /* Now we need to return a non-NULL address for the ace list even
+ if the number of aces required is zero. This is because there
+ is a distinct difference between a NULL ace and an ace with zero
+ entries in it. This is achieved by checking that num_aces is a
+ positive number. */
+
+ if (num_aces == 0) {
+ return dst;
+ }
+
+ dst->aces = talloc_array(dst, struct security_ace, num_aces);
+ if (dst->aces == NULL) {
+ TALLOC_FREE(dst);
+ return NULL;
+ }
+
+ for (i = 0; i < num_aces; i++) {
+ dst->aces[i] = ace_list[i]; /* Structure copy. */
+ dst->size += ace_list[i].size;
+ }
+
+ return dst;
+}
diff --git a/libcli/security/secacl.h b/libcli/security/secacl.h
new file mode 100644
index 0000000..961e2b4
--- /dev/null
+++ b/libcli/security/secacl.h
@@ -0,0 +1,33 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) 2009 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/>.
+*/
+
+#ifndef _SECACL_H_
+#define _SECACL_H_
+
+#include "librpc/gen_ndr/security.h"
+
+struct security_acl *make_sec_acl(
+ TALLOC_CTX *ctx,
+ enum security_acl_revision revision,
+ int num_aces,
+ const struct security_ace *ace_list);
+
+#endif /*_SECACL_H_*/
+
diff --git a/libcli/security/secdesc.c b/libcli/security/secdesc.c
new file mode 100644
index 0000000..cb8037c
--- /dev/null
+++ b/libcli/security/secdesc.c
@@ -0,0 +1,623 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_DESC handling functions
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 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/util/debug.h"
+#include "lib/util/fault.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+
+/* Map generic permissions to file object specific permissions */
+
+const struct generic_mapping file_generic_mapping = {
+ FILE_GENERIC_READ,
+ FILE_GENERIC_WRITE,
+ FILE_GENERIC_EXECUTE,
+ FILE_GENERIC_ALL
+};
+
+/*******************************************************************
+ Given a security_descriptor return the sec_info.
+********************************************************************/
+
+uint32_t get_sec_info(const struct security_descriptor *sd)
+{
+ uint32_t sec_info = 0;
+
+ SMB_ASSERT(sd);
+
+ if (sd->owner_sid != NULL) {
+ sec_info |= SECINFO_OWNER;
+ }
+ if (sd->group_sid != NULL) {
+ sec_info |= SECINFO_GROUP;
+ }
+ if (sd->sacl != NULL) {
+ sec_info |= SECINFO_SACL;
+ }
+ if (sd->dacl != NULL) {
+ sec_info |= SECINFO_DACL;
+ }
+
+ if (sd->type & SEC_DESC_SACL_PROTECTED) {
+ sec_info |= SECINFO_PROTECTED_SACL;
+ } else if (sd->type & SEC_DESC_SACL_AUTO_INHERITED) {
+ sec_info |= SECINFO_UNPROTECTED_SACL;
+ }
+ if (sd->type & SEC_DESC_DACL_PROTECTED) {
+ sec_info |= SECINFO_PROTECTED_DACL;
+ } else if (sd->type & SEC_DESC_DACL_AUTO_INHERITED) {
+ sec_info |= SECINFO_UNPROTECTED_DACL;
+ }
+
+ return sec_info;
+}
+
+
+/*******************************************************************
+ Merge part of security descriptor old_sec in to the empty sections of
+ security descriptor new_sec.
+********************************************************************/
+
+struct sec_desc_buf *sec_desc_merge_buf(TALLOC_CTX *ctx, struct sec_desc_buf *new_sdb, struct sec_desc_buf *old_sdb)
+{
+ struct dom_sid *owner_sid, *group_sid;
+ struct sec_desc_buf *return_sdb;
+ struct security_acl *dacl, *sacl;
+ struct security_descriptor *psd = NULL;
+ uint16_t secdesc_type;
+ size_t secdesc_size;
+
+ /* Copy over owner and group sids. There seems to be no flag for
+ this so just check the pointer values. */
+
+ owner_sid = new_sdb->sd->owner_sid ? new_sdb->sd->owner_sid :
+ old_sdb->sd->owner_sid;
+
+ group_sid = new_sdb->sd->group_sid ? new_sdb->sd->group_sid :
+ old_sdb->sd->group_sid;
+
+ secdesc_type = new_sdb->sd->type;
+
+ /* Ignore changes to the system ACL. This has the effect of making
+ changes through the security tab audit button not sticking.
+ Perhaps in future Samba could implement these settings somehow. */
+
+ sacl = NULL;
+ secdesc_type &= ~SEC_DESC_SACL_PRESENT;
+
+ /* Copy across discretionary ACL */
+
+ if (secdesc_type & SEC_DESC_DACL_PRESENT) {
+ dacl = new_sdb->sd->dacl;
+ } else {
+ dacl = old_sdb->sd->dacl;
+ }
+
+ /* Create new security descriptor from bits */
+
+ psd = make_sec_desc(ctx, new_sdb->sd->revision, secdesc_type,
+ owner_sid, group_sid, sacl, dacl, &secdesc_size);
+
+ return_sdb = make_sec_desc_buf(ctx, secdesc_size, psd);
+
+ return(return_sdb);
+}
+
+struct security_descriptor *sec_desc_merge(TALLOC_CTX *ctx, struct security_descriptor *new_sdb, struct security_descriptor *old_sdb)
+{
+ struct dom_sid *owner_sid, *group_sid;
+ struct security_acl *dacl, *sacl;
+ struct security_descriptor *psd = NULL;
+ uint16_t secdesc_type;
+ size_t secdesc_size;
+
+ /* Copy over owner and group sids. There seems to be no flag for
+ this so just check the pointer values. */
+
+ owner_sid = new_sdb->owner_sid ? new_sdb->owner_sid :
+ old_sdb->owner_sid;
+
+ group_sid = new_sdb->group_sid ? new_sdb->group_sid :
+ old_sdb->group_sid;
+
+ secdesc_type = new_sdb->type;
+
+ /* Ignore changes to the system ACL. This has the effect of making
+ changes through the security tab audit button not sticking.
+ Perhaps in future Samba could implement these settings somehow. */
+
+ sacl = NULL;
+ secdesc_type &= ~SEC_DESC_SACL_PRESENT;
+
+ /* Copy across discretionary ACL */
+
+ if (secdesc_type & SEC_DESC_DACL_PRESENT) {
+ dacl = new_sdb->dacl;
+ } else {
+ dacl = old_sdb->dacl;
+ }
+
+ /* Create new security descriptor from bits */
+ psd = make_sec_desc(ctx, new_sdb->revision, secdesc_type,
+ owner_sid, group_sid, sacl, dacl, &secdesc_size);
+
+ return psd;
+}
+
+/*******************************************************************
+ Creates a struct security_descriptor structure
+********************************************************************/
+struct security_descriptor *make_sec_desc(TALLOC_CTX *ctx,
+ enum security_descriptor_revision revision,
+ uint16_t type,
+ const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
+ struct security_acl *sacl, struct security_acl *dacl, size_t *sd_size)
+{
+ struct security_descriptor *dst;
+
+ if (sd_size != NULL) {
+ *sd_size = 0;
+ }
+
+ dst = security_descriptor_initialise(ctx);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ dst->revision = revision;
+ dst->type = type;
+
+ if (sacl != NULL) {
+ dst->sacl = security_acl_dup(dst, sacl);
+ if (dst->sacl == NULL) {
+ goto err_sd_free;
+ }
+ dst->type |= SEC_DESC_SACL_PRESENT;
+ }
+
+ if (dacl != NULL) {
+ dst->dacl = security_acl_dup(dst, dacl);
+ if (dst->dacl == NULL) {
+ goto err_sd_free;
+ }
+ dst->type |= SEC_DESC_DACL_PRESENT;
+ }
+
+ if (owner_sid != NULL) {
+ dst->owner_sid = dom_sid_dup(dst, owner_sid);
+ if (dst->owner_sid == NULL) {
+ goto err_sd_free;
+ }
+ }
+
+ if (grp_sid != NULL) {
+ dst->group_sid = dom_sid_dup(dst, grp_sid);
+ if (dst->group_sid == NULL) {
+ goto err_sd_free;
+ }
+ }
+
+ if (sd_size != NULL) {
+ *sd_size = ndr_size_security_descriptor(dst, 0);
+ }
+
+ return dst;
+
+err_sd_free:
+ talloc_free(dst);
+ return NULL;
+}
+
+/*******************************************************************
+ Convert a secdesc into a byte stream
+********************************************************************/
+NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *secdesc,
+ uint8_t **data, size_t *len)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, secdesc,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_push_security_descriptor failed: %s\n",
+ ndr_errstr(ndr_err)));
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ *data = blob.data;
+ *len = blob.length;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Convert a secdesc_buf into a byte stream
+********************************************************************/
+
+NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
+ const struct sec_desc_buf *secdesc_buf,
+ uint8_t **data, size_t *len)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(
+ &blob, mem_ctx, secdesc_buf,
+ (ndr_push_flags_fn_t)ndr_push_sec_desc_buf);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_push_sec_desc_buf failed: %s\n",
+ ndr_errstr(ndr_err)));
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ *data = blob.data;
+ *len = blob.length;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Parse a byte stream into a secdesc
+********************************************************************/
+NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
+ struct security_descriptor **psecdesc)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct security_descriptor *result;
+
+ if ((data == NULL) || (len == 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result = talloc_zero(mem_ctx, struct security_descriptor);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ blob = data_blob_const(data, len);
+
+ ndr_err = ndr_pull_struct_blob(&blob, result, result,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_security_descriptor failed: %s\n",
+ ndr_errstr(ndr_err)));
+ TALLOC_FREE(result);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ *psecdesc = result;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Parse a byte stream into a sec_desc_buf
+********************************************************************/
+
+NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
+ struct sec_desc_buf **psecdesc_buf)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct sec_desc_buf *result;
+
+ if ((data == NULL) || (len == 0)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ result = talloc_zero(mem_ctx, struct sec_desc_buf);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ blob = data_blob_const(data, len);
+
+ ndr_err = ndr_pull_struct_blob(&blob, result, result,
+ (ndr_pull_flags_fn_t)ndr_pull_sec_desc_buf);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DEBUG(0, ("ndr_pull_sec_desc_buf failed: %s\n",
+ ndr_errstr(ndr_err)));
+ TALLOC_FREE(result);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ *psecdesc_buf = result;
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Creates a struct security_descriptor structure with typical defaults.
+********************************************************************/
+
+struct security_descriptor *make_standard_sec_desc(TALLOC_CTX *ctx, const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
+ struct security_acl *dacl, size_t *sd_size)
+{
+ return make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE, owner_sid, grp_sid, NULL,
+ dacl, sd_size);
+}
+
+/*******************************************************************
+ Creates a struct sec_desc_buf structure.
+********************************************************************/
+
+struct sec_desc_buf *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, struct security_descriptor *sec_desc)
+{
+ struct sec_desc_buf *dst;
+
+ if((dst = talloc_zero(ctx, struct sec_desc_buf)) == NULL)
+ return NULL;
+
+ /* max buffer size (allocated size) */
+ dst->sd_size = (uint32_t)len;
+
+ if (sec_desc != NULL) {
+ dst->sd = security_descriptor_copy(ctx, sec_desc);
+ if (dst->sd == NULL) {
+ return NULL;
+ }
+ }
+
+ return dst;
+}
+
+/*
+ * Determine if an struct security_ace is inheritable
+ */
+
+static bool is_inheritable_ace(const struct security_ace *ace,
+ bool container)
+{
+ if (!container) {
+ return ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0);
+ }
+
+ if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
+ return true;
+ }
+
+ if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
+ !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Does a security descriptor have any inheritable components for
+ * the newly created type ?
+ */
+
+bool sd_has_inheritable_components(const struct security_descriptor *parent_ctr, bool container)
+{
+ unsigned int i;
+ const struct security_acl *the_acl = parent_ctr->dacl;
+
+ if (the_acl == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ const struct security_ace *ace = &the_acl->aces[i];
+
+ if (is_inheritable_ace(ace, container)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Create a child security descriptor using another security descriptor as
+ the parent container. This child object can either be a container or
+ non-container object. */
+
+NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
+ struct security_descriptor **ppsd,
+ size_t *psize,
+ const struct security_descriptor *parent_ctr,
+ const struct dom_sid *owner_sid,
+ const struct dom_sid *group_sid,
+ bool container)
+{
+ struct security_acl *new_dacl = NULL, *the_acl = NULL;
+ struct security_ace *new_ace_list = NULL;
+ unsigned int new_ace_list_ndx = 0, i;
+ bool set_inherited_flags = (parent_ctr->type & SEC_DESC_DACL_AUTO_INHERITED);
+
+ *ppsd = NULL;
+ *psize = 0;
+
+ /* Currently we only process the dacl when creating the child. The
+ sacl should also be processed but this is left out as sacls are
+ not implemented in Samba at the moment.*/
+
+ the_acl = parent_ctr->dacl;
+
+ if (the_acl->num_aces) {
+ if (2*the_acl->num_aces < the_acl->num_aces) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(new_ace_list = talloc_array(ctx, struct security_ace,
+ 2*the_acl->num_aces))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ new_ace_list = NULL;
+ }
+
+ for (i = 0; i < the_acl->num_aces; i++) {
+ const struct security_ace *ace = &the_acl->aces[i];
+ struct security_ace *new_ace = &new_ace_list[new_ace_list_ndx];
+ const struct dom_sid *ptrustee = &ace->trustee;
+ const struct dom_sid *creator = NULL;
+ uint8_t new_flags = ace->flags;
+ struct dom_sid_buf sidbuf1, sidbuf2;
+
+ if (!is_inheritable_ace(ace, container)) {
+ continue;
+ }
+
+ /* see the RAW-ACLS inheritance test for details on these rules */
+ if (!container) {
+ new_flags = 0;
+ } else {
+ /*
+ * We need to remove SEC_ACE_FLAG_INHERITED_ACE here
+ * if present because it should only be set if the
+ * parent has the AUTO_INHERITED bit set in the
+ * type/control field. If we don't it will slip through
+ * and create DACLs with incorrectly ordered ACEs
+ * when there are CREATOR_OWNER or CREATOR_GROUP
+ * ACEs.
+ */
+ new_flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY
+ | SEC_ACE_FLAG_INHERITED_ACE);
+
+ if (!(new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+ new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ }
+ if (new_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
+ new_flags = 0;
+ }
+ }
+
+ /* The CREATOR sids are special when inherited */
+ if (dom_sid_equal(ptrustee, &global_sid_Creator_Owner)) {
+ creator = &global_sid_Creator_Owner;
+ ptrustee = owner_sid;
+ } else if (dom_sid_equal(ptrustee, &global_sid_Creator_Group)) {
+ creator = &global_sid_Creator_Group;
+ ptrustee = group_sid;
+ }
+
+ if (creator && container &&
+ (new_flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+
+ /* First add the regular ACE entry. */
+ init_sec_ace(new_ace, ptrustee, ace->type,
+ ace->access_mask,
+ set_inherited_flags ? SEC_ACE_FLAG_INHERITED_ACE : 0);
+
+ DEBUG(5,("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x"
+ " inherited as %s:%d/0x%02x/0x%08x\n",
+ dom_sid_str_buf(&ace->trustee, &sidbuf1),
+ ace->type, ace->flags, ace->access_mask,
+ dom_sid_str_buf(&new_ace->trustee, &sidbuf2),
+ new_ace->type, new_ace->flags,
+ new_ace->access_mask));
+
+ new_ace_list_ndx++;
+
+ /* Now add the extra creator ACE. */
+ new_ace = &new_ace_list[new_ace_list_ndx];
+
+ ptrustee = creator;
+ new_flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+
+ } else if (container &&
+ !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
+ ptrustee = &ace->trustee;
+ }
+
+ init_sec_ace(new_ace, ptrustee, ace->type,
+ ace->access_mask, new_flags |
+ (set_inherited_flags ? SEC_ACE_FLAG_INHERITED_ACE : 0));
+
+ DEBUG(5, ("se_create_child_secdesc(): %s:%d/0x%02x/0x%08x "
+ " inherited as %s:%d/0x%02x/0x%08x\n",
+ dom_sid_str_buf(&ace->trustee, &sidbuf1),
+ ace->type, ace->flags, ace->access_mask,
+ dom_sid_str_buf(&new_ace->trustee, &sidbuf2),
+ new_ace->type, new_ace->flags,
+ new_ace->access_mask));
+
+ new_ace_list_ndx++;
+ }
+
+ /*
+ * remove duplicates
+ */
+ for (i=1; i < new_ace_list_ndx;) {
+ struct security_ace *ai = &new_ace_list[i];
+ unsigned int remaining, j;
+ bool remove_ace = false;
+
+ for (j=0; j < i; j++) {
+ struct security_ace *aj = &new_ace_list[j];
+
+ if (!security_ace_equal(ai, aj)) {
+ continue;
+ }
+
+ remove_ace = true;
+ break;
+ }
+
+ if (!remove_ace) {
+ i++;
+ continue;
+ }
+
+ new_ace_list_ndx--;
+ remaining = new_ace_list_ndx - i;
+ if (remaining == 0) {
+ ZERO_STRUCT(new_ace_list[i]);
+ continue;
+ }
+ memmove(&new_ace_list[i], &new_ace_list[i+1],
+ sizeof(new_ace_list[i]) * remaining);
+ }
+
+ /* Create child security descriptor to return */
+ if (new_ace_list_ndx) {
+ new_dacl = make_sec_acl(ctx,
+ NT4_ACL_REVISION,
+ new_ace_list_ndx,
+ new_ace_list);
+
+ if (!new_dacl) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ *ppsd = make_sec_desc(ctx,
+ SECURITY_DESCRIPTOR_REVISION_1,
+ SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT|
+ (set_inherited_flags ? SEC_DESC_DACL_AUTO_INHERITED : 0),
+ owner_sid,
+ group_sid,
+ NULL,
+ new_dacl,
+ psize);
+ if (!*ppsd) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
diff --git a/libcli/security/secdesc.h b/libcli/security/secdesc.h
new file mode 100644
index 0000000..ca9376a
--- /dev/null
+++ b/libcli/security/secdesc.h
@@ -0,0 +1,96 @@
+/*
+ * Unix SMB/Netbios implementation.
+ * SEC_DESC handling functions
+ * Copyright (C) Andrew Tridgell 1992-1998,
+ * Copyright (C) Jeremy R. Allison 1995-2003.
+ * Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
+ * Copyright (C) Paul Ashton 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/>.
+ */
+
+#ifndef _SECDESC_H_
+#define _SECDESC_H_
+
+/* The following definitions come from libcli/security/secdesc.c */
+#include "librpc/gen_ndr/security.h"
+
+/*******************************************************************
+ Given a security_descriptor return the sec_info.
+********************************************************************/
+uint32_t get_sec_info(const struct security_descriptor *sd);
+
+/*******************************************************************
+ Merge part of security descriptor old_sec in to the empty sections of
+ security descriptor new_sec.
+********************************************************************/
+struct sec_desc_buf *sec_desc_merge_buf(TALLOC_CTX *ctx, struct sec_desc_buf *new_sdb, struct sec_desc_buf *old_sdb);
+struct security_descriptor *sec_desc_merge(TALLOC_CTX *ctx, struct security_descriptor *new_sdb, struct security_descriptor *old_sdb);
+
+/*******************************************************************
+ Creates a struct security_descriptor structure
+********************************************************************/
+struct security_descriptor *make_sec_desc(TALLOC_CTX *ctx,
+ enum security_descriptor_revision revision,
+ uint16_t type,
+ const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
+ struct security_acl *sacl, struct security_acl *dacl, size_t *sd_size);
+
+/*******************************************************************
+ Convert a secdesc into a byte stream
+********************************************************************/
+NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *secdesc,
+ uint8_t **data, size_t *len);
+
+/*******************************************************************
+ Convert a secdesc_buf into a byte stream
+********************************************************************/
+NTSTATUS marshall_sec_desc_buf(TALLOC_CTX *mem_ctx,
+ const struct sec_desc_buf *secdesc_buf,
+ uint8_t **data, size_t *len);
+
+/*******************************************************************
+ Parse a byte stream into a secdesc
+********************************************************************/
+NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
+ struct security_descriptor **psecdesc);
+
+/*******************************************************************
+ Parse a byte stream into a sec_desc_buf
+********************************************************************/
+NTSTATUS unmarshall_sec_desc_buf(TALLOC_CTX *mem_ctx, uint8_t *data, size_t len,
+ struct sec_desc_buf **psecdesc_buf);
+
+/*******************************************************************
+ Creates a struct security_descriptor structure with typical defaults.
+********************************************************************/
+struct security_descriptor *make_standard_sec_desc(TALLOC_CTX *ctx, const struct dom_sid *owner_sid, const struct dom_sid *grp_sid,
+ struct security_acl *dacl, size_t *sd_size);
+
+/*******************************************************************
+ Creates a struct sec_desc_buf structure.
+********************************************************************/
+struct sec_desc_buf *make_sec_desc_buf(TALLOC_CTX *ctx, size_t len, struct security_descriptor *sec_desc);
+
+bool sd_has_inheritable_components(const struct security_descriptor *parent_ctr, bool container);
+NTSTATUS se_create_child_secdesc(TALLOC_CTX *ctx,
+ struct security_descriptor **ppsd,
+ size_t *psize,
+ const struct security_descriptor *parent_ctr,
+ const struct dom_sid *owner_sid,
+ const struct dom_sid *group_sid,
+ bool container);
+
+#endif /* _SECDESC_H_ */
diff --git a/libcli/security/security.h b/libcli/security/security.h
new file mode 100644
index 0000000..a1c26ed
--- /dev/null
+++ b/libcli/security/security.h
@@ -0,0 +1,121 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ 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/>.
+*/
+
+#ifndef _LIBCLI_SECURITY_SECURITY_H_
+#define _LIBCLI_SECURITY_SECURITY_H_
+
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+
+#include "librpc/gen_ndr/security.h"
+
+/* File Specific access rights */
+#define FILE_READ_DATA SEC_FILE_READ_DATA
+#define FILE_WRITE_DATA SEC_FILE_WRITE_DATA
+#define FILE_APPEND_DATA SEC_FILE_APPEND_DATA
+#define FILE_READ_EA SEC_FILE_READ_EA /* File and directory */
+#define FILE_WRITE_EA SEC_FILE_WRITE_EA /* File and directory */
+#define FILE_EXECUTE SEC_FILE_EXECUTE
+#define FILE_READ_ATTRIBUTES SEC_FILE_READ_ATTRIBUTE
+#define FILE_WRITE_ATTRIBUTES SEC_FILE_WRITE_ATTRIBUTE
+
+#define FILE_ALL_ACCESS SEC_FILE_ALL
+
+/* Directory specific access rights */
+#define FILE_LIST_DIRECTORY SEC_DIR_LIST
+#define FILE_ADD_FILE SEC_DIR_ADD_FILE
+#define FILE_ADD_SUBDIRECTORY SEC_DIR_ADD_SUBDIR
+#define FILE_TRAVERSE SEC_DIR_TRAVERSE
+#define FILE_DELETE_CHILD SEC_DIR_DELETE_CHILD
+
+/* Generic access masks & rights. */
+#define DELETE_ACCESS SEC_STD_DELETE /* (1L<<16) */
+#define READ_CONTROL_ACCESS SEC_STD_READ_CONTROL /* (1L<<17) */
+#define WRITE_DAC_ACCESS SEC_STD_WRITE_DAC /* (1L<<18) */
+#define WRITE_OWNER_ACCESS SEC_STD_WRITE_OWNER /* (1L<<19) */
+#define SYNCHRONIZE_ACCESS SEC_STD_SYNCHRONIZE /* (1L<<20) */
+
+#define SYSTEM_SECURITY_ACCESS SEC_FLAG_SYSTEM_SECURITY /* (1L<<24) */
+#define MAXIMUM_ALLOWED_ACCESS SEC_FLAG_MAXIMUM_ALLOWED /* (1L<<25) */
+#define GENERIC_ALL_ACCESS SEC_GENERIC_ALL /* (1<<28) */
+#define GENERIC_EXECUTE_ACCESS SEC_GENERIC_EXECUTE /* (1<<29) */
+#define GENERIC_WRITE_ACCESS SEC_GENERIC_WRITE /* (1<<30) */
+#define GENERIC_READ_ACCESS ((unsigned)SEC_GENERIC_READ) /* (((unsigned)1)<<31) */
+
+/* Mapping of generic access rights for files to specific rights. */
+
+/* This maps to 0x1F01FF */
+#define FILE_GENERIC_ALL (STANDARD_RIGHTS_REQUIRED_ACCESS|\
+ SEC_STD_SYNCHRONIZE|\
+ FILE_ALL_ACCESS)
+
+/* This maps to 0x120089 */
+#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ_ACCESS|\
+ FILE_READ_DATA|\
+ FILE_READ_ATTRIBUTES|\
+ FILE_READ_EA|\
+ SYNCHRONIZE_ACCESS)
+
+/* This maps to 0x120116 */
+#define FILE_GENERIC_WRITE (SEC_STD_READ_CONTROL|\
+ FILE_WRITE_DATA|\
+ FILE_WRITE_ATTRIBUTES|\
+ FILE_WRITE_EA|\
+ FILE_APPEND_DATA|\
+ SYNCHRONIZE_ACCESS)
+
+#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE_ACCESS|\
+ FILE_READ_ATTRIBUTES|\
+ FILE_EXECUTE|\
+ SYNCHRONIZE_ACCESS)
+
+/* Share specific rights. */
+#define SHARE_ALL_ACCESS FILE_GENERIC_ALL
+#define SHARE_READ_ONLY (FILE_GENERIC_READ|FILE_EXECUTE)
+
+/**
+ * Remaining access is a bit mask of remaining access rights (bits) that have
+ * to be granted in order to fulfill the requested access.
+ *
+ * The GUID is optional, if specified it restricts this object tree and its
+ * children to object/attributes that inherits from this GUID.
+ * For DS access an object inherits from a GUID if one of its class has this GUID
+ * in the schemaIDGUID attribute.
+ */
+struct object_tree {
+ uint32_t remaining_access;
+ struct GUID guid;
+ int num_of_children;
+ struct object_tree *children;
+};
+
+/* Moved the dom_sid functions to the top level dir with manual proto header */
+#include "libcli/security/dom_sid.h"
+#include "libcli/security/secace.h"
+#include "libcli/security/secacl.h"
+#include "libcli/security/secdesc.h"
+#include "libcli/security/security_descriptor.h"
+#include "libcli/security/security_token.h"
+#include "libcli/security/sddl.h"
+#include "libcli/security/privileges.h"
+#include "libcli/security/access_check.h"
+#include "libcli/security/session.h"
+#include "libcli/security/display_sec.h"
+
+#endif
diff --git a/libcli/security/security_descriptor.c b/libcli/security/security_descriptor.c
new file mode 100644
index 0000000..9b9f16c
--- /dev/null
+++ b/libcli/security/security_descriptor.c
@@ -0,0 +1,908 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security descriptor utility functions
+
+ 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 "libcli/security/security.h"
+#include "librpc/ndr/libndr.h"
+
+/*
+ return a blank security descriptor (no owners, dacl or sacl)
+*/
+struct security_descriptor *security_descriptor_initialise(TALLOC_CTX *mem_ctx)
+{
+ struct security_descriptor *sd;
+
+ sd = talloc(mem_ctx, struct security_descriptor);
+ if (!sd) {
+ return NULL;
+ }
+
+ sd->revision = SD_REVISION;
+ /* we mark as self relative, even though it isn't while it remains
+ a pointer in memory because this simplifies the ndr code later.
+ All SDs that we store/emit are in fact SELF_RELATIVE
+ */
+ sd->type = SEC_DESC_SELF_RELATIVE;
+
+ sd->owner_sid = NULL;
+ sd->group_sid = NULL;
+ sd->sacl = NULL;
+ sd->dacl = NULL;
+
+ return sd;
+}
+
+struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx,
+ const struct security_acl *oacl)
+{
+ struct security_acl *nacl;
+
+ if (oacl == NULL) {
+ return NULL;
+ }
+
+ if (oacl->aces == NULL && oacl->num_aces > 0) {
+ return NULL;
+ }
+
+ nacl = talloc (mem_ctx, struct security_acl);
+ if (nacl == NULL) {
+ return NULL;
+ }
+
+ *nacl = (struct security_acl) {
+ .revision = oacl->revision,
+ .size = oacl->size,
+ .num_aces = oacl->num_aces,
+ };
+ if (nacl->num_aces == 0) {
+ return nacl;
+ }
+
+ nacl->aces = (struct security_ace *)talloc_memdup (nacl, oacl->aces, sizeof(struct security_ace) * oacl->num_aces);
+ if (nacl->aces == NULL) {
+ goto failed;
+ }
+
+ return nacl;
+
+ failed:
+ talloc_free (nacl);
+ return NULL;
+
+}
+
+struct security_acl *security_acl_concatenate(TALLOC_CTX *mem_ctx,
+ const struct security_acl *acl1,
+ const struct security_acl *acl2)
+{
+ struct security_acl *nacl;
+ uint32_t i;
+
+ if (!acl1 && !acl2)
+ return NULL;
+
+ if (!acl1){
+ nacl = security_acl_dup(mem_ctx, acl2);
+ return nacl;
+ }
+
+ if (!acl2){
+ nacl = security_acl_dup(mem_ctx, acl1);
+ return nacl;
+ }
+
+ nacl = talloc (mem_ctx, struct security_acl);
+ if (nacl == NULL) {
+ return NULL;
+ }
+
+ nacl->revision = acl1->revision;
+ nacl->size = acl1->size + acl2->size;
+ nacl->num_aces = acl1->num_aces + acl2->num_aces;
+
+ if (nacl->num_aces == 0)
+ return nacl;
+
+ nacl->aces = (struct security_ace *)talloc_array (mem_ctx, struct security_ace, acl1->num_aces+acl2->num_aces);
+ if ((nacl->aces == NULL) && (nacl->num_aces > 0)) {
+ goto failed;
+ }
+
+ for (i = 0; i < acl1->num_aces; i++)
+ nacl->aces[i] = acl1->aces[i];
+ for (i = 0; i < acl2->num_aces; i++)
+ nacl->aces[i + acl1->num_aces] = acl2->aces[i];
+
+ return nacl;
+
+ failed:
+ talloc_free (nacl);
+ return NULL;
+
+}
+
+/*
+ talloc and copy a security descriptor
+ */
+struct security_descriptor *security_descriptor_copy(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *osd)
+{
+ struct security_descriptor *nsd;
+
+ nsd = talloc_zero(mem_ctx, struct security_descriptor);
+ if (!nsd) {
+ return NULL;
+ }
+
+ if (osd->owner_sid) {
+ nsd->owner_sid = dom_sid_dup(nsd, osd->owner_sid);
+ if (nsd->owner_sid == NULL) {
+ goto failed;
+ }
+ }
+
+ if (osd->group_sid) {
+ nsd->group_sid = dom_sid_dup(nsd, osd->group_sid);
+ if (nsd->group_sid == NULL) {
+ goto failed;
+ }
+ }
+
+ if (osd->sacl) {
+ nsd->sacl = security_acl_dup(nsd, osd->sacl);
+ if (nsd->sacl == NULL) {
+ goto failed;
+ }
+ }
+
+ if (osd->dacl) {
+ nsd->dacl = security_acl_dup(nsd, osd->dacl);
+ if (nsd->dacl == NULL) {
+ goto failed;
+ }
+ }
+
+ nsd->revision = osd->revision;
+ nsd->type = osd->type;
+
+ return nsd;
+
+ failed:
+ talloc_free(nsd);
+
+ return NULL;
+}
+
+NTSTATUS security_descriptor_for_client(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *ssd,
+ uint32_t sec_info,
+ uint32_t access_granted,
+ struct security_descriptor **_csd)
+{
+ struct security_descriptor *csd = NULL;
+ uint32_t access_required = 0;
+
+ *_csd = NULL;
+
+ if (sec_info & (SECINFO_OWNER|SECINFO_GROUP)) {
+ access_required |= SEC_STD_READ_CONTROL;
+ }
+ if (sec_info & SECINFO_DACL) {
+ access_required |= SEC_STD_READ_CONTROL;
+ }
+ if (sec_info & SECINFO_SACL) {
+ access_required |= SEC_FLAG_SYSTEM_SECURITY;
+ }
+
+ if (access_required & (~access_granted)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /*
+ * make a copy...
+ */
+ csd = security_descriptor_copy(mem_ctx, ssd);
+ if (csd == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * ... and remove everything not wanted
+ */
+
+ if (!(sec_info & SECINFO_OWNER)) {
+ TALLOC_FREE(csd->owner_sid);
+ csd->type &= ~SEC_DESC_OWNER_DEFAULTED;
+ }
+ if (!(sec_info & SECINFO_GROUP)) {
+ TALLOC_FREE(csd->group_sid);
+ csd->type &= ~SEC_DESC_GROUP_DEFAULTED;
+ }
+ if (!(sec_info & SECINFO_DACL)) {
+ TALLOC_FREE(csd->dacl);
+ csd->type &= ~(
+ SEC_DESC_DACL_PRESENT |
+ SEC_DESC_DACL_DEFAULTED|
+ SEC_DESC_DACL_AUTO_INHERIT_REQ |
+ SEC_DESC_DACL_AUTO_INHERITED |
+ SEC_DESC_DACL_PROTECTED |
+ SEC_DESC_DACL_TRUSTED);
+ }
+ if (!(sec_info & SECINFO_SACL)) {
+ TALLOC_FREE(csd->sacl);
+ csd->type &= ~(
+ SEC_DESC_SACL_PRESENT |
+ SEC_DESC_SACL_DEFAULTED |
+ SEC_DESC_SACL_AUTO_INHERIT_REQ |
+ SEC_DESC_SACL_AUTO_INHERITED |
+ SEC_DESC_SACL_PROTECTED |
+ SEC_DESC_SERVER_SECURITY);
+ }
+
+ *_csd = csd;
+ return NT_STATUS_OK;
+}
+
+/*
+ add an ACE to an ACL of a security_descriptor
+*/
+
+static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd,
+ bool add_to_sacl,
+ const struct security_ace *ace,
+ ssize_t _idx)
+{
+ struct security_acl *acl = NULL;
+ ssize_t idx;
+
+ if (add_to_sacl) {
+ acl = sd->sacl;
+ } else {
+ acl = sd->dacl;
+ }
+
+ if (acl == NULL) {
+ acl = talloc(sd, struct security_acl);
+ if (acl == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ acl->revision = SECURITY_ACL_REVISION_NT4;
+ acl->size = 0;
+ acl->num_aces = 0;
+ acl->aces = NULL;
+ }
+
+ if (_idx < 0) {
+ idx = (acl->num_aces + 1) + _idx;
+ } else {
+ idx = _idx;
+ }
+
+ if (idx < 0) {
+ return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
+ } else if (idx > acl->num_aces) {
+ return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
+ }
+
+ acl->aces = talloc_realloc(acl, acl->aces,
+ struct security_ace, acl->num_aces+1);
+ if (acl->aces == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ARRAY_INSERT_ELEMENT(acl->aces, acl->num_aces, *ace, idx);
+ acl->num_aces++;
+
+ if (sec_ace_object(acl->aces[idx].type)) {
+ acl->revision = SECURITY_ACL_REVISION_ADS;
+ }
+
+ if (add_to_sacl) {
+ sd->sacl = acl;
+ sd->type |= SEC_DESC_SACL_PRESENT;
+ } else {
+ sd->dacl = acl;
+ sd->type |= SEC_DESC_DACL_PRESENT;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ add an ACE to the SACL of a security_descriptor
+*/
+
+NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd,
+ const struct security_ace *ace)
+{
+ return security_descriptor_acl_add(sd, true, ace, -1);
+}
+
+/*
+ insert an ACE at a given index to the SACL of a security_descriptor
+
+ idx can be negative, which means it's related to the new size from the
+ end, so -1 means the ace is appended at the end.
+*/
+
+NTSTATUS security_descriptor_sacl_insert(struct security_descriptor *sd,
+ const struct security_ace *ace,
+ ssize_t idx)
+{
+ return security_descriptor_acl_add(sd, true, ace, idx);
+}
+
+/*
+ add an ACE to the DACL of a security_descriptor
+*/
+
+NTSTATUS security_descriptor_dacl_add(struct security_descriptor *sd,
+ const struct security_ace *ace)
+{
+ return security_descriptor_acl_add(sd, false, ace, -1);
+}
+
+/*
+ insert an ACE at a given index to the DACL of a security_descriptor
+
+ idx can be negative, which means it's related to the new size from the
+ end, so -1 means the ace is appended at the end.
+*/
+
+NTSTATUS security_descriptor_dacl_insert(struct security_descriptor *sd,
+ const struct security_ace *ace,
+ ssize_t idx)
+{
+ return security_descriptor_acl_add(sd, false, ace, idx);
+}
+
+/*
+ delete the ACE corresponding to the given trustee in an ACL of a
+ security_descriptor
+*/
+
+static NTSTATUS security_descriptor_acl_del(struct security_descriptor *sd,
+ bool sacl_del,
+ const struct dom_sid *trustee)
+{
+ uint32_t i;
+ bool found = false;
+ struct security_acl *acl = NULL;
+
+ if (sacl_del) {
+ acl = sd->sacl;
+ } else {
+ acl = sd->dacl;
+ }
+
+ if (acl == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ /* there can be multiple ace's for one trustee */
+ for (i=0;i<acl->num_aces;i++) {
+ if (dom_sid_equal(trustee, &acl->aces[i].trustee)) {
+ ARRAY_DEL_ELEMENT(acl->aces, i, acl->num_aces);
+ acl->num_aces--;
+ if (acl->num_aces == 0) {
+ acl->aces = NULL;
+ }
+ found = true;
+ --i;
+ }
+ }
+
+ if (!found) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ acl->revision = SECURITY_ACL_REVISION_NT4;
+
+ for (i=0;i<acl->num_aces;i++) {
+ if (sec_ace_object(acl->aces[i].type)) {
+ acl->revision = SECURITY_ACL_REVISION_ADS;
+ break;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ delete the ACE corresponding to the given trustee in the DACL of a
+ security_descriptor
+*/
+
+NTSTATUS security_descriptor_dacl_del(struct security_descriptor *sd,
+ const struct dom_sid *trustee)
+{
+ return security_descriptor_acl_del(sd, false, trustee);
+}
+
+/*
+ delete the ACE corresponding to the given trustee in the SACL of a
+ security_descriptor
+*/
+
+NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd,
+ const struct dom_sid *trustee)
+{
+ return security_descriptor_acl_del(sd, true, trustee);
+}
+
+/*
+ delete the given ACE in the SACL or DACL of a security_descriptor
+*/
+static NTSTATUS security_descriptor_acl_del_ace(struct security_descriptor *sd,
+ bool sacl_del,
+ const struct security_ace *ace)
+{
+ uint32_t i;
+ bool found = false;
+ struct security_acl *acl = NULL;
+
+ if (sacl_del) {
+ acl = sd->sacl;
+ } else {
+ acl = sd->dacl;
+ }
+
+ if (acl == NULL) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ for (i=0;i<acl->num_aces;i++) {
+ if (security_ace_equal(ace, &acl->aces[i])) {
+ ARRAY_DEL_ELEMENT(acl->aces, i, acl->num_aces);
+ acl->num_aces--;
+ if (acl->num_aces == 0) {
+ acl->aces = NULL;
+ }
+ found = true;
+ i--;
+ }
+ }
+
+ if (!found) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ acl->revision = SECURITY_ACL_REVISION_NT4;
+
+ for (i=0;i<acl->num_aces;i++) {
+ if (sec_ace_object(acl->aces[i].type)) {
+ acl->revision = SECURITY_ACL_REVISION_ADS;
+ break;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS security_descriptor_dacl_del_ace(struct security_descriptor *sd,
+ const struct security_ace *ace)
+{
+ return security_descriptor_acl_del_ace(sd, false, ace);
+}
+
+NTSTATUS security_descriptor_sacl_del_ace(struct security_descriptor *sd,
+ const struct security_ace *ace)
+{
+ return security_descriptor_acl_del_ace(sd, true, ace);
+}
+
+static bool security_ace_object_equal(const struct security_ace_object *object1,
+ const struct security_ace_object *object2)
+{
+ if (object1 == object2) {
+ return true;
+ }
+ if ((object1 == NULL) || (object2 == NULL)) {
+ return false;
+ }
+ if (object1->flags != object2->flags) {
+ return false;
+ }
+ if (object1->flags & SEC_ACE_OBJECT_TYPE_PRESENT
+ && !GUID_equal(&object1->type.type, &object2->type.type)) {
+ return false;
+ }
+ if (object1->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT
+ && !GUID_equal(&object1->inherited_type.inherited_type,
+ &object2->inherited_type.inherited_type)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool security_ace_claim_equal(const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim1,
+ const struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim2)
+{
+ uint32_t i;
+
+ if (claim1 == claim2) {
+ return true;
+ }
+ if (claim1 == NULL || claim2 == NULL) {
+ return false;
+ }
+ if (claim1->name != NULL && claim2->name != NULL) {
+ if (strcasecmp_m(claim1->name, claim2->name) != 0) {
+ return false;
+ }
+ } else if (claim1->name != NULL || claim2->name != NULL) {
+ return false;
+ }
+ if (claim1->value_type != claim2->value_type) {
+ return false;
+ }
+ if (claim1->flags != claim2->flags) {
+ return false;
+ }
+ if (claim1->value_count != claim2->value_count) {
+ return false;
+ }
+ for (i = 0; i < claim1->value_count; ++i) {
+ const union claim_values *values1 = claim1->values;
+ const union claim_values *values2 = claim2->values;
+
+ switch (claim1->value_type) {
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ if (values1[i].int_value != NULL && values2[i].int_value != NULL) {
+ if (*values1[i].int_value != *values2[i].int_value) {
+ return false;
+ }
+ } else if (values1[i].int_value != NULL || values2[i].int_value != NULL) {
+ return false;
+ }
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
+ if (values1[i].uint_value != NULL && values2[i].uint_value != NULL) {
+ if (*values1[i].uint_value != *values2[i].uint_value) {
+ return false;
+ }
+ } else if (values1[i].uint_value != NULL || values2[i].uint_value != NULL) {
+ return false;
+ }
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ if (values1[i].string_value != NULL && values2[i].string_value != NULL) {
+ if (strcasecmp_m(values1[i].string_value, values2[i].string_value) != 0) {
+ return false;
+ }
+ } else if (values1[i].string_value != NULL || values2[i].string_value != NULL) {
+ return false;
+ }
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_SID:
+ if (values1[i].sid_value != NULL && values2[i].sid_value != NULL) {
+ if (data_blob_cmp(values1[i].sid_value, values2[i].sid_value) != 0) {
+ return false;
+ }
+ } else if (values1[i].sid_value != NULL || values2[i].sid_value != NULL) {
+ return false;
+ }
+ break;
+ case CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING:
+ if (values1[i].octet_value != NULL && values2[i].octet_value != NULL) {
+ if (data_blob_cmp(values1[i].octet_value, values2[i].octet_value) != 0) {
+ return false;
+ }
+ } else if (values1[i].octet_value != NULL || values2[i].octet_value != NULL) {
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
+/*
+ compare two security ace structures
+*/
+bool security_ace_equal(const struct security_ace *ace1,
+ const struct security_ace *ace2)
+{
+ if (ace1 == ace2) {
+ return true;
+ }
+ if ((ace1 == NULL) || (ace2 == NULL)) {
+ return false;
+ }
+ if (ace1->type != ace2->type) {
+ return false;
+ }
+ if (ace1->flags != ace2->flags) {
+ return false;
+ }
+ if (ace1->access_mask != ace2->access_mask) {
+ return false;
+ }
+ if (sec_ace_object(ace1->type) &&
+ !security_ace_object_equal(&ace1->object.object,
+ &ace2->object.object))
+ {
+ return false;
+ }
+ if (!dom_sid_equal(&ace1->trustee, &ace2->trustee)) {
+ return false;
+ }
+
+ if (sec_ace_callback(ace1->type)) {
+ if (data_blob_cmp(&ace1->coda.conditions, &ace2->coda.conditions) != 0) {
+ return false;
+ }
+ } else if (sec_ace_resource(ace1->type)) {
+ if (!security_ace_claim_equal(&ace1->coda.claim, &ace2->coda.claim)) {
+ return false;
+ }
+ } else {
+ /*
+ * Don’t require ace1->coda.ignored to match ace2->coda.ignored.
+ */
+ }
+
+ return true;
+}
+
+
+/*
+ compare two security acl structures
+*/
+bool security_acl_equal(const struct security_acl *acl1,
+ const struct security_acl *acl2)
+{
+ uint32_t i;
+
+ if (acl1 == acl2) return true;
+ if (!acl1 || !acl2) return false;
+ if (acl1->revision != acl2->revision) return false;
+ if (acl1->num_aces != acl2->num_aces) return false;
+
+ for (i=0;i<acl1->num_aces;i++) {
+ if (!security_ace_equal(&acl1->aces[i], &acl2->aces[i])) return false;
+ }
+ return true;
+}
+
+/*
+ compare two security descriptors.
+*/
+bool security_descriptor_equal(const struct security_descriptor *sd1,
+ const struct security_descriptor *sd2)
+{
+ if (sd1 == sd2) return true;
+ if (!sd1 || !sd2) return false;
+ if (sd1->revision != sd2->revision) return false;
+ if (sd1->type != sd2->type) return false;
+
+ if (!dom_sid_equal(sd1->owner_sid, sd2->owner_sid)) return false;
+ if (!dom_sid_equal(sd1->group_sid, sd2->group_sid)) return false;
+ if (!security_acl_equal(sd1->sacl, sd2->sacl)) return false;
+ if (!security_acl_equal(sd1->dacl, sd2->dacl)) return false;
+
+ return true;
+}
+
+/*
+ compare two security descriptors, but allow certain (missing) parts
+ to be masked out of the comparison
+*/
+bool security_descriptor_mask_equal(const struct security_descriptor *sd1,
+ const struct security_descriptor *sd2,
+ uint32_t mask)
+{
+ if (sd1 == sd2) return true;
+ if (!sd1 || !sd2) return false;
+ if (sd1->revision != sd2->revision) return false;
+ if ((sd1->type & mask) != (sd2->type & mask)) return false;
+
+ if (!dom_sid_equal(sd1->owner_sid, sd2->owner_sid)) return false;
+ if (!dom_sid_equal(sd1->group_sid, sd2->group_sid)) return false;
+ if ((mask & SEC_DESC_DACL_PRESENT) && !security_acl_equal(sd1->dacl, sd2->dacl)) return false;
+ if ((mask & SEC_DESC_SACL_PRESENT) && !security_acl_equal(sd1->sacl, sd2->sacl)) return false;
+
+ return true;
+}
+
+
+static struct security_descriptor *security_descriptor_appendv(struct security_descriptor *sd,
+ bool add_ace_to_sacl,
+ va_list ap)
+{
+ const char *sidstr;
+
+ while ((sidstr = va_arg(ap, const char *))) {
+ struct dom_sid *sid;
+ struct security_ace *ace = talloc_zero(sd, struct security_ace);
+ NTSTATUS status;
+
+ if (ace == NULL) {
+ talloc_free(sd);
+ return NULL;
+ }
+ ace->type = va_arg(ap, unsigned int);
+ ace->access_mask = va_arg(ap, unsigned int);
+ ace->flags = va_arg(ap, unsigned int);
+ sid = dom_sid_parse_talloc(ace, sidstr);
+ if (sid == NULL) {
+ talloc_free(sd);
+ return NULL;
+ }
+ ace->trustee = *sid;
+ if (add_ace_to_sacl) {
+ status = security_descriptor_sacl_add(sd, ace);
+ } else {
+ status = security_descriptor_dacl_add(sd, ace);
+ }
+ /* TODO: check: would talloc_free(ace) here be correct? */
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(sd);
+ return NULL;
+ }
+ }
+
+ return sd;
+}
+
+static struct security_descriptor *security_descriptor_createv(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ bool add_ace_to_sacl,
+ va_list ap)
+{
+ struct security_descriptor *sd;
+
+ sd = security_descriptor_initialise(mem_ctx);
+ if (sd == NULL) {
+ return NULL;
+ }
+
+ sd->type |= sd_type;
+
+ if (owner_sid) {
+ sd->owner_sid = dom_sid_parse_talloc(sd, owner_sid);
+ if (sd->owner_sid == NULL) {
+ talloc_free(sd);
+ return NULL;
+ }
+ }
+ if (group_sid) {
+ sd->group_sid = dom_sid_parse_talloc(sd, group_sid);
+ if (sd->group_sid == NULL) {
+ talloc_free(sd);
+ return NULL;
+ }
+ }
+
+ return security_descriptor_appendv(sd, add_ace_to_sacl, ap);
+}
+
+/*
+ create a security descriptor using string SIDs. This is used by the
+ torture code to allow the easy creation of complex ACLs
+ This is a varargs function. The list of DACL ACEs ends with a NULL sid.
+
+ Each ACE contains a set of 4 parameters:
+ SID, ACCESS_TYPE, MASK, FLAGS
+
+ a typical call would be:
+
+ sd = security_descriptor_dacl_create(mem_ctx,
+ sd_type_flags,
+ mysid,
+ mygroup,
+ SID_NT_AUTHENTICATED_USERS,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ SEC_FILE_ALL,
+ SEC_ACE_FLAG_OBJECT_INHERIT,
+ NULL);
+ that would create a sd with one DACL ACE
+*/
+
+struct security_descriptor *security_descriptor_dacl_create(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ ...)
+{
+ struct security_descriptor *sd = NULL;
+ va_list ap;
+ va_start(ap, group_sid);
+ sd = security_descriptor_createv(mem_ctx, sd_type, owner_sid,
+ group_sid, false, ap);
+ va_end(ap);
+
+ return sd;
+}
+
+struct security_descriptor *security_descriptor_sacl_create(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ ...)
+{
+ struct security_descriptor *sd = NULL;
+ va_list ap;
+ va_start(ap, group_sid);
+ sd = security_descriptor_createv(mem_ctx, sd_type, owner_sid,
+ group_sid, true, ap);
+ va_end(ap);
+
+ return sd;
+}
+
+struct security_ace *security_ace_create(TALLOC_CTX *mem_ctx,
+ const char *sid_str,
+ enum security_ace_type type,
+ uint32_t access_mask,
+ uint8_t flags)
+
+{
+ struct security_ace *ace;
+ bool ok;
+
+ ace = talloc_zero(mem_ctx, struct security_ace);
+ if (ace == NULL) {
+ return NULL;
+ }
+
+ ok = dom_sid_parse(sid_str, &ace->trustee);
+ if (!ok) {
+ talloc_free(ace);
+ return NULL;
+ }
+ ace->type = type;
+ ace->access_mask = access_mask;
+ ace->flags = flags;
+
+ return ace;
+}
+
+/*******************************************************************
+ Check for MS NFS ACEs in a sd
+*******************************************************************/
+bool security_descriptor_with_ms_nfs(const struct security_descriptor *psd)
+{
+ uint32_t i;
+
+ if (psd->dacl == NULL) {
+ return false;
+ }
+
+ for (i = 0; i < psd->dacl->num_aces; i++) {
+ if (dom_sid_compare_domain(
+ &global_sid_Unix_NFS,
+ &psd->dacl->aces[i].trustee) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/libcli/security/security_descriptor.h b/libcli/security/security_descriptor.h
new file mode 100644
index 0000000..354bc17
--- /dev/null
+++ b/libcli/security/security_descriptor.h
@@ -0,0 +1,99 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+
+ Copyright (C) 2009 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/>.
+*/
+
+#ifndef __SECURITY_DESCRIPTOR_H__
+#define __SECURITY_DESCRIPTOR_H__
+
+#include "librpc/gen_ndr/security.h"
+
+struct security_descriptor *security_descriptor_initialise(TALLOC_CTX *mem_ctx);
+struct security_descriptor *security_descriptor_copy(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *osd);
+NTSTATUS security_descriptor_for_client(TALLOC_CTX *mem_ctx,
+ const struct security_descriptor *ssd,
+ uint32_t sec_info,
+ uint32_t access_granted,
+ struct security_descriptor **_csd);
+NTSTATUS security_descriptor_sacl_add(struct security_descriptor *sd,
+ const struct security_ace *ace);
+NTSTATUS security_descriptor_sacl_insert(struct security_descriptor *sd,
+ const struct security_ace *ace,
+ ssize_t idx);
+NTSTATUS security_descriptor_dacl_add(struct security_descriptor *sd,
+ const struct security_ace *ace);
+NTSTATUS security_descriptor_dacl_insert(struct security_descriptor *sd,
+ const struct security_ace *ace,
+ ssize_t idx);
+NTSTATUS security_descriptor_dacl_del(struct security_descriptor *sd,
+ const struct dom_sid *trustee);
+NTSTATUS security_descriptor_sacl_del(struct security_descriptor *sd,
+ const struct dom_sid *trustee);
+NTSTATUS security_descriptor_dacl_del_ace(struct security_descriptor *sd,
+ const struct security_ace *ace);
+NTSTATUS security_descriptor_sacl_del_ace(struct security_descriptor *sd,
+ const struct security_ace *ace);
+bool security_ace_equal(const struct security_ace *ace1,
+ const struct security_ace *ace2);
+bool security_acl_equal(const struct security_acl *acl1,
+ const struct security_acl *acl2);
+bool security_descriptor_equal(const struct security_descriptor *sd1,
+ const struct security_descriptor *sd2);
+bool security_descriptor_mask_equal(const struct security_descriptor *sd1,
+ const struct security_descriptor *sd2,
+ uint32_t mask);
+struct security_descriptor *security_descriptor_dacl_create(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ ...);
+struct security_descriptor *security_descriptor_sacl_create(TALLOC_CTX *mem_ctx,
+ uint16_t sd_type,
+ const char *owner_sid,
+ const char *group_sid,
+ ...);
+struct security_ace *security_ace_create(TALLOC_CTX *mem_ctx,
+ const char *sid_str,
+ enum security_ace_type type,
+ uint32_t access_mask,
+ uint8_t flags);
+
+struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx,
+ const struct security_acl *oacl);
+
+struct security_acl *security_acl_concatenate(TALLOC_CTX *mem_ctx,
+ const struct security_acl *acl1,
+ const struct security_acl *acl2);
+
+uint32_t map_generic_rights_ds(uint32_t access_mask);
+
+struct security_descriptor *create_security_descriptor(TALLOC_CTX *mem_ctx,
+ struct security_descriptor *parent_sd,
+ struct security_descriptor *creator_sd,
+ bool is_container,
+ struct GUID *object_list,
+ uint32_t inherit_flags,
+ struct security_token *token,
+ struct dom_sid *default_owner, /* valid only for DS, NULL for the other RSs */
+ struct dom_sid *default_group, /* valid only for DS, NULL for the other RSs */
+ uint32_t (*generic_map)(uint32_t access_mask));
+
+bool security_descriptor_with_ms_nfs(const struct security_descriptor *psd);
+
+#endif /* __SECURITY_DESCRIPTOR_H__ */
diff --git a/libcli/security/security_token.c b/libcli/security/security_token.c
new file mode 100644
index 0000000..79de6e3
--- /dev/null
+++ b/libcli/security/security_token.c
@@ -0,0 +1,228 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security descriptor utility functions
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett 2010
+ Copyright (C) Stefan Metzmacher 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 <talloc.h>
+#include "lib/util/talloc_stack.h"
+#include "lib/util/debug.h"
+#include "lib/util/fault.h"
+#include "libcli/security/security_token.h"
+#include "libcli/security/dom_sid.h"
+#include "libcli/security/privileges.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/util/talloc_stack.h"
+
+/*
+ return a blank security token
+*/
+struct security_token *security_token_initialise(TALLOC_CTX *mem_ctx,
+ enum claims_evaluation_control evaluate_claims)
+{
+ struct security_token *st = talloc_zero(
+ mem_ctx, struct security_token);
+ st->evaluate_claims = evaluate_claims;
+
+ return st;
+}
+
+/****************************************************************************
+ Duplicate a SID token.
+****************************************************************************/
+
+struct security_token *security_token_duplicate(TALLOC_CTX *mem_ctx, const struct security_token *src)
+{
+ TALLOC_CTX *frame = NULL;
+ struct security_token *dst = NULL;
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ frame = talloc_stackframe();
+
+ ndr_err = ndr_push_struct_blob(
+ &blob,
+ frame,
+ src,
+ (ndr_push_flags_fn_t)ndr_push_security_token);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("Failed to duplicate security_token ndr_push_security_token failed: %s\n",
+ ndr_errstr(ndr_err));
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ dst = talloc_zero(mem_ctx, struct security_token);
+ if (dst == NULL) {
+ DBG_ERR("talloc failed\n");
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ ndr_err = ndr_pull_struct_blob(
+ &blob,
+ dst,
+ dst,
+ (ndr_pull_flags_fn_t)ndr_pull_security_token);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("Failed to duplicate security_token ndr_pull_security_token "
+ "failed: %s\n",
+ ndr_errstr(ndr_err));
+ TALLOC_FREE(dst);
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ TALLOC_FREE(frame);
+ return dst;
+}
+
+/****************************************************************************
+ prints a struct security_token to debug output.
+****************************************************************************/
+void security_token_debug(int dbg_class, int dbg_lev, const struct security_token *token)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *sids = NULL;
+ char *privs = NULL;
+ uint32_t i;
+
+ if (!token) {
+ DEBUGC(dbg_class, dbg_lev, ("Security token: (NULL)\n"));
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ sids = talloc_asprintf(frame,
+ "Security token SIDs (%" PRIu32 "):\n",
+ token->num_sids);
+ for (i = 0; i < token->num_sids; i++) {
+ struct dom_sid_buf sidbuf;
+ talloc_asprintf_addbuf(
+ &sids,
+ " SID[%3" PRIu32 "]: %s\n",
+ i,
+ dom_sid_str_buf(&token->sids[i], &sidbuf));
+ }
+
+ privs = security_token_debug_privileges(frame, token);
+
+ DEBUGC(dbg_class,
+ dbg_lev,
+ ("%s%s", sids ? sids : "(NULL)", privs ? privs : "(NULL)"));
+
+ TALLOC_FREE(frame);
+}
+
+/* These really should be cheaper... */
+
+bool security_token_is_sid(const struct security_token *token, const struct dom_sid *sid)
+{
+ bool ret;
+
+ if (token->sids == NULL) {
+ return false;
+ }
+ ret = dom_sid_equal(&token->sids[PRIMARY_USER_SID_INDEX], sid);
+ return ret;
+}
+
+bool security_token_is_system(const struct security_token *token)
+{
+ return security_token_is_sid(token, &global_sid_System);
+}
+
+bool security_token_is_anonymous(const struct security_token *token)
+{
+ return security_token_is_sid(token, &global_sid_Anonymous);
+}
+
+bool security_token_has_sid(const struct security_token *token, const struct dom_sid *sid)
+{
+ uint32_t i;
+ for (i = 0; i < token->num_sids; i++) {
+ if (dom_sid_equal(&token->sids[i], sid)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t security_token_count_flag_sids(const struct security_token *token,
+ const struct dom_sid *prefix_sid,
+ size_t num_flags,
+ const struct dom_sid **_flag_sid)
+{
+ const size_t num_auths_expected = prefix_sid->num_auths + num_flags;
+ const struct dom_sid *found = NULL;
+ size_t num = 0;
+ uint32_t i;
+
+ SMB_ASSERT(num_auths_expected <= ARRAY_SIZE(prefix_sid->sub_auths));
+
+ for (i = 0; i < token->num_sids; i++) {
+ const struct dom_sid *sid = &token->sids[i];
+ int cmp;
+
+ if (sid->num_auths != num_auths_expected) {
+ continue;
+ }
+
+ cmp = dom_sid_compare_domain(sid, prefix_sid);
+ if (cmp != 0) {
+ continue;
+ }
+
+ num += 1;
+ found = sid;
+ }
+
+ if ((num == 1) && (_flag_sid != NULL)) {
+ *_flag_sid = found;
+ }
+
+ return num;
+}
+
+bool security_token_has_builtin_guests(const struct security_token *token)
+{
+ return security_token_has_sid(token, &global_sid_Builtin_Guests);
+}
+
+bool security_token_has_builtin_administrators(const struct security_token *token)
+{
+ return security_token_has_sid(token, &global_sid_Builtin_Administrators);
+}
+
+bool security_token_has_nt_authenticated_users(const struct security_token *token)
+{
+ return security_token_has_sid(token, &global_sid_Authenticated_Users);
+}
+
+bool security_token_has_enterprise_dcs(const struct security_token *token)
+{
+ return security_token_has_sid(token, &global_sid_Enterprise_DCs);
+}
diff --git a/libcli/security/security_token.h b/libcli/security/security_token.h
new file mode 100644
index 0000000..8baf4cf
--- /dev/null
+++ b/libcli/security/security_token.h
@@ -0,0 +1,74 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ security descriptor utility functions
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett 2010
+ Copyright (C) Stefan Metzmacher 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 _LIBCLI_SECURITY_SECURITY_TOKEN_H_
+#define _LIBCLI_SECURITY_SECURITY_TOKEN_H_
+
+#include "replace.h"
+#include "lib/util/data_blob.h"
+#include "librpc/gen_ndr/security.h"
+
+#define PRIMARY_USER_SID_INDEX 0
+#define PRIMARY_GROUP_SID_INDEX 1
+#define PRIMARY_SIDS_COUNT 2
+#define REMAINING_SIDS_INDEX 2
+
+/*
+ return a blank security token
+*/
+struct security_token *security_token_initialise(TALLOC_CTX *mem_ctx,
+ enum claims_evaluation_control evaluate_claims);
+
+struct security_token *security_token_duplicate(TALLOC_CTX *mem_ctx, const struct security_token *src);
+
+/****************************************************************************
+ prints a struct security_token to debug output.
+****************************************************************************/
+void security_token_debug(int dbg_class, int dbg_lev, const struct security_token *token);
+
+bool security_token_is_sid(const struct security_token *token, const struct dom_sid *sid);
+
+bool security_token_is_system(const struct security_token *token);
+
+bool security_token_is_anonymous(const struct security_token *token);
+
+bool security_token_has_sid(const struct security_token *token, const struct dom_sid *sid);
+
+/*
+ * Return any of the domain sids found in the token matching "domain"
+ * in _domain_sid, makes most sense if you just found one.
+ */
+size_t security_token_count_flag_sids(const struct security_token *token,
+ const struct dom_sid *prefix_sid,
+ size_t num_flags,
+ const struct dom_sid **_flag_sid);
+
+bool security_token_has_builtin_guests(const struct security_token *token);
+
+bool security_token_has_builtin_administrators(const struct security_token *token);
+
+bool security_token_has_nt_authenticated_users(const struct security_token *token);
+
+bool security_token_has_enterprise_dcs(const struct security_token *token);
+
+#endif
diff --git a/libcli/security/session.c b/libcli/security/session.c
new file mode 100644
index 0000000..8db341d
--- /dev/null
+++ b/libcli/security/session.c
@@ -0,0 +1,74 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ session_info utility functions
+
+ Copyright (C) Andrew Bartlett 2008-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.h"
+#include "libcli/security/security.h"
+#include "libcli/util/werror.h"
+#include "librpc/gen_ndr/auth.h"
+
+enum security_user_level security_session_user_level(struct auth_session_info *session_info,
+ const struct dom_sid *domain_sid)
+{
+ struct security_token *token = NULL;
+ bool authenticated = false;
+ bool guest = false;
+
+ if (!session_info) {
+ return SECURITY_ANONYMOUS;
+ }
+ token = session_info->security_token;
+
+ if (security_token_is_system(token)) {
+ return SECURITY_SYSTEM;
+ }
+
+ if (security_token_is_anonymous(token)) {
+ return SECURITY_ANONYMOUS;
+ }
+
+ authenticated = security_token_has_nt_authenticated_users(token);
+ guest = security_token_has_builtin_guests(token);
+ if (!authenticated) {
+ if (guest) {
+ return SECURITY_GUEST;
+ }
+ return SECURITY_ANONYMOUS;
+ }
+
+ if (security_token_has_builtin_administrators(token)) {
+ return SECURITY_ADMINISTRATOR;
+ }
+
+ if (domain_sid) {
+ struct dom_sid rodc_dcs = { .num_auths = 0 };
+ sid_compose(&rodc_dcs, domain_sid, DOMAIN_RID_READONLY_DCS);
+
+ if (security_token_has_sid(token, &rodc_dcs)) {
+ return SECURITY_RO_DOMAIN_CONTROLLER;
+ }
+ }
+
+ if (security_token_has_enterprise_dcs(token)) {
+ return SECURITY_DOMAIN_CONTROLLER;
+ }
+
+ return SECURITY_USER;
+}
diff --git a/libcli/security/session.h b/libcli/security/session.h
new file mode 100644
index 0000000..31e950e
--- /dev/null
+++ b/libcli/security/session.h
@@ -0,0 +1,44 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ session_info utility functions
+
+ Copyright (C) Andrew Bartlett 2008-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 _LIBCLI_SECURITY_SESSION_H_
+#define _LIBCLI_SECURITY_SESSION_H_
+
+enum security_user_level {
+ SECURITY_ANONYMOUS = 0,
+ SECURITY_GUEST = 1,
+ SECURITY_USER = 10,
+ SECURITY_RO_DOMAIN_CONTROLLER = 20,
+ SECURITY_DOMAIN_CONTROLLER = 30,
+ SECURITY_ADMINISTRATOR = 40,
+ SECURITY_SYSTEM = 50
+};
+
+struct cli_credentials;
+struct security_token;
+struct auth_user_info;
+struct auth_user_info_torture;
+struct auth_session_info;
+
+enum security_user_level security_session_user_level(struct auth_session_info *session_info,
+ const struct dom_sid *domain_sid);
+
+#endif
diff --git a/libcli/security/tests/data/conditional_aces.txt b/libcli/security/tests/data/conditional_aces.txt
new file mode 100644
index 0000000..cf7d7a9
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces.txt
@@ -0,0 +1,83 @@
+D:(XD;;CC;;;S-1-2-3;(@User.Title == @User.Title)) -> D:(XD;;CC;;;S-1-2-3;(@USER.Title == @USER.Title))
+D:(XA;;FX;;;S-1-1-0;(@User.Title == "PM")) -> D:(XA;;FX;;;WD;(@USER.Title == "PM"))
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.title == "perambuator"))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.title == "perambuator"))(A;OICI;GA;;;BA)
+O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "siloname")) -> O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "siloname"))
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.Title == ""))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.Title == ""))(A;OICI;GA;;;BA)
+D:(XA;;CC;;;S-1-2-3;(@User.Title != @User.Title)) -> D:(XA;;CC;;;S-1-2-3;(@USER.Title != @USER.Title))
+D:(XD;;FX;;;S-1-1-0;(@User.Title != "PM")) -> D:(XD;;FX;;;WD;(@USER.Title != "PM"))
+D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project)) -> D:(XD;;FX;;;WD;(@USER.Project Any_of @RESOURCE.Project))
+D:AI(XA;OICI;FA;;;WD;(OctetStringType==##1#2#3##)) -> D:AI(XA;OICI;FA;;;WD;(OctetStringType == #01020300))
+D:AI(XA;OICI;FA;;;WD;(OctetStringType==#01020300)) -> D:AI(XA;OICI;FA;;;WD;(OctetStringType == #01020300))
+D:(XA;;FR;;;S-1-1-0;(Member_of {SID(S-1-999-777-7-7), SID(BO)} && @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((Member_of {SID(S-1-999-777-7-7), SID(BO)}) && (@DEVICE.Bitlocker)))
+D:(XA;;FX;;;S-1-1-0;(@User.Title=="PM" && (@User.Division=="Finance" || @User.Division =="Sales"))) -> D:(XA;;FX;;;WD;((@USER.Title == "PM") && ((@USER.Division == "Finance") || (@USER.Division == "Sales"))))
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.Title == ""))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.Title == ""))(A;OICI;GA;;;BA)
+D:(XA;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project)) -> D:(XA;;FX;;;WD;(@USER.Project Any_of @RESOURCE.Project))
+D:(XA;;0x1f;;;AA;(@Device.colour == {"orange", "blue"})) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour == {"orange", "blue"}))
+D:(XA;;0x1f;;;AA;(@Device.legs >= 1)) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.legs >= 1))
+D:(XA;;0x1f;;;AA;(@Device.legs == 1)) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.legs == 1))
+D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)} && Member_of{SID(WD)})) -> D:(XA;;CCDCLCSWRP;;;AA;((Device_Member_of {SID(BA)}) && (Member_of {SID(WD)})))
+D:(XA;;0x1f;;;AA;(Device_Member_of{SID(AA)} || Member_of{SID(WD)})) -> D:(XA;;CCDCLCSWRP;;;AA;((Device_Member_of {SID(AA)}) || (Member_of {SID(WD)})))
+D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BG)} || Member_of{SID(WR)})) -> D:(XA;;CCDCLCSWRP;;;AA;((Device_Member_of {SID(BG)}) || (Member_of {SID(WR)})))
+D:(XA;;0x1ff;;;S-1-222-333;(Member_of_Any{SID(S-1-222-333)})) -> D:(XA;;CCDCLCSWRPWPDTLOCR;;;S-1-222-333;(Member_of_any {SID(S-1-222-333)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of{SID(S-1-1-0)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of {SID(WD)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of SID(S-1-1-0))) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of SID(WD)))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of(SID(S-1-1-0)))) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of SID(WD)))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any SID(S-1-1-0))) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of_any SID(WD)))
+O:S-1-1-0D:(XA;;0x1;;;WD;(Member_of_Any{SID(AS),SID(WD)})) -> O:WDD:(XA;;CC;;;WD;(Member_of_any {SID(AS), SID(WD)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-0), SID(S-1-222-333)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of_any {SID(WD), SID(S-1-222-333)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-334), SID(S-1-222-333)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of_any {SID(S-1-1-334), SID(S-1-222-333)}))
+D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-222-333)})) -> D:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of_any {SID(S-1-222-333)}))
+D:(XA;;0x1f;;;AA;(Member_of{SID(S-1-77-88-99)})) -> D:(XA;;CCDCLCSWRP;;;AA;(Member_of {SID(S-1-77-88-99)}))
+D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)})) -> D:(XA;;CCDCLCSWRP;;;AA;(Device_Member_of {SID(BA)}))
+D:(XA;;0x1f;;;AA;(!(! (Member_of{SID(AA)})))) -> D:(XA;;CCDCLCSWRP;;;AA;(!(!(Member_of {SID(AA)}))))
+D:(XA;;0x1f;;;AA;(!(!(!(!(!(! (Member_of{SID(AA)})))))))) -> D:(XA;;CCDCLCSWRP;;;AA;(!(!(!(!(!(!(Member_of {SID(AA)}))))))))
+D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;("colour",TS,0,"blue")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour Contains @RESOURCE.colour))S:(RA;;;;;WD;("colour",TS,0x0,"blue"))
+D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))S:(RA;;;;;WD;("colour",TS,0,"blue")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour == @RESOURCE.colour))S:(RA;;;;;WD;("colour",TS,0x0,"blue"))
+D:(XA;;0x1f;;;AA;(@Device.colour == "blue")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour == "blue"))
+D:(XA;;0x1f;;;AA;(@User.colour == @Device.colour)) -> D:(XA;;CCDCLCSWRP;;;AA;(@USER.colour == @DEVICE.colour))
+D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;("colour",TS,0,"blue", "red")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour Contains @RESOURCE.colour))S:(RA;;;;;WD;("colour",TS,0x0,"blue","red"))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(member_of{SID(S-1-1-0)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of {SID(WD)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(mEMBER_of{SID(S-1-1-0)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of {SID(WD)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_Of{SID(S-1-1-0)})) -> O:WDD:(XA;;CCDCLCSWRPWPDTLOCR;;;WD;(Member_of {SID(WD)}))
+O:S-1-1-0D:(XA;;0x0;;;WD;(Member_Of SID(S-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:S-1-1-0D:(XA;;0;;;WD;(Member_Of SID(S-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:S-1-1-0D:(XA;;;;;WD;(Member_Of SID(S-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+D:(XD;;FX;;;WD;(@USER.Project Any_of "pink"))
+D:(XD;;FX;;;WD;(@USER.Project Any_of 1))
+D:(XD;;FX;;;WD;(!(@USER.Project Not_Any_of 1)))
+D:(XA;;0x1f;;;AA;(a == 1)) -> D:(XA;;CCDCLCSWRP;;;AA;(a == 1))
+D:(XA;;CC;;;AA;(@User.a == @User.b)) -> D:(XA;;CC;;;AA;(@USER.a == @USER.b))
+D:(XA;;CC;;;AA;(a == @User.a)) -> D:(XA;;CC;;;AA;(a == @USER.a))
+
+D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B && @USER.C)) -> D:(XA;;FR;;;WD;(((@USER.A) && (@DEVICE.B)) && (@USER.C)))
+D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B || @USER.C)) -> D:(XA;;FR;;;WD;(((@USER.A) && (@DEVICE.B)) || (@USER.C)))
+D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B && @USER.C)) -> D:(XA;;FR;;;WD;((@USER.A) || ((@DEVICE.B) && (@USER.C))))
+D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B || @USER.C)) -> D:(XA;;FR;;;WD;(((@USER.A) || (@DEVICE.B)) || (@USER.C)))
+
+D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker && @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((@DEVICE.Bitlocker) && (@DEVICE.Bitlocker)))
+D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker || @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((@DEVICE.Bitlocker) || (@DEVICE.Bitlocker)))
+D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B)) -> D:(XA;;FR;;;WD;((@USER.A) && (@DEVICE.B)))
+D:(XA;;FR;;;S-1-1-0;(@USER.Bitlocker || @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((@USER.Bitlocker) || (@DEVICE.Bitlocker)))
+D:(XA;;;;;WD;(@Device.bb == 0x7fffffffffffffff)) -> D:(XA;;;;;WD;(@DEVICE.bb == 0x7fffffffffffffff))
+D:(XA;;;;;WD;(@Device.bb == 0xffffffff)) -> D:(XA;;;;;WD;(@DEVICE.bb == 0xffffffff))
+D:(XA;;;;;WD;(@Device.bb == 0xfffffffff)) -> D:(XA;;;;;WD;(@DEVICE.bb == 0xfffffffff))
+
+
+# Member_of is supposed to be SID only
+D:(XD;;FX;;;WD;(Member_of {1, 2, 3}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(Member_of 3))(A;;CR;;;WD)
+
+# repeated composite values
+D:(XD;;FX;;;WD;(@USER.Project Any_of 1))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {1, 1}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {"foo", "FOO"}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {"foo", "foo", "FOO"}))(A;;CR;;;WD)
+
+# composite order
+D:(XD;;FX;;;WD;(@USER.Project Any_of {1, 2, 3}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {3, 2, 1}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {1, 1, 1}))(A;;CR;;;WD)
+D:(XD;;FX;;;WD;(@USER.Project Any_of {1, 2, 3, 2, 1}))(A;;CR;;;WD)
+
+D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))S:(RA;;;;;WD;("colour",TS,0,"red", "blue")) -> D:(XA;;CCDCLCSWRP;;;AA;(@DEVICE.colour == @RESOURCE.colour))S:(RA;;;;;WD;("colour",TS,0x0,"red","blue"))
+D:(XA;;CCDCLCSWRP;;;AA;(@RESOURCE.a == @RESOURCE.b))S:(RA;;;;;WD;("a",TS,0x0,"1","2"))(RA;;;;;WD;("b",TS,0x0,"2","1"))
diff --git a/libcli/security/tests/data/conditional_aces.txt.json b/libcli/security/tests/data/conditional_aces.txt.json
new file mode 100644
index 0000000..4c8211c
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces.txt.json
@@ -0,0 +1 @@
+{"D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.Title == \"\"))(A;OICI;GA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 144, 0, 5, 0, 0, 0, 1, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 1, 3, 20, 0, 0, 0, 0, 16, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 224, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 9, 0, 48, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 0, 0, 0, 0, 128, 0, 0, 0, 0, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.title == \"perambuator\"))(A;OICI;GA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 164, 0, 5, 0, 0, 0, 1, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 1, 3, 20, 0, 0, 0, 0, 16, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 224, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 9, 0, 68, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 116, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 22, 0, 0, 0, 112, 0, 101, 0, 114, 0, 97, 0, 109, 0, 98, 0, 117, 0, 97, 0, 116, 0, 111, 0, 114, 0, 128, 0, 0, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(XA;;0x1f;;;AA;(!(! (Member_of{SID(AA)}))))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 9, 0, 60, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 137, 162, 162, 0, 0, 0], "D:(XA;;0x1f;;;AA;(!(!(!(!(!(! (Member_of{SID(AA)}))))))))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 137, 162, 162, 162, 162, 162, 162, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == \"blue\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 9, 0, 60, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 16, 8, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 128, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 92, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 18, 0, 64, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 128, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 92, 0, 1, 0, 0, 0, 9, 0, 84, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 80, 30, 0, 0, 0, 16, 12, 0, 0, 0, 111, 0, 114, 0, 97, 0, 110, 0, 103, 0, 101, 0, 16, 8, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 128, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 92, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 18, 0, 64, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 134, 0], "D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\", \"red\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 104, 0, 0, 0, 2, 0, 84, 0, 1, 0, 0, 0, 18, 0, 76, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 24, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 38, 0, 0, 0, 48, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 114, 0, 101, 0, 100, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 134, 0], "D:(XA;;0x1f;;;AA;(@Device.legs == 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 8, 0, 0, 0, 108, 0, 101, 0, 103, 0, 115, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 128, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.legs >= 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 8, 0, 0, 0, 108, 0, 101, 0, 103, 0, 115, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 133, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@User.colour == @Device.colour))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 249, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 128, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(AA)} || Member_of{SID(WD)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 161, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)} && Member_of{SID(WD)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 160, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 138, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BG)} || Member_of{SID(WR)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 33, 0, 0, 0, 137, 161, 0], "D:(XA;;0x1f;;;AA;(Member_of{SID(S-1-77-88-99)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 77, 88, 0, 0, 0, 99, 0, 0, 0, 137, 0], "D:(XA;;0x1f;;;AA;(a == 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 248, 2, 0, 0, 0, 97, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 128, 0], "D:(XA;;0x1ff;;;S-1-222-333;(Member_of_Any{SID(S-1-222-333)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 0], "D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-222-333)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 0], "D:(XA;;;;;WD;(@Device.bb == 0x7fffffffffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 255, 255, 255, 127, 3, 3, 128, 0, 0, 0], "D:(XA;;;;;WD;(@Device.bb == 0xffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 0, 0, 0, 0, 3, 3, 128, 0, 0, 0], "D:(XA;;;;;WD;(@Device.bb == 0xfffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 15, 0, 0, 0, 3, 3, 128, 0, 0, 0], "D:(XA;;CC;;;AA;(@User.a == @User.b))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 97, 0, 249, 2, 0, 0, 0, 98, 0, 128, 0], "D:(XA;;CC;;;AA;(a == @User.a))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 248, 2, 0, 0, 0, 97, 0, 249, 2, 0, 0, 0, 97, 0, 128, 0], "D:(XA;;CC;;;S-1-2-3;(@User.Title != @User.Title))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 129, 0], "D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker && @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker || @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B && @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 249, 2, 0, 0, 0, 67, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B || @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 249, 2, 0, 0, 0, 67, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 48, 0, 1, 0, 0, 0, 9, 0, 40, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B && @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 249, 2, 0, 0, 0, 67, 0, 160, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B || @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 161, 249, 2, 0, 0, 0, 67, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.Bitlocker || @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(Member_of {SID(S-1-999-777-7-7), SID(BO)} && @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 108, 0, 1, 0, 0, 0, 9, 0, 100, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 46, 0, 0, 0, 81, 20, 0, 0, 0, 1, 3, 0, 0, 0, 0, 3, 231, 9, 3, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 39, 2, 0, 0, 137, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 160], "D:(XA;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 250, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 136, 0], "D:(XA;;FX;;;S-1-1-0;(@User.Title == \"PM\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 60, 0, 1, 0, 0, 0, 9, 0, 52, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 128, 0, 0, 0], "D:(XA;;FX;;;S-1-1-0;(@User.Title==\"PM\" && (@User.Division==\"Finance\" || @User.Division ==\"Sales\")))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 140, 0, 1, 0, 0, 0, 9, 0, 132, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 128, 249, 16, 0, 0, 0, 68, 0, 105, 0, 118, 0, 105, 0, 115, 0, 105, 0, 111, 0, 110, 0, 16, 14, 0, 0, 0, 70, 0, 105, 0, 110, 0, 97, 0, 110, 0, 99, 0, 101, 0, 128, 249, 16, 0, 0, 0, 68, 0, 105, 0, 118, 0, 105, 0, 115, 0, 105, 0, 111, 0, 110, 0, 16, 10, 0, 0, 0, 83, 0, 97, 0, 108, 0, 101, 0, 115, 0, 128, 161, 160, 0, 0, 0], "D:(XD;;CC;;;S-1-2-3;(@User.Title == @User.Title))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 128, 0], "D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 10, 0, 64, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 250, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 136, 0], "D:(XD;;FX;;;S-1-1-0;(@User.Title != \"PM\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 60, 0, 1, 0, 0, 0, 10, 0, 52, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 129, 0, 0, 0], "D:(XD;;FX;;;WD;(!(@USER.Project Not_Any_of 1)))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 143, 162], "D:(XD;;FX;;;WD;(@USER.Project Any_of \"pink\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 10, 0, 60, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 16, 8, 0, 0, 0, 112, 0, 105, 0, 110, 0, 107, 0, 136, 0, 0, 0], "D:(XD;;FX;;;WD;(@USER.Project Any_of 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 136, 0], "D:AI(XA;OICI;FA;;;WD;(OctetStringType==##1#2#3##))": [1, 0, 4, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 3, 72, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 248, 30, 0, 0, 0, 79, 0, 99, 0, 116, 0, 101, 0, 116, 0, 83, 0, 116, 0, 114, 0, 105, 0, 110, 0, 103, 0, 84, 0, 121, 0, 112, 0, 101, 0, 24, 4, 0, 0, 0, 1, 2, 3, 0, 128, 0, 0, 0], "D:AI(XA;OICI;FA;;;WD;(OctetStringType==#01020300))": [1, 0, 4, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 3, 72, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 248, 30, 0, 0, 0, 79, 0, 99, 0, 116, 0, 101, 0, 116, 0, 83, 0, 116, 0, 114, 0, 105, 0, 110, 0, 103, 0, 84, 0, 121, 0, 112, 0, 101, 0, 24, 4, 0, 0, 0, 1, 2, 3, 0, 128, 0, 0, 0], "O:S-1-1-0D:(XA;;0;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x0;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1;;;WD;(Member_of_Any{SID(AS),SID(WD)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 18, 1, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_Of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of(SID(S-1-1-0))))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 139, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-0), SID(S-1-222-333)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-334), SID(S-1-222-333)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 78, 1, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(mEMBER_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(member_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == \"siloname\"))": [1, 0, 4, 128, 136, 0, 0, 0, 148, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 116, 0, 1, 0, 0, 0, 9, 3, 108, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 54, 0, 0, 0, 97, 0, 100, 0, 58, 0, 47, 0, 47, 0, 101, 0, 120, 0, 116, 0, 47, 0, 65, 0, 117, 0, 116, 0, 104, 0, 101, 0, 110, 0, 116, 0, 105, 0, 99, 0, 97, 0, 116, 0, 105, 0, 111, 0, 110, 0, 83, 0, 105, 0, 108, 0, 111, 0, 16, 16, 0, 0, 0, 115, 0, 105, 0, 108, 0, 111, 0, 110, 0, 97, 0, 109, 0, 101, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0]} \ No newline at end of file
diff --git a/libcli/security/tests/data/conditional_aces_case_insensitive.txt b/libcli/security/tests/data/conditional_aces_case_insensitive.txt
new file mode 100644
index 0000000..ee2500d
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces_case_insensitive.txt
@@ -0,0 +1 @@
+D:AI(XA;OICI;FA;;;WD;(OctetStringType==#abcdef)) -> D:AI(XA;OICI;FA;;;WD;(OctetStringType == #abcdef))
diff --git a/libcli/security/tests/data/conditional_aces_should_fail.txt b/libcli/security/tests/data/conditional_aces_should_fail.txt
new file mode 100644
index 0000000..23eadcf
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces_should_fail.txt
@@ -0,0 +1,14 @@
+# Lines starting with # are ignored.
+# These SDDL strings are expected to fail.
+D:(XA;;FR;;;S-1-1-0; (Member_of {SID(ernie), SID(BO)} && @Device.Bitlocker)) -> D:(XA;;FR;;;S-1-1-0; (Member_of {SID(ernie), SID(BO)} && @Device.Bitlocker))
+D:(XA;;0x1f;;;AA;(!!! !!! !!! Member_of{SID(BA)})) -> D:(XA;;0x1f;;;AA;(!!! !!! !!! Member_of{SID(BA)}))
+D:(XA;;0x1f;;;AA;(!!! !!! !!! Not_Member_of{SID(AA)})) -> D:(XA;;0x1f;;;AA;(!!! !!! !!! Not_Member_of{SID(AA)}))
+O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_AnySID(S-1-1-0))) -> O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_AnySID(S-1-1-0)))
+D:(XA;;CC;;;S-1-2-3;(@User.Title == !(@User.Title))) -> x
+D:(XA;;0x1f;;;AA;(! Member_of{SID(BA)})) -> x
+# local attributes on the RHS fail (ok on the LHS)
+D:(XA;;0x1f;;;AA;(a == a))
+D:(XA;;;;;WD;(@Device.bb == 055555624677746777766777767))
+D:(XA;;;;;WD;(@Device.bb == 0x624677746777766777767))
+D:(XA;;;;;WD;(@Device.bb == 624677746777766777767))
+D:(XA;;;;;WD;(@Device.bb == 0x10000000000000000))
diff --git a/libcli/security/tests/data/conditional_aces_windows_only.txt b/libcli/security/tests/data/conditional_aces_windows_only.txt
new file mode 100644
index 0000000..182d412
--- /dev/null
+++ b/libcli/security/tests/data/conditional_aces_windows_only.txt
@@ -0,0 +1,14 @@
+# Windows is far less fussy about case in general SDDL
+O:S-1-1-0D:(xd;;;;;WD;(Member_Of SID(S-1-1-0))) -> O:WDD:(XD;;;;;WD;(Member_of SID(WD)))
+O:s-1-1-0D:(xa;;;;;wd;(Member_Of SID(S-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:s-1-1-0D:(xa;;;;;wd;(member_of sid(s-1-1-0))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:s-1-1-0D:(xa;;;;;wd;(member_of(sid(s-1-1-0)))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+O:s-1-1-0D:(xa;;;;;wd;(member_of((sid(s-1-1-0))))) -> O:WDD:(XA;;;;;WD;(Member_of SID(WD)))
+# spaces in general SDDL
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A; OICI; GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.TEETH == "5"))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.TEETH == "5"))(A;OICI;GA;;;BA)
+D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A; OICI; GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.title == "perambuator"))(A;OICI;GA;;;BA) -> D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GXGWGR;;;AU)(XA;;FX;;;WD;(@USER.title == "perambuator"))(A;OICI;GA;;;BA)
+D:(XA;;FR;;;S-1-1-0; (Member_of {SID(S-1-1-0), SID(BO)} && @Device.Bitlocker)) -> D:(XA;;FR;;;WD;((Member_of {SID(WD), SID(BO)}) && (@DEVICE.Bitlocker)))
+D:(XD;;FX;;;S-1-1-0; (@User.Project Any_of @Resource.Project)) -> D:(XD;;FX;;;WD;(@USER.Project Any_of @RESOURCE.Project))
+# note the odd number of characters in this octet string; implies a leading '0'
+D:AI(XA;OICI;FA;;;WD;(OctetStringType==#1#2#3##)) -> D:AI(XA;OICI;FA;;;WD;(OctetStringType == #01020300))
+D:(XA;;;;;WD;(@Device.bb == 0xffffffffffffffff)) -> D:(XA;;;;;WD;(@DEVICE.bb == 0xffffffffffffffff))
diff --git a/libcli/security/tests/data/export-sddl-fuzz-seeds-as-json b/libcli/security/tests/data/export-sddl-fuzz-seeds-as-json
new file mode 100755
index 0000000..cbff661
--- /dev/null
+++ b/libcli/security/tests/data/export-sddl-fuzz-seeds-as-json
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+"""USAGE: $ ./export-sddl-fuzz-seeds-as-json DIR [DIR[...]] > x.json
+
+Some of our fuzzers generate SDDL strings with trailing garbage.
+
+This script converts them into the JSON format used by
+windows-sddl-tests.py, though it doesn't parse the SDDL, mapping all
+strings to an empty list. The idea is you can feed this through
+windows-sddl-tests.py or something else to get the correct bytes.
+
+Valid and invalid strings are treated alike, so long as they are
+utf-8. The JSON is un-indented, but structurally equivalent to this:
+
+{
+ "D:P" : [],
+ "yertle" : [],
+ "ł\n¼" : [],
+}
+"""
+from pathlib import Path
+import sys
+import json
+
+
+def main():
+ if {'-h', '--help'}.intersection(sys.argv) or len(sys.argv) < 2:
+ print(__doc__)
+ sys.exit(len(sys.argv) < 2)
+
+ bytes_json = {}
+ for arg in sys.argv[1:]:
+ d = Path(arg)
+ for fn in d.iterdir():
+ with fn.open("rb") as f:
+ b = f.read()
+ # the SDDL string is the nul-terminated portion.
+ if 0 in b:
+ b = b[:b.index(0)]
+ try:
+ s = b.decode()
+ except UnicodeDecodeError:
+ continue
+ bytes_json[s] = []
+
+ out = json.dumps(bytes_json)
+ print(out)
+
+
+main()
diff --git a/libcli/security/tests/data/extract-sddl-seeds b/libcli/security/tests/data/extract-sddl-seeds
new file mode 100755
index 0000000..27ca407
--- /dev/null
+++ b/libcli/security/tests/data/extract-sddl-seeds
@@ -0,0 +1,72 @@
+#!/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: extract-sddl-seeds SRCDIR SDDLDIR
+
+SRCDIR should have fuzz_security_token_vs_descriptor seeds.
+
+SDDLDIR will end up with SDDL strings representing the security
+descriptors in the seeds, along with 4 trailing bytes representing an
+access mask. This is the format used by the SDDL fuzzers.
+"""
+
+
+import sys
+sys.path.insert(0, "bin/python")
+
+from pathlib import Path
+from hashlib import md5
+from samba.ndr import ndr_unpack, ndr_pack
+from samba.dcerpc.security import token_descriptor_fuzzing_pair
+
+
+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)
+
+ raw_strings = set()
+ sddl_strings = set()
+
+ for filename in sp.iterdir():
+ with open(filename, 'rb') as f:
+ raw_strings.add(f.read())
+
+ for s in raw_strings:
+ pair = ndr_unpack(s)
+ sd = pair.sd.as_sddl()
+ mask = pair.access_desired
+ b = sd.encode() + mask.to_bytes(4, 'little')
+ sddl_strings.add(b)
+
+ for s in sddl_strings:
+ name = md5(s).hexdigest()
+ with open(dp / name, "wb") as f:
+ f.write(s)
+
+
+main()
diff --git a/libcli/security/tests/data/ndr_dumps/fileb5iJt4 b/libcli/security/tests/data/ndr_dumps/fileb5iJt4
new file mode 100644
index 0000000..c0de4da
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/fileb5iJt4
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/fileb8cNVS b/libcli/security/tests/data/ndr_dumps/fileb8cNVS
new file mode 100644
index 0000000..bee598e
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/fileb8cNVS
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/filebI7h5H b/libcli/security/tests/data/ndr_dumps/filebI7h5H
new file mode 100644
index 0000000..c98fe38
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/filebI7h5H
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/filebNdBgt b/libcli/security/tests/data/ndr_dumps/filebNdBgt
new file mode 100644
index 0000000..62e37ae
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/filebNdBgt
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/filebOjK4H b/libcli/security/tests/data/ndr_dumps/filebOjK4H
new file mode 100644
index 0000000..9a040c1
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/filebOjK4H
Binary files differ
diff --git a/libcli/security/tests/data/ndr_dumps/filebzCPTH b/libcli/security/tests/data/ndr_dumps/filebzCPTH
new file mode 100644
index 0000000..ba52884
--- /dev/null
+++ b/libcli/security/tests/data/ndr_dumps/filebzCPTH
Binary files differ
diff --git a/libcli/security/tests/data/oversize-acls.json b/libcli/security/tests/data/oversize-acls.json
new file mode 100644
index 0000000..a4559f3
--- /dev/null
+++ b/libcli/security/tests/data/oversize-acls.json
@@ -0,0 +1,20 @@
+{
+ "D:(A;OICI;FA;;;S-1-5-21-1927343755-967950539-965328874-512)(A;OICI;FA;;;S-1-5-21-1927343755-967950539-965328874-519)(A;;FA;;;BA)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;;;;AU)(A;OICI;0x1200a9;;;ED)":
+ [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 208, 0, 8, 0, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 139, 238, 224, 114, 203, 192, 177, 57, 234, 191, 137, 57, 0, 2, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 139, 238, 224, 114, 203, 192, 177, 57, 234, 191, 137, 57, 7, 2, 0, 0, 0, 0, 24, 0, 255, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 11, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 9, 0, 0, 0, 0, 0, 0, 0],
+ "D:(A;OICI;FA;;;S-1-5-21-3372605546-132586199-2553092274-512)(A;OICI;FA;;;S-1-5-21-3372605546-132586199-2553092274-519)(A;;FA;;;BA)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;;;;AU)(A;OICI;0x1200a9;;;ED)":
+ [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 208, 0, 8, 0, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 106, 224, 5, 201, 215, 26, 231, 7, 178, 24, 45, 152, 0, 2, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 106, 224, 5, 201, 215, 26, 231, 7, 178, 24, 45, 152, 7, 2, 0, 0, 0, 0, 24, 0, 255, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 11, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 9, 0, 0, 0, 0, 0, 0, 0],
+ "D:(A;OICI;FA;;;S-1-5-21-446349270-2432516025-2131592620-512)(A;OICI;FA;;;S-1-5-21-446349270-2432516025-2131592620-519)(A;;FA;;;BA)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;;;;AU)(A;OICI;0x1200a9;;;ED)":
+ [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 208, 0, 8, 0, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 214, 191, 154, 26, 185, 63, 253, 144, 172, 133, 13, 127, 0, 2, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 214, 191, 154, 26, 185, 63, 253, 144, 172, 133, 13, 127, 7, 2, 0, 0, 0, 0, 24, 0, 255, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 11, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 9, 0, 0, 0, 0, 0, 0, 0],
+ "D:(A;OICI;FA;;;S-1-5-21-926620776-2075325327-1127912823-512)(A;OICI;FA;;;S-1-5-21-926620776-2075325327-1127912823-519)(A;;FA;;;BA)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;;;;AU)(A;OICI;0x1200a9;;;ED)":
+ [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 208, 0, 8, 0, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 104, 28, 59, 55, 143, 243, 178, 123, 119, 149, 58, 67, 0, 2, 0, 0, 0, 3, 36, 0, 255, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 104, 28, 59, 55, 143, 243, 178, 123, 119, 149, 58, 67, 7, 2, 0, 0, 0, 0, 24, 0, 255, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 11, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 20, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 0, 3, 20, 0, 169, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 5, 9, 0, 0, 0, 0, 0, 0, 0],
+ "D:P(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 56, 0, 2, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "D:P(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 80, 0, 3, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "D:P(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 104, 0, 4, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ "D:P(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 176, 0, 7, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 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],
+ "D:P(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)":
+ [1, 0, 4, 144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 4, 0, 16, 1, 11, 0, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 0, 0, 1, 0, 20, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 16, 0, 33, 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]
+}
diff --git a/libcli/security/tests/data/registry-object-rights.json b/libcli/security/tests/data/registry-object-rights.json
new file mode 100644
index 0000000..97a64ea
--- /dev/null
+++ b/libcli/security/tests/data/registry-object-rights.json
@@ -0,0 +1 @@
+{"D:(A;;CCLCRPRC;;;WD)(A;;KA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 2, 0, 0, 0, 0, 0, 20, 0, 21, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 76, 0, 3, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-1069531106-184984463-4116541046-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 226, 191, 191, 63, 143, 163, 6, 11, 118, 110, 93, 245, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-1378461354-3939386343-493233828-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 170, 166, 41, 82, 231, 67, 206, 234, 164, 38, 102, 29, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-3587273675-3237974979-2131186439-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 203, 115, 209, 213, 195, 147, 255, 192, 7, 83, 7, 127, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-3984653172-1380167674-707033525-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 116, 251, 128, 237, 250, 175, 67, 82, 181, 121, 36, 42, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-4154349010-984067676-209295477-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 210, 85, 158, 247, 92, 174, 167, 58, 117, 152, 121, 12, 0, 2, 0, 0], "D:(A;;CCRPWPRC;;;WD)(A;;KA;;;BA)(A;;KA;;;AO)(A;;KA;;;S-1-5-21-536441700-3718478525-2547843259-512)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 112, 0, 4, 0, 0, 0, 0, 0, 20, 0, 49, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 36, 2, 0, 0, 0, 0, 36, 0, 63, 0, 15, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 100, 115, 249, 31, 189, 122, 163, 221, 187, 0, 221, 151, 0, 2, 0, 0], "O:BAG:SYD:(A;;KR;;;WD)(A;;KA;;;BA)(A;;KA;;;SY)": [1, 0, 4, 128, 92, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 3, 0, 0, 0, 0, 0, 20, 0, 25, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 24, 0, 63, 0, 15, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 0, 0, 20, 0, 63, 0, 15, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0], "O:S-1-5-21-3984653172-1380167674-707033525-1000G:S-1-22-2-50133D:(A;;0x1f019f;;;S-1-5-21-3984653172-1380167674-707033525-1000)(A;;0x1f019f;;;S-1-22-2-50133)(A;;0x1f019f;;;WD)(A;;KA;;;SY)": [1, 0, 4, 128, 128, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 108, 0, 4, 0, 0, 0, 0, 0, 36, 0, 159, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 116, 251, 128, 237, 250, 175, 67, 82, 181, 121, 36, 42, 232, 3, 0, 0, 0, 0, 24, 0, 159, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 213, 195, 0, 0, 0, 0, 20, 0, 159, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 20, 0, 63, 0, 15, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 116, 251, 128, 237, 250, 175, 67, 82, 181, 121, 36, 42, 232, 3, 0, 0, 1, 2, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 213, 195, 0, 0], "O:S-1-5-21-536441700-3718478525-2547843259-1000G:S-1-22-2-50133D:(A;;0x1f019f;;;S-1-5-21-536441700-3718478525-2547843259-1000)(A;;0x1f019f;;;S-1-22-2-50133)(A;;0x1f019f;;;WD)(A;;KA;;;SY)": [1, 0, 4, 128, 128, 0, 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 108, 0, 4, 0, 0, 0, 0, 0, 36, 0, 159, 1, 31, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 100, 115, 249, 31, 189, 122, 163, 221, 187, 0, 221, 151, 232, 3, 0, 0, 0, 0, 24, 0, 159, 1, 31, 0, 1, 2, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 213, 195, 0, 0, 0, 0, 20, 0, 159, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 20, 0, 63, 0, 15, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 100, 115, 249, 31, 189, 122, 163, 221, 187, 0, 221, 151, 232, 3, 0, 0, 1, 2, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 213, 195, 0, 0]} \ No newline at end of file
diff --git a/libcli/security/tests/data/short-conditional-and-resource-aces-successes.json.gz b/libcli/security/tests/data/short-conditional-and-resource-aces-successes.json.gz
new file mode 100644
index 0000000..e7f8024
--- /dev/null
+++ b/libcli/security/tests/data/short-conditional-and-resource-aces-successes.json.gz
Binary files differ
diff --git a/libcli/security/tests/data/short-conditional-and-resource-aces-tx-int.json.gz b/libcli/security/tests/data/short-conditional-and-resource-aces-tx-int.json.gz
new file mode 100644
index 0000000..e1b6157
--- /dev/null
+++ b/libcli/security/tests/data/short-conditional-and-resource-aces-tx-int.json.gz
Binary files differ
diff --git a/libcli/security/tests/data/short-ordinary-acls-v2.json.gz b/libcli/security/tests/data/short-ordinary-acls-v2.json.gz
new file mode 100644
index 0000000..1f4ef20
--- /dev/null
+++ b/libcli/security/tests/data/short-ordinary-acls-v2.json.gz
Binary files differ
diff --git a/libcli/security/tests/data/short-ordinary-acls.json.gz b/libcli/security/tests/data/short-ordinary-acls.json.gz
new file mode 100644
index 0000000..8554b7c
--- /dev/null
+++ b/libcli/security/tests/data/short-ordinary-acls.json.gz
Binary files differ
diff --git a/libcli/security/tests/test_claim_conversion.c b/libcli/security/tests/test_claim_conversion.c
new file mode 100644
index 0000000..aeb172f
--- /dev/null
+++ b/libcli/security/tests/test_claim_conversion.c
@@ -0,0 +1,171 @@
+/*
+ * Unit tests for conditional ACE SDDL.
+ *
+ * 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 <setjmp.h>
+#include "cmocka.h"
+
+#include "lib/util/attr.h"
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+#include "librpc/gen_ndr/ndr_claims.h"
+
+#define debug_message(...) print_message(__VA_ARGS__)
+
+#define debug_fail(x, ...) print_message("\033[1;31m" x "\033[0m", __VA_ARGS__)
+#define debug_ok(x, ...) print_message("\033[1;32m" x "\033[0m", __VA_ARGS__)
+
+#define assert_ntstatus_equal(got, expected, comment) \
+ do { NTSTATUS __got = got, __expected = expected; \
+ if (!NT_STATUS_EQUAL(__got, __expected)) { \
+ print_message(": "#got" was %s, expected %s: %s", \
+ nt_errstr(__got), \
+ nt_errstr(__expected), comment); \
+ fail(); \
+ } \
+ } while(0)
+
+
+
+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_one_ndr_dump(void **state, const char *name)
+{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ struct CLAIMS_SET claims_set;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *out_claims = NULL;
+ uint32_t out_n_claims = 0;
+ enum ndr_err_code ndr_err;
+ char filename[200];
+ snprintf(filename, sizeof(filename),
+ "libcli/security/tests/data/ndr_dumps/%s", name);
+
+ blob = datablob_from_file(tmp_ctx, filename);
+ ndr_err = ndr_pull_struct_blob(
+ &blob, tmp_ctx, &claims_set,
+ (ndr_pull_flags_fn_t)ndr_pull_CLAIMS_SET);
+ assert_int_equal(ndr_err, NDR_ERR_SUCCESS);
+
+ status = token_claims_to_claims_v1(tmp_ctx,
+ &claims_set,
+ &out_claims,
+ &out_n_claims);
+ assert_ntstatus_equal(status, NT_STATUS_OK, "sigh\n");
+}
+
+
+
+static void test_fileb5iJt4(void **state)
+{
+ _test_one_ndr_dump(state, "fileb5iJt4");
+}
+
+static void test_fileb8cNVS(void **state)
+{
+ _test_one_ndr_dump(state, "fileb8cNVS");
+}
+
+static void test_filebI7h5H(void **state)
+{
+ _test_one_ndr_dump(state, "filebI7h5H");
+}
+
+static void test_filebNdBgt(void **state)
+{
+ _test_one_ndr_dump(state, "filebNdBgt");
+}
+
+static void test_filebOjK4H(void **state)
+{
+ _test_one_ndr_dump(state, "filebOjK4H");
+}
+
+static void test_filebzCPTH(void **state)
+{
+ _test_one_ndr_dump(state, "filebzCPTH");
+}
+
+
+
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_fileb5iJt4),
+ cmocka_unit_test(test_fileb8cNVS),
+ cmocka_unit_test(test_filebI7h5H),
+ cmocka_unit_test(test_filebNdBgt),
+ cmocka_unit_test(test_filebOjK4H),
+ cmocka_unit_test(test_filebzCPTH),
+ };
+ if (isatty(1)) {
+ /*
+ * interactive testers can set debug level
+ * -- just give it a number.
+ */
+ int debug_level = DBGLVL_WARNING;
+ if (argc > 1) {
+ debug_level = atoi(argv[1]);
+ }
+ debuglevel_set(debug_level);
+
+ } else {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/security/tests/test_run_conditional_ace.c b/libcli/security/tests/test_run_conditional_ace.c
new file mode 100644
index 0000000..dc02e33
--- /dev/null
+++ b/libcli/security/tests/test_run_conditional_ace.c
@@ -0,0 +1,730 @@
+/*
+ * Unit tests for conditional ACE SDDL.
+ *
+ * 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 <setjmp.h>
+#include "cmocka.h"
+
+#include "lib/util/attr.h"
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+#include "libcli/security/claims-conversions.h"
+
+#define debug_message(...) print_message(__VA_ARGS__)
+
+#define debug_fail(x, ...) print_message("\033[1;31m" x "\033[0m", __VA_ARGS__)
+#define debug_ok(x, ...) print_message("\033[1;32m" x "\033[0m", __VA_ARGS__)
+
+#define assert_ntstatus_equal(got, expected, comment) \
+ do { NTSTATUS __got = got, __expected = expected; \
+ if (!NT_STATUS_EQUAL(__got, __expected)) { \
+ print_message(": "#got" was %s, expected %s: %s", \
+ nt_errstr(__got), \
+ nt_errstr(__expected), comment); \
+ fail(); \
+ } \
+ } while(0)
+
+
+
+
+/*
+static void print_error_message(const char *sddl,
+ const char *message,
+ size_t message_offset)
+{
+ print_message("%s\n\033[1;33m %*c\033[0m\n", sddl,
+ (int)message_offset, '^');
+ print_message("%s\n", message);
+}
+*/
+static bool fill_token_claims(TALLOC_CTX *mem_ctx,
+ struct security_token *token,
+ const char *claim_type,
+ const char *name,
+ ...)
+{
+ va_list args;
+ va_start(args, name);
+ while (true) {
+ struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
+ const char *str = va_arg(args, const char *);
+ if (str == NULL) {
+ break;
+ }
+ claim = parse_sddl_literal_as_claim(mem_ctx,
+ name,
+ str);
+ if (claim == NULL) {
+ va_end(args);
+ debug_fail("bad claim: %s\n", str);
+ return false;
+ }
+ add_claim_to_token(mem_ctx, token, claim, claim_type);
+ }
+ va_end(args);
+ return true;
+}
+
+
+static bool fill_token_sids(TALLOC_CTX *mem_ctx,
+ struct security_token *token,
+ const char *owner,
+ ...)
+{
+ uint32_t *n = &token->num_sids;
+ struct dom_sid **list = NULL;
+ va_list args;
+ if (strcmp(owner, "device") == 0) {
+ n = &token->num_device_sids;
+ list = &token->device_sids;
+ } else if (strcmp(owner, "user") == 0) {
+ n = &token->num_sids;
+ list = &token->sids;
+ } else {
+ return false;
+ }
+
+ *n = 0;
+ va_start(args, owner);
+ while (true) {
+ struct dom_sid *sid = NULL;
+ const char *str = va_arg(args, const char *);
+ if (str == NULL) {
+ break;
+ }
+
+ sid = sddl_decode_sid(mem_ctx, &str, NULL);
+ if (sid == NULL) {
+ debug_fail("bad SID: %s\n", str);
+ va_end(args);
+ return false;
+ }
+ add_sid_to_array(mem_ctx, sid, list, n);
+ }
+ va_end(args);
+ return true;
+}
+
+
+static void test_device_claims_composite(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct security_token token = {
+ .evaluate_claims = CLAIMS_EVALUATION_ALWAYS
+ };
+ bool ok;
+ NTSTATUS status;
+ uint32_t access_granted = 0;
+ struct security_descriptor *sd = NULL;
+ const char *sddl = \
+ "D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))";
+ ok = fill_token_sids(mem_ctx, &token,
+ "user",
+ "WD", "AA", NULL);
+ assert_true(ok);
+ ok = fill_token_claims(mem_ctx, &token,
+ "device", "colour",
+ "{\"orange\", \"blue\"}",
+ NULL);
+ assert_true(ok);
+ sd = sddl_decode(mem_ctx, sddl, NULL);
+ assert_non_null(sd);
+ status = se_access_check(sd, &token, 0x10, &access_granted);
+ assert_ntstatus_equal(status, NT_STATUS_OK, "access check failed\n");
+}
+
+
+static bool fill_sd(TALLOC_CTX *mem_ctx,
+ struct security_descriptor **sd,
+ const char *sddl)
+{
+ *sd = sddl_decode(mem_ctx, sddl, NULL);
+ return *sd != NULL;
+}
+
+#define USER_SIDS(...) \
+ assert_true(fill_token_sids(mem_ctx, &token, "user", __VA_ARGS__, NULL))
+
+#define DEVICE_SIDS(...) \
+ assert_true( \
+ fill_token_sids(mem_ctx, &token, "device", __VA_ARGS__, NULL))
+
+#define USER_CLAIMS(...) \
+ assert_true( \
+ fill_token_claims(mem_ctx, &token, "user", __VA_ARGS__, NULL))
+
+#define LOCAL_CLAIMS(...) \
+ assert_true(fill_token_claims(mem_ctx, \
+ &token, \
+ "local", \
+ __VA_ARGS__, \
+ NULL))
+
+#define DEVICE_CLAIMS(...) \
+ assert_true(fill_token_claims(mem_ctx, \
+ &token, \
+ "device", \
+ __VA_ARGS__, \
+ NULL))
+
+
+#define SD(sddl) assert_true(fill_sd(mem_ctx, &sd, sddl))
+#define SD_FAIL(sddl) assert_false(fill_sd(mem_ctx, &sd, sddl))
+
+#define ALLOW_CHECK(requested) \
+ do { \
+ NTSTATUS status; \
+ uint32_t access_granted = 0; \
+ status = se_access_check(sd, \
+ &token, \
+ requested, \
+ &access_granted); \
+ assert_ntstatus_equal(status, \
+ NT_STATUS_OK, \
+ "access not granted\n"); \
+ } while (0)
+
+
+#define DENY_CHECK(requested) \
+ do { \
+ NTSTATUS status; \
+ uint32_t access_granted = 0; \
+ status = se_access_check(sd, \
+ &token, \
+ requested, \
+ &access_granted); \
+ assert_ntstatus_equal(status, \
+ NT_STATUS_ACCESS_DENIED, \
+ "not denied\n"); \
+ } while (0)
+
+
+#define INIT() \
+ TALLOC_CTX *mem_ctx = talloc_new(NULL); \
+ struct security_token token = { \
+ .evaluate_claims = CLAIMS_EVALUATION_ALWAYS \
+ }; \
+ struct security_descriptor *sd = NULL;
+
+
+
+static void test_composite_different_order(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"blue\", \"orange\"}");
+ /*
+ * Claim arrays are sets, so we assume conditional ACE ones are too.
+ */
+ ALLOW_CHECK(0x10);
+}
+
+static void test_composite_different_order_with_dupes(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\", \"orange\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\", \"orange\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_composite_different_order_with_dupes_in_composite(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\", \"orange\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_composite_different_order_with_SID_dupes(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {SID(WD), SID(AA), SID(WD)}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(AA), SID(WD)}");
+ DENY_CHECK(0x10);
+}
+
+static void test_composite_different_order_with_SID_dupes_in_composite(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {SID(WD), SID(AA), SID(WD)}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(WD)}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_composite_mixed_types(void **state)
+{
+ /*
+ * If the conditional ACE composite has mixed types, it can
+ * never equal a claim, which only has one type.
+ */
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {2, SID(WD), SID(AA), SID(WD)}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(WD)}");
+ DENY_CHECK(0x10);
+}
+
+static void test_composite_mixed_types_different_last(void **state)
+{
+ /*
+ * If the conditional ACE composite has mixed types, it can
+ * never equal a claim, which only has one type.
+ */
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {SID(WD), SID(AA), 2}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(WD)}");
+ DENY_CHECK(0x10);
+}
+
+static void test_composite_mixed_types_deny(void **state)
+{
+ /*
+ * If the conditional ACE composite has mixed types, it can
+ * never equal a claim, which only has one type.
+ */
+ INIT()
+ SD("D:(XD;;0x1f;;;AA;(@Device.colour == {2, SID(WD), SID(AA), SID(WD)}))"
+ "(D;;;;;WD)");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{SID(AA), SID(WD)}");
+ DENY_CHECK(0x10);
+}
+
+static void test_different_case(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"OraNgE\", \"BLuE\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_different_case_with_case_sensitive_flag(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"OraNgE\", \"BLuE\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ /* set the flag bit */
+ token.device_claims[0].flags = CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ DENY_CHECK(0x10);
+}
+
+
+static void test_claim_name_different_case(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.Colour == {\"orange\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_claim_name_different_case_case_flag(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.Colour == {\"orange\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ /*
+ * The CASE_SENSITIVE flag is for the values, not the names.
+ */
+ token.device_claims[0].flags = CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE;
+ ALLOW_CHECK(0x10);
+}
+
+static void test_more_values_not_equal(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour != {\"orange\", \"blue\", \"green\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_contains(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains {\"orange\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_contains_incomplete(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains {\"orange\", \"blue\", \"red\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_any_of(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of {\"orange\", \"blue\", \"red\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_any_of_match_last(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of {\"a\", \"b\", \"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_any_of_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of\"blue\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_contains_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains \"blue\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_contains_1_fail(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains \"pink\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_any_of_1_fail(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of \"pink\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+
+static void test_not_any_of_1_fail(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Any_of\"blue\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_any_of_composite_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Any_of{\"blue\"}))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_contains_1_fail(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Contains \"blue\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_contains_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Contains \"pink\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_not_any_of_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Not_Any_of \"pink\"))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_not_Not_Any_of_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(!(@Device.colour Not_Any_of \"pink\")))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_Not_Contains_1(void **state)
+{
+ INIT()
+ SD("D:(XA;;0x1f;;;AA;(! (@Device.colour Not_Contains \"blue\")))");
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_not_not_Not_Member_of(void **state)
+{
+ INIT();
+ SD("D:(XA;;0x1f;;;AA;(!(!(Not_Member_of{SID(BA)}))))");
+ USER_SIDS("WD", "AA");
+ DEVICE_SIDS("BA", "BG");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_not_not_Not_Member_of_fail(void **state)
+{
+ INIT();
+ SD("D:(XA;;0x1f;;;AA;(!(!(Not_Member_of{SID(AA)}))))");
+ USER_SIDS("WD", "AA");
+ DEVICE_SIDS("BA", "BG");
+ DENY_CHECK(0x10);
+}
+
+static void test_not_not_not_not_not_not_not_not_not_not_Not_Member_of(void **state)
+{
+ INIT();
+ SD("D:(XA;;0x1f;;;AA;(!(!(!( !(!(!( !(!(!( "
+ "Not_Member_of{SID(AA)})))))))))))");
+ USER_SIDS("WD", "AA");
+ DEVICE_SIDS("BA", "BG");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_Device_Member_of_and_Member_of(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_SIDS("BA", "BG");
+ SD("D:(XA;;0x1f;;;AA;"
+ "(Device_Member_of{SID(BA)} && Member_of{SID(WD)}))");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_Device_claim_contains_Resource_claim(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_device_claim_contains_resource_claim(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_device_claim_eq_resource_claim(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_user_claim_eq_device_claim(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ USER_CLAIMS("colour", "\"blue\"");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@User.colour == @Device.colour))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_device_claim_eq_resource_claim_2(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"orange\", \"blue\"}");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_resource_ace_multi(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "{\"blue\", \"red\"}");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\", \"red\"))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_resource_ace_multi_any_of(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Any_of @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"grue\", \"blue\", \"red\"))");
+ ALLOW_CHECK(0x10);
+}
+
+static void test_horrible_fuzz_derived_test_3(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA", "IS");
+ SD_FAIL("S:PPD:(XA;OI;0x1;;;IS;(q>))");
+}
+
+static void test_resource_ace_single(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))"
+ "S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))");
+ ALLOW_CHECK(0x10);
+}
+
+
+static void test_user_attr_any_of_missing_resource_and_user_attr(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ DEVICE_CLAIMS("colour", "\"blue\"");
+ SD("D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))");
+ DENY_CHECK(0x10);
+}
+
+static void test_user_attr_any_of_missing_resource_attr(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ USER_CLAIMS("Project", "3");
+ SD("D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))");
+ DENY_CHECK(0x10);
+}
+
+static void test_user_attr_any_of_missing_user_attr(void **state)
+{
+ INIT();
+ USER_SIDS("WD", "AA");
+ SD("D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))"
+ "S:(RA;;;;;WD;(\"Project\",TX,0,1234))");
+ DENY_CHECK(0x10);
+}
+
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_user_attr_any_of_missing_resource_and_user_attr),
+ cmocka_unit_test(test_user_attr_any_of_missing_resource_attr),
+ cmocka_unit_test(test_user_attr_any_of_missing_user_attr),
+ cmocka_unit_test(test_composite_mixed_types),
+ cmocka_unit_test(test_composite_mixed_types_different_last),
+ cmocka_unit_test(test_composite_mixed_types_deny),
+ cmocka_unit_test(test_composite_different_order_with_SID_dupes),
+ cmocka_unit_test(test_composite_different_order_with_SID_dupes_in_composite),
+ cmocka_unit_test(test_device_claim_eq_resource_claim_2),
+ cmocka_unit_test(test_not_Not_Any_of_1),
+ cmocka_unit_test(test_not_any_of_composite_1),
+ cmocka_unit_test(test_resource_ace_single),
+ cmocka_unit_test(test_horrible_fuzz_derived_test_3),
+ cmocka_unit_test(test_Device_Member_of_and_Member_of),
+ cmocka_unit_test(test_resource_ace_multi),
+ cmocka_unit_test(test_resource_ace_multi_any_of),
+ cmocka_unit_test(test_user_claim_eq_device_claim),
+ cmocka_unit_test(test_device_claim_contains_resource_claim),
+ cmocka_unit_test(test_device_claim_eq_resource_claim),
+ cmocka_unit_test(test_Device_claim_contains_Resource_claim),
+ cmocka_unit_test(test_not_Not_Contains_1),
+ cmocka_unit_test(test_not_not_Not_Member_of_fail),
+ cmocka_unit_test(test_not_not_Not_Member_of),
+ cmocka_unit_test(test_not_not_not_not_not_not_not_not_not_not_Not_Member_of),
+ cmocka_unit_test(test_not_any_of_1_fail),
+ cmocka_unit_test(test_not_any_of_1),
+ cmocka_unit_test(test_not_contains_1),
+ cmocka_unit_test(test_not_contains_1_fail),
+ cmocka_unit_test(test_any_of_1_fail),
+ cmocka_unit_test(test_any_of_1),
+ cmocka_unit_test(test_any_of),
+ cmocka_unit_test(test_any_of_match_last),
+ cmocka_unit_test(test_contains_incomplete),
+ cmocka_unit_test(test_contains),
+ cmocka_unit_test(test_contains_1),
+ cmocka_unit_test(test_contains_1_fail),
+ cmocka_unit_test(test_device_claims_composite),
+ cmocka_unit_test(test_claim_name_different_case),
+ cmocka_unit_test(test_claim_name_different_case_case_flag),
+ cmocka_unit_test(test_different_case_with_case_sensitive_flag),
+ cmocka_unit_test(test_composite_different_order),
+ cmocka_unit_test(test_different_case),
+ cmocka_unit_test(test_composite_different_order_with_dupes),
+ cmocka_unit_test(test_composite_different_order_with_dupes_in_composite),
+ cmocka_unit_test(test_more_values_not_equal),
+ };
+ if (isatty(1)) {
+ /*
+ * interactive testers can set debug level
+ * -- just give it a number.
+ */
+ int debug_level = DBGLVL_WARNING;
+ if (argc > 1) {
+ debug_level = atoi(argv[1]);
+ }
+ debuglevel_set(debug_level);
+
+ } else {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/security/tests/test_sddl_conditional_ace.c b/libcli/security/tests/test_sddl_conditional_ace.c
new file mode 100644
index 0000000..fc9281d
--- /dev/null
+++ b/libcli/security/tests/test_sddl_conditional_ace.c
@@ -0,0 +1,1003 @@
+/*
+ * Unit tests for conditional ACE SDDL.
+ *
+ * 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 <setjmp.h>
+#include "cmocka.h"
+
+#include "lib/util/attr.h"
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "libcli/security/security.h"
+#include "libcli/security/conditional_ace.h"
+#include "librpc/gen_ndr/conditional_ace.h"
+
+/*
+ * Some of the test strings break subunit, so we only print those if
+ * stdout is a terminal.
+ */
+#define debug_message(...) do { \
+ if (isatty(1)) { \
+ print_message(__VA_ARGS__); \
+ } \
+ } while(0)
+
+#define debug_fail(x, ...) debug_message("\033[1;31m" x "\033[0m", __VA_ARGS__)
+#define debug_ok(x, ...) debug_message("\033[1;32m" x "\033[0m", __VA_ARGS__)
+
+#define ACEINT64(x, b, s) CONDITIONAL_ACE_TOKEN_INT64, \
+ (x & 0xff), ((x >> 8) & 0xff), ((x >> 16) & 0xff), \
+ ((x >> 24) & 0xff), (((uint64_t)x >> 32) & 0xff), (((uint64_t)x >> 40) & 0xff), \
+ (((uint64_t)x >> 48) & 0xff), (((uint64_t)x >> 56) & 0xff), b, s
+
+
+static void print_error_message(const char *sddl,
+ const char *message,
+ size_t message_offset)
+{
+ print_message("%s\n\033[1;33m %*c\033[0m\n", sddl,
+ (int)message_offset, '^');
+ print_message("%s\n", message);
+}
+
+static void test_sddl_compile(void **state)
+{
+ /*
+ * Example codes:
+ *
+ * CONDITIONAL_ACE_LOCAL_ATTRIBUTE, 2,0,0,0, 'x',0,
+ * ^attr byte code ^ ^
+ * 32 bit little-endian length |
+ * utf-16, little endian
+ *
+ * CONDITIONAL_ACE_TOKEN_EQUAL
+ * ^ op byte code with no following data
+ */
+ static const char *sddl = "(x==41 &&(x >@device.x ) )";
+ static const uint8_t ace[] = {
+ 'a', 'r', 't', 'x',
+ CONDITIONAL_ACE_LOCAL_ATTRIBUTE, 2, 0, 0, 0, 'x', 0,
+ ACEINT64(41,
+ CONDITIONAL_ACE_INT_SIGN_NONE,
+ CONDITIONAL_ACE_INT_BASE_10),
+ CONDITIONAL_ACE_TOKEN_EQUAL,
+ CONDITIONAL_ACE_LOCAL_ATTRIBUTE, 2, 0, 0, 0, 'x', 0,
+ CONDITIONAL_ACE_DEVICE_ATTRIBUTE, 2, 0, 0, 0, 'x', 0,
+ CONDITIONAL_ACE_TOKEN_GREATER_THAN,
+ CONDITIONAL_ACE_TOKEN_AND, 0,0,0,0,
+ };
+
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ bool ok;
+ DATA_BLOB compiled;
+ size_t length;
+
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl,
+ &message,
+ &message_offset,
+ &length);
+ if (message != NULL) {
+ print_error_message(sddl, message, message_offset);
+ }
+ if (s == NULL) {
+ debug_fail("%s\n", sddl);
+ fail();
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s, &compiled);
+ assert_true(ok);
+
+ assert_true(compiled.length <= ARRAY_SIZE(ace));
+ for (i = 0; i < compiled.length; i++) {
+ assert_int_equal(compiled.data[i], ace[i]);
+ }
+}
+
+static void test_sddl_compile2(void **state)
+{
+ /* this one is from Windows, not hand-calculated */
+ static const char *sddl = "(@USER.Project Any_of 1))";
+ static const uint8_t ace[] = ("artx\xf9\x0e\x00\x00\x00P\x00r"
+ "\x00o\x00j\x00""e\x00""c\x00t\x00"
+ "\x04\x01\x00\x00\x00\x00\x00\x00"
+ "\x00\x03\x02\x88\x00");
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ bool ok;
+ DATA_BLOB compiled;
+ size_t length;
+
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl,
+ &message,
+ &message_offset,
+ &length);
+ if (message != NULL) {
+ print_error_message(sddl, message, message_offset);
+ }
+ if (s == NULL) {
+ debug_fail("%s\n", sddl);
+ fail();
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s, &compiled);
+ assert_true(ok);
+
+ assert_true(compiled.length <= ARRAY_SIZE(ace));
+ for (i = 0; i < compiled.length; i++) {
+ assert_int_equal(compiled.data[i], ace[i]);
+ }
+}
+
+static void test_full_sddl_compile(void **state)
+{
+ /*
+ * This one is from Windows, and annotated by hand.
+ *
+ * We have the bytes of a full security descriptor, in
+ * "relative" form, which is the same as the its NDR
+ * representation.
+ *
+ * *In general* we can't necessarily assert that Samba's NDR
+ * will be the same as Windows, because they could e.g. put
+ * the two ACLs in the reverse order which is also legitimate
+ * (there are hints this may vary on Windows). But in this
+ * particular case Samba and the Windows 2022 sample agree, so
+ * we can compare the bytes here.
+ *
+ * We can assert that unpacking these bytes as a security
+ * descriptor should succeed and give us exactly the same
+ * descriptor as parsing the SDDL.
+ */
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct security_descriptor sec_desc_windows = {};
+ struct security_descriptor *sec_desc_samba = NULL;
+ DATA_BLOB sd_ndr = {};
+ DATA_BLOB sd_win_push = {};
+ DATA_BLOB sd_samba_push = {};
+ bool ok;
+ enum ndr_err_code ndr_err;
+ const char *sddl = "D:(XA;;CCDCLCSWRPWP;;;MP;"\
+ "(@RESOURCE.c))S:(RA;;;;;WD;(\"colOIr\",TU,0xe,29925))";
+
+ uint8_t sd_bytes[] = {
+ 1, /* 0 version */
+ 0, /* 1 reserved */
+ 20, 128, /* 2 control */
+ 0, 0, 0, 0, /* 4 owner (null relative pointer == no owner) */
+ 0, 0, 0, 0, /* 8 group */
+ 20, 0, 0, 0,/* 12 SACL */
+ 92, 0, 0, 0,/* 16 DACL, i.e. pointer to 92 below */
+
+ /* 20 SACL (from pointer above) */
+ 4, /* 20 revision (ADS) */
+ 0, /* 21 reserved */
+ 72, 0, /* 22 size --> takes us to 92 */
+ 1, 0, /* 24 ace count */
+ 0, 0, /* 26 reserved */
+
+ /* now come SACL aces, of which there should be one */
+ 18, /* 28 ace type (SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) */
+ 0, /* 29 ace flags */
+ 64, 0, /* 30 ace size (from start of ACE, again adds to ending at 92) */
+ 0, 0, 0, 0, /* 32 mask */
+
+ /* here's the ACE SID */
+ 1, /* 36 revision */
+ 1, /* 37 sub-auth count */
+ 0, 0, 0, 0, 0, 1, /* 38 big endian ident auth */
+ 0, 0, 0, 0, /* 44 the sub-auth (so SID is S-1-1-0 (everyone), mandatory with RA ace) */
+
+ /* here starts the actual claim, at 48 */
+ 20, 0, 0, 0, /* 48 pointer to name (relative to claim, at 68) */
+ 2, 0, /* 52 value type (uint64) */
+ 0, 0, /* 54 reserved */
+ 14, 0, 0, 0, /* 56 flags (case-sensitive|deny-only|disabled-by-default -- the "0xe" in the SDDL) */
+ 1, 0, 0, 0, /* 60 value count */
+ 34, 0, 0, 0, /* 64 array of pointers, 1-long, points to 48 + 34 == 82 */
+ /* 68 utf-16 letters "colOIr\0", indicated by name pointer at 48 */
+ 'c', 0,
+ 'o', 0,
+ 'l', 0,
+ 'O', 0, /* unlike conditional ACE strings, this is nul-terminated. */
+ 'I', 0, /* where does the next thing start: */
+ 'r', 0, /* 6 letters + '\0' * 2 = 14. 68 + 14 = 82 */
+ 0, 0,
+ /* 82 is the value pointed to at 64 above (LE uint64) */
+ 229, 116, 0, 0, 0, 0, 0, 0, /* this equals 229 + 116 * 256 == 29925, as we see in the SDDL. */
+
+ /* 88 the claim has ended. the ace has NEARLY ended, but we need to round up: */
+
+ 0, 0, /* 90 two bytes of padding to get to a multiple of 4. */
+ /* The ace and SACL have ended */
+
+ /* 92 the DACL starts. */
+ 2, /* 92 version (NT) */
+ 0, /* 93 reserved */
+ 40, 0, /* 94 size */
+ 1, 0, /* 96 ace count */
+ 0, 0, /* 98 reserved */
+ /* 100 the DACL aces start */
+ 9, /* 100 ace type (SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK) */
+ 0, /* 101 flags */
+ 32, 0, /* 102 ace size (ending at 132) */
+ 63, 0, 0, 0, /* 104 mask (let's assume CCDCLCSWRPWP as in sddl, not checked, but it's the right number of bits) */
+ /* 108 the ACE sid */
+ 1, /* 108 version */
+ 1, /* 109 sub-auths */
+ 0, 0, 0, 0, 0, 16,/* 110 bigendian 16 identauth */
+ 0, 33, 0, 0, /* 116 sub-auth 1, 33 << 8 == 8448; "S-1-16-8448" == "ML_MEDIUM_PLUS" == "MP" */
+ /* 120 here starts the callback */
+ 97, 114, 116, 120, /* 120 'artx' */
+ 250, /* 124 0xfa CONDITIONAL_ACE_RESOURCE_ATTRIBUTE token */
+ 2, 0, 0, 0, /* 125 length 2 (bytes) */
+ 'c', 0, /* 129 utf-16 "c" -- NOT nul-terminated */
+ 0 /* 131 padding to bring length to a multiple of 4 (132) */
+ };
+ sd_ndr.length = 132;
+ sd_ndr.data = sd_bytes;
+
+ sec_desc_samba = sddl_decode(mem_ctx, sddl, NULL);
+ assert_non_null(sec_desc_samba);
+ ndr_err = ndr_pull_struct_blob(
+ &sd_ndr, mem_ctx, &sec_desc_windows,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+
+ /*
+ * look, we munge the DACL version byte before comparing,
+ * because Samba currently always does version 4.
+ */
+ sec_desc_windows.dacl->revision = SECURITY_ACL_REVISION_ADS;
+ sd_bytes[92] = SECURITY_ACL_REVISION_ADS;
+
+ /* push the structures back into blobs for 3-way comparisons. */
+ ndr_err = ndr_push_struct_blob(
+ &sd_win_push, mem_ctx,
+ &sec_desc_windows,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+
+ ndr_err = ndr_push_struct_blob(
+ &sd_samba_push, mem_ctx,
+ sec_desc_samba,
+ (ndr_push_flags_fn_t)ndr_push_security_descriptor);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+
+ assert_int_equal(sd_samba_push.length, sd_win_push.length);
+ assert_int_equal(sd_samba_push.length, sd_ndr.length);
+ assert_memory_equal(sd_samba_push.data,
+ sd_win_push.data,
+ sd_win_push.length);
+ assert_memory_equal(sd_win_push.data,
+ sd_ndr.data,
+ sd_ndr.length);
+
+ ok = security_descriptor_equal(sec_desc_samba, &sec_desc_windows);
+ assert_true(ok);
+ talloc_free(mem_ctx);
+}
+
+
+static void debug_conditional_ace_stderr(TALLOC_CTX *mem_ctx,
+ struct ace_condition_script *program)
+{
+ char * debug_string = debug_conditional_ace(mem_ctx, program);
+
+ if (debug_string != NULL) {
+ fputs(debug_string, stderr);
+ TALLOC_FREE(debug_string);
+ } else {
+ print_message("failed to debug!\n");
+ }
+}
+
+
+static void test_full_sddl_ra_encode(void **state)
+{
+ /*
+ * This is an example from Windows that Samba once had trouble
+ * with.
+ */
+ bool ok;
+ enum ndr_err_code ndr_err;
+ char *sddl = NULL;
+ struct dom_sid domain_sid;
+ uint8_t win_bytes[] = {
+ 0x01, 0x00, 0x14, 0x80, /* descriptor header */
+ 0x00, 0x00, 0x00, 0x00, /* NULL owner pointer */
+ 0x00, 0x00, 0x00, 0x00, /* NULL group pointer */
+ 0x14, 0x00, 0x00, 0x00, /* SACL at 0x14 (20) */
+ 0x58, 0x01, 0x00, 0x00, /* DACL at 0x158 (344) */
+ /* SACL starts here (20) */
+ 0x02, 0x00, /* rev 2, NT */
+ 0x44, 0x01, /* size 0x0144 (324) -- ends at 344 */
+ 0x01, 0x00, /* ace count */
+ 0x00, 0x00, /* reserved */
+ /* ace starts here, 28 */
+ 0x12, 0x00, /* ace type, flags: 0x12(18) is resource attribute */
+ 0x3c, 0x01, /* ACE size 0x13c == 316, from ACE start, end at 344 */
+ 0x00, 0x00, 0x00, 0x00, /*ACE mask */
+ 0x01, 0x01, /* SID S-1-<identauth>-<1 subauth>) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* -1- indent auth */
+ 0x00, 0x00, 0x00, 0x00, /* -0 -> S-1-1-0, world */
+ /* claim starts here, 48 */
+ 0x28, 0x00, 0x00, 0x00, /* pointer to name 40 (from claim start 48) = 88 */
+ 0x10, 0x00, /* type octet string */
+ 0x00, 0x00, /* empty */
+ 0x00, 0x00, 0x00, 0x00, /* zero flags */
+ 0x06, 0x00, 0x00, 0x00, /* value count */
+ /* array of 6 value pointers (at claim + 16, 64) */
+ 0xf2, 0x00, 0x00, 0x00, /* value 0xf2 = 242 from claim (48) == 290 */
+ 0xf8, 0x00, 0x00, 0x00, /* 0xf8, 248 */
+ 0x0d, 0x01, 0x00, 0x00, /* 0x10d, 269 */
+ 0x14, 0x01, 0x00, 0x00, /* 0x114, 276 */
+ 0x1a, 0x01, 0x00, 0x00, /* 0x11a, 282 */
+ 0x21, 0x01, 0x00, 0x00, /* 0x121, 289 */
+ /* here's the name, at 88 */
+ 'c', 0x00,
+ 'o', 0x00,
+ 'l', 0x00,
+ 'O', 0x00,
+ 'I', 0x00,
+ 'r', 0x00, /* the following lines are all \x16 */
+ /* 100 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ /* 150 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ /* 200 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ /* 250 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ /* 280 */
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, /* 286 */
+ 'r', 0x00,
+ 0x00, 0x00, /* name is nul-terminated */
+ /* 290, first octet string blob */
+ 0x02, 0x00, 0x00, 0x00, /* length 2 */
+ 0x00, 0x77, /* 2 blob bytes */
+ /* second blob @ 48 + 248 == 296 */
+ 0x11, 0x00, 0x00, 0x00, /* length 0x11 = 17 */
+ 0x00, 0x77, 0x77, 0x71, 0x83, 0x68, 0x96, 0x62, 0x95, 0x93,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+ /* third blob at 269 + 48 == 317 */
+ 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x77,
+ /* fourth blob, 276 + 48 == 324 */
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x77,
+ /* fifth blob, 282 + 48 == 330 */
+ 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x77,
+ /* last blob 289 + 48 == 337 */
+ 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x77,
+ /* claim ends */
+ /* 344 DACL starts */
+ 0x02, 0x00, /* rev 2 (NT) */
+ 0x28, 0x00, /* size 40, ending at 384 */
+ 0x01, 0x00, /* ace count */
+ 0x00, 0x00,
+ /* ACE starts here, 352 */
+ 0x09, 0x00, /* type 9, access allowed callback */
+ 0x20, 0x00, /* size 32 */
+ 0x3f, 0x00, 0x00, 0x00, /*mask */
+ 0x01, 0x01, /* S-1-... (1 subauth) */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, /*...-16-...*/
+ 0x00, 0x21, 0x00, 0x00, /* -5356. S-1-16-5376 */
+ 'a', 'r', 't', 'x',
+ 0xfa, /* resource attr */
+ 0x02, 0x00, 0x00, 0x00, /*name is 2 bytes long (i.e. 1 UTF-16) */
+ 'c', 0x00, /* name is "c" */
+ /* here we're at 383, but need to round to a multiple of 4 with zeros: */
+ 0x00
+ };
+ DATA_BLOB win_blob = {
+ .data = win_bytes,
+ .length = sizeof(win_bytes)
+ };
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct security_descriptor sec_desc_windows = {};
+ struct security_descriptor *sec_desc_samba = NULL;
+
+ ndr_err = ndr_pull_struct_blob(
+ &win_blob, mem_ctx, &sec_desc_windows,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+
+ string_to_sid(&domain_sid, "S-1-2-3");
+ sddl = sddl_encode(mem_ctx, &sec_desc_windows, &domain_sid);
+ assert_non_null(sddl);
+ sec_desc_samba = sddl_decode(mem_ctx, sddl, &domain_sid);
+
+ /* hack the acl revision numbers */
+ sec_desc_windows.dacl->revision = SECURITY_ACL_REVISION_ADS;
+ sec_desc_windows.sacl->revision = SECURITY_ACL_REVISION_ADS;
+ ok = security_descriptor_equal(sec_desc_samba, &sec_desc_windows);
+ assert_true(ok);
+ talloc_free(mem_ctx);
+}
+
+
+static void test_full_sddl_ra_escapes(void **state)
+{
+ /*
+ * This is the security descriptor described in
+ * test_full_sddl_ra_encode(), with SDDL.
+ */
+ enum ndr_err_code ndr_err;
+ const char *sddl = (
+ "D:(XA;;CCDCLCSWRPWP;;;MP;(@RESOURCE.c))S:(RA;;;;;WD;(\""
+ "colOIr%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016%0016"
+ "%0016%0016%0016%0016%0016%0016r\","
+ "TX,0x0,"
+ "0077,00,0077,00,0077,00,00,00,0077,00,0077,"
+ "00,0077,007777,007777,0077,007777,0077,007777,"
+ "007770,0077,00,0077,00,00,00,0077,00,0077,00,"
+ "0077,007777,007777,0077,007777,0077,007777,007777))");
+ uint8_t win_bytes[] = {
+ 0x01, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xb0, 0x02, 0x00, 0x00,
+ 0x02, 0x00, 0x9c, 0x02, 0x01, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x94, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x26, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x00, 0x00, 0xa4, 0x01,
+ 0x00, 0x00, 0xa9, 0x01, 0x00, 0x00, 0xaf, 0x01, 0x00, 0x00,
+ 0xb4, 0x01, 0x00, 0x00, 0xba, 0x01, 0x00, 0x00, 0xbf, 0x01,
+ 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, 0xc9, 0x01, 0x00, 0x00,
+ 0xcf, 0x01, 0x00, 0x00, 0xd4, 0x01, 0x00, 0x00, 0xda, 0x01,
+ 0x00, 0x00, 0xdf, 0x01, 0x00, 0x00, 0xe5, 0x01, 0x00, 0x00,
+ 0xec, 0x01, 0x00, 0x00, 0xf3, 0x01, 0x00, 0x00, 0xf9, 0x01,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00,
+ 0x0d, 0x02, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, 0x1a, 0x02,
+ 0x00, 0x00, 0x1f, 0x02, 0x00, 0x00, 0x25, 0x02, 0x00, 0x00,
+ 0x2a, 0x02, 0x00, 0x00, 0x2f, 0x02, 0x00, 0x00, 0x34, 0x02,
+ 0x00, 0x00, 0x3a, 0x02, 0x00, 0x00, 0x3f, 0x02, 0x00, 0x00,
+ 0x45, 0x02, 0x00, 0x00, 0x4a, 0x02, 0x00, 0x00, 0x50, 0x02,
+ 0x00, 0x00, 0x57, 0x02, 0x00, 0x00, 0x5e, 0x02, 0x00, 0x00,
+ 0x64, 0x02, 0x00, 0x00, 0x6b, 0x02, 0x00, 0x00, 0x71, 0x02,
+ 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00,
+ 0x6c, 0x00, 0x4f, 0x00, 0x49, 0x00, 0x72, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x77, 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x70,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x77, 0x77, 0x02, 0x00, 0x00, 0x00, 0x00, 0x77,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x02, 0x00,
+ 0x28, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x20, 0x00,
+ 0x3f, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x00, 0x21, 0x00, 0x00, 0x61, 0x72, 0x74, 0x78,
+ 0xfa, 0x02, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00};
+ DATA_BLOB win_blob = {
+ .data = win_bytes,
+ .length = sizeof(win_bytes)
+ };
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ struct security_descriptor sec_desc_windows = {};
+ struct security_descriptor *sec_desc_samba = sddl_decode(mem_ctx, sddl,
+ NULL);
+ assert_non_null(sec_desc_samba);
+ ndr_err = ndr_pull_struct_blob(
+ &win_blob, mem_ctx, &sec_desc_windows,
+ (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
+}
+
+static void test_round_trips(void **state)
+{
+ /*
+ * These expressions should parse into proper conditional
+ * ACEs, which then encode into an equivalent SDDL string,
+ * which then parses again into the same conditional ACE.
+ */
+ static const char *sddl[] = {
+ "(0>-0)",
+ "(0>+0)",
+ ("(Member_of{SID(AA)})"),
+ ("(a Contains @USER.b == @device.c)"),
+ ("(a == @user.b == @resource.c)"),
+ ("(@Device.bb <= -00624677746777766777767)"),
+ ("(@Device.bb == 0624677746777766777767)"),
+ ("(@Device.%025cɜ == 3)"),
+ ("(17pq == 3||2a==@USER.7)"),
+ ("(x==1 && x >= 2 && @User.Title == @User.shoes || "
+ "Member_of{SID(CD)} && !(Member_of_Any{ 3 }) || "
+ "Device_Member_of{SID(BA), 7, 1, 3} "
+ "|| Exists hooly)"),
+ ("(!(!(!(!(!((!(x==1))))))))"),
+ ("(@User.a == {})"),
+ ("(Member_of{})"),
+ ("(Member_of {SID(S-1-33-5), "
+ "SID(BO)} && @Device.Bitlocker)"),
+ "(@USER.ad://ext/AuthenticationSilo == \"siloname\")",
+ "(@User.Division==\"Finance\" || @User.Division ==\"Sales\")",
+ "(@User.Title == @User.Title)",
+ "(@User.Title == \"PM\")",
+ "(OctetStringType==#01020300)",
+ "(@User.Project Any_of @Resource.Project)",
+ "(@user.x==1 &&(@user.x >@user.x ) )",
+ "(x==1) ",
+ "( x Contains 3)",
+ "( x < 3)",
+ "(x Any_of 3)",
+ "( x == SID(BA))",
+ "((x) == SID(BA))",
+ "(OctetStringType==#1#2#3###))",
+ "(@user.x == 00)",
+ "(@user.x == 01)",
+ "(@user.x == -00)",
+ "(@user.x == -01)",
+ "(@user.x == 0x0)",
+ "(@user.x == 0x1)",
+ "(@user.x == -0x0)",
+ "(@user.x == -0x1)",
+ };
+ size_t i, length;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed = false;
+ bool ok;
+ for (i = 0; i < ARRAY_SIZE(sddl); i++) {
+ struct ace_condition_script *s1 = NULL;
+ struct ace_condition_script *s2 = NULL;
+ struct ace_condition_script *s3 = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ const char *resddl1 = NULL;
+ const char *resddl2 = NULL;
+ DATA_BLOB e1, e2, e3;
+ fputs("=======================\n", stderr);
+ s1 = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl[i],
+ &message,
+ &message_offset,
+ &length);
+ if (s1 == NULL) {
+ debug_fail("%s\n", sddl[i]);
+ failed = true;
+ print_error_message(sddl[i], message, message_offset);
+ continue;
+ }
+ if (false) {
+ debug_conditional_ace_stderr(mem_ctx, s1);
+ }
+ ok = conditional_ace_encode_binary(mem_ctx, s1, &e1);
+ if (! ok) {
+ failed = true;
+ debug_fail("%s could not encode\n", sddl[i]);
+ continue;
+ }
+
+ s2 = parse_conditional_ace(mem_ctx, e1);
+ if (s2 == NULL) {
+ debug_fail("%s failed to decode ace\n", sddl[i]);
+ failed = true;
+ continue;
+ }
+
+ ok = conditional_ace_encode_binary(mem_ctx, s2, &e2);
+ if (! ok) {
+ failed = true;
+ debug_fail("%s could not re-encode\n", sddl[i]);
+ continue;
+ }
+ if (data_blob_cmp(&e1, &e2) != 0) {
+ failed = true;
+ }
+
+ resddl1 = sddl_from_conditional_ace(mem_ctx, s1);
+ if (resddl1 == NULL) {
+ failed = true;
+ debug_fail("could not re-make SDDL of %s\n", sddl[i]);
+ continue;
+ }
+ resddl2 = sddl_from_conditional_ace(mem_ctx, s2);
+ if (resddl2 == NULL) {
+ failed = true;
+ debug_fail("could not re-make SDDL of %s\n", sddl[i]);
+ continue;
+ }
+ if (strcmp(resddl1, resddl2) != 0) {
+ print_message("SDDL 2: %s\n", resddl2);
+ failed = true;
+ }
+ print_message("SDDL: '%s' -> '%s'\n", sddl[i], resddl1);
+ s3 = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ resddl1,
+ &message,
+ &message_offset,
+ &length);
+ if (s3 == NULL) {
+ debug_fail("resddl: %s\n", resddl1);
+ failed = true;
+ print_error_message(resddl1, message, message_offset);
+ continue;
+ }
+ ok = conditional_ace_encode_binary(mem_ctx, s3, &e3);
+ if (! ok) {
+ failed = true;
+ debug_fail("%s could not encode\n", resddl1);
+ continue;
+ }
+ if (data_blob_cmp(&e1, &e3) != 0) {
+ debug_fail("'%s' and '%s' compiled differently\n", sddl[i], resddl1);
+ failed = true;
+ }
+ }
+ assert_false(failed);
+}
+
+static void test_a_number_of_valid_strings(void **state)
+{
+ /*
+ * These expressions should parse into proper conditional ACEs.
+ */
+ static const char *sddl[] = {
+ "(@User.TEETH == \"5\")",
+ "(x==1) ",
+ "( x Contains 3)",
+ "( x < 3)",
+ "(x Any_of 3)",
+ "( x == SID(BA))",
+ "(x ANY_Of 3)",
+ "((x) == SID(BA))",
+ "(x==1 && x >= 2)", /* logical consistency not required */
+ };
+ size_t i, length;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed = false;
+ for (i = 0; i < ARRAY_SIZE(sddl); i++) {
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl[i],
+ &message,
+ &message_offset,
+ &length);
+ if (s == NULL) {
+ debug_fail("%s\n", sddl[i]);
+ failed = true;
+ } else if (length != strlen(sddl[i])) {
+ debug_fail("%s failed to consume whole string\n",
+ sddl[i]);
+ failed = true;
+ }
+ if (message != NULL) {
+ print_error_message(sddl[i], message, message_offset);
+ } else if (s == NULL) {
+ print_message("failed without message\n");
+ }
+ }
+ assert_false(failed);
+}
+
+
+static void test_a_number_of_invalid_strings(void **state)
+{
+ /*
+ * These expressions should fail to parse.
+ */
+ static const char *sddl[] = {
+ /* '!' is only allowed before parens or @attr */
+ "(!!! !!! !!! Not_Member_of{SID(AA)}))",
+ /* overflowing numbers can't be sensibly interpreted */
+ ("(@Device.bb == 055555624677746777766777767)"),
+ ("(@Device.bb == 0x624677746777766777767)"),
+ ("(@Device.bb == 624677746777766777767)"),
+ /* insufficient arguments */
+ "(!)",
+ "(x >)",
+ "(> 3)",
+ /* keyword as local attribute name */
+ "( Member_of Contains 3)",
+ /* no parens */
+ " x < 3",
+ /* wants '==' */
+ "( x = SID(BA))",
+ /* invalid SID strings */
+ "( x == SID(ZZ))",
+ "( x == SID(S-1-))",
+ "( x == SID())",
+ /* literal on LHS */
+ "(\"x\" == \"x\")",
+ /* odd number of digits following '#' */
+ "(OctetStringType==#1#2#3##))",
+ /* empty expression */
+ "()",
+ /* relational op with with complex RHS */
+ "(@Device.bb == (@USER.x < 62))",
+ /* hex‐escapes that should be literals */
+ ("(@Device.%002e == 3)"),
+ ("(@Device.%002f == 3)"),
+ ("(@Device.%003a == 3)"),
+ /* trailing comma in composite */
+ "(Member_of{SID(AA),})",
+ /* missing comma between elements of a composite */
+ "(Member_of{SID(AA) SID(AC)})",
+ /* unexpected comma in composite */
+ "(Member_of{,})",
+ };
+ size_t i, length;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed_to_fail = false;
+ for (i = 0; i < ARRAY_SIZE(sddl); i++) {
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ sddl[i],
+ &message,
+ &message_offset,
+ &length);
+ if (s != NULL) {
+ print_message("unexpected success: ");
+ debug_fail("%s\n", sddl[i]);
+ failed_to_fail = true;
+ }
+ if (message != NULL) {
+ print_error_message(sddl[i], message, message_offset);
+ } else if (s == NULL) {
+ print_message("failed without message\n");
+ }
+ }
+ assert_false(failed_to_fail);
+}
+
+
+static void test_a_number_of_invalid_full_sddl_strings(void **state)
+{
+ /*
+ * These ones are complete SDDL sentences and should fail to parse,
+ * with specific message snippets.
+ */
+ static struct {
+ const char *sddl;
+ const char *snippet;
+ ssize_t offset;
+ } cases[] = {
+ {
+ "O:SYG:SYD:(A;;;;ZZ)(XA;OICI;CR;;;WD;(Member_of {WD}))",
+ "malformed ACE with only 4 ';'",
+ 11
+ },
+ {
+ "O:SYG:SYD:QQ(A;;;;ZZ)(XA;OICI;CR;;;WD;(Member_of {WD}))",
+ "expected '[OGDS]:' section start",
+ 10
+ }
+ };
+ size_t i;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed_to_fail = false;
+ bool message_wrong = false;
+ enum ace_condition_flags ace_condition_flags = \
+ ACE_CONDITION_FLAG_ALLOW_DEVICE;
+ struct dom_sid domain_sid;
+ string_to_sid(&domain_sid, "S-1-2-3");
+
+ for (i = 0; i < ARRAY_SIZE(cases); i++) {
+ struct security_descriptor *sd = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ sd = sddl_decode_err_msg(mem_ctx,
+ cases[i].sddl,
+ &domain_sid,
+ ace_condition_flags,
+ &message,
+ &message_offset);
+ if (sd != NULL) {
+ print_message("unexpected success: ");
+ debug_fail("%s\n", cases[i].sddl);
+ failed_to_fail = true;
+ }
+ if (cases[i].snippet != NULL) {
+ if (message != NULL) {
+ char *c = strstr(message, cases[i].snippet);
+ print_error_message(cases[i].sddl,
+ message,
+ message_offset);
+ if (c == NULL) {
+ message_wrong = true;
+ print_message("expected '%s'\n",
+ cases[i].snippet);
+ }
+ } else {
+ message_wrong = true;
+ print_error_message(cases[i].sddl,
+ "NO MESSAGE!",
+ message_offset);
+ print_message("expected '%s', got no message!\n",
+ cases[i].snippet);
+ }
+ } else {
+ print_message("no assertion about message, got '%s'\n",
+ message);
+ }
+ if (cases[i].offset >= 0) {
+ if (cases[i].offset != message_offset) {
+ message_wrong = true;
+ print_message("expected offset %zd, got %zu\n",
+ cases[i].offset,
+ message_offset);
+ }
+ } else {
+ print_message("no assertion about offset, got '%zu\n",
+ message_offset);
+ }
+ }
+ assert_false(failed_to_fail);
+ assert_false(message_wrong);
+}
+
+
+static void test_valid_strings_with_trailing_crap(void **state)
+{
+ /*
+ * These expressions should parse even though they have
+ * trailing bytes that look bad.
+ *
+ * ace_conditions_compile_sddl() will return when it has
+ * found a complete expression, and tell us how much it used.
+ */
+ static struct {
+ const char *sddl;
+ size_t length;
+ } pairs[] = {
+ {"(x==1 &&(x < 5 )) )", 18},
+ {"(x==1) &&", 7},
+ {"(x)) ", 3},
+ };
+ size_t i, length;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ bool failed = false;
+ for (i = 0; i < ARRAY_SIZE(pairs); i++) {
+ struct ace_condition_script *s = NULL;
+ const char *message = NULL;
+ size_t message_offset;
+ s = ace_conditions_compile_sddl(mem_ctx,
+ ACE_CONDITION_FLAG_ALLOW_DEVICE,
+ pairs[i].sddl,
+ &message,
+ &message_offset,
+ &length);
+
+ if (s == NULL) {
+ debug_fail("%s\n", pairs[i].sddl);
+ failed = true;
+ } else if (pairs[i].length == length) {
+ debug_ok("%s\n", pairs[i].sddl);
+ } else {
+ debug_fail("expected to consume %zu bytes, actual %zu\n",
+ pairs[i].length, length);
+ failed = true;
+ }
+ if (message != NULL) {
+ print_error_message(pairs[i].sddl, message, message_offset);
+ } else if (s == NULL) {
+ print_message("failed without message\n");
+ }
+ }
+ assert_false(failed);
+}
+
+
+int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_a_number_of_invalid_full_sddl_strings),
+ cmocka_unit_test(test_full_sddl_ra_encode),
+ cmocka_unit_test(test_full_sddl_ra_escapes),
+ cmocka_unit_test(test_full_sddl_compile),
+ cmocka_unit_test(test_round_trips),
+ cmocka_unit_test(test_a_number_of_invalid_strings),
+ cmocka_unit_test(test_a_number_of_valid_strings),
+ cmocka_unit_test(test_valid_strings_with_trailing_crap),
+ cmocka_unit_test(test_sddl_compile),
+ cmocka_unit_test(test_sddl_compile2),
+ };
+ if (!isatty(1)) {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/security/tests/windows/canonical.txt b/libcli/security/tests/windows/canonical.txt
new file mode 100644
index 0000000..edeae63
--- /dev/null
+++ b/libcli/security/tests/windows/canonical.txt
@@ -0,0 +1,19 @@
+O:S-1-5-21-1225132014-296224811-2507946102-512G:S-1-5-21-1225132014-296224811-2507946102-512D:P -> O:S-1-5-21-1225132014-296224811-2507946102-512G:S-1-5-21-1225132014-296224811-2507946102-512D:P
+D:(A;;GA;;;SY) -> D:(A;;GA;;;SY)
+D:(A;;GA;;;RU) -> D:(A;;GA;;;RU)
+D:(A;;GA;;;LG) -> D:(A;;GA;;;LG)
+D:(A;;0x401200a0;;;LG) -> D:(A;;0x401200a0;;;LG)
+D:S: -> D:S:
+D:PS: -> D:PS:
+D:(A;;GA;;;RD) -> D:(A;;GA;;;RD)
+S:(AU;SA;CR;;;WD)(AU;SA;CR;;;WD) -> S:(AU;SA;CR;;;WD)(AU;SA;CR;;;WD)
+S:(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD) -> S:(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)
+D:(A;;GA;;;S-1-3-4294967295-3-4) -> D:(A;;GA;;;S-1-3-4294967295-3-4)
+D:(A;;GA;;;S-1-5-21-1-2-3-513) -> D:(A;;GA;;;S-1-5-21-1-2-3-513)
+D:(A;;GA;;;S-1-5-21-2447931902-1787058256-3961074038-1201) -> D:(A;;GA;;;S-1-5-21-2447931902-1787058256-3961074038-1201)
+O:S-1-2-512D: -> O:S-1-2-512D:
+D:PARAI(A;;GA;;;SY) -> D:PARAI(A;;GA;;;SY)
+D:P(A;;GA;;;LG)(A;;GX;;;AA) -> D:P(A;;GA;;;LG)(A;;GX;;;AA)
+D:(A;;FA;;;WD) -> D:(A;;FA;;;WD)
+D:(A;;CCDCLCSWRPWPDTLOCR;;;WD) -> D:(A;;CCDCLCSWRPWPDTLOCR;;;WD)
+D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)
diff --git a/libcli/security/tests/windows/conditional_aces.txt.json b/libcli/security/tests/windows/conditional_aces.txt.json
new file mode 100644
index 0000000..4c8211c
--- /dev/null
+++ b/libcli/security/tests/windows/conditional_aces.txt.json
@@ -0,0 +1 @@
+{"D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.Title == \"\"))(A;OICI;GA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 144, 0, 5, 0, 0, 0, 1, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 1, 3, 20, 0, 0, 0, 0, 16, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 224, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 9, 0, 48, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 0, 0, 0, 0, 128, 0, 0, 0, 0, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(D;OICI;GA;;;BG)(D;OICI;GA;;;AN)(A;OICI;GRGWGX;;;AU)(XA;;FX;;;S-1-1-0;(@User.title == \"perambuator\"))(A;OICI;GA;;;BA)": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 164, 0, 5, 0, 0, 0, 1, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 1, 3, 20, 0, 0, 0, 0, 16, 1, 1, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, 0, 3, 20, 0, 0, 0, 0, 224, 1, 1, 0, 0, 0, 0, 0, 5, 11, 0, 0, 0, 9, 0, 68, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 116, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 22, 0, 0, 0, 112, 0, 101, 0, 114, 0, 97, 0, 109, 0, 98, 0, 117, 0, 97, 0, 116, 0, 111, 0, 114, 0, 128, 0, 0, 3, 24, 0, 0, 0, 0, 16, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0], "D:(XA;;0x1f;;;AA;(!(! (Member_of{SID(AA)}))))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 9, 0, 60, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 137, 162, 162, 0, 0, 0], "D:(XA;;0x1f;;;AA;(!(!(!(!(!(! (Member_of{SID(AA)}))))))))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 137, 162, 162, 162, 162, 162, 162, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == \"blue\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 9, 0, 60, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 16, 8, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 128, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 92, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 18, 0, 64, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 128, 0], "D:(XA;;0x1f;;;AA;(@Device.colour == {\"orange\", \"blue\"}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 92, 0, 1, 0, 0, 0, 9, 0, 84, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 80, 30, 0, 0, 0, 16, 12, 0, 0, 0, 111, 0, 114, 0, 97, 0, 110, 0, 103, 0, 101, 0, 16, 8, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 128, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 92, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 18, 0, 64, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 20, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 134, 0], "D:(XA;;0x1f;;;AA;(@Device.colour Contains @Resource.colour))S:(RA;;;;;WD;(\"colour\",TS,0,\"blue\", \"red\"))": [1, 0, 20, 128, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 104, 0, 0, 0, 2, 0, 84, 0, 1, 0, 0, 0, 18, 0, 76, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 24, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 38, 0, 0, 0, 48, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 0, 0, 98, 0, 108, 0, 117, 0, 101, 0, 0, 0, 114, 0, 101, 0, 100, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 250, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 134, 0], "D:(XA;;0x1f;;;AA;(@Device.legs == 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 8, 0, 0, 0, 108, 0, 101, 0, 103, 0, 115, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 128, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@Device.legs >= 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 251, 8, 0, 0, 0, 108, 0, 101, 0, 103, 0, 115, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 133, 0, 0, 0], "D:(XA;;0x1f;;;AA;(@User.colour == @Device.colour))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 249, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 251, 12, 0, 0, 0, 99, 0, 111, 0, 108, 0, 111, 0, 117, 0, 114, 0, 128, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(AA)} || Member_of{SID(WD)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 161, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)} && Member_of{SID(WD)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 160, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BA)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 32, 2, 0, 0, 138, 0], "D:(XA;;0x1f;;;AA;(Device_Member_of{SID(BG)} || Member_of{SID(WR)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 88, 0, 1, 0, 0, 0, 9, 0, 80, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 34, 2, 0, 0, 138, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 33, 0, 0, 0, 137, 161, 0], "D:(XA;;0x1f;;;AA;(Member_of{SID(S-1-77-88-99)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 80, 21, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 77, 88, 0, 0, 0, 99, 0, 0, 0, 137, 0], "D:(XA;;0x1f;;;AA;(a == 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 31, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 248, 2, 0, 0, 0, 97, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 128, 0], "D:(XA;;0x1ff;;;S-1-222-333;(Member_of_Any{SID(S-1-222-333)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 0], "D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-222-333)}))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 0], "D:(XA;;;;;WD;(@Device.bb == 0x7fffffffffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 255, 255, 255, 127, 3, 3, 128, 0, 0, 0], "D:(XA;;;;;WD;(@Device.bb == 0xffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 0, 0, 0, 0, 3, 3, 128, 0, 0, 0], "D:(XA;;;;;WD;(@Device.bb == 0xfffffffff))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 4, 0, 0, 0, 98, 0, 98, 0, 4, 255, 255, 255, 255, 15, 0, 0, 0, 3, 3, 128, 0, 0, 0], "D:(XA;;CC;;;AA;(@User.a == @User.b))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 97, 0, 249, 2, 0, 0, 0, 98, 0, 128, 0], "D:(XA;;CC;;;AA;(a == @User.a))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 67, 2, 0, 0, 97, 114, 116, 120, 248, 2, 0, 0, 0, 97, 0, 249, 2, 0, 0, 0, 97, 0, 128, 0], "D:(XA;;CC;;;S-1-2-3;(@User.Title != @User.Title))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 9, 0, 56, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 129, 0], "D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker && @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@Device.Bitlocker || @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B && @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 249, 2, 0, 0, 0, 67, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B || @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 249, 2, 0, 0, 0, 67, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A && @Device.B))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 48, 0, 1, 0, 0, 0, 9, 0, 40, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 160, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B && @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 249, 2, 0, 0, 0, 67, 0, 160, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.A || @Device.B || @USER.C))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 2, 0, 0, 0, 65, 0, 251, 2, 0, 0, 0, 66, 0, 161, 249, 2, 0, 0, 0, 67, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(@USER.Bitlocker || @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 0, 72, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 161, 0], "D:(XA;;FR;;;S-1-1-0;(Member_of {SID(S-1-999-777-7-7), SID(BO)} && @Device.Bitlocker))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 108, 0, 1, 0, 0, 0, 9, 0, 100, 0, 137, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 46, 0, 0, 0, 81, 20, 0, 0, 0, 1, 3, 0, 0, 0, 0, 3, 231, 9, 3, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 81, 16, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 5, 32, 0, 0, 0, 39, 2, 0, 0, 137, 251, 18, 0, 0, 0, 66, 0, 105, 0, 116, 0, 108, 0, 111, 0, 99, 0, 107, 0, 101, 0, 114, 0, 160], "D:(XA;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 250, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 136, 0], "D:(XA;;FX;;;S-1-1-0;(@User.Title == \"PM\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 60, 0, 1, 0, 0, 0, 9, 0, 52, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 128, 0, 0, 0], "D:(XA;;FX;;;S-1-1-0;(@User.Title==\"PM\" && (@User.Division==\"Finance\" || @User.Division ==\"Sales\")))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 140, 0, 1, 0, 0, 0, 9, 0, 132, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 128, 249, 16, 0, 0, 0, 68, 0, 105, 0, 118, 0, 105, 0, 115, 0, 105, 0, 111, 0, 110, 0, 16, 14, 0, 0, 0, 70, 0, 105, 0, 110, 0, 97, 0, 110, 0, 99, 0, 101, 0, 128, 249, 16, 0, 0, 0, 68, 0, 105, 0, 118, 0, 105, 0, 115, 0, 105, 0, 111, 0, 110, 0, 16, 10, 0, 0, 0, 83, 0, 97, 0, 108, 0, 101, 0, 115, 0, 128, 161, 160, 0, 0, 0], "D:(XD;;CC;;;S-1-2-3;(@User.Title == @User.Title))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 128, 0], "D:(XD;;FX;;;S-1-1-0;(@User.Project Any_of @Resource.Project))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 10, 0, 64, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 250, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 136, 0], "D:(XD;;FX;;;S-1-1-0;(@User.Title != \"PM\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 60, 0, 1, 0, 0, 0, 10, 0, 52, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 10, 0, 0, 0, 84, 0, 105, 0, 116, 0, 108, 0, 101, 0, 16, 4, 0, 0, 0, 80, 0, 77, 0, 129, 0, 0, 0], "D:(XD;;FX;;;WD;(!(@USER.Project Not_Any_of 1)))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 143, 162], "D:(XD;;FX;;;WD;(@USER.Project Any_of \"pink\"))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 68, 0, 1, 0, 0, 0, 10, 0, 60, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 16, 8, 0, 0, 0, 112, 0, 105, 0, 110, 0, 107, 0, 136, 0, 0, 0], "D:(XD;;FX;;;WD;(@USER.Project Any_of 1))": [1, 0, 4, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 64, 0, 1, 0, 0, 0, 10, 0, 56, 0, 160, 0, 18, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 14, 0, 0, 0, 80, 0, 114, 0, 111, 0, 106, 0, 101, 0, 99, 0, 116, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 136, 0], "D:AI(XA;OICI;FA;;;WD;(OctetStringType==##1#2#3##))": [1, 0, 4, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 3, 72, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 248, 30, 0, 0, 0, 79, 0, 99, 0, 116, 0, 101, 0, 116, 0, 83, 0, 116, 0, 114, 0, 105, 0, 110, 0, 103, 0, 84, 0, 121, 0, 112, 0, 101, 0, 24, 4, 0, 0, 0, 1, 2, 3, 0, 128, 0, 0, 0], "D:AI(XA;OICI;FA;;;WD;(OctetStringType==#01020300))": [1, 0, 4, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 80, 0, 1, 0, 0, 0, 9, 3, 72, 0, 255, 1, 31, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 248, 30, 0, 0, 0, 79, 0, 99, 0, 116, 0, 101, 0, 116, 0, 83, 0, 116, 0, 114, 0, 105, 0, 110, 0, 103, 0, 84, 0, 121, 0, 112, 0, 101, 0, 24, 4, 0, 0, 0, 1, 2, 3, 0, 128, 0, 0, 0], "O:S-1-1-0D:(XA;;0;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x0;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1;;;WD;(Member_of_Any{SID(AS),SID(WD)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 18, 1, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_Of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of(SID(S-1-1-0))))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 139, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-0), SID(S-1-222-333)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of_Any{SID(S-1-1-334), SID(S-1-222-333)}))": [1, 0, 4, 128, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 72, 0, 1, 0, 0, 0, 9, 0, 64, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 34, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 78, 1, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 222, 77, 1, 0, 0, 139, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(Member_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(mEMBER_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;0x1ff;;;WD;(member_of{SID(S-1-1-0)}))": [1, 0, 4, 128, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 56, 0, 1, 0, 0, 0, 9, 0, 48, 0, 255, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 80, 17, 0, 0, 0, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:S-1-1-0D:(XA;;;;;WD;(Member_Of SID(S-1-1-0)))": [1, 0, 4, 128, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 52, 0, 1, 0, 0, 0, 9, 0, 44, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 81, 12, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 137, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == \"siloname\"))": [1, 0, 4, 128, 136, 0, 0, 0, 148, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 0, 116, 0, 1, 0, 0, 0, 9, 3, 108, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 97, 114, 116, 120, 249, 54, 0, 0, 0, 97, 0, 100, 0, 58, 0, 47, 0, 47, 0, 101, 0, 120, 0, 116, 0, 47, 0, 65, 0, 117, 0, 116, 0, 104, 0, 101, 0, 110, 0, 116, 0, 105, 0, 99, 0, 97, 0, 116, 0, 105, 0, 111, 0, 110, 0, 83, 0, 105, 0, 108, 0, 111, 0, 16, 16, 0, 0, 0, 115, 0, 105, 0, 108, 0, 111, 0, 110, 0, 97, 0, 109, 0, 101, 0, 128, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 5, 18, 0, 0, 0]} \ No newline at end of file
diff --git a/libcli/security/tests/windows/non_canonical.txt b/libcli/security/tests/windows/non_canonical.txt
new file mode 100644
index 0000000..5506d9b
--- /dev/null
+++ b/libcli/security/tests/windows/non_canonical.txt
@@ -0,0 +1,50 @@
+D:(A;;CC;;;BA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;;CC;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+D:(A;;RP;;;WD)(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)(A;;RPLCLORC;;;AU)(A;;RPWPCRLCLOCCRCWDWOSW;;;BO)(A;CI;RPWPCRLCLOCCRCWDWOSDSW;;;BA)(A;;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;SY)(A;CI;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;ES)(A;CI;LC;;;RU)(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)(A;;RPRC;;;RU)(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(A;;LCRPLORC;;;ED)(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;CIIO;RPLCLORC;;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;NO)(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;SU)(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)S:(AU;SA;WDWOWP;;;WD) -> D:(A;;RP;;;WD)(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)(A;;LCRPLORC;;;AU)(A;;CCLCSWRPWPLOCRRCWDWO;;;BO)(A;CI;CCLCSWRPWPLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;CI;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;ES)(A;CI;LC;;;RU)(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)(OA;CIIO;LCRPLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)(A;;RPRC;;;RU)(OA;CIIO;LCRPLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(A;;LCRPLORC;;;ED)(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIO;LCRPLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;NO)(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;SU)(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)S:(AU;SA;WPWDWO;;;WD)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)(A;;WPRPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPCRLCLORCSDDT;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;RPLCLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;S-1-5-32-560) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPDTLOCRSDRC;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;LCRPLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77b5b886-944a-11d1-aebd-0000f80367c1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;S-1-5-32-560)
+D:(A;;RPLCLORC;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;;LCRPLORC;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+D:(A;;WPCRCCDCLCLORCWOWDSDDTSWRP;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)(A;;RPWPCRCCDCLCLORCWOWDSDSWDT;;;SY)(A;;RPCRLCLORCSDDT;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;RPLCLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPDTLOCRSDRC;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;LCRPLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77b5b886-944a-11d1-aebd-0000f80367c1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+D:(A;;;;;BO)(A;;;;;AO)(A;;;;;SY)(A;;RPCRLCLORCSDDT;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;RPLCLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU) -> D:(A;;;;;BO)(A;;;;;AO)(A;;;;;SY)(A;;LCRPDTLOCRSDRC;;;CO)(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)(A;;LCRPLORC;;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(A;;CCDC;;;PS)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)(OA;;RPWP;77b5b886-944a-11d1-aebd-0000f80367c1;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)
+D:(A;;RPLCLORC;;;AU) -> D:(A;;LCRPLORC;;;AU)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)(A;;RPLCLORC;;;PS)(OA;;CR;ab721a55-1e2f-11d0-9819-00aa0040529b;;AU)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AO)(A;;LCRPLORC;;;PS)(OA;;CR;ab721a55-1e2f-11d0-9819-00aa0040529b;;AU)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;CO) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;CO)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)S:(AU;SA;CRWP;;;WD) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)S:(AU;SA;WPCR;;;WD)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSWRP;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)(A;;RPLCLORC;;;PS)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;CR;ab721a54-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;CR;ab721a56-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)(OA;;RPWP;E45795B2-9455-11d1-AEBD-0000F80367C1;;PS)(OA;;RPWP;E45795B3-9455-11d1-AEBD-0000F80367C1;;PS)(OA;;RP;037088f8-0ae1-11d2-b422-00a0c968f939;;RD)(OA;;RP;4c164200-20c0-11d0-a768-00aa006e0529;;RD)(OA;;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;;RD)(A;;RC;;;AU)(OA;;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;;AU)(OA;;RP;77B5B886-944A-11d1-AEBD-0000F80367C1;;AU)(OA;;RP;E45795B3-9455-11d1-AEBD-0000F80367C1;;AU)(OA;;RP;e48d0154-bcf8-11d1-8702-00c04fb96050;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(OA;;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;;RD)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)(OA;;WPRP;6db69a1c-9422-11d1-aebd-0000f80367c1;;SU) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AO)(A;;LCRPLORC;;;PS)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;CR;ab721a54-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;CR;ab721a56-1e2f-11d0-9819-00aa0040529b;;PS)(OA;;RPWP;77b5b886-944a-11d1-aebd-0000f80367c1;;PS)(OA;;RPWP;e45795b2-9455-11d1-aebd-0000f80367c1;;PS)(OA;;RPWP;e45795b3-9455-11d1-aebd-0000f80367c1;;PS)(OA;;RP;037088f8-0ae1-11d2-b422-00a0c968f939;;RD)(OA;;RP;4c164200-20c0-11d0-a768-00aa006e0529;;RD)(OA;;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;;RD)(A;;RC;;;AU)(OA;;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;;AU)(OA;;RP;77b5b886-944a-11d1-aebd-0000f80367c1;;AU)(OA;;RP;e45795b3-9455-11d1-aebd-0000f80367c1;;AU)(OA;;RP;e48d0154-bcf8-11d1-8702-00c04fb96050;;AU)(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)(OA;;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;;RD)(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)(OA;;RPWP;6db69a1c-9422-11d1-aebd-0000f80367c1;;SU)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)(A;;LCRPLORC;;;ED) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)(A;;LCRPLORC;;;ED)
+D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(OA;;CCDC;bf967a86-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(A;;RPLCLORC;;;AU)(A;;LCRPLORC;;;ED)(OA;;CCDC;4828CC14-1437-45bc-9B07-AD6F015E5F28;;AO) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(OA;;CCDC;bf967a86-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)(A;;LCRPLORC;;;AU)(A;;LCRPLORC;;;ED)(OA;;CCDC;4828cc14-1437-45bc-9b07-ad6f015e5f28;;AO)
+D:(A;;RPWPCRCCDCLCLORCWOWDSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;;CCDCLCSWRPWPLOCRRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+D:(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU) -> D:(A;CI;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;LCRPLORC;;;AU)
+S:D:P -> D:PS:
+S:D: -> D:S:
+D:(A;;123456789;;;LG) -> D:(A;;0x75bcd15;;;LG)
+D:(A;;01234567;;;LG) -> D:(A;;0x53977;;;LG)
+D:(A;;16;;;LG) -> D:(A;;RP;;;LG)
+D:(A;;17;;;LG) -> D:(A;;CCRP;;;LG)
+D:(A;;0xff;;;LG) -> D:(A;;CCDCLCSWRPWPDTLO;;;LG)
+D:(A;;0xf01ff;;;LG) -> D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;LG)
+D:(A;;0xe00f0000;;;LG) -> D:(A;;SDRCWDWOGXGWGR;;;LG)
+D:ARPAI(A;;GA;;;SY) -> D:PARAI(A;;GA;;;SY)
+D:AIPAR(A;;GA;;;SY) -> D:PARAI(A;;GA;;;SY)
+D:PARP(A;;GA;;;SY) -> D:PAR(A;;GA;;;SY)
+D:PPPPPPPPPPPP(A;;GA;;;SY) -> D:P(A;;GA;;;SY)
+D:(A;;CC;;;S-1-21474836480-32-579) -> D:(A;;CC;;;S-1-0x500000000-32-579)
+D:(A;;GA;;;S-1-5000000000-30-40) -> D:(A;;GA;;;S-1-0x12A05F200-30-40)
+D:(A;;GA;;;S-1-0x2-3-4) -> D:(A;;GA;;;S-1-2-3-4)
+D:(A;;GA;;;S-1-0x20-3-4) -> D:(A;;GA;;;S-1-32-3-4)
+D:(A;;GA;;;S-1-3-0x00000002-3-4) -> D:(A;;GA;;;S-1-3-2-3-4)
+D:(A;;GA;;;S-1-3-0xffffffff-3-4) -> D:(A;;GA;;;S-1-3-4294967295-3-4)
+D:(A;;GA;;;S-1-5-21-0x1-0x2-0x3-513) -> D:(A;;GA;;;S-1-5-21-1-2-3-513)
+D:(A;;GA;;;S-1-5-21-2447931902-1787058256-3961074038-0x4b1) -> D:(A;;GA;;;S-1-5-21-2447931902-1787058256-3961074038-1201)
+O:S-1-2-0x200D: -> O:S-1-2-512D:
+O:S-1-2-0x2D:(A;;GA;;;LG) -> O:S-1-2-2D:(A;;GA;;;LG)
+D:(A;;0x00654321;;;WD)(A;;0x00abc101;;;S-1-5-21-11111111-22222222-33333333-101)(A;;0x00abc102;;;S-1-5-21-11111111-22222222-33333333-102)(A;;0x00abc103;;;S-1-5-21-11111111-22222222-33333333-103)(A;;0x00abc104;;;S-1-5-21-11111111-22222222-33333333-104)(A;;0x00abc105;;;S-1-5-21-11111111-22222222-33333333-105)(A;;0x00abc106;;;S-1-5-21-11111111-22222222-33333333-106)(A;;0x00abc107;;;S-1-5-21-11111111-22222222-33333333-107)(A;;0x00abc108;;;S-1-5-21-11111111-22222222-33333333-108)(A;;0x00abc109;;;S-1-5-21-11111111-22222222-33333333-109)(A;;0x00abc110;;;S-1-5-21-11111111-22222222-33333333-110)(A;;0x00abc111;;;S-1-5-21-11111111-22222222-33333333-111)(A;;0x00abc112;;;S-1-5-21-11111111-22222222-33333333-112)(A;;0x00abc113;;;S-1-5-21-11111111-22222222-33333333-113)(A;;0x00abc114;;;S-1-5-21-11111111-22222222-33333333-114)(A;;0x00abc115;;;S-1-5-21-11111111-22222222-33333333-115)(A;;0x00abc116;;;S-1-5-21-11111111-22222222-33333333-116)(A;;0x00abc117;;;S-1-5-21-11111111-22222222-33333333-117)(A;;0x00abc118;;;S-1-5-21-11111111-22222222-33333333-118)(A;;0x00abc119;;;S-1-5-21-11111111-22222222-33333333-119)(A;;0x00abc120;;;S-1-5-21-11111111-22222222-33333333-120)(A;;0x00abc121;;;S-1-5-21-11111111-22222222-33333333-121)(A;;0x00abc122;;;S-1-5-21-11111111-22222222-33333333-122)(A;;0x00abc123;;;S-1-5-21-11111111-22222222-33333333-123)(A;;0x00abc124;;;S-1-5-21-11111111-22222222-33333333-124)(A;;0x00abc125;;;S-1-5-21-11111111-22222222-33333333-125)(A;;0x00abc126;;;S-1-5-21-11111111-22222222-33333333-126)(A;;0x00abc127;;;S-1-5-21-11111111-22222222-33333333-127)(A;;0x00abc128;;;S-1-5-21-11111111-22222222-33333333-128)(A;;0x00abc129;;;S-1-5-21-11111111-22222222-33333333-129)(A;;0x00abc130;;;S-1-5-21-11111111-22222222-33333333-130)(A;;0x00abc131;;;S-1-5-21-11111111-22222222-33333333-131)(A;;0x00abc132;;;S-1-5-21-11111111-22222222-33333333-132)(A;;0x00abc133;;;S-1-5-21-11111111-22222222-33333333-133)(A;;0x00abc134;;;S-1-5-21-11111111-22222222-33333333-134)(A;;0x00abc135;;;S-1-5-21-11111111-22222222-33333333-135)(A;;0x00abc136;;;S-1-5-21-11111111-22222222-33333333-136)(A;;0x00abc137;;;S-1-5-21-11111111-22222222-33333333-137)(A;;0x00abc138;;;S-1-5-21-11111111-22222222-33333333-138)(A;;0x00abc139;;;S-1-5-21-11111111-22222222-33333333-139)(A;;0x00abc140;;;S-1-5-21-11111111-22222222-33333333-140)(A;;0x00abc141;;;S-1-5-21-11111111-22222222-33333333-141)(A;;0x00abc142;;;S-1-5-21-11111111-22222222-33333333-142)(A;;0x00abc143;;;S-1-5-21-11111111-22222222-33333333-143)(A;;0x00abc144;;;S-1-5-21-11111111-22222222-33333333-144)(A;;0x00abc145;;;S-1-5-21-11111111-22222222-33333333-145)(A;;0x00abc146;;;S-1-5-21-11111111-22222222-33333333-146)(A;;0x00abc147;;;S-1-5-21-11111111-22222222-33333333-147)(A;;0x00abc148;;;S-1-5-21-11111111-22222222-33333333-148)(A;;0x00abc149;;;S-1-5-21-11111111-22222222-33333333-149)(A;;0x00abc150;;;S-1-5-21-11111111-22222222-33333333-150)(A;;0x00abc151;;;S-1-5-21-11111111-22222222-33333333-151)(A;;0x00abc152;;;S-1-5-21-11111111-22222222-33333333-152)(A;;0x00abc153;;;S-1-5-21-11111111-22222222-33333333-153)(A;;0x00abc154;;;S-1-5-21-11111111-22222222-33333333-154)(A;;0x00abc155;;;S-1-5-21-11111111-22222222-33333333-155)(A;;0x00abc156;;;S-1-5-21-11111111-22222222-33333333-156)(A;;0x00abc157;;;S-1-5-21-11111111-22222222-33333333-157)(A;;0x00abc158;;;S-1-5-21-11111111-22222222-33333333-158)(A;;0x00abc159;;;S-1-5-21-11111111-22222222-33333333-159)(A;;0x00abc160;;;S-1-5-21-11111111-22222222-33333333-160)(A;;0x00abc161;;;S-1-5-21-11111111-22222222-33333333-161)(A;;0x00abc162;;;S-1-5-21-11111111-22222222-33333333-162)(A;;0x00abc163;;;S-1-5-21-11111111-22222222-33333333-163)(A;;0x00abc164;;;S-1-5-21-11111111-22222222-33333333-164)(A;;0x00abc165;;;S-1-5-21-11111111-22222222-33333333-165)(A;;0x00abc166;;;S-1-5-21-11111111-22222222-33333333-166)(A;;0x00abc167;;;S-1-5-21-11111111-22222222-33333333-167)(A;;0x00abc168;;;S-1-5-21-11111111-22222222-33333333-168)(A;;0x00abc169;;;S-1-5-21-11111111-22222222-33333333-169)(A;;0x00abc170;;;S-1-5-21-11111111-22222222-33333333-170)(A;;0x00abc171;;;S-1-5-21-11111111-22222222-33333333-171)(A;;0x00abc172;;;S-1-5-21-11111111-22222222-33333333-172)(A;;0x00abc173;;;S-1-5-21-11111111-22222222-33333333-173)(A;;0x00abc174;;;S-1-5-21-11111111-22222222-33333333-174)(A;;0x00abc175;;;S-1-5-21-11111111-22222222-33333333-175)(A;;0x00abc176;;;S-1-5-21-11111111-22222222-33333333-176)(A;;0x00abc177;;;S-1-5-21-11111111-22222222-33333333-177)(A;;0x00abc178;;;S-1-5-21-11111111-22222222-33333333-178)(A;;0x00abc179;;;S-1-5-21-11111111-22222222-33333333-179)(A;;0x00abc180;;;S-1-5-21-11111111-22222222-33333333-180)(A;;0x00abc181;;;S-1-5-21-11111111-22222222-33333333-181)(A;;0x00abc182;;;S-1-5-21-11111111-22222222-33333333-182)(A;;0x00abc183;;;S-1-5-21-11111111-22222222-33333333-183)(A;;0x00abc184;;;S-1-5-21-11111111-22222222-33333333-184)(A;;0x00abc185;;;S-1-5-21-11111111-22222222-33333333-185)(A;;0x00abc186;;;S-1-5-21-11111111-22222222-33333333-186)(A;;0x00abc187;;;S-1-5-21-11111111-22222222-33333333-187)(A;;0x00abc188;;;S-1-5-21-11111111-22222222-33333333-188)(A;;0x00abc189;;;S-1-5-21-11111111-22222222-33333333-189)(A;;0x00abc190;;;S-1-5-21-11111111-22222222-33333333-190)(A;;0x00abc191;;;S-1-5-21-11111111-22222222-33333333-191)(A;;0x00abc192;;;S-1-5-21-11111111-22222222-33333333-192)(A;;0x00abc193;;;S-1-5-21-11111111-22222222-33333333-193)(A;;0x00abc194;;;S-1-5-21-11111111-22222222-33333333-194)(A;;0x00abc195;;;S-1-5-21-11111111-22222222-33333333-195)(A;;0x00abc196;;;S-1-5-21-11111111-22222222-33333333-196)(A;;0x00abc197;;;S-1-5-21-11111111-22222222-33333333-197)(A;;0x00abc198;;;S-1-5-21-11111111-22222222-33333333-198)(A;;0x00abc199;;;S-1-5-21-11111111-22222222-33333333-199)(A;;0x00abc200;;;S-1-5-21-11111111-22222222-33333333-200)(A;;0x00abc201;;;S-1-5-21-11111111-22222222-33333333-201)(A;;0x00abc202;;;S-1-5-21-11111111-22222222-33333333-202)(A;;0x00abc203;;;S-1-5-21-11111111-22222222-33333333-203)(A;;0x00abc204;;;S-1-5-21-11111111-22222222-33333333-204)(A;;0x00abc205;;;S-1-5-21-11111111-22222222-33333333-205)(A;;0x00abc206;;;S-1-5-21-11111111-22222222-33333333-206)(A;;0x00abc207;;;S-1-5-21-11111111-22222222-33333333-207)(A;;0x00abc208;;;S-1-5-21-11111111-22222222-33333333-208)(A;;0x00abc209;;;S-1-5-21-11111111-22222222-33333333-209)(A;;0x00abc210;;;S-1-5-21-11111111-22222222-33333333-210)(A;;0x00abc211;;;S-1-5-21-11111111-22222222-33333333-211)(A;;0x00abc212;;;S-1-5-21-11111111-22222222-33333333-212)(A;;0x00abc213;;;S-1-5-21-11111111-22222222-33333333-213)(A;;0x00abc214;;;S-1-5-21-11111111-22222222-33333333-214)(A;;0x00abc215;;;S-1-5-21-11111111-22222222-33333333-215)(A;;0x00abc216;;;S-1-5-21-11111111-22222222-33333333-216)(A;;0x00abc217;;;S-1-5-21-11111111-22222222-33333333-217)(A;;0x00abc218;;;S-1-5-21-11111111-22222222-33333333-218)(A;;0x00abc219;;;S-1-5-21-11111111-22222222-33333333-219)(A;;0x00abc220;;;S-1-5-21-11111111-22222222-33333333-220)(A;;0x00abc221;;;S-1-5-21-11111111-22222222-33333333-221)(A;;0x00abc222;;;S-1-5-21-11111111-22222222-33333333-222)(A;;0x00abc223;;;S-1-5-21-11111111-22222222-33333333-223)(A;;0x00abc224;;;S-1-5-21-11111111-22222222-33333333-224)(A;;0x00abc225;;;S-1-5-21-11111111-22222222-33333333-225)(A;;0x00abc226;;;S-1-5-21-11111111-22222222-33333333-226)(A;;0x00abc227;;;S-1-5-21-11111111-22222222-33333333-227)(A;;0x00abc228;;;S-1-5-21-11111111-22222222-33333333-228)(A;;0x00abc229;;;S-1-5-21-11111111-22222222-33333333-229)(A;;0x00abc230;;;S-1-5-21-11111111-22222222-33333333-230)(A;;0x00abc231;;;S-1-5-21-11111111-22222222-33333333-231)(A;;0x00abc232;;;S-1-5-21-11111111-22222222-33333333-232)(A;;0x00abc233;;;S-1-5-21-11111111-22222222-33333333-233)(A;;0x00abc234;;;S-1-5-21-11111111-22222222-33333333-234)(A;;0x00abc235;;;S-1-5-21-11111111-22222222-33333333-235)(A;;0x00abc236;;;S-1-5-21-11111111-22222222-33333333-236)(A;;0x00abc237;;;S-1-5-21-11111111-22222222-33333333-237)(A;;0x00abc238;;;S-1-5-21-11111111-22222222-33333333-238)(A;;0x00abc239;;;S-1-5-21-11111111-22222222-33333333-239)(A;;0x00abc240;;;S-1-5-21-11111111-22222222-33333333-240)(A;;0x00abc241;;;S-1-5-21-11111111-22222222-33333333-241)(A;;0x00abc242;;;S-1-5-21-11111111-22222222-33333333-242)(A;;0x00abc243;;;S-1-5-21-11111111-22222222-33333333-243)(A;;0x00abc244;;;S-1-5-21-11111111-22222222-33333333-244)(A;;0x00abc245;;;S-1-5-21-11111111-22222222-33333333-245)(A;;0x00abc246;;;S-1-5-21-11111111-22222222-33333333-246)(A;;0x00abc247;;;S-1-5-21-11111111-22222222-33333333-247)(A;;0x00abc248;;;S-1-5-21-11111111-22222222-33333333-248)(A;;0x00abc249;;;S-1-5-21-11111111-22222222-33333333-249)(A;;0x00abc250;;;S-1-5-21-11111111-22222222-33333333-250)(A;;0x00abc251;;;S-1-5-21-11111111-22222222-33333333-251)(A;;0x00abc252;;;S-1-5-21-11111111-22222222-33333333-252)(A;;0x00abc253;;;S-1-5-21-11111111-22222222-33333333-253)(A;;0x00abc254;;;S-1-5-21-11111111-22222222-33333333-254)(A;;0x00abc255;;;S-1-5-21-11111111-22222222-33333333-255)(A;;0x00abc256;;;S-1-5-21-11111111-22222222-33333333-256)(A;;0x00abc257;;;S-1-5-21-11111111-22222222-33333333-257)(A;;0x00abc258;;;S-1-5-21-11111111-22222222-33333333-258)(A;;0x00abc259;;;S-1-5-21-11111111-22222222-33333333-259)(A;;0x00abc260;;;S-1-5-21-11111111-22222222-33333333-260)(A;;0x00abc261;;;S-1-5-21-11111111-22222222-33333333-261)(A;;0x00abc262;;;S-1-5-21-11111111-22222222-33333333-262)(A;;0x00abc263;;;S-1-5-21-11111111-22222222-33333333-263)(A;;0x00abc264;;;S-1-5-21-11111111-22222222-33333333-264)(A;;0x00abc265;;;S-1-5-21-11111111-22222222-33333333-265)(A;;0x00abc266;;;S-1-5-21-11111111-22222222-33333333-266)(A;;0x00abc267;;;S-1-5-21-11111111-22222222-33333333-267)(A;;0x00abc268;;;S-1-5-21-11111111-22222222-33333333-268)(A;;0x00abc269;;;S-1-5-21-11111111-22222222-33333333-269)(A;;0x00abc270;;;S-1-5-21-11111111-22222222-33333333-270)(A;;0x00abc271;;;S-1-5-21-11111111-22222222-33333333-271)(A;;0x00abc272;;;S-1-5-21-11111111-22222222-33333333-272)(A;;0x00abc273;;;S-1-5-21-11111111-22222222-33333333-273)(A;;0x00abc274;;;S-1-5-21-11111111-22222222-33333333-274)(A;;0x00abc275;;;S-1-5-21-11111111-22222222-33333333-275)(A;;0x00abc276;;;S-1-5-21-11111111-22222222-33333333-276)(A;;0x00abc277;;;S-1-5-21-11111111-22222222-33333333-277)(A;;0x00abc278;;;S-1-5-21-11111111-22222222-33333333-278)(A;;0x00abc279;;;S-1-5-21-11111111-22222222-33333333-279)(A;;0x00abc280;;;S-1-5-21-11111111-22222222-33333333-280)(A;;0x00abc281;;;S-1-5-21-11111111-22222222-33333333-281)(A;;0x00abc282;;;S-1-5-21-11111111-22222222-33333333-282)(A;;0x00abc283;;;S-1-5-21-11111111-22222222-33333333-283)(A;;0x00abc284;;;S-1-5-21-11111111-22222222-33333333-284)(A;;0x00abc285;;;S-1-5-21-11111111-22222222-33333333-285)(A;;0x00abc286;;;S-1-5-21-11111111-22222222-33333333-286)(A;;0x00abc287;;;S-1-5-21-11111111-22222222-33333333-287)(A;;0x00abc288;;;S-1-5-21-11111111-22222222-33333333-288)(A;;0x00abc289;;;S-1-5-21-11111111-22222222-33333333-289)(A;;0x00abc290;;;S-1-5-21-11111111-22222222-33333333-290)(A;;0x00abc291;;;S-1-5-21-11111111-22222222-33333333-291)(A;;0x00abc292;;;S-1-5-21-11111111-22222222-33333333-292)(A;;0x00abc293;;;S-1-5-21-11111111-22222222-33333333-293)(A;;0x00abc294;;;S-1-5-21-11111111-22222222-33333333-294)(A;;0x00abc295;;;S-1-5-21-11111111-22222222-33333333-295)(A;;0x00abc296;;;S-1-5-21-11111111-22222222-33333333-296)(A;;0x00abc297;;;S-1-5-21-11111111-22222222-33333333-297)(A;;0x00abc298;;;S-1-5-21-11111111-22222222-33333333-298)(A;;0x00abc299;;;S-1-5-21-11111111-22222222-33333333-299)(A;;0x00abc300;;;S-1-5-21-11111111-22222222-33333333-300)(A;;0x00abc301;;;S-1-5-21-11111111-22222222-33333333-301)(A;;0x00abc302;;;S-1-5-21-11111111-22222222-33333333-302)(A;;0x00abc303;;;S-1-5-21-11111111-22222222-33333333-303)(A;;0x00abc304;;;S-1-5-21-11111111-22222222-33333333-304)(A;;0x00abc305;;;S-1-5-21-11111111-22222222-33333333-305)(A;;0x00abc306;;;S-1-5-21-11111111-22222222-33333333-306)(A;;0x00abc307;;;S-1-5-21-11111111-22222222-33333333-307)(A;;0x00abc308;;;S-1-5-21-11111111-22222222-33333333-308)(A;;0x00abc309;;;S-1-5-21-11111111-22222222-33333333-309)(A;;0x00abc310;;;S-1-5-21-11111111-22222222-33333333-310)(A;;0x00abc311;;;S-1-5-21-11111111-22222222-33333333-311)(A;;0x00abc312;;;S-1-5-21-11111111-22222222-33333333-312)(A;;0x00abc313;;;S-1-5-21-11111111-22222222-33333333-313)(A;;0x00abc314;;;S-1-5-21-11111111-22222222-33333333-314)(A;;0x00abc315;;;S-1-5-21-11111111-22222222-33333333-315)(A;;0x00abc316;;;S-1-5-21-11111111-22222222-33333333-316)(A;;0x00abc317;;;S-1-5-21-11111111-22222222-33333333-317)(A;;0x00abc318;;;S-1-5-21-11111111-22222222-33333333-318)(A;;0x00abc319;;;S-1-5-21-11111111-22222222-33333333-319)(A;;0x00abc320;;;S-1-5-21-11111111-22222222-33333333-320)(A;;0x00abc321;;;S-1-5-21-11111111-22222222-33333333-321)(A;;0x00abc322;;;S-1-5-21-11111111-22222222-33333333-322)(A;;0x00abc323;;;S-1-5-21-11111111-22222222-33333333-323)(A;;0x00abc324;;;S-1-5-21-11111111-22222222-33333333-324)(A;;0x00abc325;;;S-1-5-21-11111111-22222222-33333333-325)(A;;0x00abc326;;;S-1-5-21-11111111-22222222-33333333-326)(A;;0x00abc327;;;S-1-5-21-11111111-22222222-33333333-327)(A;;0x00abc328;;;S-1-5-21-11111111-22222222-33333333-328)(A;;0x00abc329;;;S-1-5-21-11111111-22222222-33333333-329)(A;;0x00abc330;;;S-1-5-21-11111111-22222222-33333333-330)(A;;0x00abc331;;;S-1-5-21-11111111-22222222-33333333-331)(A;;0x00abc332;;;S-1-5-21-11111111-22222222-33333333-332)(A;;0x00abc333;;;S-1-5-21-11111111-22222222-33333333-333)(A;;0x00abc334;;;S-1-5-21-11111111-22222222-33333333-334)(A;;0x00abc335;;;S-1-5-21-11111111-22222222-33333333-335)(A;;0x00abc336;;;S-1-5-21-11111111-22222222-33333333-336)(A;;0x00abc337;;;S-1-5-21-11111111-22222222-33333333-337)(A;;0x00abc338;;;S-1-5-21-11111111-22222222-33333333-338)(A;;0x00abc339;;;S-1-5-21-11111111-22222222-33333333-339)(A;;0x00abc340;;;S-1-5-21-11111111-22222222-33333333-340)(A;;0x00abc341;;;S-1-5-21-11111111-22222222-33333333-341)(A;;0x00abc342;;;S-1-5-21-11111111-22222222-33333333-342)(A;;0x00abc343;;;S-1-5-21-11111111-22222222-33333333-343)(A;;0x00abc344;;;S-1-5-21-11111111-22222222-33333333-344)(A;;0x00abc345;;;S-1-5-21-11111111-22222222-33333333-345)(A;;0x00abc346;;;S-1-5-21-11111111-22222222-33333333-346)(A;;0x00abc347;;;S-1-5-21-11111111-22222222-33333333-347)(A;;0x00abc348;;;S-1-5-21-11111111-22222222-33333333-348)(A;;0x00abc349;;;S-1-5-21-11111111-22222222-33333333-349)(A;;0x00abc350;;;S-1-5-21-11111111-22222222-33333333-350)(A;;0x00abc351;;;S-1-5-21-11111111-22222222-33333333-351)(A;;0x00abc352;;;S-1-5-21-11111111-22222222-33333333-352)(A;;0x00abc353;;;S-1-5-21-11111111-22222222-33333333-353)(A;;0x00abc354;;;S-1-5-21-11111111-22222222-33333333-354)(A;;0x00abc355;;;S-1-5-21-11111111-22222222-33333333-355)(A;;0x00abc356;;;S-1-5-21-11111111-22222222-33333333-356)(A;;0x00abc357;;;S-1-5-21-11111111-22222222-33333333-357)(A;;0x00abc358;;;S-1-5-21-11111111-22222222-33333333-358)(A;;0x00abc359;;;S-1-5-21-11111111-22222222-33333333-359)(A;;0x00abc360;;;S-1-5-21-11111111-22222222-33333333-360)(A;;0x00abc361;;;S-1-5-21-11111111-22222222-33333333-361)(A;;0x00abc362;;;S-1-5-21-11111111-22222222-33333333-362)(A;;0x00abc363;;;S-1-5-21-11111111-22222222-33333333-363)(A;;0x00abc364;;;S-1-5-21-11111111-22222222-33333333-364)(A;;0x00abc365;;;S-1-5-21-11111111-22222222-33333333-365)(A;;0x00abc366;;;S-1-5-21-11111111-22222222-33333333-366)(A;;0x00abc367;;;S-1-5-21-11111111-22222222-33333333-367)(A;;0x00abc368;;;S-1-5-21-11111111-22222222-33333333-368)(A;;0x00abc369;;;S-1-5-21-11111111-22222222-33333333-369)(A;;0x00abc370;;;S-1-5-21-11111111-22222222-33333333-370)(A;;0x00abc371;;;S-1-5-21-11111111-22222222-33333333-371)(A;;0x00abc372;;;S-1-5-21-11111111-22222222-33333333-372)(A;;0x00abc373;;;S-1-5-21-11111111-22222222-33333333-373)(A;;0x00abc374;;;S-1-5-21-11111111-22222222-33333333-374)(A;;0x00abc375;;;S-1-5-21-11111111-22222222-33333333-375)(A;;0x00abc376;;;S-1-5-21-11111111-22222222-33333333-376)(A;;0x00abc377;;;S-1-5-21-11111111-22222222-33333333-377)(A;;0x00abc378;;;S-1-5-21-11111111-22222222-33333333-378)(A;;0x00abc379;;;S-1-5-21-11111111-22222222-33333333-379)(A;;0x00abc380;;;S-1-5-21-11111111-22222222-33333333-380)(A;;0x00abc381;;;S-1-5-21-11111111-22222222-33333333-381)(A;;0x00abc382;;;S-1-5-21-11111111-22222222-33333333-382)(A;;0x00abc383;;;S-1-5-21-11111111-22222222-33333333-383)(A;;0x00abc384;;;S-1-5-21-11111111-22222222-33333333-384)(A;;0x00abc385;;;S-1-5-21-11111111-22222222-33333333-385)(A;;0x00abc386;;;S-1-5-21-11111111-22222222-33333333-386)(A;;0x00abc387;;;S-1-5-21-11111111-22222222-33333333-387)(A;;0x00abc388;;;S-1-5-21-11111111-22222222-33333333-388)(A;;0x00abc389;;;S-1-5-21-11111111-22222222-33333333-389)(A;;0x00abc390;;;S-1-5-21-11111111-22222222-33333333-390)(A;;0x00abc391;;;S-1-5-21-11111111-22222222-33333333-391)(A;;0x00abc392;;;S-1-5-21-11111111-22222222-33333333-392)(A;;0x00abc393;;;S-1-5-21-11111111-22222222-33333333-393)(A;;0x00abc394;;;S-1-5-21-11111111-22222222-33333333-394)(A;;0x00abc395;;;S-1-5-21-11111111-22222222-33333333-395)(A;;0x00abc396;;;S-1-5-21-11111111-22222222-33333333-396)(A;;0x00abc397;;;S-1-5-21-11111111-22222222-33333333-397)(A;;0x00abc398;;;S-1-5-21-11111111-22222222-33333333-398)(A;;0x00abc399;;;S-1-5-21-11111111-22222222-33333333-399)(A;;0x00abc400;;;S-1-5-21-11111111-22222222-33333333-400)(A;;0x00abc401;;;S-1-5-21-11111111-22222222-33333333-401)(A;;0x00abc402;;;S-1-5-21-11111111-22222222-33333333-402)(A;;0x00abc403;;;S-1-5-21-11111111-22222222-33333333-403)(A;;0x00abc404;;;S-1-5-21-11111111-22222222-33333333-404)(A;;0x00abc405;;;S-1-5-21-11111111-22222222-33333333-405)(A;;0x00abc406;;;S-1-5-21-11111111-22222222-33333333-406)(A;;0x00abc407;;;S-1-5-21-11111111-22222222-33333333-407)(A;;0x00abc408;;;S-1-5-21-11111111-22222222-33333333-408)(A;;0x00abc409;;;S-1-5-21-11111111-22222222-33333333-409)(A;;0x00abc410;;;S-1-5-21-11111111-22222222-33333333-410)(A;;0x00abc411;;;S-1-5-21-11111111-22222222-33333333-411)(A;;0x00abc412;;;S-1-5-21-11111111-22222222-33333333-412)(A;;0x00abc413;;;S-1-5-21-11111111-22222222-33333333-413)(A;;0x00abc414;;;S-1-5-21-11111111-22222222-33333333-414)(A;;0x00abc415;;;S-1-5-21-11111111-22222222-33333333-415)(A;;0x00abc416;;;S-1-5-21-11111111-22222222-33333333-416)(A;;0x00abc417;;;S-1-5-21-11111111-22222222-33333333-417)(A;;0x00abc418;;;S-1-5-21-11111111-22222222-33333333-418)(A;;0x00abc419;;;S-1-5-21-11111111-22222222-33333333-419)(A;;0x00abc420;;;S-1-5-21-11111111-22222222-33333333-420)(A;;0x00abc421;;;S-1-5-21-11111111-22222222-33333333-421)(A;;0x00abc422;;;S-1-5-21-11111111-22222222-33333333-422)(A;;0x00abc423;;;S-1-5-21-11111111-22222222-33333333-423)(A;;0x00abc424;;;S-1-5-21-11111111-22222222-33333333-424)(A;;0x00abc425;;;S-1-5-21-11111111-22222222-33333333-425)(A;;0x00abc426;;;S-1-5-21-11111111-22222222-33333333-426)(A;;0x00abc427;;;S-1-5-21-11111111-22222222-33333333-427)(A;;0x00abc428;;;S-1-5-21-11111111-22222222-33333333-428)(A;;0x00abc429;;;S-1-5-21-11111111-22222222-33333333-429)(A;;0x00abc430;;;S-1-5-21-11111111-22222222-33333333-430)(A;;0x00abc431;;;S-1-5-21-11111111-22222222-33333333-431)(A;;0x00abc432;;;S-1-5-21-11111111-22222222-33333333-432)(A;;0x00abc433;;;S-1-5-21-11111111-22222222-33333333-433)(A;;0x00abc434;;;S-1-5-21-11111111-22222222-33333333-434)(A;;0x00abc435;;;S-1-5-21-11111111-22222222-33333333-435)(A;;0x00abc436;;;S-1-5-21-11111111-22222222-33333333-436)(A;;0x00abc437;;;S-1-5-21-11111111-22222222-33333333-437)(A;;0x00abc438;;;S-1-5-21-11111111-22222222-33333333-438)(A;;0x00abc439;;;S-1-5-21-11111111-22222222-33333333-439)(A;;0x00abc440;;;S-1-5-21-11111111-22222222-33333333-440)(A;;0x00abc441;;;S-1-5-21-11111111-22222222-33333333-441)(A;;0x00abc442;;;S-1-5-21-11111111-22222222-33333333-442)(A;;0x00abc443;;;S-1-5-21-11111111-22222222-33333333-443)(A;;0x00abc444;;;S-1-5-21-11111111-22222222-33333333-444)(A;;0x00abc445;;;S-1-5-21-11111111-22222222-33333333-445)(A;;0x00abc446;;;S-1-5-21-11111111-22222222-33333333-446)(A;;0x00abc447;;;S-1-5-21-11111111-22222222-33333333-447)(A;;0x00abc448;;;S-1-5-21-11111111-22222222-33333333-448)(A;;0x00abc449;;;S-1-5-21-11111111-22222222-33333333-449)(A;;0x00abc450;;;S-1-5-21-11111111-22222222-33333333-450)(A;;0x00abc451;;;S-1-5-21-11111111-22222222-33333333-451)(A;;0x00abc452;;;S-1-5-21-11111111-22222222-33333333-452)(A;;0x00abc453;;;S-1-5-21-11111111-22222222-33333333-453)(A;;0x00abc454;;;S-1-5-21-11111111-22222222-33333333-454)(A;;0x00abc455;;;S-1-5-21-11111111-22222222-33333333-455)(A;;0x00abc456;;;S-1-5-21-11111111-22222222-33333333-456)(A;;0x00abc457;;;S-1-5-21-11111111-22222222-33333333-457)(A;;0x00abc458;;;S-1-5-21-11111111-22222222-33333333-458)(A;;0x00abc459;;;S-1-5-21-11111111-22222222-33333333-459)(A;;0x00abc460;;;S-1-5-21-11111111-22222222-33333333-460)(A;;0x00abc461;;;S-1-5-21-11111111-22222222-33333333-461)(A;;0x00abc462;;;S-1-5-21-11111111-22222222-33333333-462)(A;;0x00abc463;;;S-1-5-21-11111111-22222222-33333333-463)(A;;0x00abc464;;;S-1-5-21-11111111-22222222-33333333-464)(A;;0x00abc465;;;S-1-5-21-11111111-22222222-33333333-465)(A;;0x00abc466;;;S-1-5-21-11111111-22222222-33333333-466)(A;;0x00abc467;;;S-1-5-21-11111111-22222222-33333333-467)(A;;0x00abc468;;;S-1-5-21-11111111-22222222-33333333-468)(A;;0x00abc469;;;S-1-5-21-11111111-22222222-33333333-469)(A;;0x00abc470;;;S-1-5-21-11111111-22222222-33333333-470)(A;;0x00abc471;;;S-1-5-21-11111111-22222222-33333333-471)(A;;0x00abc472;;;S-1-5-21-11111111-22222222-33333333-472)(A;;0x00abc473;;;S-1-5-21-11111111-22222222-33333333-473)(A;;0x00abc474;;;S-1-5-21-11111111-22222222-33333333-474)(A;;0x00abc475;;;S-1-5-21-11111111-22222222-33333333-475)(A;;0x00abc476;;;S-1-5-21-11111111-22222222-33333333-476)(A;;0x00abc477;;;S-1-5-21-11111111-22222222-33333333-477)(A;;0x00abc478;;;S-1-5-21-11111111-22222222-33333333-478)(A;;0x00abc479;;;S-1-5-21-11111111-22222222-33333333-479)(A;;0x00abc480;;;S-1-5-21-11111111-22222222-33333333-480)(A;;0x00abc481;;;S-1-5-21-11111111-22222222-33333333-481)(A;;0x00abc482;;;S-1-5-21-11111111-22222222-33333333-482)(A;;0x00abc483;;;S-1-5-21-11111111-22222222-33333333-483)(A;;0x00abc484;;;S-1-5-21-11111111-22222222-33333333-484)(A;;0x00abc485;;;S-1-5-21-11111111-22222222-33333333-485)(A;;0x00abc486;;;S-1-5-21-11111111-22222222-33333333-486)(A;;0x00abc487;;;S-1-5-21-11111111-22222222-33333333-487)(A;;0x00abc488;;;S-1-5-21-11111111-22222222-33333333-488)(A;;0x00abc489;;;S-1-5-21-11111111-22222222-33333333-489)(A;;0x00abc490;;;S-1-5-21-11111111-22222222-33333333-490)(A;;0x00abc491;;;S-1-5-21-11111111-22222222-33333333-491)(A;;0x00abc492;;;S-1-5-21-11111111-22222222-33333333-492)(A;;0x00abc493;;;S-1-5-21-11111111-22222222-33333333-493)(A;;0x00abc494;;;S-1-5-21-11111111-22222222-33333333-494)(A;;0x00abc495;;;S-1-5-21-11111111-22222222-33333333-495)(A;;0x00abc496;;;S-1-5-21-11111111-22222222-33333333-496)(A;;0x00abc497;;;S-1-5-21-11111111-22222222-33333333-497)(A;;0x00abc498;;;S-1-5-21-11111111-22222222-33333333-498)(A;;0x00abc499;;;S-1-5-21-11111111-22222222-33333333-499)(A;;0x00abc500;;;S-1-5-21-11111111-22222222-33333333-500)(A;;0x00abc501;;;S-1-5-21-11111111-22222222-33333333-501)(A;;0x00abc502;;;S-1-5-21-11111111-22222222-33333333-502)(A;;0x00abc503;;;S-1-5-21-11111111-22222222-33333333-503)(A;;0x00abc504;;;S-1-5-21-11111111-22222222-33333333-504)(A;;0x00abc505;;;S-1-5-21-11111111-22222222-33333333-505)(A;;0x00abc506;;;S-1-5-21-11111111-22222222-33333333-506)(A;;0x00abc507;;;S-1-5-21-11111111-22222222-33333333-507)(A;;0x00abc508;;;S-1-5-21-11111111-22222222-33333333-508)(A;;0x00abc509;;;S-1-5-21-11111111-22222222-33333333-509)(A;;0x00abc510;;;S-1-5-21-11111111-22222222-33333333-510)(A;;0x00abc511;;;S-1-5-21-11111111-22222222-33333333-511)(A;;0x00abc512;;;S-1-5-21-11111111-22222222-33333333-512)(A;;0x00abc513;;;S-1-5-21-11111111-22222222-33333333-513)(A;;0x00abc514;;;S-1-5-21-11111111-22222222-33333333-514)(A;;0x00abc515;;;S-1-5-21-11111111-22222222-33333333-515)(A;;0x00abc516;;;S-1-5-21-11111111-22222222-33333333-516)(A;;0x00abc517;;;S-1-5-21-11111111-22222222-33333333-517)(A;;0x00abc518;;;S-1-5-21-11111111-22222222-33333333-518)(A;;0x00abc519;;;S-1-5-21-11111111-22222222-33333333-519)(A;;0x00abc520;;;S-1-5-21-11111111-22222222-33333333-520)(A;;0x00abc521;;;S-1-5-21-11111111-22222222-33333333-521)(A;;0x00abc522;;;S-1-5-21-11111111-22222222-33333333-522)(A;;0x00abc523;;;S-1-5-21-11111111-22222222-33333333-523)(A;;0x00abc524;;;S-1-5-21-11111111-22222222-33333333-524)(A;;0x00abc525;;;S-1-5-21-11111111-22222222-33333333-525)(A;;0x00abc526;;;S-1-5-21-11111111-22222222-33333333-526)(A;;0x00abc527;;;S-1-5-21-11111111-22222222-33333333-527)(A;;0x00abc528;;;S-1-5-21-11111111-22222222-33333333-528)(A;;0x00abc529;;;S-1-5-21-11111111-22222222-33333333-529)(A;;0x00abc530;;;S-1-5-21-11111111-22222222-33333333-530)(A;;0x00abc531;;;S-1-5-21-11111111-22222222-33333333-531)(A;;0x00abc532;;;S-1-5-21-11111111-22222222-33333333-532)(A;;0x00abc533;;;S-1-5-21-11111111-22222222-33333333-533)(A;;0x00abc534;;;S-1-5-21-11111111-22222222-33333333-534)(A;;0x00abc535;;;S-1-5-21-11111111-22222222-33333333-535)(A;;0x00abc536;;;S-1-5-21-11111111-22222222-33333333-536)(A;;0x00abc537;;;S-1-5-21-11111111-22222222-33333333-537)(A;;0x00abc538;;;S-1-5-21-11111111-22222222-33333333-538)(A;;0x00abc539;;;S-1-5-21-11111111-22222222-33333333-539)(A;;0x00abc540;;;S-1-5-21-11111111-22222222-33333333-540)(A;;0x00abc541;;;S-1-5-21-11111111-22222222-33333333-541)(A;;0x00abc542;;;S-1-5-21-11111111-22222222-33333333-542)(A;;0x00abc543;;;S-1-5-21-11111111-22222222-33333333-543)(A;;0x00abc544;;;S-1-5-21-11111111-22222222-33333333-544)(A;;0x00abc545;;;S-1-5-21-11111111-22222222-33333333-545)(A;;0x00abc546;;;S-1-5-21-11111111-22222222-33333333-546)(A;;0x00abc547;;;S-1-5-21-11111111-22222222-33333333-547)(A;;0x00abc548;;;S-1-5-21-11111111-22222222-33333333-548)(A;;0x00abc549;;;S-1-5-21-11111111-22222222-33333333-549)(A;;0x00abc550;;;S-1-5-21-11111111-22222222-33333333-550)(A;;0x00abc551;;;S-1-5-21-11111111-22222222-33333333-551)(A;;0x00abc552;;;S-1-5-21-11111111-22222222-33333333-552)(A;;0x00abc553;;;S-1-5-21-11111111-22222222-33333333-553)(A;;0x00abc554;;;S-1-5-21-11111111-22222222-33333333-554)(A;;0x00abc555;;;S-1-5-21-11111111-22222222-33333333-555)(A;;0x00abc556;;;S-1-5-21-11111111-22222222-33333333-556)(A;;0x00abc557;;;S-1-5-21-11111111-22222222-33333333-557)(A;;0x00abc558;;;S-1-5-21-11111111-22222222-33333333-558)(A;;0x00abc559;;;S-1-5-21-11111111-22222222-33333333-559)(A;;0x00abc560;;;S-1-5-21-11111111-22222222-33333333-560)(A;;0x00abc561;;;S-1-5-21-11111111-22222222-33333333-561)(A;;0x00abc562;;;S-1-5-21-11111111-22222222-33333333-562)(A;;0x00abc563;;;S-1-5-21-11111111-22222222-33333333-563)(A;;0x00abc564;;;S-1-5-21-11111111-22222222-33333333-564)(A;;0x00abc565;;;S-1-5-21-11111111-22222222-33333333-565)(A;;0x00abc566;;;S-1-5-21-11111111-22222222-33333333-566)(A;;0x00abc567;;;S-1-5-21-11111111-22222222-33333333-567)(A;;0x00abc568;;;S-1-5-21-11111111-22222222-33333333-568)(A;;0x00abc569;;;S-1-5-21-11111111-22222222-33333333-569)(A;;0x00abc570;;;S-1-5-21-11111111-22222222-33333333-570)(A;;0x00abc571;;;S-1-5-21-11111111-22222222-33333333-571)(A;;0x00abc572;;;S-1-5-21-11111111-22222222-33333333-572)(A;;0x00abc573;;;S-1-5-21-11111111-22222222-33333333-573)(A;;0x00abc574;;;S-1-5-21-11111111-22222222-33333333-574)(A;;0x00abc575;;;S-1-5-21-11111111-22222222-33333333-575)(A;;0x00abc576;;;S-1-5-21-11111111-22222222-33333333-576)(A;;0x00abc577;;;S-1-5-21-11111111-22222222-33333333-577)(A;;0x00abc578;;;S-1-5-21-11111111-22222222-33333333-578)(A;;0x00abc579;;;S-1-5-21-11111111-22222222-33333333-579)(A;;0x00abc580;;;S-1-5-21-11111111-22222222-33333333-580)(A;;0x00abc581;;;S-1-5-21-11111111-22222222-33333333-581)(A;;0x00abc582;;;S-1-5-21-11111111-22222222-33333333-582)(A;;0x00abc583;;;S-1-5-21-11111111-22222222-33333333-583)(A;;0x00abc584;;;S-1-5-21-11111111-22222222-33333333-584)(A;;0x00abc585;;;S-1-5-21-11111111-22222222-33333333-585)(A;;0x00abc586;;;S-1-5-21-11111111-22222222-33333333-586)(A;;0x00abc587;;;S-1-5-21-11111111-22222222-33333333-587)(A;;0x00abc588;;;S-1-5-21-11111111-22222222-33333333-588)(A;;0x00abc589;;;S-1-5-21-11111111-22222222-33333333-589)(A;;0x00abc590;;;S-1-5-21-11111111-22222222-33333333-590)(A;;0x00abc591;;;S-1-5-21-11111111-22222222-33333333-591)(A;;0x00abc592;;;S-1-5-21-11111111-22222222-33333333-592)(A;;0x00abc593;;;S-1-5-21-11111111-22222222-33333333-593)(A;;0x00abc594;;;S-1-5-21-11111111-22222222-33333333-594)(A;;0x00abc595;;;S-1-5-21-11111111-22222222-33333333-595)(A;;0x00abc596;;;S-1-5-21-11111111-22222222-33333333-596)(A;;0x00abc597;;;S-1-5-21-11111111-22222222-33333333-597)(A;;0x00abc598;;;S-1-5-21-11111111-22222222-33333333-598)(A;;0x00abc599;;;S-1-5-21-11111111-22222222-33333333-599)(A;;0x00abc600;;;S-1-5-21-11111111-22222222-33333333-600) -> D:(A;;0x654321;;;WD)(A;;0xabc101;;;S-1-5-21-11111111-22222222-33333333-101)(A;;0xabc102;;;S-1-5-21-11111111-22222222-33333333-102)(A;;0xabc103;;;S-1-5-21-11111111-22222222-33333333-103)(A;;0xabc104;;;S-1-5-21-11111111-22222222-33333333-104)(A;;0xabc105;;;S-1-5-21-11111111-22222222-33333333-105)(A;;0xabc106;;;S-1-5-21-11111111-22222222-33333333-106)(A;;0xabc107;;;S-1-5-21-11111111-22222222-33333333-107)(A;;0xabc108;;;S-1-5-21-11111111-22222222-33333333-108)(A;;0xabc109;;;S-1-5-21-11111111-22222222-33333333-109)(A;;0xabc110;;;S-1-5-21-11111111-22222222-33333333-110)(A;;0xabc111;;;S-1-5-21-11111111-22222222-33333333-111)(A;;0xabc112;;;S-1-5-21-11111111-22222222-33333333-112)(A;;0xabc113;;;S-1-5-21-11111111-22222222-33333333-113)(A;;0xabc114;;;S-1-5-21-11111111-22222222-33333333-114)(A;;0xabc115;;;S-1-5-21-11111111-22222222-33333333-115)(A;;0xabc116;;;S-1-5-21-11111111-22222222-33333333-116)(A;;0xabc117;;;S-1-5-21-11111111-22222222-33333333-117)(A;;0xabc118;;;S-1-5-21-11111111-22222222-33333333-118)(A;;0xabc119;;;S-1-5-21-11111111-22222222-33333333-119)(A;;0xabc120;;;S-1-5-21-11111111-22222222-33333333-120)(A;;0xabc121;;;S-1-5-21-11111111-22222222-33333333-121)(A;;0xabc122;;;S-1-5-21-11111111-22222222-33333333-122)(A;;0xabc123;;;S-1-5-21-11111111-22222222-33333333-123)(A;;0xabc124;;;S-1-5-21-11111111-22222222-33333333-124)(A;;0xabc125;;;S-1-5-21-11111111-22222222-33333333-125)(A;;0xabc126;;;S-1-5-21-11111111-22222222-33333333-126)(A;;0xabc127;;;S-1-5-21-11111111-22222222-33333333-127)(A;;0xabc128;;;S-1-5-21-11111111-22222222-33333333-128)(A;;0xabc129;;;S-1-5-21-11111111-22222222-33333333-129)(A;;0xabc130;;;S-1-5-21-11111111-22222222-33333333-130)(A;;0xabc131;;;S-1-5-21-11111111-22222222-33333333-131)(A;;0xabc132;;;S-1-5-21-11111111-22222222-33333333-132)(A;;0xabc133;;;S-1-5-21-11111111-22222222-33333333-133)(A;;0xabc134;;;S-1-5-21-11111111-22222222-33333333-134)(A;;0xabc135;;;S-1-5-21-11111111-22222222-33333333-135)(A;;0xabc136;;;S-1-5-21-11111111-22222222-33333333-136)(A;;0xabc137;;;S-1-5-21-11111111-22222222-33333333-137)(A;;0xabc138;;;S-1-5-21-11111111-22222222-33333333-138)(A;;0xabc139;;;S-1-5-21-11111111-22222222-33333333-139)(A;;0xabc140;;;S-1-5-21-11111111-22222222-33333333-140)(A;;0xabc141;;;S-1-5-21-11111111-22222222-33333333-141)(A;;0xabc142;;;S-1-5-21-11111111-22222222-33333333-142)(A;;0xabc143;;;S-1-5-21-11111111-22222222-33333333-143)(A;;0xabc144;;;S-1-5-21-11111111-22222222-33333333-144)(A;;0xabc145;;;S-1-5-21-11111111-22222222-33333333-145)(A;;0xabc146;;;S-1-5-21-11111111-22222222-33333333-146)(A;;0xabc147;;;S-1-5-21-11111111-22222222-33333333-147)(A;;0xabc148;;;S-1-5-21-11111111-22222222-33333333-148)(A;;0xabc149;;;S-1-5-21-11111111-22222222-33333333-149)(A;;0xabc150;;;S-1-5-21-11111111-22222222-33333333-150)(A;;0xabc151;;;S-1-5-21-11111111-22222222-33333333-151)(A;;0xabc152;;;S-1-5-21-11111111-22222222-33333333-152)(A;;0xabc153;;;S-1-5-21-11111111-22222222-33333333-153)(A;;0xabc154;;;S-1-5-21-11111111-22222222-33333333-154)(A;;0xabc155;;;S-1-5-21-11111111-22222222-33333333-155)(A;;0xabc156;;;S-1-5-21-11111111-22222222-33333333-156)(A;;0xabc157;;;S-1-5-21-11111111-22222222-33333333-157)(A;;0xabc158;;;S-1-5-21-11111111-22222222-33333333-158)(A;;0xabc159;;;S-1-5-21-11111111-22222222-33333333-159)(A;;0xabc160;;;S-1-5-21-11111111-22222222-33333333-160)(A;;0xabc161;;;S-1-5-21-11111111-22222222-33333333-161)(A;;0xabc162;;;S-1-5-21-11111111-22222222-33333333-162)(A;;0xabc163;;;S-1-5-21-11111111-22222222-33333333-163)(A;;0xabc164;;;S-1-5-21-11111111-22222222-33333333-164)(A;;0xabc165;;;S-1-5-21-11111111-22222222-33333333-165)(A;;0xabc166;;;S-1-5-21-11111111-22222222-33333333-166)(A;;0xabc167;;;S-1-5-21-11111111-22222222-33333333-167)(A;;0xabc168;;;S-1-5-21-11111111-22222222-33333333-168)(A;;0xabc169;;;S-1-5-21-11111111-22222222-33333333-169)(A;;0xabc170;;;S-1-5-21-11111111-22222222-33333333-170)(A;;0xabc171;;;S-1-5-21-11111111-22222222-33333333-171)(A;;0xabc172;;;S-1-5-21-11111111-22222222-33333333-172)(A;;0xabc173;;;S-1-5-21-11111111-22222222-33333333-173)(A;;0xabc174;;;S-1-5-21-11111111-22222222-33333333-174)(A;;0xabc175;;;S-1-5-21-11111111-22222222-33333333-175)(A;;0xabc176;;;S-1-5-21-11111111-22222222-33333333-176)(A;;0xabc177;;;S-1-5-21-11111111-22222222-33333333-177)(A;;0xabc178;;;S-1-5-21-11111111-22222222-33333333-178)(A;;0xabc179;;;S-1-5-21-11111111-22222222-33333333-179)(A;;0xabc180;;;S-1-5-21-11111111-22222222-33333333-180)(A;;0xabc181;;;S-1-5-21-11111111-22222222-33333333-181)(A;;0xabc182;;;S-1-5-21-11111111-22222222-33333333-182)(A;;0xabc183;;;S-1-5-21-11111111-22222222-33333333-183)(A;;0xabc184;;;S-1-5-21-11111111-22222222-33333333-184)(A;;0xabc185;;;S-1-5-21-11111111-22222222-33333333-185)(A;;0xabc186;;;S-1-5-21-11111111-22222222-33333333-186)(A;;0xabc187;;;S-1-5-21-11111111-22222222-33333333-187)(A;;0xabc188;;;S-1-5-21-11111111-22222222-33333333-188)(A;;0xabc189;;;S-1-5-21-11111111-22222222-33333333-189)(A;;0xabc190;;;S-1-5-21-11111111-22222222-33333333-190)(A;;0xabc191;;;S-1-5-21-11111111-22222222-33333333-191)(A;;0xabc192;;;S-1-5-21-11111111-22222222-33333333-192)(A;;0xabc193;;;S-1-5-21-11111111-22222222-33333333-193)(A;;0xabc194;;;S-1-5-21-11111111-22222222-33333333-194)(A;;0xabc195;;;S-1-5-21-11111111-22222222-33333333-195)(A;;0xabc196;;;S-1-5-21-11111111-22222222-33333333-196)(A;;0xabc197;;;S-1-5-21-11111111-22222222-33333333-197)(A;;0xabc198;;;S-1-5-21-11111111-22222222-33333333-198)(A;;0xabc199;;;S-1-5-21-11111111-22222222-33333333-199)(A;;0xabc200;;;S-1-5-21-11111111-22222222-33333333-200)(A;;0xabc201;;;S-1-5-21-11111111-22222222-33333333-201)(A;;0xabc202;;;S-1-5-21-11111111-22222222-33333333-202)(A;;0xabc203;;;S-1-5-21-11111111-22222222-33333333-203)(A;;0xabc204;;;S-1-5-21-11111111-22222222-33333333-204)(A;;0xabc205;;;S-1-5-21-11111111-22222222-33333333-205)(A;;0xabc206;;;S-1-5-21-11111111-22222222-33333333-206)(A;;0xabc207;;;S-1-5-21-11111111-22222222-33333333-207)(A;;0xabc208;;;S-1-5-21-11111111-22222222-33333333-208)(A;;0xabc209;;;S-1-5-21-11111111-22222222-33333333-209)(A;;0xabc210;;;S-1-5-21-11111111-22222222-33333333-210)(A;;0xabc211;;;S-1-5-21-11111111-22222222-33333333-211)(A;;0xabc212;;;S-1-5-21-11111111-22222222-33333333-212)(A;;0xabc213;;;S-1-5-21-11111111-22222222-33333333-213)(A;;0xabc214;;;S-1-5-21-11111111-22222222-33333333-214)(A;;0xabc215;;;S-1-5-21-11111111-22222222-33333333-215)(A;;0xabc216;;;S-1-5-21-11111111-22222222-33333333-216)(A;;0xabc217;;;S-1-5-21-11111111-22222222-33333333-217)(A;;0xabc218;;;S-1-5-21-11111111-22222222-33333333-218)(A;;0xabc219;;;S-1-5-21-11111111-22222222-33333333-219)(A;;0xabc220;;;S-1-5-21-11111111-22222222-33333333-220)(A;;0xabc221;;;S-1-5-21-11111111-22222222-33333333-221)(A;;0xabc222;;;S-1-5-21-11111111-22222222-33333333-222)(A;;0xabc223;;;S-1-5-21-11111111-22222222-33333333-223)(A;;0xabc224;;;S-1-5-21-11111111-22222222-33333333-224)(A;;0xabc225;;;S-1-5-21-11111111-22222222-33333333-225)(A;;0xabc226;;;S-1-5-21-11111111-22222222-33333333-226)(A;;0xabc227;;;S-1-5-21-11111111-22222222-33333333-227)(A;;0xabc228;;;S-1-5-21-11111111-22222222-33333333-228)(A;;0xabc229;;;S-1-5-21-11111111-22222222-33333333-229)(A;;0xabc230;;;S-1-5-21-11111111-22222222-33333333-230)(A;;0xabc231;;;S-1-5-21-11111111-22222222-33333333-231)(A;;0xabc232;;;S-1-5-21-11111111-22222222-33333333-232)(A;;0xabc233;;;S-1-5-21-11111111-22222222-33333333-233)(A;;0xabc234;;;S-1-5-21-11111111-22222222-33333333-234)(A;;0xabc235;;;S-1-5-21-11111111-22222222-33333333-235)(A;;0xabc236;;;S-1-5-21-11111111-22222222-33333333-236)(A;;0xabc237;;;S-1-5-21-11111111-22222222-33333333-237)(A;;0xabc238;;;S-1-5-21-11111111-22222222-33333333-238)(A;;0xabc239;;;S-1-5-21-11111111-22222222-33333333-239)(A;;0xabc240;;;S-1-5-21-11111111-22222222-33333333-240)(A;;0xabc241;;;S-1-5-21-11111111-22222222-33333333-241)(A;;0xabc242;;;S-1-5-21-11111111-22222222-33333333-242)(A;;0xabc243;;;S-1-5-21-11111111-22222222-33333333-243)(A;;0xabc244;;;S-1-5-21-11111111-22222222-33333333-244)(A;;0xabc245;;;S-1-5-21-11111111-22222222-33333333-245)(A;;0xabc246;;;S-1-5-21-11111111-22222222-33333333-246)(A;;0xabc247;;;S-1-5-21-11111111-22222222-33333333-247)(A;;0xabc248;;;S-1-5-21-11111111-22222222-33333333-248)(A;;0xabc249;;;S-1-5-21-11111111-22222222-33333333-249)(A;;0xabc250;;;S-1-5-21-11111111-22222222-33333333-250)(A;;0xabc251;;;S-1-5-21-11111111-22222222-33333333-251)(A;;0xabc252;;;S-1-5-21-11111111-22222222-33333333-252)(A;;0xabc253;;;S-1-5-21-11111111-22222222-33333333-253)(A;;0xabc254;;;S-1-5-21-11111111-22222222-33333333-254)(A;;0xabc255;;;S-1-5-21-11111111-22222222-33333333-255)(A;;0xabc256;;;S-1-5-21-11111111-22222222-33333333-256)(A;;0xabc257;;;S-1-5-21-11111111-22222222-33333333-257)(A;;0xabc258;;;S-1-5-21-11111111-22222222-33333333-258)(A;;0xabc259;;;S-1-5-21-11111111-22222222-33333333-259)(A;;0xabc260;;;S-1-5-21-11111111-22222222-33333333-260)(A;;0xabc261;;;S-1-5-21-11111111-22222222-33333333-261)(A;;0xabc262;;;S-1-5-21-11111111-22222222-33333333-262)(A;;0xabc263;;;S-1-5-21-11111111-22222222-33333333-263)(A;;0xabc264;;;S-1-5-21-11111111-22222222-33333333-264)(A;;0xabc265;;;S-1-5-21-11111111-22222222-33333333-265)(A;;0xabc266;;;S-1-5-21-11111111-22222222-33333333-266)(A;;0xabc267;;;S-1-5-21-11111111-22222222-33333333-267)(A;;0xabc268;;;S-1-5-21-11111111-22222222-33333333-268)(A;;0xabc269;;;S-1-5-21-11111111-22222222-33333333-269)(A;;0xabc270;;;S-1-5-21-11111111-22222222-33333333-270)(A;;0xabc271;;;S-1-5-21-11111111-22222222-33333333-271)(A;;0xabc272;;;S-1-5-21-11111111-22222222-33333333-272)(A;;0xabc273;;;S-1-5-21-11111111-22222222-33333333-273)(A;;0xabc274;;;S-1-5-21-11111111-22222222-33333333-274)(A;;0xabc275;;;S-1-5-21-11111111-22222222-33333333-275)(A;;0xabc276;;;S-1-5-21-11111111-22222222-33333333-276)(A;;0xabc277;;;S-1-5-21-11111111-22222222-33333333-277)(A;;0xabc278;;;S-1-5-21-11111111-22222222-33333333-278)(A;;0xabc279;;;S-1-5-21-11111111-22222222-33333333-279)(A;;0xabc280;;;S-1-5-21-11111111-22222222-33333333-280)(A;;0xabc281;;;S-1-5-21-11111111-22222222-33333333-281)(A;;0xabc282;;;S-1-5-21-11111111-22222222-33333333-282)(A;;0xabc283;;;S-1-5-21-11111111-22222222-33333333-283)(A;;0xabc284;;;S-1-5-21-11111111-22222222-33333333-284)(A;;0xabc285;;;S-1-5-21-11111111-22222222-33333333-285)(A;;0xabc286;;;S-1-5-21-11111111-22222222-33333333-286)(A;;0xabc287;;;S-1-5-21-11111111-22222222-33333333-287)(A;;0xabc288;;;S-1-5-21-11111111-22222222-33333333-288)(A;;0xabc289;;;S-1-5-21-11111111-22222222-33333333-289)(A;;0xabc290;;;S-1-5-21-11111111-22222222-33333333-290)(A;;0xabc291;;;S-1-5-21-11111111-22222222-33333333-291)(A;;0xabc292;;;S-1-5-21-11111111-22222222-33333333-292)(A;;0xabc293;;;S-1-5-21-11111111-22222222-33333333-293)(A;;0xabc294;;;S-1-5-21-11111111-22222222-33333333-294)(A;;0xabc295;;;S-1-5-21-11111111-22222222-33333333-295)(A;;0xabc296;;;S-1-5-21-11111111-22222222-33333333-296)(A;;0xabc297;;;S-1-5-21-11111111-22222222-33333333-297)(A;;0xabc298;;;S-1-5-21-11111111-22222222-33333333-298)(A;;0xabc299;;;S-1-5-21-11111111-22222222-33333333-299)(A;;0xabc300;;;S-1-5-21-11111111-22222222-33333333-300)(A;;0xabc301;;;S-1-5-21-11111111-22222222-33333333-301)(A;;0xabc302;;;S-1-5-21-11111111-22222222-33333333-302)(A;;0xabc303;;;S-1-5-21-11111111-22222222-33333333-303)(A;;0xabc304;;;S-1-5-21-11111111-22222222-33333333-304)(A;;0xabc305;;;S-1-5-21-11111111-22222222-33333333-305)(A;;0xabc306;;;S-1-5-21-11111111-22222222-33333333-306)(A;;0xabc307;;;S-1-5-21-11111111-22222222-33333333-307)(A;;0xabc308;;;S-1-5-21-11111111-22222222-33333333-308)(A;;0xabc309;;;S-1-5-21-11111111-22222222-33333333-309)(A;;0xabc310;;;S-1-5-21-11111111-22222222-33333333-310)(A;;0xabc311;;;S-1-5-21-11111111-22222222-33333333-311)(A;;0xabc312;;;S-1-5-21-11111111-22222222-33333333-312)(A;;0xabc313;;;S-1-5-21-11111111-22222222-33333333-313)(A;;0xabc314;;;S-1-5-21-11111111-22222222-33333333-314)(A;;0xabc315;;;S-1-5-21-11111111-22222222-33333333-315)(A;;0xabc316;;;S-1-5-21-11111111-22222222-33333333-316)(A;;0xabc317;;;S-1-5-21-11111111-22222222-33333333-317)(A;;0xabc318;;;S-1-5-21-11111111-22222222-33333333-318)(A;;0xabc319;;;S-1-5-21-11111111-22222222-33333333-319)(A;;0xabc320;;;S-1-5-21-11111111-22222222-33333333-320)(A;;0xabc321;;;S-1-5-21-11111111-22222222-33333333-321)(A;;0xabc322;;;S-1-5-21-11111111-22222222-33333333-322)(A;;0xabc323;;;S-1-5-21-11111111-22222222-33333333-323)(A;;0xabc324;;;S-1-5-21-11111111-22222222-33333333-324)(A;;0xabc325;;;S-1-5-21-11111111-22222222-33333333-325)(A;;0xabc326;;;S-1-5-21-11111111-22222222-33333333-326)(A;;0xabc327;;;S-1-5-21-11111111-22222222-33333333-327)(A;;0xabc328;;;S-1-5-21-11111111-22222222-33333333-328)(A;;0xabc329;;;S-1-5-21-11111111-22222222-33333333-329)(A;;0xabc330;;;S-1-5-21-11111111-22222222-33333333-330)(A;;0xabc331;;;S-1-5-21-11111111-22222222-33333333-331)(A;;0xabc332;;;S-1-5-21-11111111-22222222-33333333-332)(A;;0xabc333;;;S-1-5-21-11111111-22222222-33333333-333)(A;;0xabc334;;;S-1-5-21-11111111-22222222-33333333-334)(A;;0xabc335;;;S-1-5-21-11111111-22222222-33333333-335)(A;;0xabc336;;;S-1-5-21-11111111-22222222-33333333-336)(A;;0xabc337;;;S-1-5-21-11111111-22222222-33333333-337)(A;;0xabc338;;;S-1-5-21-11111111-22222222-33333333-338)(A;;0xabc339;;;S-1-5-21-11111111-22222222-33333333-339)(A;;0xabc340;;;S-1-5-21-11111111-22222222-33333333-340)(A;;0xabc341;;;S-1-5-21-11111111-22222222-33333333-341)(A;;0xabc342;;;S-1-5-21-11111111-22222222-33333333-342)(A;;0xabc343;;;S-1-5-21-11111111-22222222-33333333-343)(A;;0xabc344;;;S-1-5-21-11111111-22222222-33333333-344)(A;;0xabc345;;;S-1-5-21-11111111-22222222-33333333-345)(A;;0xabc346;;;S-1-5-21-11111111-22222222-33333333-346)(A;;0xabc347;;;S-1-5-21-11111111-22222222-33333333-347)(A;;0xabc348;;;S-1-5-21-11111111-22222222-33333333-348)(A;;0xabc349;;;S-1-5-21-11111111-22222222-33333333-349)(A;;0xabc350;;;S-1-5-21-11111111-22222222-33333333-350)(A;;0xabc351;;;S-1-5-21-11111111-22222222-33333333-351)(A;;0xabc352;;;S-1-5-21-11111111-22222222-33333333-352)(A;;0xabc353;;;S-1-5-21-11111111-22222222-33333333-353)(A;;0xabc354;;;S-1-5-21-11111111-22222222-33333333-354)(A;;0xabc355;;;S-1-5-21-11111111-22222222-33333333-355)(A;;0xabc356;;;S-1-5-21-11111111-22222222-33333333-356)(A;;0xabc357;;;S-1-5-21-11111111-22222222-33333333-357)(A;;0xabc358;;;S-1-5-21-11111111-22222222-33333333-358)(A;;0xabc359;;;S-1-5-21-11111111-22222222-33333333-359)(A;;0xabc360;;;S-1-5-21-11111111-22222222-33333333-360)(A;;0xabc361;;;S-1-5-21-11111111-22222222-33333333-361)(A;;0xabc362;;;S-1-5-21-11111111-22222222-33333333-362)(A;;0xabc363;;;S-1-5-21-11111111-22222222-33333333-363)(A;;0xabc364;;;S-1-5-21-11111111-22222222-33333333-364)(A;;0xabc365;;;S-1-5-21-11111111-22222222-33333333-365)(A;;0xabc366;;;S-1-5-21-11111111-22222222-33333333-366)(A;;0xabc367;;;S-1-5-21-11111111-22222222-33333333-367)(A;;0xabc368;;;S-1-5-21-11111111-22222222-33333333-368)(A;;0xabc369;;;S-1-5-21-11111111-22222222-33333333-369)(A;;0xabc370;;;S-1-5-21-11111111-22222222-33333333-370)(A;;0xabc371;;;S-1-5-21-11111111-22222222-33333333-371)(A;;0xabc372;;;S-1-5-21-11111111-22222222-33333333-372)(A;;0xabc373;;;S-1-5-21-11111111-22222222-33333333-373)(A;;0xabc374;;;S-1-5-21-11111111-22222222-33333333-374)(A;;0xabc375;;;S-1-5-21-11111111-22222222-33333333-375)(A;;0xabc376;;;S-1-5-21-11111111-22222222-33333333-376)(A;;0xabc377;;;S-1-5-21-11111111-22222222-33333333-377)(A;;0xabc378;;;S-1-5-21-11111111-22222222-33333333-378)(A;;0xabc379;;;S-1-5-21-11111111-22222222-33333333-379)(A;;0xabc380;;;S-1-5-21-11111111-22222222-33333333-380)(A;;0xabc381;;;S-1-5-21-11111111-22222222-33333333-381)(A;;0xabc382;;;S-1-5-21-11111111-22222222-33333333-382)(A;;0xabc383;;;S-1-5-21-11111111-22222222-33333333-383)(A;;0xabc384;;;S-1-5-21-11111111-22222222-33333333-384)(A;;0xabc385;;;S-1-5-21-11111111-22222222-33333333-385)(A;;0xabc386;;;S-1-5-21-11111111-22222222-33333333-386)(A;;0xabc387;;;S-1-5-21-11111111-22222222-33333333-387)(A;;0xabc388;;;S-1-5-21-11111111-22222222-33333333-388)(A;;0xabc389;;;S-1-5-21-11111111-22222222-33333333-389)(A;;0xabc390;;;S-1-5-21-11111111-22222222-33333333-390)(A;;0xabc391;;;S-1-5-21-11111111-22222222-33333333-391)(A;;0xabc392;;;S-1-5-21-11111111-22222222-33333333-392)(A;;0xabc393;;;S-1-5-21-11111111-22222222-33333333-393)(A;;0xabc394;;;S-1-5-21-11111111-22222222-33333333-394)(A;;0xabc395;;;S-1-5-21-11111111-22222222-33333333-395)(A;;0xabc396;;;S-1-5-21-11111111-22222222-33333333-396)(A;;0xabc397;;;S-1-5-21-11111111-22222222-33333333-397)(A;;0xabc398;;;S-1-5-21-11111111-22222222-33333333-398)(A;;0xabc399;;;S-1-5-21-11111111-22222222-33333333-399)(A;;0xabc400;;;S-1-5-21-11111111-22222222-33333333-400)(A;;0xabc401;;;S-1-5-21-11111111-22222222-33333333-401)(A;;0xabc402;;;S-1-5-21-11111111-22222222-33333333-402)(A;;0xabc403;;;S-1-5-21-11111111-22222222-33333333-403)(A;;0xabc404;;;S-1-5-21-11111111-22222222-33333333-404)(A;;0xabc405;;;S-1-5-21-11111111-22222222-33333333-405)(A;;0xabc406;;;S-1-5-21-11111111-22222222-33333333-406)(A;;0xabc407;;;S-1-5-21-11111111-22222222-33333333-407)(A;;0xabc408;;;S-1-5-21-11111111-22222222-33333333-408)(A;;0xabc409;;;S-1-5-21-11111111-22222222-33333333-409)(A;;0xabc410;;;S-1-5-21-11111111-22222222-33333333-410)(A;;0xabc411;;;S-1-5-21-11111111-22222222-33333333-411)(A;;0xabc412;;;S-1-5-21-11111111-22222222-33333333-412)(A;;0xabc413;;;S-1-5-21-11111111-22222222-33333333-413)(A;;0xabc414;;;S-1-5-21-11111111-22222222-33333333-414)(A;;0xabc415;;;S-1-5-21-11111111-22222222-33333333-415)(A;;0xabc416;;;S-1-5-21-11111111-22222222-33333333-416)(A;;0xabc417;;;S-1-5-21-11111111-22222222-33333333-417)(A;;0xabc418;;;S-1-5-21-11111111-22222222-33333333-418)(A;;0xabc419;;;S-1-5-21-11111111-22222222-33333333-419)(A;;0xabc420;;;S-1-5-21-11111111-22222222-33333333-420)(A;;0xabc421;;;S-1-5-21-11111111-22222222-33333333-421)(A;;0xabc422;;;S-1-5-21-11111111-22222222-33333333-422)(A;;0xabc423;;;S-1-5-21-11111111-22222222-33333333-423)(A;;0xabc424;;;S-1-5-21-11111111-22222222-33333333-424)(A;;0xabc425;;;S-1-5-21-11111111-22222222-33333333-425)(A;;0xabc426;;;S-1-5-21-11111111-22222222-33333333-426)(A;;0xabc427;;;S-1-5-21-11111111-22222222-33333333-427)(A;;0xabc428;;;S-1-5-21-11111111-22222222-33333333-428)(A;;0xabc429;;;S-1-5-21-11111111-22222222-33333333-429)(A;;0xabc430;;;S-1-5-21-11111111-22222222-33333333-430)(A;;0xabc431;;;S-1-5-21-11111111-22222222-33333333-431)(A;;0xabc432;;;S-1-5-21-11111111-22222222-33333333-432)(A;;0xabc433;;;S-1-5-21-11111111-22222222-33333333-433)(A;;0xabc434;;;S-1-5-21-11111111-22222222-33333333-434)(A;;0xabc435;;;S-1-5-21-11111111-22222222-33333333-435)(A;;0xabc436;;;S-1-5-21-11111111-22222222-33333333-436)(A;;0xabc437;;;S-1-5-21-11111111-22222222-33333333-437)(A;;0xabc438;;;S-1-5-21-11111111-22222222-33333333-438)(A;;0xabc439;;;S-1-5-21-11111111-22222222-33333333-439)(A;;0xabc440;;;S-1-5-21-11111111-22222222-33333333-440)(A;;0xabc441;;;S-1-5-21-11111111-22222222-33333333-441)(A;;0xabc442;;;S-1-5-21-11111111-22222222-33333333-442)(A;;0xabc443;;;S-1-5-21-11111111-22222222-33333333-443)(A;;0xabc444;;;S-1-5-21-11111111-22222222-33333333-444)(A;;0xabc445;;;S-1-5-21-11111111-22222222-33333333-445)(A;;0xabc446;;;S-1-5-21-11111111-22222222-33333333-446)(A;;0xabc447;;;S-1-5-21-11111111-22222222-33333333-447)(A;;0xabc448;;;S-1-5-21-11111111-22222222-33333333-448)(A;;0xabc449;;;S-1-5-21-11111111-22222222-33333333-449)(A;;0xabc450;;;S-1-5-21-11111111-22222222-33333333-450)(A;;0xabc451;;;S-1-5-21-11111111-22222222-33333333-451)(A;;0xabc452;;;S-1-5-21-11111111-22222222-33333333-452)(A;;0xabc453;;;S-1-5-21-11111111-22222222-33333333-453)(A;;0xabc454;;;S-1-5-21-11111111-22222222-33333333-454)(A;;0xabc455;;;S-1-5-21-11111111-22222222-33333333-455)(A;;0xabc456;;;S-1-5-21-11111111-22222222-33333333-456)(A;;0xabc457;;;S-1-5-21-11111111-22222222-33333333-457)(A;;0xabc458;;;S-1-5-21-11111111-22222222-33333333-458)(A;;0xabc459;;;S-1-5-21-11111111-22222222-33333333-459)(A;;0xabc460;;;S-1-5-21-11111111-22222222-33333333-460)(A;;0xabc461;;;S-1-5-21-11111111-22222222-33333333-461)(A;;0xabc462;;;S-1-5-21-11111111-22222222-33333333-462)(A;;0xabc463;;;S-1-5-21-11111111-22222222-33333333-463)(A;;0xabc464;;;S-1-5-21-11111111-22222222-33333333-464)(A;;0xabc465;;;S-1-5-21-11111111-22222222-33333333-465)(A;;0xabc466;;;S-1-5-21-11111111-22222222-33333333-466)(A;;0xabc467;;;S-1-5-21-11111111-22222222-33333333-467)(A;;0xabc468;;;S-1-5-21-11111111-22222222-33333333-468)(A;;0xabc469;;;S-1-5-21-11111111-22222222-33333333-469)(A;;0xabc470;;;S-1-5-21-11111111-22222222-33333333-470)(A;;0xabc471;;;S-1-5-21-11111111-22222222-33333333-471)(A;;0xabc472;;;S-1-5-21-11111111-22222222-33333333-472)(A;;0xabc473;;;S-1-5-21-11111111-22222222-33333333-473)(A;;0xabc474;;;S-1-5-21-11111111-22222222-33333333-474)(A;;0xabc475;;;S-1-5-21-11111111-22222222-33333333-475)(A;;0xabc476;;;S-1-5-21-11111111-22222222-33333333-476)(A;;0xabc477;;;S-1-5-21-11111111-22222222-33333333-477)(A;;0xabc478;;;S-1-5-21-11111111-22222222-33333333-478)(A;;0xabc479;;;S-1-5-21-11111111-22222222-33333333-479)(A;;0xabc480;;;S-1-5-21-11111111-22222222-33333333-480)(A;;0xabc481;;;S-1-5-21-11111111-22222222-33333333-481)(A;;0xabc482;;;S-1-5-21-11111111-22222222-33333333-482)(A;;0xabc483;;;S-1-5-21-11111111-22222222-33333333-483)(A;;0xabc484;;;S-1-5-21-11111111-22222222-33333333-484)(A;;0xabc485;;;S-1-5-21-11111111-22222222-33333333-485)(A;;0xabc486;;;S-1-5-21-11111111-22222222-33333333-486)(A;;0xabc487;;;S-1-5-21-11111111-22222222-33333333-487)(A;;0xabc488;;;S-1-5-21-11111111-22222222-33333333-488)(A;;0xabc489;;;S-1-5-21-11111111-22222222-33333333-489)(A;;0xabc490;;;S-1-5-21-11111111-22222222-33333333-490)(A;;0xabc491;;;S-1-5-21-11111111-22222222-33333333-491)(A;;0xabc492;;;S-1-5-21-11111111-22222222-33333333-492)(A;;0xabc493;;;S-1-5-21-11111111-22222222-33333333-493)(A;;0xabc494;;;S-1-5-21-11111111-22222222-33333333-494)(A;;0xabc495;;;S-1-5-21-11111111-22222222-33333333-495)(A;;0xabc496;;;S-1-5-21-11111111-22222222-33333333-496)(A;;0xabc497;;;S-1-5-21-11111111-22222222-33333333-497)(A;;0xabc498;;;S-1-5-21-11111111-22222222-33333333-498)(A;;0xabc499;;;S-1-5-21-11111111-22222222-33333333-499)(A;;0xabc500;;;S-1-5-21-11111111-22222222-33333333-500)(A;;0xabc501;;;S-1-5-21-11111111-22222222-33333333-501)(A;;0xabc502;;;S-1-5-21-11111111-22222222-33333333-502)(A;;0xabc503;;;S-1-5-21-11111111-22222222-33333333-503)(A;;0xabc504;;;S-1-5-21-11111111-22222222-33333333-504)(A;;0xabc505;;;S-1-5-21-11111111-22222222-33333333-505)(A;;0xabc506;;;S-1-5-21-11111111-22222222-33333333-506)(A;;0xabc507;;;S-1-5-21-11111111-22222222-33333333-507)(A;;0xabc508;;;S-1-5-21-11111111-22222222-33333333-508)(A;;0xabc509;;;S-1-5-21-11111111-22222222-33333333-509)(A;;0xabc510;;;S-1-5-21-11111111-22222222-33333333-510)(A;;0xabc511;;;S-1-5-21-11111111-22222222-33333333-511)(A;;0xabc512;;;S-1-5-21-11111111-22222222-33333333-512)(A;;0xabc513;;;S-1-5-21-11111111-22222222-33333333-513)(A;;0xabc514;;;S-1-5-21-11111111-22222222-33333333-514)(A;;0xabc515;;;S-1-5-21-11111111-22222222-33333333-515)(A;;0xabc516;;;S-1-5-21-11111111-22222222-33333333-516)(A;;0xabc517;;;S-1-5-21-11111111-22222222-33333333-517)(A;;0xabc518;;;S-1-5-21-11111111-22222222-33333333-518)(A;;0xabc519;;;S-1-5-21-11111111-22222222-33333333-519)(A;;0xabc520;;;S-1-5-21-11111111-22222222-33333333-520)(A;;0xabc521;;;S-1-5-21-11111111-22222222-33333333-521)(A;;0xabc522;;;S-1-5-21-11111111-22222222-33333333-522)(A;;0xabc523;;;S-1-5-21-11111111-22222222-33333333-523)(A;;0xabc524;;;S-1-5-21-11111111-22222222-33333333-524)(A;;0xabc525;;;S-1-5-21-11111111-22222222-33333333-525)(A;;0xabc526;;;S-1-5-21-11111111-22222222-33333333-526)(A;;0xabc527;;;S-1-5-21-11111111-22222222-33333333-527)(A;;0xabc528;;;S-1-5-21-11111111-22222222-33333333-528)(A;;0xabc529;;;S-1-5-21-11111111-22222222-33333333-529)(A;;0xabc530;;;S-1-5-21-11111111-22222222-33333333-530)(A;;0xabc531;;;S-1-5-21-11111111-22222222-33333333-531)(A;;0xabc532;;;S-1-5-21-11111111-22222222-33333333-532)(A;;0xabc533;;;S-1-5-21-11111111-22222222-33333333-533)(A;;0xabc534;;;S-1-5-21-11111111-22222222-33333333-534)(A;;0xabc535;;;S-1-5-21-11111111-22222222-33333333-535)(A;;0xabc536;;;S-1-5-21-11111111-22222222-33333333-536)(A;;0xabc537;;;S-1-5-21-11111111-22222222-33333333-537)(A;;0xabc538;;;S-1-5-21-11111111-22222222-33333333-538)(A;;0xabc539;;;S-1-5-21-11111111-22222222-33333333-539)(A;;0xabc540;;;S-1-5-21-11111111-22222222-33333333-540)(A;;0xabc541;;;S-1-5-21-11111111-22222222-33333333-541)(A;;0xabc542;;;S-1-5-21-11111111-22222222-33333333-542)(A;;0xabc543;;;S-1-5-21-11111111-22222222-33333333-543)(A;;0xabc544;;;S-1-5-21-11111111-22222222-33333333-544)(A;;0xabc545;;;S-1-5-21-11111111-22222222-33333333-545)(A;;0xabc546;;;S-1-5-21-11111111-22222222-33333333-546)(A;;0xabc547;;;S-1-5-21-11111111-22222222-33333333-547)(A;;0xabc548;;;S-1-5-21-11111111-22222222-33333333-548)(A;;0xabc549;;;S-1-5-21-11111111-22222222-33333333-549)(A;;0xabc550;;;S-1-5-21-11111111-22222222-33333333-550)(A;;0xabc551;;;S-1-5-21-11111111-22222222-33333333-551)(A;;0xabc552;;;S-1-5-21-11111111-22222222-33333333-552)(A;;0xabc553;;;S-1-5-21-11111111-22222222-33333333-553)(A;;0xabc554;;;S-1-5-21-11111111-22222222-33333333-554)(A;;0xabc555;;;S-1-5-21-11111111-22222222-33333333-555)(A;;0xabc556;;;S-1-5-21-11111111-22222222-33333333-556)(A;;0xabc557;;;S-1-5-21-11111111-22222222-33333333-557)(A;;0xabc558;;;S-1-5-21-11111111-22222222-33333333-558)(A;;0xabc559;;;S-1-5-21-11111111-22222222-33333333-559)(A;;0xabc560;;;S-1-5-21-11111111-22222222-33333333-560)(A;;0xabc561;;;S-1-5-21-11111111-22222222-33333333-561)(A;;0xabc562;;;S-1-5-21-11111111-22222222-33333333-562)(A;;0xabc563;;;S-1-5-21-11111111-22222222-33333333-563)(A;;0xabc564;;;S-1-5-21-11111111-22222222-33333333-564)(A;;0xabc565;;;S-1-5-21-11111111-22222222-33333333-565)(A;;0xabc566;;;S-1-5-21-11111111-22222222-33333333-566)(A;;0xabc567;;;S-1-5-21-11111111-22222222-33333333-567)(A;;0xabc568;;;S-1-5-21-11111111-22222222-33333333-568)(A;;0xabc569;;;S-1-5-21-11111111-22222222-33333333-569)(A;;0xabc570;;;S-1-5-21-11111111-22222222-33333333-570)(A;;0xabc571;;;S-1-5-21-11111111-22222222-33333333-571)(A;;0xabc572;;;S-1-5-21-11111111-22222222-33333333-572)(A;;0xabc573;;;S-1-5-21-11111111-22222222-33333333-573)(A;;0xabc574;;;S-1-5-21-11111111-22222222-33333333-574)(A;;0xabc575;;;S-1-5-21-11111111-22222222-33333333-575)(A;;0xabc576;;;S-1-5-21-11111111-22222222-33333333-576)(A;;0xabc577;;;S-1-5-21-11111111-22222222-33333333-577)(A;;0xabc578;;;S-1-5-21-11111111-22222222-33333333-578)(A;;0xabc579;;;S-1-5-21-11111111-22222222-33333333-579)(A;;0xabc580;;;S-1-5-21-11111111-22222222-33333333-580)(A;;0xabc581;;;S-1-5-21-11111111-22222222-33333333-581)(A;;0xabc582;;;S-1-5-21-11111111-22222222-33333333-582)(A;;0xabc583;;;S-1-5-21-11111111-22222222-33333333-583)(A;;0xabc584;;;S-1-5-21-11111111-22222222-33333333-584)(A;;0xabc585;;;S-1-5-21-11111111-22222222-33333333-585)(A;;0xabc586;;;S-1-5-21-11111111-22222222-33333333-586)(A;;0xabc587;;;S-1-5-21-11111111-22222222-33333333-587)(A;;0xabc588;;;S-1-5-21-11111111-22222222-33333333-588)(A;;0xabc589;;;S-1-5-21-11111111-22222222-33333333-589)(A;;0xabc590;;;S-1-5-21-11111111-22222222-33333333-590)(A;;0xabc591;;;S-1-5-21-11111111-22222222-33333333-591)(A;;0xabc592;;;S-1-5-21-11111111-22222222-33333333-592)(A;;0xabc593;;;S-1-5-21-11111111-22222222-33333333-593)(A;;0xabc594;;;S-1-5-21-11111111-22222222-33333333-594)(A;;0xabc595;;;S-1-5-21-11111111-22222222-33333333-595)(A;;0xabc596;;;S-1-5-21-11111111-22222222-33333333-596)(A;;0xabc597;;;S-1-5-21-11111111-22222222-33333333-597)(A;;0xabc598;;;S-1-5-21-11111111-22222222-33333333-598)(A;;0xabc599;;;S-1-5-21-11111111-22222222-33333333-599)(A;;0xabc600;;;S-1-5-21-11111111-22222222-33333333-600)
+D:AI(A;CI;RP LCLORC;;;AU) -> D:AI(A;CI;LCRPLORC;;;AU)
+D:AI(A;CI;RP LCLO RC;;;AU) -> D:AI(A;CI;LCRPLORC;;;AU)
+D:(A;; GA;;;LG) -> D:(A;;GA;;;LG)
+D:(A;; 0x75bcd15;;;LG) -> D:(A;;0x75bcd15;;;LG)
+D:(A;;0x001f01ff;;;WD)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1001)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1002)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1003)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1004)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1005)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1006)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1007)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1008)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1009)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1010)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1011)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1012)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1013)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1014)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1015)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1016)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1017)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1018)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1019)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1020)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1021)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1022)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1023)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1024)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1025)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1026)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1027)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1028)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1029)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1030)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1031)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1032)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1033)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1034)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1035)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1036)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1037)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1038)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1039)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1040)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1041)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1042)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1043)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1044)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1045)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1046)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1047)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1048)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1049)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1050)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1051)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1052)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1053)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1054)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1055)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1056)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1057)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1058)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1059)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1060)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1061)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1062)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1063)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1064)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1065)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1066)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1067)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1068)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1069)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1070)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1071)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1072)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1073)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1074)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1075)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1076)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1077)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1078)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1079)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1080)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1081)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1082)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1083)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1084)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1085)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1086)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1087)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1088)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1089)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1090)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1091)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1092)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1093)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1094)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1095)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1096)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1097)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1098)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1099)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1100)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1101)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1102)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1103)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1104)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1105)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1106)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1107)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1108)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1109)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1110)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1111)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1112)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1113)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1114)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1115)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1116)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1117)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1118)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1119)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1120)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1121)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1122)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1123)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1124)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1125)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1126)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1127)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1128)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1129)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1130)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1131)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1132)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1133)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1134)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1135)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1136)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1137)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1138)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1139)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1140)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1141)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1142)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1143)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1144)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1145)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1146)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1147)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1148)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1149)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1150)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1151)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1152)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1153)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1154)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1155)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1156)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1157)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1158)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1159)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1160)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1161)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1162)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1163)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1164)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1165)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1166)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1167)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1168)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1169)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1170)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1171)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1172)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1173)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1174)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1175)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1176)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1177)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1178)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1179)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1180)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1181)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1182)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1183)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1184)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1185)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1186)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1187)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1188)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1189)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1190)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1191)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1192)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1193)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1194)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1195)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1196)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1197)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1198)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1199)(A;;0x001f01ff;;;S-1-5-21-11111111-22222222-33333333-1200) -> D:(A;;FA;;;WD)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1001)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1002)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1003)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1004)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1005)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1006)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1007)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1008)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1009)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1010)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1011)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1012)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1013)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1014)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1015)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1016)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1017)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1018)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1019)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1020)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1021)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1022)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1023)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1024)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1025)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1026)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1027)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1028)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1029)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1030)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1031)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1032)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1033)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1034)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1035)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1036)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1037)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1038)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1039)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1040)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1041)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1042)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1043)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1044)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1045)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1046)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1047)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1048)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1049)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1050)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1051)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1052)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1053)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1054)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1055)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1056)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1057)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1058)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1059)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1060)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1061)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1062)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1063)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1064)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1065)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1066)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1067)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1068)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1069)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1070)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1071)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1072)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1073)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1074)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1075)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1076)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1077)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1078)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1079)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1080)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1081)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1082)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1083)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1084)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1085)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1086)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1087)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1088)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1089)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1090)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1091)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1092)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1093)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1094)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1095)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1096)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1097)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1098)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1099)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1100)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1101)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1102)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1103)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1104)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1105)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1106)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1107)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1108)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1109)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1110)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1111)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1112)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1113)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1114)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1115)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1116)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1117)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1118)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1119)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1120)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1121)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1122)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1123)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1124)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1125)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1126)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1127)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1128)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1129)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1130)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1131)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1132)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1133)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1134)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1135)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1136)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1137)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1138)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1139)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1140)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1141)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1142)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1143)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1144)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1145)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1146)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1147)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1148)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1149)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1150)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1151)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1152)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1153)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1154)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1155)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1156)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1157)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1158)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1159)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1160)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1161)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1162)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1163)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1164)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1165)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1166)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1167)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1168)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1169)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1170)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1171)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1172)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1173)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1174)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1175)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1176)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1177)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1178)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1179)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1180)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1181)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1182)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1183)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1184)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1185)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1186)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1187)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1188)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1189)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1190)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1191)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1192)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1193)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1194)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1195)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1196)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1197)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1198)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1199)(A;;FA;;;S-1-5-21-11111111-22222222-33333333-1200)
+O:S-1-5-21-2212615479-2695158682-2101375468-512G:S-1-5-21-2212615479-2695158682-2101375468-513D:P(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375468-512)(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375468-519)(A;OICIIO;0x001f01ff;;;CO)(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375468-512)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)(A;OICI;0x001200a9;;;ED)S:AI(OU;CIIDSA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CIIDSA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD) -> O:S-1-5-21-2212615479-2695158682-2101375468-512G:S-1-5-21-2212615479-2695158682-2101375468-513D:P(A;OICI;FA;;;S-1-5-21-2212615479-2695158682-2101375468-512)(A;OICI;FA;;;S-1-5-21-2212615479-2695158682-2101375468-519)(A;OICIIO;FA;;;CO)(A;OICI;FA;;;S-1-5-21-2212615479-2695158682-2101375468-512)(A;OICI;FA;;;SY)(A;OICI;0x1200a9;;;AU)(A;OICI;0x1200a9;;;ED)S:AI(OU;CIIDSA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CIIDSA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)
+O:LAG:BAD:P(A;OICI;0x1f01ff;;;BA) -> O:LAG:BAD:P(A;OICI;FA;;;BA)
+O:LAG:BAD:(A;;0x1ff;;;WD) -> O:LAG:BAD:(A;;CCDCLCSWRPWPDTLOCR;;;WD)
+D:(A;;FAGX;;;SY) -> D:(A;;0x201f01ff;;;SY)
diff --git a/libcli/security/tests/windows/should_fail.txt b/libcli/security/tests/windows/should_fail.txt
new file mode 100644
index 0000000..35a813d
--- /dev/null
+++ b/libcli/security/tests/windows/should_fail.txt
@@ -0,0 +1,47 @@
+Z:(A;;GA;;;SY) -> Z:(A;;GA;;;SY)
+D:(Antlers;;GA;;;SY) -> D:(Antlers;;GA;;;SY)
+Q:(A;;GA;;;RU) -> Q:(A;;GA;;;RU)
+d:(A;;GA;;;LG) -> d:(A;;GA;;;LG)
+D:((A;;GA;;;LG)) -> D:((A;;GA;;;LG))
+D:(A;;GA;;) -> D:(A;;GA;;)
+D :S: -> D :S:
+S:(AU;SA;CROOO;;;WD)(AU;SA;CR;;;WD) -> S:(AU;SA;CROOO;;;WD)(AU;SA;CR;;;WD)
+D:(A;;GA;;;S-1-0x1313131313131-513) -> D:(A;;GA;;;S-1-0x1313131313131-513)
+D:(A;;GA;a;;S-1-5-21-2447931902-1787058256-0x3961074038-1201) -> D:(A;;GA;a;;S-1-5-21-2447931902-1787058256-0x3961074038-1201)
+D:(A;;GA;a;;S-1-5-21-2447931902-1787058256-0xec193176-1201) -> D:(A;;GA;a;;S-1-5-21-2447931902-1787058256-0xec193176-1201)
+S:(OOU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD) -> S:(OOU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)
+S:(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-00potato7c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-00chips7c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD) -> S:(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-00potato7c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-00chips7c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)
+D:P:S: -> D:P:S:
+D:(Ā;;GA;;;LG) -> D:(Ā;;GA;;;LG)
+D:(A;;123456789 ;;;LG) -> D:(A;;123456789 ;;;LG)
+D:(A;;0x75bcd15 ;;;LG) -> D:(A;;0x75bcd15 ;;;LG)
+D:(A;; 0x75bcd15;;;LG -> D:(A;; 0x75bcd15;;;LG
+D:(A;;0x 75bcd15;;;LG) -> D:(A;;0x 75bcd15;;;LG)
+D:(A;;GA ;;;LG) -> D:(A;;GA ;;;LG)
+D:(A;;RP ;;;LG) -> D:(A;;RP ;;;LG)
+D:(A;;GA;;;LG;) -> D:(A;;GA;;;LG;)
+D:(A;;GA;;;LG;;) -> D:(A;;GA;;;LG;;)
+D:(A;;GA) -> D:(A;;GA)
+D:(A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;) -> D:(A;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;)
+D:(A;;GA;;;S-1-3-4 ) -> D:(A;;GA;;;S-1-3-4 )
+D:(A;;GA; f30e3bbf-9ff0-11d1-b603-0000f80367c1;;WD) -> D:(A;;GA; f30e3bbf-9ff0-11d1-b603-0000f80367c1;;WD)
+D:(A;;GA;f30e3bbf-9ff0-11d1-b603-0000f80367c1 ;;WD) -> D:(A;;GA;f30e3bbf-9ff0-11d1-b603-0000f80367c1 ;;WD)
+D:(A;;GA;; f30e3bbf-9ff0-11d1-b603-0000f80367c1;WD) -> D:(A;;GA;; f30e3bbf-9ff0-11d1-b603-0000f80367c1;WD)
+D:(A;;GA;;f30e3bbf-9ff0-11d1-b603-0000f80367c1 ;WD) -> D:(A;;GA;;f30e3bbf-9ff0-11d1-b603-0000f80367c1 ;WD)
+D:(A;;GA;;{f30e3bbf-9ff0-11d1-b603-0000f80367c1};WD) -> D:(A;;GA;;{f30e3bbf-9ff0-11d1-b603-0000f80367c1};WD)
+D:(A;;GA;;0123456789abcdef;WD) -> D:(A;;GA;;0123456789abcdef;WD)
+D:(A;;GA;;0123456789abcdef0123456789abcdef;WD) -> D:(A;;GA;;0123456789abcdef0123456789abcdef;WD)
+D:AI(A;CI;RP LCLOR C;;;AU) -> D:AI(A;CI;RP LCLOR C;;;AU)
+D:AI(A;CI;RP LC LORC;;;AU) -> D:AI(A;CI;RP LC LORC;;;AU)
+D:AI(A;CI;RP LC LORC;;;AU) -> D:AI(A;CI;RP LC LORC;;;AU)
+O:S -> O:S
+O:S- -> O:S-
+O:S-1 -> O:S-1
+O:S-10 -> O:S-10
+O:S-0 -> O:S-0
+O:S-1- -> O:S-1-
+O:S-0x1 -> O:S-0x1
+O:S-0x1- -> O:S-0x1-
+O: -> O:
+O:XX -> O:XX
+D:(D:()D:())D:(A;;0x75bcd15;;;LG)) -> D:(D:()D:())D:(A;;0x75bcd15;;;LG))
diff --git a/libcli/security/tests/windows/windows-sddl-tests.c b/libcli/security/tests/windows/windows-sddl-tests.c
new file mode 100644
index 0000000..3857aef
--- /dev/null
+++ b/libcli/security/tests/windows/windows-sddl-tests.c
@@ -0,0 +1,341 @@
+/*
+ * Test Windows SDDL handling.
+ *
+ * Copyright (c) 2023 Douglas Bagnall <dbagnall@samba.org>
+ *
+ * GPLv3+.
+ *
+ * This can be compiled on Windows under Cygwin, like this:
+ *
+ *
+ * gcc -o windows-sddl-tests windows-sddl-tests.c \
+ * C:/Windows/System32/advapi32.dll -ladvapi32
+ *
+ *
+ * then run like this:
+ *
+ * ./windows-sddl-tests.exe
+ *
+ *
+ * That will show you a mix of success and failure.
+ *
+ * To run the tests in python/samba/tests/sddl.py, edit the method
+ * _test_write_test_strings(), removing the leading underscore so it starts
+ * with "test_". Then running
+ *
+ * make test TESTS='sddl\\b'
+ *
+ * will write some files into /tmp, containing lines like this:
+ *
+ * D:(A;;GA;;;RU) -> D:(A;;GA;;;RU)
+ *
+ * Copy these files to Windows. Then in Cygwin, run this:
+ *
+ * ./windows-sddl-tests.exe -i non_canonical.txt canonical.txt [...]
+ *
+ * and the part of each line before the " -> " will be fed into the SDDL
+ * parser, and back through the serialiser, which should result in the string
+ * after the " -> ". These are the tests that sddl.py does.
+ */
+
+#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>
+#include <windows.h>
+#include <sddl.h>
+
+#define RED "\033[1;31m"
+#define GREEN "\033[1;32m"
+#define AMBER "\033[33m"
+#define CYAN "\033[1;36m"
+#define C_NORMAL "\033[0m"
+
+/*
+ * Note that the SIDs SA, CA, RS, EA, PA, RO, and CN cannot be set by
+ * an ordinary local Administrator (error 1337, invalid SID). For this
+ * reason we use other SIDs instead/as well, so the list differs from
+ * the python/samba/tests/sddl.py list, which it is otherwise based on.
+ */
+const char *strings[] = {
+ "D:(A;;CC;;;BA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)",
+
+ "D:(A;;GA;;;RU)",
+
+ "D:(A;;GA;;;LG)",
+
+ ("D:(A;;RP;;;WD)"
+ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)"
+ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)"
+ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)"
+ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)"
+ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)"
+ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;RPWPCRLCLOCCRCWDWOSW;;;BO)"
+ "(A;CI;RPWPCRLCLOCCRCWDWOSDSW;;;BA)"
+ "(A;;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;SY)"
+ "(A;CI;RPWPCRLCLOCCDCRCWDWOSDDTSW;;;ES)"
+ "(A;CI;LC;;;RU)"
+ "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)"
+ "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)"
+ "(A;;RPRC;;;RU)"
+ "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)"
+ "(A;;LCRPLORC;;;ED)"
+ "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;CIIO;RPLCLORC;;4828CC14-1437-45bc-9B07-AD6F015E5F28;RU)"
+ "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)"
+ "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)"
+ "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)"
+ "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)"
+ "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)"
+ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;NO)"
+ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)"
+ "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;SU)"
+ "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)"
+ "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)"
+ "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)S:(AU;SA;WDWOWP;;;WD)"),
+
+ ("S:(AU;SA;CR;;;WD)"
+ "(AU;SA;CR;;;WD)"),
+
+ ("S:""(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)"
+ "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)"),
+
+ ("D:(A;;RPLCLORC;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPCRLCLORCSDDT;;;CO)"
+ "(OA;;WP;4c164200-20c0-11d0-a768-00aa006e0529;;CO)"
+ "(A;;RPLCLORC;;;AU)"
+ "(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)"
+ "(A;;CCDC;;;PS)"
+ "(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)"
+ "(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)"
+ "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;PS)"
+ "(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)"
+ "(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;PS)"
+ "(OA;;SW;72e39547-7b18-11d1-adef-00c04fd8d5cd;;CO)"
+ "(OA;;SW;f3a64788-5306-11d1-a9c5-0000f80367c1;;CO)"
+ "(OA;;WP;3e0abfd0-126a-11d0-a060-00aa006c33ed;bf967a86-0de6-11d0-a285-00aa003049e2;CO)"
+ "(OA;;WP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967a86-0de6-11d0-a285-00aa003049e2;CO)"
+ "(OA;;WP;bf967950-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)"
+ "(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;bf967a86-0de6-11d0-a285-00aa003049e2;CO)"
+ "(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)"
+ "(A;;RPLCLORC;;;PS)"
+ "(OA;;CR;ab721a55-1e2f-11d0-9819-00aa0040529b;;AU)"
+ "(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;CO)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)S:(AU;SA;CRWP;;;WD)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;AO)"
+ "(A;;RPLCLORC;;;PS)"
+ "(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;PS)"
+ "(OA;;CR;ab721a54-1e2f-11d0-9819-00aa0040529b;;PS)"
+ "(OA;;CR;ab721a56-1e2f-11d0-9819-00aa0040529b;;PS)"
+ "(OA;;RPWP;77B5B886-944A-11d1-AEBD-0000F80367C1;;PS)"
+ "(OA;;RPWP;E45795B2-9455-11d1-AEBD-0000F80367C1;;PS)"
+ "(OA;;RPWP;E45795B3-9455-11d1-AEBD-0000F80367C1;;PS)"
+ "(OA;;RP;037088f8-0ae1-11d2-b422-00a0c968f939;;RD)"
+ "(OA;;RP;4c164200-20c0-11d0-a768-00aa006e0529;;RD)"
+ "(OA;;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;;RD)"
+ "(A;;RC;;;AU)"
+ "(OA;;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;;AU)"
+ "(OA;;RP;77B5B886-944A-11d1-AEBD-0000F80367C1;;AU)"
+ "(OA;;RP;E45795B3-9455-11d1-AEBD-0000F80367C1;;AU)"
+ "(OA;;RP;e48d0154-bcf8-11d1-8702-00c04fb96050;;AU)"
+ "(OA;;CR;ab721a53-1e2f-11d0-9819-00aa0040529b;;WD)"
+ "(OA;;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;;RD)"
+ "(OA;;RPWP;bf967a7f-0de6-11d0-a285-00aa003049e2;;SY)"
+ "(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;SU)"
+ "(OA;;WPRP;6db69a1c-9422-11d1-aebd-0000f80367c1;;SU)"),
+
+ "D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)",
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;LCRPLORC;;;ED)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(OA;;CCDC;bf967a86-0de6-11d0-a285-00aa003049e2;;AO)"
+ "(OA;;CCDC;bf967aba-0de6-11d0-a285-00aa003049e2;;AO)"
+ "(OA;;CCDC;bf967a9c-0de6-11d0-a285-00aa003049e2;;AO)"
+ "(OA;;CCDC;bf967aa8-0de6-11d0-a285-00aa003049e2;;PO)"
+ "(A;;RPLCLORC;;;AU)"
+ "(A;;LCRPLORC;;;ED)"
+ "(OA;;CCDC;4828CC14-1437-45bc-9B07-AD6F015E5F28;;AO)"),
+
+ ("D:(A;;RPWPCRCCDCLCLORCWOWDSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"),
+
+ ("D:(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;BO)"
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
+ "(A;;RPLCLORC;;;AU)"),
+
+ "D:S:",
+ "D:PS:",
+ NULL
+};
+
+
+static int test_pair(const char *s, const char *canonical)
+{
+ PSECURITY_DESCRIPTOR sd = NULL;
+ ULONG len;
+ char *return_string = NULL;
+ ULONG return_len;
+ int ok = ConvertStringSecurityDescriptorToSecurityDescriptorA(s,
+ 1,
+ &sd,
+ &len);
+ if (!ok) {
+ int e = GetLastError();
+ const char *ename = NULL;
+ switch(e) {
+ case 1337:
+ ename = " invalid sid";
+ break;
+ case 1336:
+ ename = " insufficient privs/SACL vs DACL/something something";
+ break;
+ case 1804:
+ ename = " invalid datatype";
+ break;
+ default:
+ ename = "";
+ }
+
+ printf(RED "not ok:" AMBER " %d%s" C_NORMAL ": %s\n",
+ e, ename, s);
+ return e;
+ }
+ if (sd == NULL) {
+ printf(RED "NULL sd" C_NORMAL": %s\n", s);
+ return -1;
+ }
+
+ ok = ConvertSecurityDescriptorToStringSecurityDescriptorA(
+ sd,
+ 1,
+ ~BACKUP_SECURITY_INFORMATION,
+ &return_string,
+ &return_len);
+ if (strncmp(return_string, canonical, return_len) != 0) {
+ printf(RED "return differs:" AMBER " %u vs %u" C_NORMAL "\n",
+ len, return_len);
+ printf(RED "original:" C_NORMAL ": %s\n", s);
+ printf(RED "returned:" C_NORMAL ": %s\n", return_string);
+ return -2;
+ }
+ printf(GREEN "GOOD" C_NORMAL ": %s\n", s);
+ if (strncmp(return_string, s, return_len) != 0) {
+ printf(CYAN "original:" C_NORMAL ": %s\n", s);
+ printf(CYAN "returned:" C_NORMAL ": %s\n", return_string);
+ return -2;
+ }
+ return 0;
+}
+
+
+int test_from_files(int argc, const char *argv[])
+{
+ size_t i, j;
+ static char buf[100000];
+
+ for (i = 0; i < argc; i++) {
+ char *orig = NULL;
+ char *canon = NULL;
+ size_t len;
+ FILE *f = fopen(argv[i], "r");
+ if (f == NULL) {
+ printf(RED "bad filename? %s\n" C_NORMAL,
+ argv[i]);
+ }
+ len = fread(buf, 1, sizeof(buf), f);
+
+ if (len >= sizeof(buf) - 1 || len == 0) {
+ printf(RED "couldn't read %s\n" C_NORMAL, argv[i]);
+ continue;
+ }
+ printf(CYAN "%s\n" C_NORMAL, argv[i]);
+ buf[len] = 0;
+ orig = buf;
+ for (j = 0; j < len; j++) {
+ char c = buf[j];
+ if (c == '\n') {
+ buf[j] = 0;
+ if (j != 0 && buf[j - 1] == '\r') {
+ buf[j - 1] = 0;
+ }
+ if (orig && canon) {
+ test_pair(orig, canon);
+ canon = NULL;
+ } else {
+ printf(RED "bad pair %s -> %s\n" C_NORMAL,
+ orig, canon);
+ }
+ orig = buf + j + 1;
+ } else if (c == ' ' && j + 4 < len &&
+ buf[j + 1] == '-' &&
+ buf[j + 2] == '>' &&
+ buf[j + 3] == ' ') {
+ buf[j] = 0;
+ canon = buf + j + 4;
+ }
+ }
+ }
+}
+
+int main(int argc, const char *argv[])
+{
+ uint32_t i;
+ if (argc < 2) {
+ for (i = 0; strings[i] != NULL; i++) {
+ test_pair(strings[i], strings[i]);
+ }
+ } else if (strncmp("-i", argv[1], 2) == 0) {
+ return test_from_files(argc - 2, argv + 2);
+ } else {
+ for (i = 1; i < argc; i++) {
+ test_pair(argv[i], argv[i]);
+ }
+ }
+ return 0;
+}
diff --git a/libcli/security/tests/windows/windows-sddl-tests.py b/libcli/security/tests/windows/windows-sddl-tests.py
new file mode 100644
index 0000000..38acb44
--- /dev/null
+++ b/libcli/security/tests/windows/windows-sddl-tests.py
@@ -0,0 +1,181 @@
+# Test SDDL strings on Windows
+#
+#
+# Copyright (c) 2023 Catalyst IT
+#
+# GPLv3+.
+#
+# This uses the Python win32 module to access
+# ConvertStringSecurityDescriptorToSecurityDescriptor and the like. To
+# install this, you need to go
+#
+# pip install pywin32
+#
+# or something like that.
+
+import argparse
+from difflib import SequenceMatcher
+from collections import defaultdict
+import sys
+import json
+
+try:
+ import win32security as w
+except ImportError:
+ print("This test script is meant to be run on Windows using the pywin32 module.")
+ print("To install this module, try:\n")
+ print("pip install pywin32")
+ sys.exit(1)
+
+
+# This is necessary for ANSI colour escapes to work in Powershell.
+import os
+os.system('')
+
+RED = "\033[1;31m"
+GREEN = "\033[1;32m"
+DARK_YELLOW = "\033[0;33m"
+C_NORMAL = "\033[0m"
+
+def c_RED(s):
+ return f"{RED}{s}{C_NORMAL}"
+def c_GREEN(s):
+ return f"{GREEN}{s}{C_NORMAL}"
+def c_DY(s):
+ return f"{DARK_YELLOW}{s}{C_NORMAL}"
+
+
+def read_strings(files):
+ """Try to read as JSON a JSON dictionary first, then secondly in the bespoke
+ sddl-in -> sddl-out
+ format used by other Samba SDDL test programs on Windows.
+ """
+ pairs = []
+ for filename in files:
+ with open(filename) as f:
+ try:
+ data = json.load(f)
+ print(f"loading {filename} as JSON")
+ for k, v in data.items():
+ if not v or not isinstance(v, str):
+ v = k
+ pairs.append((k, v))
+ continue
+ except json.JSONDecodeError:
+ pass
+
+ print(f"loading {filename} as 'a -> b' style")
+ f.seek(0)
+ for line in f:
+ line = line.rstrip()
+ if line.startswith('#') or line == '':
+ continue
+ # note: if the line does not have ' -> ', we expect a
+ # perfect round trip.
+ o, _, c = line.partition(' -> ')
+ if c == '':
+ c = o
+ pairs.append((o, c))
+
+ return pairs
+
+
+def colourdiff(a, b):
+ out = []
+ a = a.replace(' ', '␠')
+ b = b.replace(' ', '␠')
+
+ s = SequenceMatcher(None, a, b)
+ for op, al, ar, bl, br in s.get_opcodes():
+ if op == 'equal':
+ out.append(a[al: ar])
+ elif op == 'delete':
+ out.append(c_RED(a[al: ar]))
+ elif op == 'insert':
+ out.append(c_GREEN(b[bl: br]))
+ elif op == 'replace':
+ out.append(c_RED(a[al: ar]))
+ out.append(c_GREEN(b[bl: br]))
+ else:
+ print(f'unknown op {op}!')
+
+ return ''.join(out)
+
+
+def no_print(*args, **kwargs):
+ pass
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--export-bytes', const='sddl_bytes.json', nargs='?',
+ help='write JSON file containing SD bytes')
+ parser.add_argument('--quiet', action='store_true',
+ help='avoid printing to stdout')
+ parser.add_argument('files', nargs='+', help='read these files')
+
+ args = parser.parse_args()
+
+ if args.quiet:
+ global print
+ print = no_print
+
+ cases = read_strings(args.files)
+ parseable_cases = []
+ unparseable_cases = []
+ unserializeable_cases = []
+ round_trip_failures = []
+ exceptions = defaultdict(list)
+ bytes_json = {}
+
+ print(f"{len(set(cases))}/{len(cases)} unique pairs, "
+ f"{len(set(x[0] for x in cases))}/{len(cases)} unique strings")
+
+ for a, b in sorted(set(cases)):
+ try:
+ sd = w.ConvertStringSecurityDescriptorToSecurityDescriptor(a, 1)
+ except Exception as e:
+ print(a)
+ exceptions[f"{e} parse"].append(a)
+ print(c_RED(e))
+ unparseable_cases.append(a)
+ continue
+
+ parseable_cases.append(a)
+
+ try:
+ # maybe 0xffff is an incorrect guess -- it gives use v2 (NT), not v4 (AD)
+ c = w.ConvertSecurityDescriptorToStringSecurityDescriptor(sd, 1, 0xffff)
+ except Exception as e:
+ print(f"could not serialize '{sd}': {e}")
+ print(f" derived from '{a}'")
+ exceptions[f"{e} serialize"].append(a)
+ unserializeable_cases.append(a)
+ continue
+
+ if args.export_bytes:
+ bytes_json[c] = list(bytes(sd))
+
+ if c != b:
+ round_trip_failures.append((a, b, c))
+ exceptions["mismatch"].append(a)
+ #print(f"{c_GREEN(a)} -> {c_DY(c)}")
+ print(colourdiff(b, c))
+ print(c_DY(f"{b} -> {c}"))
+
+ for k, v in exceptions.items():
+ print(f"{k}: {len(v)}")
+
+ print(f"{len(unparseable_cases)} failed to parse")
+ print(f"{len(parseable_cases)} successfully parsed")
+ print(f"{len(unserializeable_cases)} of these failed to re-serialize")
+ print(f"{len(round_trip_failures)} of these failed to round trip")
+ #for p in parseable_cases:
+ # print(f"«{c_GREEN(p)}»")
+
+ if args.export_bytes:
+ with open(args.export_bytes, 'w') as f:
+ json.dump(bytes_json, f)
+ print(f"wrote bytes to {args.export_bytes}")
+
+main()
diff --git a/libcli/security/tests/windows/windows_is_fussy.txt b/libcli/security/tests/windows/windows_is_fussy.txt
new file mode 100644
index 0000000..b058a67
--- /dev/null
+++ b/libcli/security/tests/windows/windows_is_fussy.txt
@@ -0,0 +1 @@
+D:(A;;RP;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU) -> D:(A;;RP;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)
diff --git a/libcli/security/tests/windows/windows_is_less_fussy.txt b/libcli/security/tests/windows/windows_is_less_fussy.txt
new file mode 100644
index 0000000..17e2e5b
--- /dev/null
+++ b/libcli/security/tests/windows/windows_is_less_fussy.txt
@@ -0,0 +1,23 @@
+D:(A;;GA;;; LG) -> D:(A;;GA;;;LG)
+D: (A;;GA;;;LG) -> D:(A;;GA;;;LG)
+D: AI(A;;GA;;;LG) -> D:AI(A;;GA;;;LG)
+D:(a;;GA;;;LG) -> D:(A;;GA;;;LG)
+D:(A;;GA;;;lg) -> D:(A;;GA;;;LG)
+D:(A;;ga;;;LG) -> D:(A;;GA;;;LG)
+D: S: -> D:S:
+D: P(A;;GA;;;LG) -> D:P(A;;GA;;;LG)
+D:P (A;;GA;;;LG) -> D:P(A;;GA;;;LG)
+D:P(A;;GA;;;LG) (A;;GX;;;AA) -> D:P(A;;GA;;;LG)(A;;GX;;;AA)
+D:(A; ;GA;;;LG) -> D:(A;;GA;;;LG)
+D:AI (A;;GA;;;LG) -> D:AI(A;;GA;;;LG)
+D:(A;;GA;;; WD) -> D:(A;;GA;;;WD)
+D:(A;;GA;;;WD ) -> D:(A;;GA;;;WD)
+D:(A;;GA;;; S-1-3-4) -> D:(A;;GA;;;OW)
+D:(A;;GA;; ;S-1-3-4) -> D:(A;;GA;;;OW)
+D:(A;;GA; ;;S-1-3-4) -> D:(A;;GA;;;OW)
+D:(A;;GA;;; S-1-333-4) -> D:(A;;GA;;;S-1-333-4)
+D:(A;;GA; ;;S-1-333-4) -> D:(A;;GA;;;S-1-333-4)
+ O:AA -> O:AA
+ O:AA -> O:AA
+ O:AA G:WD -> O:AAG:WD
+O:S- 1- 2-3 -> O:S-1-2-3
diff --git a/libcli/security/tests/windows/windows_is_weird.txt b/libcli/security/tests/windows/windows_is_weird.txt
new file mode 100644
index 0000000..7c9d265
--- /dev/null
+++ b/libcli/security/tests/windows/windows_is_weird.txt
@@ -0,0 +1,10 @@
+D:(A;;0x123456789;;;LG) -> D:(A;;0xffffffff;;;LG)
+D:(A;;CC;;;S-0x1-0-0-579) -> D:(A;;CC;;;S-1-0-0-1401)
+O:S-0x1-20-0-579 -> O:S-1-32-0-1401
+D:(A;;GA;;;S-1-3-4294967296-3-4) -> D:(A;;GA;;;S-1-3-4294967295-3-4)
+D:(A;;GA;;;S-1-3-0x100000000-3-4) -> D:(A;;GA;;;S-1-3-4294967295-3-4)
+D:(A;;GA;;;S-1-5-21-0x1313131313131-513) -> D:(A;;GA;;;S-1-5-21-4294967295-513)
+D:(A;;-99;;;LG) -> D:(A;;0xffffff9d;;;LG)
+D:(A;;-0xffffff55;;;LG) -> D:(A;;CCDCSWWPLO;;;LG)
+D:(A;;-9876543210;;;LG) -> D:(A;;CC;;;LG)
+D:(A;;100000000000000000000000;;;LG) -> D:(A;;0xffffffff;;;LG)
diff --git a/libcli/security/util_sid.c b/libcli/security/util_sid.c
new file mode 100644
index 0000000..54a2fc3
--- /dev/null
+++ b/libcli/security/util_sid.c
@@ -0,0 +1,1117 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba utility functions
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Luke Kenneth Caseson Leighton 1998-1999
+ Copyright (C) Jeremy Allison 1999
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Simo Sorce 2002
+ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
+ 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 "replace.h"
+#include "lib/util/samba_util.h"
+#include "../librpc/gen_ndr/ndr_security.h"
+#include "../librpc/gen_ndr/netlogon.h"
+#include "../libcli/security/security.h"
+#include "auth/auth.h"
+
+
+#undef strcasecmp
+#undef strncasecmp
+
+/*
+ * Some useful sids, more well known sids can be found at
+ * http://support.microsoft.com/kb/243330/EN-US/
+ */
+
+
+/* S-1-1 */
+const struct dom_sid global_sid_World_Domain = /* Everyone domain */
+{ 1, 0, {0,0,0,0,0,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-1-0 */
+const struct dom_sid global_sid_World = /* Everyone */
+{ 1, 1, {0,0,0,0,0,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-2 */
+const struct dom_sid global_sid_Local_Authority = /* Local Authority */
+{ 1, 0, {0,0,0,0,0,2}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-3 */
+const struct dom_sid global_sid_Creator_Owner_Domain = /* Creator Owner domain */
+{ 1, 0, {0,0,0,0,0,3}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5 */
+const struct dom_sid global_sid_NT_Authority = /* NT Authority */
+{ 1, 0, {0,0,0,0,0,5}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-18 */
+const struct dom_sid global_sid_System = /* System */
+{ 1, 1, {0,0,0,0,0,5}, {18,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-0-0 */
+const struct dom_sid global_sid_NULL = /* NULL sid */
+{ 1, 1, {0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-10 */
+const struct dom_sid global_sid_Self = /* SELF */
+{ 1, 1, {0,0,0,0,0,5}, {10,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-11 */
+const struct dom_sid global_sid_Authenticated_Users = /* All authenticated rids */
+{ 1, 1, {0,0,0,0,0,5}, {11,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+#if 0
+/* for documentation S-1-5-12 */
+const struct dom_sid global_sid_Restricted = /* Restricted Code */
+{ 1, 1, {0,0,0,0,0,5}, {12,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+#endif
+
+/* S-1-18 */
+const struct dom_sid global_sid_Asserted_Identity = /* Asserted Identity */
+{ 1, 0, {0,0,0,0,0,18}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-18-1 */
+const struct dom_sid global_sid_Asserted_Identity_Authentication_Authority = /* Asserted Identity Authentication Authority */
+{ 1, 1, {0,0,0,0,0,18}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-18-2 */
+const struct dom_sid global_sid_Asserted_Identity_Service = /* Asserted Identity Service */
+{ 1, 1, {0,0,0,0,0,18}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+/* S-1-5-2 */
+const struct dom_sid global_sid_Network = /* Network rids */
+{ 1, 1, {0,0,0,0,0,5}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+/* S-1-3 */
+const struct dom_sid global_sid_Creator_Owner = /* Creator Owner */
+{ 1, 1, {0,0,0,0,0,3}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-3-1 */
+const struct dom_sid global_sid_Creator_Group = /* Creator Group */
+{ 1, 1, {0,0,0,0,0,3}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-3-4 */
+const struct dom_sid global_sid_Owner_Rights = /* Owner Rights */
+{ 1, 1, {0,0,0,0,0,3}, {4,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-7 */
+const struct dom_sid global_sid_Anonymous = /* Anonymous login */
+{ 1, 1, {0,0,0,0,0,5}, {7,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-9 */
+const struct dom_sid global_sid_Enterprise_DCs = /* Enterprise DCs */
+{ 1, 1, {0,0,0,0,0,5}, {9,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-21-0-0-0-496 */
+const struct dom_sid global_sid_Compounded_Authentication = /* Compounded Authentication */
+{1, 5, {0,0,0,0,0,5}, {21,0,0,0,496,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-21-0-0-0-497 */
+const struct dom_sid global_sid_Claims_Valid = /* Claims Valid */
+{1, 5, {0,0,0,0,0,5}, {21,0,0,0,497,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32 */
+const struct dom_sid global_sid_Builtin = /* Local well-known domain */
+{ 1, 1, {0,0,0,0,0,5}, {32,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-544 */
+const struct dom_sid global_sid_Builtin_Administrators = /* Builtin administrators */
+{ 1, 2, {0,0,0,0,0,5}, {32,544,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-545 */
+const struct dom_sid global_sid_Builtin_Users = /* Builtin users */
+{ 1, 2, {0,0,0,0,0,5}, {32,545,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-546 */
+const struct dom_sid global_sid_Builtin_Guests = /* Builtin guest users */
+{ 1, 2, {0,0,0,0,0,5}, {32,546,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-547 */
+const struct dom_sid global_sid_Builtin_Power_Users = /* Builtin power users */
+{ 1, 2, {0,0,0,0,0,5}, {32,547,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-548 */
+const struct dom_sid global_sid_Builtin_Account_Operators = /* Builtin account operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,548,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-549 */
+const struct dom_sid global_sid_Builtin_Server_Operators = /* Builtin server operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,549,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-550 */
+const struct dom_sid global_sid_Builtin_Print_Operators = /* Builtin print operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,550,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-551 */
+const struct dom_sid global_sid_Builtin_Backup_Operators = /* Builtin backup operators */
+{ 1, 2, {0,0,0,0,0,5}, {32,551,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-552 */
+const struct dom_sid global_sid_Builtin_Replicator = /* Builtin replicator */
+{ 1, 2, {0,0,0,0,0,5}, {32,552,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-32-554 */
+const struct dom_sid global_sid_Builtin_PreWin2kAccess = /* Builtin pre win2k access */
+{ 1, 2, {0,0,0,0,0,5}, {32,554,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+/* S-1-22-1 */
+const struct dom_sid global_sid_Unix_Users = /* Unmapped Unix users */
+{ 1, 1, {0,0,0,0,0,22}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-22-2 */
+const struct dom_sid global_sid_Unix_Groups = /* Unmapped Unix groups */
+{ 1, 1, {0,0,0,0,0,22}, {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+/*
+ * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
+ */
+/* S-1-5-88 */
+const struct dom_sid global_sid_Unix_NFS = /* MS NFS and Apple style */
+{ 1, 1, {0,0,0,0,0,5}, {88,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-88-1 */
+const struct dom_sid global_sid_Unix_NFS_Users = /* Unix uid, MS NFS and Apple style */
+{ 1, 2, {0,0,0,0,0,5}, {88,1,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-88-2 */
+const struct dom_sid global_sid_Unix_NFS_Groups = /* Unix gid, MS NFS and Apple style */
+{ 1, 2, {0,0,0,0,0,5}, {88,2,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* S-1-5-88-3 */
+const struct dom_sid global_sid_Unix_NFS_Mode = /* Unix mode */
+{ 1, 2, {0,0,0,0,0,5}, {88,3,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+/* Unused, left here for documentary purposes */
+#if 0
+const struct dom_sid global_sid_Unix_NFS_Other = /* Unix other, MS NFS and Apple style */
+{ 1, 2, {0,0,0,0,0,5}, {88,4,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+#endif
+
+/* Information passing via security token */
+const struct dom_sid global_sid_Samba_SMB3 =
+{1, 1, {0,0,0,0,0,22}, {1397571891, }};
+
+const struct dom_sid global_sid_Samba_NPA_Flags = {1,
+ 1,
+ {0, 0, 0, 0, 0, 22},
+ {
+ 2041152804,
+ }};
+
+/* Unused, left here for documentary purposes */
+#if 0
+#define SECURITY_NULL_SID_AUTHORITY 0
+#define SECURITY_WORLD_SID_AUTHORITY 1
+#define SECURITY_LOCAL_SID_AUTHORITY 2
+#define SECURITY_CREATOR_SID_AUTHORITY 3
+#define SECURITY_NT_AUTHORITY 5
+#endif
+
+static struct dom_sid system_sid_array[1] =
+{ { 1, 1, {0,0,0,0,0,5}, {18,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} };
+static const struct security_token system_token = {
+ .num_sids = ARRAY_SIZE(system_sid_array),
+ .sids = system_sid_array,
+ .privilege_mask = SE_ALL_PRIVS
+};
+
+/****************************************************************************
+ Lookup string names for SID types.
+****************************************************************************/
+
+const char *sid_type_lookup(uint32_t sid_type)
+{
+ switch (sid_type) {
+ case SID_NAME_USE_NONE:
+ return "None";
+ break;
+ case SID_NAME_USER:
+ return "User";
+ break;
+ case SID_NAME_DOM_GRP:
+ return "Domain Group";
+ break;
+ case SID_NAME_DOMAIN:
+ return "Domain";
+ break;
+ case SID_NAME_ALIAS:
+ return "Local Group";
+ break;
+ case SID_NAME_WKN_GRP:
+ return "Well-known Group";
+ break;
+ case SID_NAME_DELETED:
+ return "Deleted Account";
+ break;
+ case SID_NAME_INVALID:
+ return "Invalid Account";
+ break;
+ case SID_NAME_UNKNOWN:
+ return "UNKNOWN";
+ break;
+ case SID_NAME_COMPUTER:
+ return "Computer";
+ break;
+ case SID_NAME_LABEL:
+ return "Mandatory Label";
+ break;
+ }
+
+ /* Default return */
+ return "SID *TYPE* is INVALID";
+}
+
+/**************************************************************************
+ Create the SYSTEM token.
+***************************************************************************/
+
+const struct security_token *get_system_token(void)
+{
+ return &system_token;
+}
+
+bool sid_compose(struct dom_sid *dst, const struct dom_sid *domain_sid, uint32_t rid)
+{
+ sid_copy(dst, domain_sid);
+ return sid_append_rid(dst, rid);
+}
+
+/*****************************************************************
+ Removes the last rid from the end of a sid
+*****************************************************************/
+
+bool sid_split_rid(struct dom_sid *sid, uint32_t *rid)
+{
+ if (sid->num_auths > 0) {
+ sid->num_auths--;
+ if (rid != NULL) {
+ *rid = sid->sub_auths[sid->num_auths];
+ }
+ return true;
+ }
+ return false;
+}
+
+/*****************************************************************
+ Return the last rid from the end of a sid
+*****************************************************************/
+
+bool sid_peek_rid(const struct dom_sid *sid, uint32_t *rid)
+{
+ if (!sid || !rid)
+ return false;
+
+ if (sid->num_auths > 0) {
+ *rid = sid->sub_auths[sid->num_auths - 1];
+ return true;
+ }
+ return false;
+}
+
+/*****************************************************************
+ Return the last rid from the end of a sid
+ and check the sid against the exp_dom_sid
+*****************************************************************/
+
+bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid *sid, uint32_t *rid)
+{
+ if (!exp_dom_sid || !sid || !rid)
+ return false;
+
+ if (sid->num_auths != (exp_dom_sid->num_auths+1)) {
+ return false;
+ }
+
+ if (dom_sid_compare_domain(exp_dom_sid, sid)!=0){
+ *rid=(-1);
+ return false;
+ }
+
+ return sid_peek_rid(sid, rid);
+}
+
+/*****************************************************************
+ Copies a sid
+*****************************************************************/
+
+void sid_copy(struct dom_sid *dst, const struct dom_sid *src)
+{
+ int i;
+
+ *dst = (struct dom_sid) {
+ .sid_rev_num = src->sid_rev_num,
+ .num_auths = src->num_auths,
+ };
+
+ memcpy(&dst->id_auth[0], &src->id_auth[0], sizeof(src->id_auth));
+
+ for (i = 0; i < src->num_auths; i++)
+ dst->sub_auths[i] = src->sub_auths[i];
+}
+
+/*****************************************************************
+ Parse a on-the-wire SID to a struct dom_sid.
+*****************************************************************/
+
+ssize_t sid_parse(const uint8_t *inbuf, size_t len, struct dom_sid *sid)
+{
+ DATA_BLOB in = data_blob_const(inbuf, len);
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_pull_struct_blob_all(
+ &in, NULL, sid, (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+ return ndr_size_dom_sid(sid, 0);
+}
+
+/********************************************************************
+ Add SID to an array of SIDs
+********************************************************************/
+
+NTSTATUS add_sid_to_array(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **sids, uint32_t *num)
+{
+ struct dom_sid *tmp;
+
+ if ((*num) == UINT32_MAX) {
+ return NT_STATUS_INTEGER_OVERFLOW;
+ }
+
+ tmp = talloc_realloc(mem_ctx, *sids, struct dom_sid, (*num)+1);
+ if (tmp == NULL) {
+ *num = 0;
+ return NT_STATUS_NO_MEMORY;
+ }
+ *sids = tmp;
+
+ sid_copy(&((*sids)[*num]), sid);
+ *num += 1;
+
+ return NT_STATUS_OK;
+}
+
+
+/********************************************************************
+ Add SID to an array of SIDs ensuring that it is not already there
+********************************************************************/
+
+NTSTATUS add_sid_to_array_unique(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
+ struct dom_sid **sids, uint32_t *num_sids)
+{
+ bool contains;
+
+ contains = sids_contains_sid(*sids, *num_sids, sid);
+ if (contains) {
+ return NT_STATUS_OK;
+ }
+
+ return add_sid_to_array(mem_ctx, sid, sids, num_sids);
+}
+
+/**
+ * Appends a SID and attribute to an array of auth_SidAttr.
+ *
+ * @param [in] mem_ctx Talloc memory context on which to allocate the array.
+ * @param [in] sid The SID to append.
+ * @param [in] attrs SE_GROUP_* flags to go with the SID.
+ * @param [inout] sids A pointer to the auth_SidAttr array.
+ * @param [inout] num A pointer to the size of the auth_SidArray array.
+ * @returns NT_STATUS_OK on success.
+ */
+NTSTATUS add_sid_to_array_attrs(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid, uint32_t attrs,
+ struct auth_SidAttr **sids, uint32_t *num)
+{
+ struct auth_SidAttr *tmp = NULL;
+
+ if ((*num) == UINT32_MAX) {
+ return NT_STATUS_INTEGER_OVERFLOW;
+ }
+
+ tmp = talloc_realloc(mem_ctx, *sids, struct auth_SidAttr, (*num)+1);
+ if (tmp == NULL) {
+ *num = 0;
+ return NT_STATUS_NO_MEMORY;
+ }
+ *sids = tmp;
+
+ sid_copy(&((*sids)[*num].sid), sid);
+ (*sids)[*num].attrs = attrs;
+ *num += 1;
+
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Appends a SID and attribute to an array of auth_SidAttr,
+ * ensuring that it is not already there.
+ *
+ * @param [in] mem_ctx Talloc memory context on which to allocate the array.
+ * @param [in] sid The SID to append.
+ * @param [in] attrs SE_GROUP_* flags to go with the SID.
+ * @param [inout] sids A pointer to the auth_SidAttr array.
+ * @param [inout] num_sids A pointer to the size of the auth_SidArray array.
+ * @returns NT_STATUS_OK on success.
+ */
+NTSTATUS add_sid_to_array_attrs_unique(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid, uint32_t attrs,
+ struct auth_SidAttr **sids, uint32_t *num_sids)
+{
+ bool contains;
+
+ contains = sids_contains_sid_attrs(*sids, *num_sids, sid, attrs);
+ if (contains) {
+ return NT_STATUS_OK;
+ }
+
+ return add_sid_to_array_attrs(mem_ctx, sid, attrs, sids, num_sids);
+}
+
+/********************************************************************
+ Remove SID from an array
+********************************************************************/
+
+void del_sid_from_array(const struct dom_sid *sid, struct dom_sid **sids,
+ uint32_t *num)
+{
+ struct dom_sid *sid_list = *sids;
+ uint32_t i;
+
+ for ( i=0; i<*num; i++ ) {
+
+ /* if we find the SID, then decrement the count
+ and break out of the loop */
+
+ if (dom_sid_equal(sid, &sid_list[i])) {
+ *num -= 1;
+ break;
+ }
+ }
+
+ /* This loop will copy the remainder of the array
+ if i < num of sids in the array */
+
+ for ( ; i<*num; i++ ) {
+ sid_copy( &sid_list[i], &sid_list[i+1] );
+ }
+}
+
+bool add_rid_to_array_unique(TALLOC_CTX *mem_ctx,
+ uint32_t rid, uint32_t **pp_rids, size_t *p_num)
+{
+ size_t i;
+
+ for (i=0; i<*p_num; i++) {
+ if ((*pp_rids)[i] == rid)
+ return true;
+ }
+
+ *pp_rids = talloc_realloc(mem_ctx, *pp_rids, uint32_t, *p_num+1);
+
+ if (*pp_rids == NULL) {
+ *p_num = 0;
+ return false;
+ }
+
+ (*pp_rids)[*p_num] = rid;
+ *p_num += 1;
+ return true;
+}
+
+bool is_null_sid(const struct dom_sid *sid)
+{
+ static const struct dom_sid null_sid = {0};
+ return dom_sid_equal(sid, &null_sid);
+}
+
+/**
+ * Return true if an array of SIDs contains a certain SID.
+ *
+ * @param [in] sids The SID array.
+ * @param [in] num_sids The size of the SID array.
+ * @param [in] sid The SID in question.
+ * @returns true if the array contains the SID.
+ */
+bool sids_contains_sid(const struct dom_sid *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid)
+{
+ uint32_t i;
+
+ for (i = 0; i < num_sids; i++) {
+ if (dom_sid_equal(&sids[i], sid)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Return true if an array of auth_SidAttr contains a certain SID.
+ *
+ * @param [in] sids The auth_SidAttr array.
+ * @param [in] num_sids The size of the auth_SidArray array.
+ * @param [in] sid The SID in question.
+ * @returns true if the array contains the SID.
+ */
+bool sid_attrs_contains_sid(const struct auth_SidAttr *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid)
+{
+ uint32_t i;
+
+ for (i = 0; i < num_sids; i++) {
+ if (dom_sid_equal(&sids[i].sid, sid)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Return true if an array of auth_SidAttr contains a certain SID with certain
+ * attributes.
+ *
+ * @param [in] sids The auth_SidAttr array.
+ * @param [in] num_sids The size of the auth_SidArray array.
+ * @param [in] sid The SID in question.
+ * @param [in] attrs The attributes of the SID.
+ * @returns true if the array contains the SID.
+ */
+bool sids_contains_sid_attrs(const struct auth_SidAttr *sids,
+ const uint32_t num_sids,
+ const struct dom_sid *sid,
+ uint32_t attrs)
+{
+ uint32_t i;
+
+ for (i = 0; i < num_sids; i++) {
+ if (attrs != sids[i].attrs) {
+ continue;
+ }
+ if (!dom_sid_equal(&sids[i].sid, sid)) {
+ continue;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+/*
+ * See [MS-LSAT] 3.1.1.1.1 Predefined Translation Database and Corresponding View
+ */
+struct predefined_name_mapping {
+ const char *name;
+ enum lsa_SidType type;
+ struct dom_sid sid;
+};
+
+struct predefined_domain_mapping {
+ const char *domain;
+ struct dom_sid sid;
+ size_t num_names;
+ const struct predefined_name_mapping *names;
+};
+
+/* S-1-${AUTHORITY} */
+#define _SID0(authority) \
+ { 1, 0, {0,0,0,0,0,authority}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+/* S-1-${AUTHORITY}-${SUB1} */
+#define _SID1(authority,sub1) \
+ { 1, 1, {0,0,0,0,0,authority}, {sub1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+/* S-1-${AUTHORITY}-${SUB1}-${SUB2} */
+#define _SID2(authority,sub1,sub2) \
+ { 1, 2, {0,0,0,0,0,authority}, {sub1,sub2,0,0,0,0,0,0,0,0,0,0,0,0,0}}
+
+/*
+ * S-1-0
+ */
+static const struct predefined_name_mapping predefined_names_S_1_0[] = {
+ {
+ .name = "NULL SID",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(0, 0), /* S-1-0-0 */
+ },
+};
+
+/*
+ * S-1-1
+ */
+static const struct predefined_name_mapping predefined_names_S_1_1[] = {
+ {
+ .name = "Everyone",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(1, 0), /* S-1-1-0 */
+ },
+};
+
+/*
+ * S-1-2
+ */
+static const struct predefined_name_mapping predefined_names_S_1_2[] = {
+ {
+ .name = "LOCAL",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(2, 0), /* S-1-2-0 */
+ },
+};
+
+/*
+ * S-1-3
+ */
+static const struct predefined_name_mapping predefined_names_S_1_3[] = {
+ {
+ .name = "CREATOR OWNER",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 0), /* S-1-3-0 */
+ },
+ {
+ .name = "CREATOR GROUP",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 1), /* S-1-3-1 */
+ },
+ {
+ .name = "CREATOR OWNER SERVER",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 0), /* S-1-3-2 */
+ },
+ {
+ .name = "CREATOR GROUP SERVER",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 1), /* S-1-3-3 */
+ },
+ {
+ .name = "OWNER RIGHTS",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(3, 4), /* S-1-3-4 */
+ },
+};
+
+/*
+ * S-1-5 only 'NT Pseudo Domain'
+ */
+static const struct predefined_name_mapping predefined_names_S_1_5p[] = {
+ {
+ .name = "NT Pseudo Domain",
+ .type = SID_NAME_DOMAIN,
+ .sid = _SID0(5), /* S-1-5 */
+ },
+};
+
+/*
+ * S-1-5 'NT AUTHORITY'
+ */
+static const struct predefined_name_mapping predefined_names_S_1_5a[] = {
+ {
+ .name = "DIALUP",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 1), /* S-1-5-1 */
+ },
+ {
+ .name = "NETWORK",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 2), /* S-1-5-2 */
+ },
+ {
+ .name = "BATCH",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 3), /* S-1-5-3 */
+ },
+ {
+ .name = "INTERACTIVE",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 4), /* S-1-5-4 */
+ },
+ {
+ .name = "SERVICE",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 6), /* S-1-5-6 */
+ },
+ {
+ .name = "ANONYMOUS LOGON",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 7), /* S-1-5-7 */
+ },
+ {
+ .name = "PROXY",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 8), /* S-1-5-8 */
+ },
+ {
+ .name = "ENTERPRISE DOMAIN CONTROLLERS",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 9), /* S-1-5-9 */
+ },
+ {
+ .name = "SELF",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 10), /* S-1-5-10 */
+ },
+ {
+ .name = "Authenticated Users",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 11), /* S-1-5-11 */
+ },
+ {
+ .name = "RESTRICTED",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 12), /* S-1-5-12 */
+ },
+ {
+ .name = "TERMINAL SERVER USER",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 13), /* S-1-5-13 */
+ },
+ {
+ .name = "REMOTE INTERACTIVE LOGON",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 14), /* S-1-5-14 */
+ },
+ {
+ .name = "This Organization",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 15), /* S-1-5-15 */
+ },
+ {
+ .name = "IUSR",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 17), /* S-1-5-17 */
+ },
+ {
+ .name = "SYSTEM",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 18), /* S-1-5-18 */
+ },
+ {
+ .name = "LOCAL SERVICE",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 19), /* S-1-5-19 */
+ },
+ {
+ .name = "NETWORK SERVICE",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 20), /* S-1-5-20 */
+ },
+ {
+ .name = "WRITE RESTRICTED",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 33), /* S-1-5-33 */
+ },
+ {
+ .name = "Other Organization",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID1(5, 1000), /* S-1-5-1000 */
+ },
+};
+
+/*
+ * S-1-5-32
+ */
+static const struct predefined_name_mapping predefined_names_S_1_5_32[] = {
+ {
+ .name = "BUILTIN",
+ .type = SID_NAME_DOMAIN,
+ .sid = _SID1(5, 32), /* S-1-5-32 */
+ },
+};
+
+/*
+ * S-1-5-64
+ */
+static const struct predefined_name_mapping predefined_names_S_1_5_64[] = {
+ {
+ .name = "NTLM Authentication",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID2(5, 64, 10), /* S-1-5-64-10 */
+ },
+ {
+ .name = "SChannel Authentication",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID2(5, 64, 14), /* S-1-5-64-14 */
+ },
+ {
+ .name = "Digest Authentication",
+ .type = SID_NAME_WKN_GRP,
+ .sid = _SID2(5, 64, 21), /* S-1-5-64-21 */
+ },
+};
+
+/*
+ * S-1-7
+ */
+static const struct predefined_name_mapping predefined_names_S_1_7[] = {
+ {
+ .name = "Internet$",
+ .type = SID_NAME_DOMAIN,
+ .sid = _SID0(7), /* S-1-7 */
+ },
+};
+
+/*
+ * S-1-16
+ */
+static const struct predefined_name_mapping predefined_names_S_1_16[] = {
+ {
+ .name = "Mandatory Label",
+ .type = SID_NAME_DOMAIN,
+ .sid = _SID0(16), /* S-1-16 */
+ },
+ {
+ .name = "Untrusted Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 0), /* S-1-16-0 */
+ },
+ {
+ .name = "Low Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 4096), /* S-1-16-4096 */
+ },
+ {
+ .name = "Medium Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 8192), /* S-1-16-8192 */
+ },
+ {
+ .name = "High Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 12288), /* S-1-16-12288 */
+ },
+ {
+ .name = "System Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 16384), /* S-1-16-16384 */
+ },
+ {
+ .name = "Protected Process Mandatory Level",
+ .type = SID_NAME_LABEL,
+ .sid = _SID1(16, 20480), /* S-1-16-20480 */
+ },
+};
+
+static const struct predefined_domain_mapping predefined_domains[] = {
+ {
+ .domain = "",
+ .sid = _SID0(0), /* S-1-0 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_0),
+ .names = predefined_names_S_1_0,
+ },
+ {
+ .domain = "",
+ .sid = _SID0(1), /* S-1-1 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_1),
+ .names = predefined_names_S_1_1,
+ },
+ {
+ .domain = "",
+ .sid = _SID0(2), /* S-1-2 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_2),
+ .names = predefined_names_S_1_2,
+ },
+ {
+ .domain = "",
+ .sid = _SID0(3), /* S-1-3 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_3),
+ .names = predefined_names_S_1_3,
+ },
+ {
+ .domain = "",
+ .sid = _SID0(3), /* S-1-3 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_3),
+ .names = predefined_names_S_1_3,
+ },
+ /*
+ * S-1-5 is split here
+ *
+ * 'NT Pseudo Domain' has precedence before 'NT AUTHORITY'.
+ *
+ * In a LookupSids with multiple sids e.g. S-1-5 and S-1-5-7
+ * the domain section (struct lsa_DomainInfo) gets
+ * 'NT Pseudo Domain' with S-1-5. If asked in reversed order
+ * S-1-5-7 and then S-1-5, you get struct lsa_DomainInfo
+ * with 'NT AUTHORITY' and S-1-5.
+ */
+ {
+ .domain = "NT Pseudo Domain",
+ .sid = _SID0(5), /* S-1-5 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_5p),
+ .names = predefined_names_S_1_5p,
+ },
+ {
+ .domain = "NT AUTHORITY",
+ .sid = _SID0(5), /* S-1-5 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_5a),
+ .names = predefined_names_S_1_5a,
+ },
+ {
+ .domain = "BUILTIN",
+ .sid = _SID1(5, 32), /* S-1-5-32 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_5_32),
+ .names = predefined_names_S_1_5_32,
+ },
+ /*
+ * 'NT AUTHORITY' again with S-1-5-64 this time
+ */
+ {
+ .domain = "NT AUTHORITY",
+ .sid = _SID1(5, 64), /* S-1-5-64 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_5_64),
+ .names = predefined_names_S_1_5_64,
+ },
+ {
+ .domain = "Internet$",
+ .sid = _SID0(7), /* S-1-7 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_7),
+ .names = predefined_names_S_1_7,
+ },
+ {
+ .domain = "Mandatory Label",
+ .sid = _SID0(16), /* S-1-16 */
+ .num_names = ARRAY_SIZE(predefined_names_S_1_16),
+ .names = predefined_names_S_1_16,
+ },
+};
+
+NTSTATUS dom_sid_lookup_predefined_name(const char *name,
+ const struct dom_sid **sid,
+ enum lsa_SidType *type,
+ const struct dom_sid **authority_sid,
+ const char **authority_name)
+{
+ size_t di;
+ const char *domain = "";
+ size_t domain_len = 0;
+ const char *p;
+ bool match;
+
+ *sid = NULL;
+ *type = SID_NAME_UNKNOWN;
+ *authority_sid = NULL;
+ *authority_name = NULL;
+
+ if (name == NULL) {
+ name = "";
+ }
+
+ p = strchr(name, '\\');
+ if (p != NULL) {
+ domain = name;
+ domain_len = PTR_DIFF(p, domain);
+ name = p + 1;
+ }
+
+ match = strequal(name, "");
+ if (match) {
+ /*
+ * Strange, but that's what W2012R2 does.
+ */
+ name = "BUILTIN";
+ }
+
+ for (di = 0; di < ARRAY_SIZE(predefined_domains); di++) {
+ const struct predefined_domain_mapping *d =
+ &predefined_domains[di];
+ size_t ni;
+
+ if (domain_len != 0) {
+ int cmp;
+
+ cmp = strncasecmp(d->domain, domain, domain_len);
+ if (cmp != 0) {
+ continue;
+ }
+ }
+
+ for (ni = 0; ni < d->num_names; ni++) {
+ const struct predefined_name_mapping *n =
+ &d->names[ni];
+
+ match = strequal(n->name, name);
+ if (!match) {
+ continue;
+ }
+
+ *sid = &n->sid;
+ *type = n->type;
+ *authority_sid = &d->sid;
+ *authority_name = d->domain;
+ return NT_STATUS_OK;
+ }
+ }
+
+ return NT_STATUS_NONE_MAPPED;
+}
+
+bool dom_sid_lookup_is_predefined_domain(const char *domain)
+{
+ size_t di;
+ bool match;
+
+ if (domain == NULL) {
+ domain = "";
+ }
+
+ match = strequal(domain, "");
+ if (match) {
+ /*
+ * Strange, but that's what W2012R2 does.
+ */
+ domain = "BUILTIN";
+ }
+
+ for (di = 0; di < ARRAY_SIZE(predefined_domains); di++) {
+ const struct predefined_domain_mapping *d =
+ &predefined_domains[di];
+ int cmp;
+
+ cmp = strcasecmp(d->domain, domain);
+ if (cmp != 0) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+NTSTATUS dom_sid_lookup_predefined_sid(const struct dom_sid *sid,
+ const char **name,
+ enum lsa_SidType *type,
+ const struct dom_sid **authority_sid,
+ const char **authority_name)
+{
+ size_t di;
+ bool match_domain = false;
+
+ *name = NULL;
+ *type = SID_NAME_UNKNOWN;
+ *authority_sid = NULL;
+ *authority_name = NULL;
+
+ if (sid == NULL) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ for (di = 0; di < ARRAY_SIZE(predefined_domains); di++) {
+ const struct predefined_domain_mapping *d =
+ &predefined_domains[di];
+ size_t ni;
+ int cmp;
+
+ cmp = dom_sid_compare_auth(&d->sid, sid);
+ if (cmp != 0) {
+ continue;
+ }
+
+ match_domain = true;
+
+ for (ni = 0; ni < d->num_names; ni++) {
+ const struct predefined_name_mapping *n =
+ &d->names[ni];
+
+ cmp = dom_sid_compare(&n->sid, sid);
+ if (cmp != 0) {
+ continue;
+ }
+
+ *name = n->name;
+ *type = n->type;
+ *authority_sid = &d->sid;
+ *authority_name = d->domain;
+ return NT_STATUS_OK;
+ }
+ }
+
+ if (!match_domain) {
+ return NT_STATUS_INVALID_SID;
+ }
+
+ return NT_STATUS_NONE_MAPPED;
+}
diff --git a/libcli/security/wscript_build b/libcli/security/wscript_build
new file mode 100644
index 0000000..db8a9b9
--- /dev/null
+++ b/libcli/security/wscript_build
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_LIBRARY('samba-security',
+ source=['dom_sid.c',
+ 'display_sec.c', 'secace.c', 'secacl.c',
+ 'security_descriptor.c', 'sddl.c', 'privileges.c',
+ 'security_token.c', 'access_check.c',
+ 'object_tree.c', 'create_descriptor.c',
+ 'util_sid.c', 'session.c', 'secdesc.c',
+ 'conditional_ace.c', 'sddl_conditional_ace.c',
+ 'claims-conversions.c'],
+ private_library=True,
+ deps='stable_sort talloc ndr NDR_SECURITY NDR_CONDITIONAL_ACE')
+
+pytalloc_util = bld.pyembed_libname('pytalloc-util')
+bld.SAMBA_PYTHON('pysecurity',
+ source='pysecurity.c',
+ deps='samba-security %s' % pytalloc_util,
+ realname='samba/security.so'
+ )
+
+bld.SAMBA_BINARY(
+ 'test_sddl_conditional_ace',
+ source='tests/test_sddl_conditional_ace.c',
+ deps='''
+ cmocka
+ talloc
+ samba-util
+ asn1util
+ NDR_SECURITY
+ samba-security
+ ''',
+ for_selftest=True
+)
+
+bld.SAMBA_BINARY(
+ 'test_run_conditional_ace',
+ source='tests/test_run_conditional_ace.c',
+ deps='''
+ cmocka
+ talloc
+ samba-util
+ asn1util
+ NDR_SECURITY
+ samba-security
+ ''',
+ for_selftest=True
+)
+
+bld.SAMBA_BINARY(
+ 'test_claim_conversion',
+ source='tests/test_claim_conversion.c',
+ deps='''
+ cmocka
+ talloc
+ samba-util
+ asn1util
+ NDR_SECURITY
+ NDR_CLAIMS
+ samba-security
+ ''',
+ for_selftest=True
+)
diff --git a/libcli/smb/py_reparse_symlink.c b/libcli/smb/py_reparse_symlink.c
new file mode 100644
index 0000000..5626e27
--- /dev/null
+++ b/libcli/smb/py_reparse_symlink.c
@@ -0,0 +1,198 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 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 "replace.h"
+#include "python/modules.h"
+#include "python/py3compat.h"
+#include "libcli/util/pyerrors.h"
+#include "reparse.h"
+#include "lib/util/iov_buf.h"
+#include "smb_constants.h"
+
+static PyObject *py_reparse_put(PyObject *module, PyObject *args)
+{
+ char *reparse = NULL;
+ Py_ssize_t reparse_len;
+ unsigned long long tag = 0;
+ unsigned reserved = 0;
+ uint8_t *buf = NULL;
+ ssize_t buflen;
+ PyObject *result = NULL;
+ struct reparse_data_buffer reparse_buf = {};
+ bool ok;
+
+ ok = PyArg_ParseTuple(
+ args,
+ "Kk"PYARG_BYTES_LEN":put",
+ &tag,
+ &reserved,
+ &reparse,
+ &reparse_len);
+ if (!ok) {
+ return NULL;
+ }
+
+ reparse_buf.tag = tag;
+ reparse_buf.parsed.raw.data = (uint8_t *)reparse;
+ reparse_buf.parsed.raw.length = reparse_len;
+ reparse_buf.parsed.raw.reserved = reserved;
+
+ buflen = reparse_data_buffer_marshall(&reparse_buf, NULL, 0);
+ if (buflen == -1) {
+ errno = EINVAL;
+ PyErr_SetFromErrno(PyExc_RuntimeError);
+ return NULL;
+ }
+ buf = talloc_array(NULL, uint8_t, buflen);
+ if (buf == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ reparse_data_buffer_marshall(&reparse_buf, buf, buflen);
+
+ result = PyBytes_FromStringAndSize((char *)buf, buflen);
+ TALLOC_FREE(buf);
+ return result;
+}
+
+static PyObject *py_reparse_symlink_put(PyObject *module, PyObject *args)
+{
+ int unparsed = 0;
+ int flags = 0;
+ struct reparse_data_buffer reparse = {
+ .tag = IO_REPARSE_TAG_SYMLINK,
+ };
+ struct symlink_reparse_struct *lnk = &reparse.parsed.lnk;
+ uint8_t stackbuf[1024];
+ uint8_t *buf = stackbuf;
+ ssize_t buflen = sizeof(stackbuf);
+ PyObject *result = NULL;
+ bool ok;
+
+ ok = PyArg_ParseTuple(args,
+ "ssii:symlink_put",
+ &lnk->substitute_name,
+ &lnk->print_name,
+ &unparsed,
+ &flags);
+ if (!ok) {
+ return NULL;
+ }
+ lnk->unparsed_path_length = unparsed;
+ lnk->flags = flags;
+
+ buflen = reparse_data_buffer_marshall(&reparse, buf, buflen);
+
+ if ((buflen > 0) && ((size_t)buflen > sizeof(stackbuf))) {
+ buf = malloc(buflen);
+ buflen = reparse_data_buffer_marshall(&reparse, buf, buflen);
+ }
+
+ if (buflen == -1) {
+ PyErr_NoMemory();
+ } else {
+ result = PyBytes_FromStringAndSize((char *)buf, buflen);
+ }
+
+ if (buf != stackbuf) {
+ free(buf);
+ }
+
+ return result;
+}
+
+static PyObject *py_reparse_symlink_get(PyObject *module, PyObject *args)
+{
+ char *buf = NULL;
+ Py_ssize_t buflen;
+ struct reparse_data_buffer *syml = NULL;
+ struct symlink_reparse_struct *lnk = NULL;
+ PyObject *result = NULL;
+ NTSTATUS status;
+ bool ok;
+
+ ok = PyArg_ParseTuple(args, PYARG_BYTES_LEN ":get", &buf, &buflen);
+ if (!ok) {
+ return NULL;
+ }
+
+ syml = talloc(NULL, struct reparse_data_buffer);
+ if (syml == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ status = reparse_data_buffer_parse(syml, syml, (uint8_t *)buf, buflen);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(syml);
+ PyErr_SetNTSTATUS(status);
+ return NULL;
+ }
+
+ if (syml->tag != IO_REPARSE_TAG_SYMLINK) {
+ TALLOC_FREE(syml);
+ PyErr_SetNTSTATUS(NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return NULL;
+ }
+ lnk = &syml->parsed.lnk;
+
+ result = Py_BuildValue("ssII",
+ lnk->substitute_name,
+ lnk->print_name,
+ (unsigned)lnk->unparsed_path_length,
+ (unsigned)lnk->flags);
+
+ TALLOC_FREE(syml);
+ return result;
+}
+
+static PyMethodDef py_reparse_symlink_methods[] = {
+ { "put",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_reparse_put),
+ METH_VARARGS,
+ "Create a reparse point blob"},
+ { "symlink_put",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_reparse_symlink_put),
+ METH_VARARGS,
+ "Create a reparse symlink blob"},
+ { "symlink_get",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_reparse_symlink_get),
+ METH_VARARGS,
+ "Parse a reparse symlink blob"},
+ {0},
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "reparse_symlink",
+ .m_doc = "[un]marshall reparse symlink blobs",
+ .m_size = -1,
+ .m_methods = py_reparse_symlink_methods,
+};
+
+MODULE_INIT_FUNC(reparse_symlink)
+{
+ PyObject *m;
+
+ m = PyModule_Create(&moduledef);
+ if (m == NULL)
+ return NULL;
+
+ return m;
+}
diff --git a/libcli/smb/read_smb.c b/libcli/smb/read_smb.c
new file mode 100644
index 0000000..a40f702
--- /dev/null
+++ b/libcli/smb/read_smb.c
@@ -0,0 +1,114 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "lib/async_req/async_sock.h"
+#include "read_smb.h"
+#include "lib/util/tevent_unix.h"
+#include "libcli/smb/smb_constants.h"
+
+/*
+ * Read an smb packet asynchronously, discard keepalives
+ */
+
+struct read_smb_state {
+ struct tevent_context *ev;
+ int fd;
+ uint8_t *buf;
+};
+
+static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data);
+static void read_smb_done(struct tevent_req *subreq);
+
+struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd)
+{
+ struct tevent_req *result, *subreq;
+ struct read_smb_state *state;
+
+ result = tevent_req_create(mem_ctx, &state, struct read_smb_state);
+ if (result == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->fd = fd;
+
+ subreq = read_packet_send(state, ev, fd, 4, read_smb_more, NULL);
+ if (subreq == NULL) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, read_smb_done, result);
+ return result;
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data)
+{
+ if (buflen > 4) {
+ return 0; /* We've been here, we're done */
+ }
+ return smb_len_tcp(buf);
+}
+
+static void read_smb_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct read_smb_state *state = tevent_req_data(
+ req, struct read_smb_state);
+ ssize_t len;
+ int err;
+
+ len = read_packet_recv(subreq, state, &state->buf, &err);
+ TALLOC_FREE(subreq);
+ if (len == -1) {
+ tevent_req_error(req, err);
+ return;
+ }
+
+ if (CVAL(state->buf, 0) == NBSSkeepalive) {
+ subreq = read_packet_send(state, state->ev, state->fd, 4,
+ read_smb_more, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, read_smb_done, req);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **pbuf, int *perrno)
+{
+ struct read_smb_state *state = tevent_req_data(
+ req, struct read_smb_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);
+}
diff --git a/libcli/smb/read_smb.h b/libcli/smb/read_smb.h
new file mode 100644
index 0000000..1df2dc2
--- /dev/null
+++ b/libcli/smb/read_smb.h
@@ -0,0 +1,33 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 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 __LIBSMB_READ_SMB_H
+#define __LIBSMB_READ_SMB_H
+
+struct tevent_context;
+struct tevent_req;
+
+struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int fd);
+
+ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **pbuf, int *perrno);
+
+#endif
diff --git a/libcli/smb/reparse.c b/libcli/smb/reparse.c
new file mode 100644
index 0000000..49ecc77
--- /dev/null
+++ b/libcli/smb/reparse.c
@@ -0,0 +1,567 @@
+/*
+ * 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 "libcli/smb/reparse.h"
+#include "lib/util/iov_buf.h"
+#include "libcli/smb/smb_constants.h"
+#include "libcli/util/error.h"
+#include "lib/util/debug.h"
+#include "lib/util/bytearray.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/charset/charset.h"
+#include "smb_util.h"
+
+static NTSTATUS reparse_buffer_check(const uint8_t *in_data,
+ size_t in_len,
+ uint32_t *reparse_tag,
+ const uint8_t **_reparse_data,
+ size_t *_reparse_data_length)
+{
+ uint16_t reparse_data_length;
+
+ if (in_len == 0) {
+ DBG_DEBUG("in_len=0\n");
+ return NT_STATUS_INVALID_BUFFER_SIZE;
+ }
+ if (in_len < 8) {
+ DBG_DEBUG("in_len=%zu\n", in_len);
+ return NT_STATUS_IO_REPARSE_DATA_INVALID;
+ }
+
+ reparse_data_length = PULL_LE_U16(in_data, 4);
+
+ if (reparse_data_length > (in_len - 8)) {
+ DBG_DEBUG("in_len=%zu, reparse_data_length=%" PRIu16 "\n",
+ in_len,
+ reparse_data_length);
+ return NT_STATUS_IO_REPARSE_DATA_INVALID;
+ }
+
+ *reparse_tag = PULL_LE_U32(in_data, 0);
+ *_reparse_data = in_data + 8;
+ *_reparse_data_length = reparse_data_length;
+
+ return NT_STATUS_OK;
+}
+
+static int nfs_reparse_buffer_parse(TALLOC_CTX *mem_ctx,
+ struct nfs_reparse_data_buffer *dst,
+ const uint8_t *src,
+ size_t srclen)
+{
+ uint64_t type;
+
+ if (srclen < 8) {
+ DBG_DEBUG("srclen=%zu too short\n", srclen);
+ return EINVAL;
+ }
+
+ type = PULL_LE_U64(src, 0);
+
+ switch (type) {
+ case NFS_SPECFILE_CHR:
+ FALL_THROUGH;
+ case NFS_SPECFILE_BLK:
+ if (srclen < 16) {
+ DBG_DEBUG("srclen %zu too short for type %" PRIx64 "\n",
+ srclen,
+ type);
+ return EINVAL;
+ }
+ dst->data.dev.major = PULL_LE_U32(src, 8);
+ dst->data.dev.minor = PULL_LE_U32(src, 12);
+ break;
+ case NFS_SPECFILE_LNK: {
+ bool ok;
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16,
+ CH_UNIX,
+ src + 8,
+ srclen - 8,
+ &dst->data.lnk_target,
+ NULL);
+ if (!ok) {
+ return errno;
+ }
+ break;
+ }
+ case NFS_SPECFILE_FIFO:
+ break; /* empty, no data */
+ case NFS_SPECFILE_SOCK:
+ break; /* empty, no data */
+ default:
+ DBG_DEBUG("Unknown NFS reparse type %" PRIx64 "\n", type);
+ return EINVAL;
+ }
+
+ dst->type = type;
+
+ return 0;
+}
+
+static int symlink_reparse_buffer_parse(TALLOC_CTX *mem_ctx,
+ struct symlink_reparse_struct *dst,
+ const uint8_t *src,
+ size_t srclen)
+{
+ uint16_t reparse_data_length;
+ uint16_t substitute_name_offset, substitute_name_length;
+ uint16_t print_name_offset, print_name_length;
+ bool ok;
+
+ if (srclen < 20) {
+ DBG_DEBUG("srclen = %zu, expected >= 20\n", srclen);
+ return EINVAL;
+ }
+ if (PULL_LE_U32(src, 0) != IO_REPARSE_TAG_SYMLINK) {
+ DBG_DEBUG("Got ReparseTag %8.8x, expected %8.8x\n",
+ PULL_LE_U32(src, 0),
+ IO_REPARSE_TAG_SYMLINK);
+ return EINVAL;
+ }
+
+ reparse_data_length = PULL_LE_U16(src, 4);
+ substitute_name_offset = PULL_LE_U16(src, 8);
+ substitute_name_length = PULL_LE_U16(src, 10);
+ print_name_offset = PULL_LE_U16(src, 12);
+ print_name_length = PULL_LE_U16(src, 14);
+
+ if (reparse_data_length < 12) {
+ DBG_DEBUG("reparse_data_length = %"PRIu16", expected >= 12\n",
+ reparse_data_length);
+ return EINVAL;
+ }
+ if (smb_buffer_oob(srclen - 8, reparse_data_length, 0)) {
+ DBG_DEBUG("reparse_data_length (%"PRIu16") too large for "
+ "src_len (%zu)\n",
+ reparse_data_length,
+ srclen);
+ return EINVAL;
+ }
+ if (smb_buffer_oob(reparse_data_length - 12, substitute_name_offset,
+ substitute_name_length)) {
+ DBG_DEBUG("substitute_name (%"PRIu16"/%"PRIu16") does not fit "
+ "in reparse_data_length (%"PRIu16")\n",
+ substitute_name_offset,
+ substitute_name_length,
+ reparse_data_length - 12);
+ return EINVAL;
+ }
+ if (smb_buffer_oob(reparse_data_length - 12, print_name_offset,
+ print_name_length)) {
+ DBG_DEBUG("print_name (%"PRIu16"/%"PRIu16") does not fit in "
+ "reparse_data_length (%"PRIu16")\n",
+ print_name_offset,
+ print_name_length,
+ reparse_data_length - 12);
+ return EINVAL;
+ }
+
+ *dst = (struct symlink_reparse_struct) {
+ .unparsed_path_length = PULL_LE_U16(src, 6),
+ .flags = PULL_LE_U32(src, 16),
+ };
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16,
+ CH_UNIX,
+ src + 20 + substitute_name_offset,
+ substitute_name_length,
+ &dst->substitute_name,
+ NULL);
+ if (!ok) {
+ int ret = errno;
+ DBG_DEBUG("convert_string_talloc for substitute_name "
+ "failed\n");
+ return ret;
+ }
+
+ ok = convert_string_talloc(mem_ctx,
+ CH_UTF16,
+ CH_UNIX,
+ src + 20 + print_name_offset,
+ print_name_length,
+ &dst->print_name,
+ NULL);
+ if (!ok) {
+ int ret = errno;
+ DBG_DEBUG("convert_string_talloc for print_name failed\n");
+ TALLOC_FREE(dst->substitute_name);
+ return ret;
+ }
+
+ return 0;
+}
+
+NTSTATUS reparse_data_buffer_parse(TALLOC_CTX *mem_ctx,
+ struct reparse_data_buffer *dst,
+ const uint8_t *buf,
+ size_t buflen)
+{
+ const uint8_t *reparse_data;
+ size_t reparse_data_length;
+ NTSTATUS status;
+ int ret;
+
+ status = reparse_buffer_check(buf,
+ buflen,
+ &dst->tag,
+ &reparse_data,
+ &reparse_data_length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ switch (dst->tag) {
+ case IO_REPARSE_TAG_SYMLINK:
+ ret = symlink_reparse_buffer_parse(mem_ctx,
+ &dst->parsed.lnk,
+ buf,
+ buflen);
+ if (ret != 0) {
+ return map_nt_error_from_unix_common(ret);
+ }
+ break;
+ case IO_REPARSE_TAG_NFS:
+ ret = nfs_reparse_buffer_parse(mem_ctx,
+ &dst->parsed.nfs,
+ reparse_data,
+ reparse_data_length);
+ if (ret != 0) {
+ return map_nt_error_from_unix_common(ret);
+ }
+ break;
+ default:
+ dst->parsed.raw.data = talloc_memdup(mem_ctx,
+ reparse_data,
+ reparse_data_length);
+ if (dst->parsed.raw.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ dst->parsed.raw.length = reparse_data_length;
+ dst->parsed.raw.reserved = PULL_LE_U16(buf, 6);
+ break;
+ }
+
+ return NT_STATUS_OK;
+}
+
+char *reparse_data_buffer_str(TALLOC_CTX *mem_ctx,
+ const struct reparse_data_buffer *dst)
+{
+ char *s = talloc_strdup(mem_ctx, "");
+
+ switch (dst->tag) {
+ case IO_REPARSE_TAG_SYMLINK: {
+ const struct symlink_reparse_struct *lnk = &dst->parsed.lnk;
+ talloc_asprintf_addbuf(&s,
+ "0x%" PRIx32
+ " (IO_REPARSE_TAG_SYMLINK)\n",
+ dst->tag);
+ talloc_asprintf_addbuf(&s,
+ "unparsed=%" PRIu16 "\n",
+ lnk->unparsed_path_length);
+ talloc_asprintf_addbuf(&s,
+ "substitute_name=%s\n",
+ lnk->substitute_name);
+ talloc_asprintf_addbuf(&s, "print_name=%s\n", lnk->print_name);
+ talloc_asprintf_addbuf(&s, "flags=%" PRIu32 "\n", lnk->flags);
+ break;
+ }
+ case IO_REPARSE_TAG_NFS: {
+ const struct nfs_reparse_data_buffer *nfs = &dst->parsed.nfs;
+
+ talloc_asprintf_addbuf(&s,
+ "0x%" PRIx32 " (IO_REPARSE_TAG_NFS)\n",
+ dst->tag);
+
+ switch (nfs->type) {
+ case NFS_SPECFILE_FIFO:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_FIFO)\n",
+ nfs->type);
+ break;
+ case NFS_SPECFILE_SOCK:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_SOCK)\n",
+ nfs->type);
+ break;
+ case NFS_SPECFILE_LNK:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_LNK)\n",
+ nfs->type);
+ talloc_asprintf_addbuf(&s,
+ " -> %s\n ",
+ nfs->data.lnk_target);
+ break;
+ case NFS_SPECFILE_BLK:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_BLK)\n",
+ nfs->type);
+ talloc_asprintf_addbuf(&s,
+ " %" PRIu32 "/%" PRIu32 "\n",
+ nfs->data.dev.major,
+ nfs->data.dev.minor);
+ break;
+ case NFS_SPECFILE_CHR:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIx64
+ " (NFS_SPECFILE_CHR)\n",
+ nfs->type);
+ talloc_asprintf_addbuf(&s,
+ " %" PRIu32 "/%" PRIu32 "\n",
+ nfs->data.dev.major,
+ nfs->data.dev.minor);
+ break;
+ default:
+ talloc_asprintf_addbuf(&s,
+ " 0x%" PRIu64
+ " (Unknown type)\n",
+ nfs->type);
+ break;
+ }
+ break;
+ }
+ default:
+ talloc_asprintf_addbuf(&s, "%" PRIu32 "\n", dst->tag);
+ break;
+ }
+ return s;
+}
+
+static ssize_t reparse_buffer_marshall(uint32_t reparse_tag,
+ uint16_t reserved,
+ const struct iovec *iov,
+ int iovlen,
+ uint8_t *buf,
+ size_t buflen)
+{
+ ssize_t reparse_data_length = iov_buflen(iov, iovlen);
+ size_t needed;
+
+ if (reparse_data_length == -1) {
+ return -1;
+ }
+ if (reparse_data_length > UINT16_MAX) {
+ return -1;
+ }
+
+ needed = reparse_data_length + 8;
+ if (needed < reparse_data_length) {
+ return -1;
+ }
+
+ if (buflen >= needed) {
+ PUSH_LE_U32(buf, 0, reparse_tag);
+ PUSH_LE_U16(buf, 4, reparse_data_length);
+ PUSH_LE_U16(buf, 6, reserved);
+ iov_buf(iov, iovlen, buf + 8, buflen - 8);
+ }
+
+ return needed;
+}
+
+static ssize_t
+reparse_data_buffer_marshall_syml(const struct symlink_reparse_struct *src,
+ uint8_t *buf,
+ size_t buflen)
+{
+ uint8_t sbuf[12];
+ struct iovec iov[3];
+ const char *print_name = src->print_name;
+ uint8_t *subst_utf16 = NULL;
+ uint8_t *print_utf16 = NULL;
+ size_t subst_len = 0;
+ size_t print_len = 0;
+ ssize_t ret = -1;
+ bool ok;
+
+ if (src->substitute_name == NULL) {
+ return -1;
+ }
+ if (src->print_name == NULL) {
+ print_name = src->substitute_name;
+ }
+
+ iov[0] = (struct iovec){
+ .iov_base = sbuf,
+ .iov_len = sizeof(sbuf),
+ };
+
+ ok = convert_string_talloc(talloc_tos(),
+ CH_UNIX,
+ CH_UTF16,
+ src->substitute_name,
+ strlen(src->substitute_name),
+ &subst_utf16,
+ &subst_len);
+ if (!ok) {
+ goto fail;
+ }
+ if (subst_len > UINT16_MAX) {
+ goto fail;
+ }
+ iov[1] = (struct iovec){
+ .iov_base = subst_utf16,
+ .iov_len = subst_len,
+ };
+
+ ok = convert_string_talloc(talloc_tos(),
+ CH_UNIX,
+ CH_UTF16,
+ print_name,
+ strlen(print_name),
+ &print_utf16,
+ &print_len);
+ if (!ok) {
+ goto fail;
+ }
+ if (print_len > UINT16_MAX) {
+ goto fail;
+ }
+ iov[2] = (struct iovec){
+ .iov_base = print_utf16,
+ .iov_len = print_len,
+ };
+
+ PUSH_LE_U16(sbuf, 0, 0); /* SubstituteNameOffset */
+ PUSH_LE_U16(sbuf, 2, subst_len); /* SubstituteNameLength */
+ PUSH_LE_U16(sbuf, 4, subst_len); /* PrintNameOffset */
+ PUSH_LE_U16(sbuf, 6, print_len); /* PrintNameLength */
+ PUSH_LE_U32(sbuf, 8, src->flags); /* Flags */
+
+ ret = reparse_buffer_marshall(IO_REPARSE_TAG_SYMLINK,
+ src->unparsed_path_length,
+ iov,
+ ARRAY_SIZE(iov),
+ buf,
+ buflen);
+
+fail:
+ TALLOC_FREE(subst_utf16);
+ TALLOC_FREE(print_utf16);
+ return ret;
+}
+
+static ssize_t
+reparse_data_buffer_marshall_nfs(const struct nfs_reparse_data_buffer *src,
+ uint8_t *buf,
+ size_t buflen)
+{
+ uint8_t typebuf[8];
+ uint8_t devbuf[8];
+ struct iovec iov[2] = {};
+ size_t iovlen;
+ uint8_t *lnk_utf16 = NULL;
+ size_t lnk_len = 0;
+ ssize_t ret;
+
+ PUSH_LE_U64(typebuf, 0, src->type);
+ iov[0] = (struct iovec){
+ .iov_base = typebuf,
+ .iov_len = sizeof(typebuf),
+ };
+ iovlen = 1;
+
+ switch (src->type) {
+ case NFS_SPECFILE_LNK: {
+ bool ok = convert_string_talloc(talloc_tos(),
+ CH_UNIX,
+ CH_UTF16,
+ src->data.lnk_target,
+ strlen(src->data.lnk_target),
+ &lnk_utf16,
+ &lnk_len);
+ if (!ok) {
+ return -1;
+ }
+ iov[1] = (struct iovec){
+ .iov_base = lnk_utf16,
+ .iov_len = lnk_len,
+ };
+ iovlen = 2;
+ break;
+ }
+ case NFS_SPECFILE_CHR:
+ FALL_THROUGH;
+ case NFS_SPECFILE_BLK:
+ PUSH_LE_U32(devbuf, 0, src->data.dev.major);
+ PUSH_LE_U32(devbuf, 4, src->data.dev.minor);
+ iov[1] = (struct iovec){
+ .iov_base = devbuf,
+ .iov_len = sizeof(devbuf),
+ };
+ iovlen = 2;
+ break;
+ default:
+ break;
+ /* Nothing to do for NFS_SPECFILE_FIFO and _SOCK */
+ }
+
+ ret = reparse_buffer_marshall(IO_REPARSE_TAG_NFS,
+ 0,
+ iov,
+ iovlen,
+ buf,
+ buflen);
+ TALLOC_FREE(lnk_utf16);
+ return ret;
+}
+
+ssize_t reparse_data_buffer_marshall(const struct reparse_data_buffer *src,
+ uint8_t *buf,
+ size_t buflen)
+{
+ ssize_t ret = -1;
+
+ switch (src->tag) {
+ case IO_REPARSE_TAG_SYMLINK:
+
+ ret = reparse_data_buffer_marshall_syml(&src->parsed.lnk,
+ buf,
+ buflen);
+ break;
+
+ case IO_REPARSE_TAG_NFS:
+
+ ret = reparse_data_buffer_marshall_nfs(&src->parsed.nfs,
+ buf,
+ buflen);
+ break;
+
+ default: {
+ struct iovec iov = {
+ .iov_base = src->parsed.raw.data,
+ .iov_len = src->parsed.raw.length,
+ };
+ ret = reparse_buffer_marshall(src->tag,
+ src->parsed.raw.reserved,
+ &iov,
+ 1,
+ buf,
+ buflen);
+ }
+ }
+
+ return ret;
+}
diff --git a/libcli/smb/reparse.h b/libcli/smb/reparse.h
new file mode 100644
index 0000000..23274bf
--- /dev/null
+++ b/libcli/smb/reparse.h
@@ -0,0 +1,77 @@
+/*
+ * 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/>.
+ */
+
+#ifndef __LIBCLI_SMB_REPARSE_H__
+#define __LIBCLI_SMB_REPARSE_H__
+
+#include <talloc.h>
+#include "replace.h"
+#include "libcli/util/ntstatus.h"
+
+struct symlink_reparse_struct {
+ uint16_t unparsed_path_length; /* reserved for the reparse point */
+ char *substitute_name;
+ char *print_name;
+ uint32_t flags;
+};
+
+struct nfs_reparse_data_buffer {
+ uint64_t type;
+
+ union {
+ char *lnk_target; /* NFS_SPECFILE_LNK */
+ struct {
+ uint32_t major;
+ uint32_t minor;
+ } dev; /* NFS_SPECFILE_[CHR|BLK] */
+
+ /* NFS_SPECFILE_[FIFO|SOCK] have no data */
+ } data;
+};
+
+struct reparse_data_buffer {
+ uint32_t tag;
+
+ union {
+ /* IO_REPARSE_TAG_NFS */
+ struct nfs_reparse_data_buffer nfs;
+
+ /* IO_REPARSE_TAG_SYMLINK */
+ struct symlink_reparse_struct lnk;
+
+ /* Unknown reparse tag */
+ struct {
+ uint16_t length;
+ uint16_t reserved;
+ uint8_t *data;
+ } raw;
+
+ } parsed;
+};
+
+NTSTATUS reparse_data_buffer_parse(TALLOC_CTX *mem_ctx,
+ struct reparse_data_buffer *dst,
+ const uint8_t *buf,
+ size_t buflen);
+char *reparse_data_buffer_str(TALLOC_CTX *mem_ctx,
+ const struct reparse_data_buffer *dst);
+
+ssize_t reparse_data_buffer_marshall(const struct reparse_data_buffer *src,
+ uint8_t *buf,
+ size_t buflen);
+
+#endif
diff --git a/libcli/smb/smb1cli_close.c b/libcli/smb/smb1cli_close.c
new file mode 100644
index 0000000..00baa58
--- /dev/null
+++ b/libcli/smb/smb1cli_close.c
@@ -0,0 +1,188 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Gregor Beck 2013
+ Copyright (C) Stefan Metzmacher 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_close_state {
+ uint16_t vwv[3];
+};
+
+static void smb1cli_close_done(struct tevent_req *subreq);
+
+/**
+ * Send an asynchronous SMB_COM_CLOSE request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee442151.aspx">MS-CIFS 2.2.4.5.1</a>
+ * @see smb1cli_close_recv(), smb1cli_close()
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ * @param[in] ev The event context to work on.
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier.
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file to be closed.
+ * @param[in] last_modified If not 0 or 0xFFFFFFFF request to set modification time to this number of seconds since January 1, 1970.
+ *
+ * @return a tevent_req or NULL.
+ */
+struct tevent_req *smb1cli_close_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint32_t last_modified)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_close_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_close_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ SSVAL(state->vwv+0, 0, fnum);
+ SIVALS(state->vwv+1, 0, last_modified);
+
+ subreq = smb1cli_req_send(state, ev, conn, SMBclose,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec, pid, tcon, session,
+ ARRAY_SIZE(state->vwv), state->vwv,
+ 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_close_done, req);
+ return req;
+}
+
+static void smb1cli_close_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_close_state *state = tevent_req_data(
+ req, struct smb1cli_close_state);
+ NTSTATUS status;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x00
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ NULL, /* recv_iov */
+ NULL, /* phdr */
+ NULL, /* wct */
+ NULL, /* vwv */
+ NULL, /* pvwv_offset */
+ NULL, /* num_bytes */
+ NULL, /* bytes */
+ NULL, /* pbytes_offset */
+ NULL, /* inbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/**
+ * Receive the response to an asynchronous SMB_COM_CLOSE request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441667.aspx">MS-CIFS 2.2.4.5.2</a>
+ *
+ * @param req A tevent_req created with smb1cli_close_send()
+ *
+ * @return NT_STATUS_OK on success
+ */
+NTSTATUS smb1cli_close_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+/**
+ * Send an synchronous SMB_COM_CLOSE request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441493.aspx">MS-CIFS 2.2.4.5</a>
+ * @see smb1cli_close_send(), smb1cli_close_recv()
+ *
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier.
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file to be closed.
+ * @param[in] last_modified If not 0 or 0xFFFFFFFF request to set modification time to this number of seconds since J
+ *
+ * @return NT_STATUS_OK on success.
+ */
+NTSTATUS smb1cli_close(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint32_t last_modified)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct tevent_req *req;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ req = smb1cli_close_send(frame, ev, conn,
+ timeout_msec, pid, tcon, session,
+ fnum, last_modified);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto done;
+ }
+
+ status = smb1cli_close_recv(req);
+done:
+ talloc_free(frame);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_create.c b/libcli/smb/smb1cli_create.c
new file mode 100644
index 0000000..fc1e16b
--- /dev/null
+++ b/libcli/smb/smb1cli_create.c
@@ -0,0 +1,296 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Gregor Beck 2013
+ Copyright (C) Stefan Metzmacher 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_ntcreatex_state {
+ uint16_t vwv[24];
+ uint16_t fnum;
+};
+
+static void smb1cli_ntcreatex_done(struct tevent_req *subreq);
+
+/**
+ * Send an asynchronous SMB_COM_NT_CREATE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee442175.aspx">MS-CIFS 2.2.4.64.1</a>
+ * @see smb1cli_ntcreatex_recv(), smb1cli_ntcreatex()
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ * @param[in] ev The event context to work on.
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fname The name of the file or directory to be opened or created.
+ * @param[in] CreatFlags
+ * @param[in] RootDirectoryFid The file id of an opened root directory fname is based on. 0 means root of the share.
+ * @param[in] DesiredAccess A field of flags that indicate standard, specific, and generic access rights to be requested.
+ * @param[in] AllocationSize Number of Bytes to allocate if the file is to be created or overwritten.
+ * @param[in] FileAttributes <a href="http://msdn.microsoft.com/en-us/library/ee878573.aspx">Extended file attributes</a>
+ * @param[in] ShareAccess A field that specifies how the file should be shared with other processes.
+ * @param[in] CreateDisposition A value that represents the action to take if the file already exists or if the file is a new file and does not already exist.
+ * @param[in] CreateOptions A field of flag options to use if creating a file or directory.
+ * @param[in] ImpersonationLevel
+ * @param[in] SecurityFlags
+ *
+ * @return a tevent_req or NULL
+ */
+struct tevent_req *smb1cli_ntcreatex_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *fname,
+ uint32_t CreatFlags,
+ uint32_t RootDirectoryFid,
+ uint32_t DesiredAccess,
+ uint64_t AllocationSize,
+ uint32_t FileAttributes,
+ uint32_t ShareAccess,
+ uint32_t CreateDisposition,
+ uint32_t CreateOptions,
+ uint32_t ImpersonationLevel,
+ uint8_t SecurityFlags)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_ntcreatex_state *state;
+ uint8_t *bytes;
+ size_t converted_len;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_ntcreatex_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ SCVAL(state->vwv+0, 0, 0xFF);
+ SCVAL(state->vwv+0, 1, 0);
+ SSVAL(state->vwv+1, 0, 0);
+ SCVAL(state->vwv+2, 0, 0);
+ SIVAL(state->vwv+3, 1, CreatFlags);
+ SIVAL(state->vwv+5, 1, RootDirectoryFid);
+ SIVAL(state->vwv+7, 1, DesiredAccess);
+ SBVAL(state->vwv+9, 1, AllocationSize);
+ SIVAL(state->vwv+13, 1, FileAttributes);
+ SIVAL(state->vwv+15, 1, ShareAccess);
+ SIVAL(state->vwv+17, 1, CreateDisposition);
+ SIVAL(state->vwv+19, 1, CreateOptions);
+ SIVAL(state->vwv+21, 1, ImpersonationLevel);
+ SCVAL(state->vwv+23, 1, SecurityFlags);
+
+ bytes = talloc_array(state, uint8_t, 0);
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(conn),
+ fname, strlen(fname)+1,
+ &converted_len);
+
+ /* sigh. this copes with broken netapp filer behaviour */
+ bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(conn), "", 1, NULL);
+
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ SSVAL(state->vwv+2, 1, converted_len);
+
+ subreq = smb1cli_req_send(state, ev, conn, SMBntcreateX,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec, pid, tcon, session,
+ ARRAY_SIZE(state->vwv), state->vwv,
+ talloc_get_size(bytes), bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_ntcreatex_done, req);
+
+ return req;
+}
+
+static void smb1cli_ntcreatex_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_ntcreatex_state *state = tevent_req_data(
+ req, struct smb1cli_ntcreatex_state);
+ struct iovec *recv_iov = NULL;
+ uint8_t wct;
+ uint16_t *vwv;
+ NTSTATUS status;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x22
+ },
+ {
+ /*
+ * This is the broken version see from
+ * [MS-SMB]:
+ * Windows-based SMB servers send 50 (0x32) words in the extended
+ * response although they set the WordCount field to 0x2A.
+ *
+ * And Samba does the same...
+ */
+ .status = NT_STATUS_OK,
+ .wct = 0x2a
+ },
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x32
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ NULL, /* phdr */
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ NULL, /* num_bytes */
+ NULL, /* bytes */
+ NULL, /* pbytes_offset */
+ NULL, /* inbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->fnum = SVAL(vwv+2, 1);
+ tevent_req_done(req);
+}
+
+/**
+ * Receive the response to an asynchronous SMB_COM_NT_CREATE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441612.aspx">MS-CIFS 2.2.4.64.2</a>
+ *
+ * @param[in] req A tevent request created with smb1cli_ntcreatex_send()
+ * @param[out] pfnum The file id of the opened file or directory.
+ *
+ * @return NT_STATUS_OK on success
+ */
+NTSTATUS smb1cli_ntcreatex_recv(struct tevent_req *req, uint16_t *pfnum)
+{
+ struct smb1cli_ntcreatex_state *state = tevent_req_data(
+ req, struct smb1cli_ntcreatex_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *pfnum = state->fnum;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Send a synchronous SMB_COM_NT_CREATE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee442091.aspx">MS-CIFS 2.2.4.64</a>
+ * @see smb1cli_ntcreatex_send() smb1cli_ntcreatex_recv()
+ *
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fname The name of the file or directory to be opened or created.
+ * @param[in] CreatFlags
+ * @param[in] RootDirectoryFid The file id of an opened root directory fname is based on. 0 means root of the share.
+ * @param[in] DesiredAccess A field of flags that indicate standard, specific, and generic access rights to be requested.
+ * @param[in] AllocationSize Number of Bytes to allocate if the file is to be created or overwritten.
+ * @param[in] FileAttributes <a href="http://msdn.microsoft.com/en-us/library/ee878573.aspx">Extended file attributes</a>
+ * @param[in] ShareAccess A field that specifies how the file should be shared with other processes.
+ * @param[in] CreateDisposition A value that represents the action to take if the file already exists or if the file is a new file and does not already exist.
+ * @param[in] CreateOptions A field of flag options to use if creating a file or directory.
+ * @param[in] ImpersonationLevel
+ * @param[in] SecurityFlags
+ * @param[out] pfnum The file id representing the file or directory created or opened.
+ *
+ * @return NT_STATUS_OK on success
+ */
+NTSTATUS smb1cli_ntcreatex(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *fname,
+ uint32_t CreatFlags,
+ uint32_t RootDirectoryFid,
+ uint32_t DesiredAccess,
+ uint64_t AllocationSize,
+ uint32_t FileAttributes,
+ uint32_t ShareAccess,
+ uint32_t CreateDisposition,
+ uint32_t CreateOptions,
+ uint32_t ImpersonationLevel,
+ uint8_t SecurityFlags,
+ uint16_t *pfnum)
+{
+ TALLOC_CTX *frame = NULL;
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
+
+ frame = talloc_stackframe();
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ req = smb1cli_ntcreatex_send(frame, ev, conn,
+ timeout_msec,
+ pid, tcon, session,
+ fname, CreatFlags, RootDirectoryFid,
+ DesiredAccess, AllocationSize,
+ FileAttributes, ShareAccess,
+ CreateDisposition, CreateOptions,
+ ImpersonationLevel, SecurityFlags);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+
+ status = smb1cli_ntcreatex_recv(req, pfnum);
+fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_echo.c b/libcli/smb/smb1cli_echo.c
new file mode 100644
index 0000000..10dff2d
--- /dev/null
+++ b/libcli/smb/smb1cli_echo.c
@@ -0,0 +1,169 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_echo_state {
+ uint16_t vwv[1];
+ DATA_BLOB data;
+ uint16_t num_echos;
+};
+
+static void smb1cli_echo_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_echo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint16_t num_echos,
+ DATA_BLOB data)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_echo_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_echo_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ SSVAL(state->vwv, 0, num_echos);
+ state->data = data;
+ state->num_echos = num_echos;
+
+ subreq = smb1cli_req_send(state, ev, conn, SMBecho,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec,
+ 0, /* pid */
+ NULL, /* tcon */
+ NULL, /* session */
+ ARRAY_SIZE(state->vwv), state->vwv,
+ data.length, data.data);
+ if (subreq == NULL) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, smb1cli_echo_done, req);
+ return req;
+ fail:
+ TALLOC_FREE(req);
+ return NULL;
+}
+
+static void smb1cli_echo_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_echo_state *state = tevent_req_data(
+ req, struct smb1cli_echo_state);
+ NTSTATUS status;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ struct iovec *recv_iov;
+ struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 1,
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ NULL, /* phdr */
+ NULL, /* pwct */
+ NULL, /* pvwv */
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ NULL, /* pinbuf */
+ expected, ARRAY_SIZE(expected));
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (num_bytes != state->data.length) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (memcmp(bytes, state->data.data, num_bytes) != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ /* TODO: do we want to verify the sequence number? */
+
+ state->num_echos -=1;
+ if (state->num_echos == 0) {
+ tevent_req_done(req);
+ return;
+ }
+
+ if (!smbXcli_req_set_pending(subreq)) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+}
+
+/**
+ * Get the result out from an echo request
+ * @param[in] req The async_req from smb1cli_echo_send
+ * @retval Did the server reply correctly?
+ */
+
+NTSTATUS smb1cli_echo_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb1cli_echo(struct smbXcli_conn *conn, uint32_t timeout_msec,
+ uint16_t num_echos, DATA_BLOB data)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb1cli_echo_send(frame, ev, conn, timeout_msec, num_echos, data);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb1cli_echo_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_read.c b/libcli/smb/smb1cli_read.c
new file mode 100644
index 0000000..877aab5
--- /dev/null
+++ b/libcli/smb/smb1cli_read.c
@@ -0,0 +1,241 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Gregor Beck 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_readx_state {
+ uint32_t size;
+ uint16_t vwv[12];
+ uint32_t received;
+ uint8_t *buf;
+ bool out_valid;
+};
+
+static void smb1cli_readx_done(struct tevent_req *subreq);
+
+/**
+ * Send an asynchrounus SMB_COM_READ_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441839.aspx">MS-CIFS 2.2.4.42.1</a>,
+ * <a href="http://msdn.microsoft.com/en-us/library/ff470250.aspx">MS-SMB 2.2.4.2.1</a>
+ * @see smb1cli_readx_recv()
+ * @todo fix API (min/max size, timeout)
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ * @param[in] ev The event context to work on.
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file the data should be read from.
+ * @param[in] offset The offset in bytes from the begin of file where to start reading.
+ * @param[in] size The number of bytes to read.
+ *
+ * @return a tevent_req or NULL
+ */
+struct tevent_req *smb1cli_readx_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint64_t offset,
+ uint32_t size)
+{
+ NTSTATUS status;
+ struct tevent_req *req, *subreq;
+ struct smb1cli_readx_state *state;
+ uint8_t wct = 10;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_readx_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->size = size;
+
+ SCVAL(state->vwv + 0, 0, 0xFF);
+ SCVAL(state->vwv + 0, 1, 0);
+ SSVAL(state->vwv + 1, 0, 0);
+ SSVAL(state->vwv + 2, 0, fnum);
+ SIVAL(state->vwv + 3, 0, offset);
+ SSVAL(state->vwv + 5, 0, size);
+ SSVAL(state->vwv + 6, 0, size);
+ SSVAL(state->vwv + 7, 0, (size >> 16));
+ SSVAL(state->vwv + 8, 0, 0);
+ SSVAL(state->vwv + 9, 0, 0);
+
+ if (smb1cli_conn_capabilities(conn) & CAP_LARGE_FILES) {
+ SIVAL(state->vwv + 10, 0,
+ (((uint64_t)offset)>>32) & 0xffffffff);
+ wct = 12;
+ } else {
+ if ((((uint64_t)offset) & 0xffffffff00000000LL) != 0) {
+ DEBUG(10, ("smb1cli_readx_send got large offset where "
+ "the server does not support it\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ subreq = smb1cli_req_create(state, ev, conn, SMBreadX,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec, pid, tcon, session,
+ wct, state->vwv,
+ 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_readx_done, req);
+
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void smb1cli_readx_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_readx_state *state = tevent_req_data(
+ req, struct smb1cli_readx_state);
+ struct iovec *recv_iov = NULL;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ uint16_t data_offset;
+ uint32_t bytes_offset;
+ NTSTATUS status;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x0C
+ },
+ {
+ .status = STATUS_BUFFER_OVERFLOW,
+ .wct = 0x0C
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ NULL, /* phdr */
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ &bytes_offset,
+ NULL, /* inbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /* no error */
+ } else {
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ /* size is the number of bytes the server returned.
+ * Might be zero. */
+ state->received = SVAL(vwv + 5, 0);
+ state->received |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
+
+ if (state->received > state->size) {
+ DEBUG(5,("server returned more than we wanted!\n"));
+ tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
+ return;
+ }
+
+ /*
+ * bcc field must be valid for small reads, for large reads the 16-bit
+ * bcc field can't be correct.
+ */
+ if ((state->received < 0xffff) && (state->received > num_bytes)) {
+ DEBUG(5, ("server announced more bytes than sent\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ data_offset = SVAL(vwv+6, 0);
+ if (data_offset < bytes_offset) {
+ DEBUG(5, ("server returned invalid read&x data offset\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ if (smb_buffer_oob(num_bytes, data_offset - bytes_offset, state->received)) {
+ DEBUG(5, ("server returned invalid read&x data offset\n"));
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->buf = bytes + (data_offset - bytes_offset);
+
+ state->out_valid = true;
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/**
+ * Receive the response to an asynchronous SMB_COM_READ_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441872.aspx">MS-CIFS 2.2.4.42.2</a>,
+ * <a href="http://msdn.microsoft.com/en-us/library/ff470017.aspx">MS-SMB 2.2.4.2.2</a>
+ *
+ * @warning rcvbuf is talloced from the request, so better make sure that you
+ * copy it away before you talloc_free(req). rcvbuf is NOT a talloc_ctx of its
+ * own, so do not talloc_move it!
+ *
+ * @param[in] req A tevent request created with smb1cli_readx_send()
+ * @param[out] received The number of bytes received.
+ * @param[out] rcvbuf Pointer to the bytes received.
+ *
+ * @return NT_STATUS_OK or STATUS_BUFFER_OVERFLOW on success.
+ */
+NTSTATUS smb1cli_readx_recv(struct tevent_req *req,
+ uint32_t *received,
+ uint8_t **rcvbuf)
+{
+ struct smb1cli_readx_state *state = tevent_req_data(
+ req, struct smb1cli_readx_state);
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+ *received = 0;
+ *rcvbuf = NULL;
+ return status;
+ }
+ *received = state->received;
+ *rcvbuf = state->buf;
+ return status;
+}
diff --git a/libcli/smb/smb1cli_session.c b/libcli/smb/smb1cli_session.c
new file mode 100644
index 0000000..a8ad9b8
--- /dev/null
+++ b/libcli/smb/smb1cli_session.c
@@ -0,0 +1,821 @@
+/*
+ Unix SMB/CIFS implementation.
+ client connect/disconnect routines
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Andrew Bartlett 2001-2003
+ Copyright (C) Volker Lendecke 2011
+ Copyright (C) Jeremy Allison 2011
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+
+struct smb1cli_session_setup_lm21_state {
+ struct smbXcli_session *session;
+ uint16_t vwv[10];
+ struct iovec *recv_iov;
+ uint16_t out_session_id;
+ uint16_t out_action;
+ char *out_native_os;
+ char *out_native_lm;
+};
+
+static void smb1cli_session_setup_lm21_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_session_setup_lm21_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const char *in_user,
+ const char *in_domain,
+ const DATA_BLOB in_apassword,
+ const char *in_native_os,
+ const char *in_native_lm)
+{
+ struct tevent_req *req = NULL;
+ struct smb1cli_session_setup_lm21_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ uint16_t *vwv = NULL;
+ uint8_t *bytes = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb1cli_session_setup_lm21_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->session = session;
+ vwv = state->vwv;
+
+ if (in_user == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_domain == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_apassword.length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_native_os == NULL && in_native_lm != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, in_buf_size);
+ SSVAL(vwv+3, 0, in_mpx_max);
+ SSVAL(vwv+4, 0, in_vc_num);
+ SIVAL(vwv+5, 0, in_sess_key);
+ SSVAL(vwv+7, 0, in_apassword.length);
+ SSVAL(vwv+8, 0, 0); /* reserved */
+ SSVAL(vwv+9, 0, 0); /* reserved */
+
+ bytes = talloc_array(state, uint8_t,
+ in_apassword.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (in_apassword.length != 0) {
+ memcpy(bytes,
+ in_apassword.data,
+ in_apassword.length);
+ }
+
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_user, strlen(in_user)+1,
+ NULL);
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_domain, strlen(in_domain)+1,
+ NULL);
+ if (in_native_os != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_os, strlen(in_native_os)+1,
+ NULL);
+ }
+ if (in_native_lm != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_lm, strlen(in_native_lm)+1,
+ NULL);
+ }
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = smb1cli_req_send(state, ev, conn,
+ SMBsesssetupX,
+ 0, /* additional_flags */
+ 0, /* clear_flags */
+ 0, /* additional_flags2 */
+ 0, /* clear_flags2 */
+ timeout_msec,
+ pid,
+ NULL, /* tcon */
+ session,
+ 10, /* wct */
+ vwv,
+ talloc_get_size(bytes),
+ bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_session_setup_lm21_done, req);
+
+ return req;
+}
+
+static void smb1cli_session_setup_lm21_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb1cli_session_setup_lm21_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_lm21_state);
+ NTSTATUS status;
+ uint8_t *inhdr = NULL;
+ uint8_t wct;
+ uint16_t *vwv = NULL;
+ uint32_t num_bytes;
+ uint8_t *bytes = NULL;
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ uint16_t flags2;
+ bool use_unicode = false;
+ struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 3,
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &state->recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ NULL, /* pinbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ flags2 = SVAL(inhdr, HDR_FLG2);
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ use_unicode = true;
+ }
+
+ state->out_session_id = SVAL(inhdr, HDR_UID);
+ state->out_action = SVAL(vwv+2, 0);
+
+ p = bytes;
+
+ status = smb_bytes_pull_str(state, &state->out_native_os,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_pull_str(state, &state->out_native_lm,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ smb1cli_session_set_id(state->session, state->out_session_id);
+ smb1cli_session_set_action(state->session, state->out_action);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb1cli_session_setup_lm21_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **out_native_os,
+ char **out_native_lm)
+{
+ struct smb1cli_session_setup_lm21_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_lm21_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (out_native_os != NULL) {
+ *out_native_os = talloc_move(mem_ctx, &state->out_native_os);
+ }
+
+ if (out_native_lm != NULL) {
+ *out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+struct smb1cli_session_setup_nt1_state {
+ struct smbXcli_session *session;
+ uint16_t vwv[13];
+ struct iovec *recv_iov;
+ uint8_t *inbuf;
+ uint16_t out_session_id;
+ uint16_t out_action;
+ char *out_native_os;
+ char *out_native_lm;
+ char *out_primary_domain;
+};
+
+static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_session_setup_nt1_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const char *in_user,
+ const char *in_domain,
+ const DATA_BLOB in_apassword,
+ const DATA_BLOB in_upassword,
+ uint32_t in_capabilities,
+ const char *in_native_os,
+ const char *in_native_lm)
+{
+ struct tevent_req *req = NULL;
+ struct smb1cli_session_setup_nt1_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ uint16_t *vwv = NULL;
+ uint8_t *bytes = NULL;
+ size_t align_upassword = 0;
+ size_t apassword_ofs = 0;
+ size_t upassword_ofs = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb1cli_session_setup_nt1_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->session = session;
+ vwv = state->vwv;
+
+ if (in_user == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_domain == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_apassword.length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_upassword.length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_native_os == NULL && in_native_lm != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, in_buf_size);
+ SSVAL(vwv+3, 0, in_mpx_max);
+ SSVAL(vwv+4, 0, in_vc_num);
+ SIVAL(vwv+5, 0, in_sess_key);
+ SSVAL(vwv+7, 0, in_apassword.length);
+ SSVAL(vwv+8, 0, in_upassword.length);
+ SSVAL(vwv+9, 0, 0); /* reserved */
+ SSVAL(vwv+10, 0, 0); /* reserved */
+ SIVAL(vwv+11, 0, in_capabilities);
+
+ if (in_apassword.length == 0 && in_upassword.length > 0) {
+ /*
+ * This is plaintext auth with a unicode password,
+ * we need to align the buffer.
+ *
+ * This is what smbclient and Windows XP send as
+ * a client. And what smbd expects.
+ *
+ * But it doesn't follow [MS-CIFS] (v20160714)
+ * 2.2.4.53.1 SMB_COM_SESSION_SETUP_ANDX Request:
+ *
+ * ...
+ *
+ * If SMB_FLAGS2_UNICODE is set (1), the value of OEMPasswordLen
+ * MUST be 0x0000 and the password MUST be encoded using
+ * UTF-16LE Unicode. Padding MUST NOT be added to
+ * align this plaintext Unicode string to a word boundary.
+ *
+ * ...
+ */
+ uint16_t security_mode = smb1cli_conn_server_security_mode(conn);
+
+ if (!(security_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) {
+ align_upassword = 1;
+ }
+ }
+
+ bytes = talloc_array(state, uint8_t,
+ in_apassword.length +
+ align_upassword +
+ in_upassword.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (in_apassword.length != 0) {
+ memcpy(bytes + apassword_ofs,
+ in_apassword.data,
+ in_apassword.length);
+ upassword_ofs += in_apassword.length;
+ }
+ if (align_upassword != 0) {
+ memset(bytes + upassword_ofs, 0, align_upassword);
+ upassword_ofs += align_upassword;
+ }
+ if (in_upassword.length != 0) {
+ memcpy(bytes + upassword_ofs,
+ in_upassword.data,
+ in_upassword.length);
+ }
+
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_user, strlen(in_user)+1,
+ NULL);
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_domain, strlen(in_domain)+1,
+ NULL);
+ if (in_native_os != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_os, strlen(in_native_os)+1,
+ NULL);
+ }
+ if (in_native_lm != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_lm, strlen(in_native_lm)+1,
+ NULL);
+ }
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = smb1cli_req_send(state, ev, conn,
+ SMBsesssetupX,
+ 0, /* additional_flags */
+ 0, /* clear_flags */
+ 0, /* additional_flags2 */
+ 0, /* clear_flags2 */
+ timeout_msec,
+ pid,
+ NULL, /* tcon */
+ session,
+ 13, /* wct */
+ vwv,
+ talloc_get_size(bytes),
+ bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_session_setup_nt1_done, req);
+
+ return req;
+}
+
+static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb1cli_session_setup_nt1_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_nt1_state);
+ NTSTATUS status;
+ uint8_t *inhdr = NULL;
+ uint8_t wct;
+ uint16_t *vwv = NULL;
+ uint32_t num_bytes;
+ uint8_t *bytes = NULL;
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ uint16_t flags2;
+ bool use_unicode = false;
+ struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 3,
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &state->recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ &state->inbuf,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ flags2 = SVAL(inhdr, HDR_FLG2);
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ use_unicode = true;
+ }
+
+ state->out_session_id = SVAL(inhdr, HDR_UID);
+ state->out_action = SVAL(vwv+2, 0);
+
+ p = bytes;
+
+ status = smb_bytes_pull_str(state, &state->out_native_os,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_pull_str(state, &state->out_native_lm,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_pull_str(state, &state->out_primary_domain,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ smb1cli_session_set_id(state->session, state->out_session_id);
+ smb1cli_session_set_action(state->session, state->out_action);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb1cli_session_setup_nt1_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **precv_iov,
+ const uint8_t **precv_inbuf,
+ char **out_native_os,
+ char **out_native_lm,
+ char **out_primary_domain)
+{
+ struct smb1cli_session_setup_nt1_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_nt1_state);
+ NTSTATUS status;
+ struct iovec *recv_iov = NULL;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ recv_iov = talloc_move(mem_ctx, &state->recv_iov);
+ if (precv_iov != NULL) {
+ *precv_iov = recv_iov;
+ }
+ if (precv_inbuf != NULL) {
+ *precv_inbuf = state->inbuf;
+ }
+
+ if (out_native_os != NULL) {
+ *out_native_os = talloc_move(mem_ctx, &state->out_native_os);
+ }
+
+ if (out_native_lm != NULL) {
+ *out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
+ }
+
+ if (out_primary_domain != NULL) {
+ *out_primary_domain = talloc_move(mem_ctx,
+ &state->out_primary_domain);
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+struct smb1cli_session_setup_ext_state {
+ struct smbXcli_session *session;
+ uint16_t vwv[12];
+ struct iovec *recv_iov;
+ uint8_t *inbuf;
+ NTSTATUS status;
+ uint16_t out_session_id;
+ uint16_t out_action;
+ DATA_BLOB out_security_blob;
+ char *out_native_os;
+ char *out_native_lm;
+};
+
+static void smb1cli_session_setup_ext_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_session_setup_ext_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const DATA_BLOB in_security_blob,
+ uint32_t in_capabilities,
+ const char *in_native_os,
+ const char *in_native_lm)
+{
+ struct tevent_req *req = NULL;
+ struct smb1cli_session_setup_ext_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ uint16_t *vwv = NULL;
+ uint8_t *bytes = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb1cli_session_setup_ext_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->session = session;
+ vwv = state->vwv;
+
+ if (in_security_blob.length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (in_native_os == NULL && in_native_lm != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, in_buf_size);
+ SSVAL(vwv+3, 0, in_mpx_max);
+ SSVAL(vwv+4, 0, in_vc_num);
+ SIVAL(vwv+5, 0, in_sess_key);
+ SSVAL(vwv+7, 0, in_security_blob.length);
+ SSVAL(vwv+8, 0, 0); /* reserved */
+ SSVAL(vwv+9, 0, 0); /* reserved */
+ SIVAL(vwv+10, 0, in_capabilities);
+
+ bytes = talloc_array(state, uint8_t,
+ in_security_blob.length);
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (in_security_blob.length != 0) {
+ memcpy(bytes,
+ in_security_blob.data,
+ in_security_blob.length);
+ }
+
+ if (in_native_os != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_os, strlen(in_native_os)+1,
+ NULL);
+ }
+ if (in_native_lm != NULL) {
+ bytes = smb_bytes_push_str(bytes,
+ smbXcli_conn_use_unicode(conn),
+ in_native_lm, strlen(in_native_lm)+1,
+ NULL);
+ }
+ if (tevent_req_nomem(bytes, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = smb1cli_req_send(state, ev, conn,
+ SMBsesssetupX,
+ 0, /* additional_flags */
+ 0, /* clear_flags */
+ 0, /* additional_flags2 */
+ 0, /* clear_flags2 */
+ timeout_msec,
+ pid,
+ NULL, /* tcon */
+ session,
+ 12, /* wct */
+ vwv,
+ talloc_get_size(bytes),
+ bytes);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_session_setup_ext_done, req);
+
+ return req;
+}
+
+static void smb1cli_session_setup_ext_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb1cli_session_setup_ext_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_ext_state);
+ NTSTATUS status;
+ uint8_t *inhdr = NULL;
+ uint8_t wct;
+ uint16_t *vwv = NULL;
+ uint32_t num_bytes;
+ uint8_t *bytes = NULL;
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ uint16_t flags2;
+ uint16_t out_security_blob_length = 0;
+ bool use_unicode = false;
+ struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 4,
+ },
+ {
+ .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
+ .wct = 4,
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &state->recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ &state->inbuf,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ state->status = status;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ status = NT_STATUS_OK;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ flags2 = SVAL(inhdr, HDR_FLG2);
+ if (flags2 & FLAGS2_UNICODE_STRINGS) {
+ use_unicode = true;
+ }
+
+ state->out_session_id = SVAL(inhdr, HDR_UID);
+ state->out_action = SVAL(vwv+2, 0);
+ out_security_blob_length = SVAL(vwv+3, 0);
+
+ if (out_security_blob_length > num_bytes) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ p = bytes;
+
+ /*
+ * Note: this points into state->recv_iov!
+ */
+ state->out_security_blob = data_blob_const(p, out_security_blob_length);
+ p += out_security_blob_length;
+
+ status = smb_bytes_pull_str(state, &state->out_native_os,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ p += ret;
+
+ status = smb_bytes_pull_str(state, &state->out_native_lm,
+ use_unicode, bytes, num_bytes,
+ p, &ret);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ /* p += ret; */
+
+ smb1cli_session_set_id(state->session, state->out_session_id);
+ smb1cli_session_set_action(state->session, state->out_action);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb1cli_session_setup_ext_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **precv_iov,
+ const uint8_t **precv_inbuf,
+ DATA_BLOB *out_security_blob,
+ char **out_native_os,
+ char **out_native_lm)
+{
+ struct smb1cli_session_setup_ext_state *state =
+ tevent_req_data(req,
+ struct smb1cli_session_setup_ext_state);
+ NTSTATUS status;
+ struct iovec *recv_iov = NULL;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ recv_iov = talloc_move(mem_ctx, &state->recv_iov);
+ if (precv_iov != NULL) {
+ *precv_iov = recv_iov;
+ }
+ if (precv_inbuf != NULL) {
+ *precv_inbuf = state->inbuf;
+ }
+
+ *out_security_blob = state->out_security_blob;
+
+ if (out_native_os != NULL) {
+ *out_native_os = talloc_move(mem_ctx, &state->out_native_os);
+ }
+
+ if (out_native_lm != NULL) {
+ *out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
+ }
+
+ /*
+ * Return the status from the server:
+ * NT_STATUS_MORE_PROCESSING_REQUIRED or
+ * NT_STATUS_OK.
+ */
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_trans.c b/libcli/smb/smb1cli_trans.c
new file mode 100644
index 0000000..99021ce
--- /dev/null
+++ b/libcli/smb/smb1cli_trans.c
@@ -0,0 +1,908 @@
+/*
+ Unix SMB/CIFS implementation.
+ client transaction calls
+ Copyright (C) Andrew Tridgell 1994-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 "includes.h"
+#include "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+struct trans_recvblob {
+ uint8_t *data;
+ uint32_t max, total, received;
+};
+
+struct smb1cli_trans_state {
+ struct smbXcli_conn *conn;
+ struct tevent_context *ev;
+ uint8_t cmd;
+ uint8_t additional_flags;
+ uint8_t clear_flags;
+ uint16_t additional_flags2;
+ uint16_t clear_flags2;
+ uint32_t timeout_msec;
+ uint16_t mid;
+ uint32_t pid;
+ struct smbXcli_tcon *tcon;
+ struct smbXcli_session *session;
+ const char *pipe_name;
+ uint8_t *pipe_name_conv;
+ size_t pipe_name_conv_len;
+ uint16_t fid;
+ uint16_t function;
+ int flags;
+ uint16_t *setup;
+ uint8_t num_setup, max_setup;
+ uint8_t *param;
+ uint32_t num_param, param_sent;
+ uint8_t *data;
+ uint32_t num_data, data_sent;
+
+ uint8_t num_rsetup;
+ uint16_t *rsetup;
+ struct trans_recvblob rparam;
+ struct trans_recvblob rdata;
+ uint16_t recv_flags2;
+
+ struct iovec iov[6];
+ uint8_t pad[4];
+ uint8_t zero_pad[4];
+ uint16_t vwv[32];
+
+ NTSTATUS status;
+
+ struct tevent_req *primary_subreq;
+};
+
+static void smb1cli_trans_cleanup_primary(struct smb1cli_trans_state *state)
+{
+ if (state->primary_subreq) {
+ smb1cli_req_set_mid(state->primary_subreq, 0);
+ smbXcli_req_unset_pending(state->primary_subreq);
+ TALLOC_FREE(state->primary_subreq);
+ }
+}
+
+static int smb1cli_trans_state_destructor(struct smb1cli_trans_state *state)
+{
+ smb1cli_trans_cleanup_primary(state);
+ return 0;
+}
+
+static NTSTATUS smb1cli_pull_trans(uint8_t *inhdr,
+ uint8_t wct,
+ uint16_t *vwv,
+ uint32_t vwv_ofs,
+ uint32_t num_bytes,
+ uint8_t *bytes,
+ uint32_t bytes_ofs,
+ uint8_t smb_cmd, bool expect_first_reply,
+ uint8_t *pnum_setup, uint16_t **psetup,
+ uint32_t *ptotal_param, uint32_t *pnum_param,
+ uint32_t *pparam_disp, uint8_t **pparam,
+ uint32_t *ptotal_data, uint32_t *pnum_data,
+ uint32_t *pdata_disp, uint8_t **pdata)
+{
+ uint32_t param_ofs, data_ofs;
+ uint8_t expected_num_setup;
+ uint32_t max_bytes = UINT32_MAX - bytes_ofs;
+ uint32_t bytes_end;
+
+ if (num_bytes > max_bytes) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ bytes_end = bytes_ofs + num_bytes;
+
+ if (expect_first_reply) {
+ if ((wct != 0) || (num_bytes != 0)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ return NT_STATUS_OK;
+ }
+
+ switch (smb_cmd) {
+ case SMBtrans:
+ case SMBtrans2:
+ if (wct < 10) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ expected_num_setup = wct - 10;
+ *ptotal_param = SVAL(vwv + 0, 0);
+ *ptotal_data = SVAL(vwv + 1, 0);
+ *pnum_param = SVAL(vwv + 3, 0);
+ param_ofs = SVAL(vwv + 4, 0);
+ *pparam_disp = SVAL(vwv + 5, 0);
+ *pnum_data = SVAL(vwv + 6, 0);
+ data_ofs = SVAL(vwv + 7, 0);
+ *pdata_disp = SVAL(vwv + 8, 0);
+ *pnum_setup = CVAL(vwv + 9, 0);
+ if (expected_num_setup < (*pnum_setup)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ *psetup = vwv + 10;
+
+ break;
+ case SMBnttrans:
+ if (wct < 18) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ expected_num_setup = wct - 18;
+ *ptotal_param = IVAL(vwv, 3);
+ *ptotal_data = IVAL(vwv, 7);
+ *pnum_param = IVAL(vwv, 11);
+ param_ofs = IVAL(vwv, 15);
+ *pparam_disp = IVAL(vwv, 19);
+ *pnum_data = IVAL(vwv, 23);
+ data_ofs = IVAL(vwv, 27);
+ *pdata_disp = IVAL(vwv, 31);
+ *pnum_setup = CVAL(vwv, 35);
+ if (expected_num_setup < (*pnum_setup)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ *psetup = vwv + 18;
+ break;
+
+ default:
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /*
+ * Check for buffer overflows. data_ofs needs to be checked against
+ * the incoming buffer length, data_disp against the total
+ * length. Likewise for param_ofs/param_disp.
+ */
+
+ if (smb_buffer_oob(bytes_end, param_ofs, *pnum_param)
+ || smb_buffer_oob(*ptotal_param, *pparam_disp, *pnum_param)
+ || smb_buffer_oob(bytes_end, data_ofs, *pnum_data)
+ || smb_buffer_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *pparam = (uint8_t *)inhdr + param_ofs;
+ *pdata = (uint8_t *)inhdr + data_ofs;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smb1cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
+ struct trans_recvblob *blob,
+ uint32_t total, uint32_t thistime,
+ uint8_t *buf, uint32_t displacement)
+{
+ if (blob->data == NULL) {
+ if (total > blob->max) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ blob->total = total;
+ blob->data = talloc_array(mem_ctx, uint8_t, total);
+ if (blob->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (total > blob->total) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (thistime) {
+ memcpy(blob->data + displacement, buf, thistime);
+ blob->received += thistime;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void smb1cli_trans_format(struct smb1cli_trans_state *state,
+ uint8_t *pwct,
+ int *piov_count)
+{
+ uint8_t wct = 0;
+ struct iovec *iov = state->iov;
+ uint8_t *pad = state->pad;
+ uint16_t *vwv = state->vwv;
+ uint32_t param_offset;
+ uint32_t this_param = 0;
+ uint32_t param_pad;
+ uint32_t data_offset;
+ uint32_t this_data = 0;
+ uint32_t data_pad;
+ uint32_t useable_space;
+ uint8_t cmd;
+ uint32_t max_trans = smb1cli_conn_max_xmit(state->conn);
+
+ cmd = state->cmd;
+
+ if ((state->param_sent != 0) || (state->data_sent != 0)) {
+ /* The secondary commands are one after the primary ones */
+ cmd += 1;
+ }
+
+ param_offset = MIN_SMB_SIZE;
+
+ switch (cmd) {
+ case SMBtrans:
+ if (smbXcli_conn_use_unicode(state->conn)) {
+ pad[0] = 0;
+ iov[0].iov_base = (void *)pad;
+ iov[0].iov_len = 1;
+ param_offset += 1;
+ iov += 1;
+ }
+ iov[0].iov_base = (void *)state->pipe_name_conv;
+ iov[0].iov_len = state->pipe_name_conv_len;
+ wct = 14 + state->num_setup;
+ param_offset += iov[0].iov_len;
+ iov += 1;
+ break;
+ case SMBtrans2:
+ pad[0] = 0;
+ pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
+ pad[2] = ' ';
+ iov[0].iov_base = (void *)pad;
+ iov[0].iov_len = 3;
+ wct = 14 + state->num_setup;
+ param_offset += 3;
+ iov += 1;
+ break;
+ case SMBtranss:
+ wct = 8;
+ break;
+ case SMBtranss2:
+ wct = 9;
+ break;
+ case SMBnttrans:
+ wct = 19 + state->num_setup;
+ break;
+ case SMBnttranss:
+ wct = 18;
+ break;
+ }
+
+ param_offset += wct * sizeof(uint16_t);
+ useable_space = max_trans - param_offset;
+
+ param_pad = param_offset % 4;
+ if (param_pad > 0) {
+ param_pad = MIN(param_pad, useable_space);
+ iov[0].iov_base = (void *)state->zero_pad;
+ iov[0].iov_len = param_pad;
+ iov += 1;
+ param_offset += param_pad;
+ }
+ useable_space = max_trans - param_offset;
+
+ if (state->param_sent < state->num_param) {
+ this_param = MIN(state->num_param - state->param_sent,
+ useable_space);
+ iov[0].iov_base = (void *)(state->param + state->param_sent);
+ iov[0].iov_len = this_param;
+ iov += 1;
+ }
+
+ data_offset = param_offset + this_param;
+ useable_space = max_trans - data_offset;
+
+ data_pad = data_offset % 4;
+ if (data_pad > 0) {
+ data_pad = MIN(data_pad, useable_space);
+ iov[0].iov_base = (void *)state->zero_pad;
+ iov[0].iov_len = data_pad;
+ iov += 1;
+ data_offset += data_pad;
+ }
+ useable_space = max_trans - data_offset;
+
+ if (state->data_sent < state->num_data) {
+ this_data = MIN(state->num_data - state->data_sent,
+ useable_space);
+ iov[0].iov_base = (void *)(state->data + state->data_sent);
+ iov[0].iov_len = this_data;
+ iov += 1;
+ }
+
+ DEBUG(10, ("num_setup=%u, max_setup=%u, "
+ "param_total=%u, this_param=%u, max_param=%u, "
+ "data_total=%u, this_data=%u, max_data=%u, "
+ "param_offset=%u, param_pad=%u, param_disp=%u, "
+ "data_offset=%u, data_pad=%u, data_disp=%u\n",
+ (unsigned)state->num_setup, (unsigned)state->max_setup,
+ (unsigned)state->num_param, (unsigned)this_param,
+ (unsigned)state->rparam.max,
+ (unsigned)state->num_data, (unsigned)this_data,
+ (unsigned)state->rdata.max,
+ (unsigned)param_offset, (unsigned)param_pad,
+ (unsigned)state->param_sent,
+ (unsigned)data_offset, (unsigned)data_pad,
+ (unsigned)state->data_sent));
+
+ switch (cmd) {
+ case SMBtrans:
+ case SMBtrans2:
+ SSVAL(vwv + 0, 0, state->num_param);
+ SSVAL(vwv + 1, 0, state->num_data);
+ SSVAL(vwv + 2, 0, state->rparam.max);
+ SSVAL(vwv + 3, 0, state->rdata.max);
+ SCVAL(vwv + 4, 0, state->max_setup);
+ SCVAL(vwv + 4, 1, 0); /* reserved */
+ SSVAL(vwv + 5, 0, state->flags);
+ SIVAL(vwv + 6, 0, 0); /* timeout */
+ SSVAL(vwv + 8, 0, 0); /* reserved */
+ SSVAL(vwv + 9, 0, this_param);
+ SSVAL(vwv +10, 0, param_offset);
+ SSVAL(vwv +11, 0, this_data);
+ SSVAL(vwv +12, 0, data_offset);
+ SCVAL(vwv +13, 0, state->num_setup);
+ SCVAL(vwv +13, 1, 0); /* reserved */
+ if (state->num_setup > 0) {
+ memcpy(vwv + 14, state->setup,
+ sizeof(uint16_t) * state->num_setup);
+ }
+ break;
+ case SMBtranss:
+ case SMBtranss2:
+ SSVAL(vwv + 0, 0, state->num_param);
+ SSVAL(vwv + 1, 0, state->num_data);
+ SSVAL(vwv + 2, 0, this_param);
+ SSVAL(vwv + 3, 0, param_offset);
+ SSVAL(vwv + 4, 0, state->param_sent);
+ SSVAL(vwv + 5, 0, this_data);
+ SSVAL(vwv + 6, 0, data_offset);
+ SSVAL(vwv + 7, 0, state->data_sent);
+ if (cmd == SMBtranss2) {
+ SSVAL(vwv + 8, 0, state->fid);
+ }
+ break;
+ case SMBnttrans:
+ SCVAL(vwv + 0, 0, state->max_setup);
+ SSVAL(vwv + 0, 1, 0); /* reserved */
+ SIVAL(vwv + 1, 1, state->num_param);
+ SIVAL(vwv + 3, 1, state->num_data);
+ SIVAL(vwv + 5, 1, state->rparam.max);
+ SIVAL(vwv + 7, 1, state->rdata.max);
+ SIVAL(vwv + 9, 1, this_param);
+ SIVAL(vwv +11, 1, param_offset);
+ SIVAL(vwv +13, 1, this_data);
+ SIVAL(vwv +15, 1, data_offset);
+ SCVAL(vwv +17, 1, state->num_setup);
+ SSVAL(vwv +18, 0, state->function);
+ memcpy(vwv + 19, state->setup,
+ sizeof(uint16_t) * state->num_setup);
+ break;
+ case SMBnttranss:
+ SSVAL(vwv + 0, 0, 0); /* reserved */
+ SCVAL(vwv + 1, 0, 0); /* reserved */
+ SIVAL(vwv + 1, 1, state->num_param);
+ SIVAL(vwv + 3, 1, state->num_data);
+ SIVAL(vwv + 5, 1, this_param);
+ SIVAL(vwv + 7, 1, param_offset);
+ SIVAL(vwv + 9, 1, state->param_sent);
+ SIVAL(vwv +11, 1, this_data);
+ SIVAL(vwv +13, 1, data_offset);
+ SIVAL(vwv +15, 1, state->data_sent);
+ SCVAL(vwv +17, 1, 0); /* reserved */
+ break;
+ }
+
+ state->param_sent += this_param;
+ state->data_sent += this_data;
+
+ *pwct = wct;
+ *piov_count = iov - state->iov;
+}
+
+static bool smb1cli_trans_cancel(struct tevent_req *req);
+static void smb1cli_trans_done(struct tevent_req *subreq);
+
+struct tevent_req *smb1cli_trans_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct smbXcli_conn *conn, uint8_t cmd,
+ uint8_t additional_flags, uint8_t clear_flags,
+ uint16_t additional_flags2, uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *pipe_name, uint16_t fid, uint16_t function, int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_trans_state *state;
+ int iov_count;
+ uint8_t wct;
+ NTSTATUS status;
+ charset_t charset;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb1cli_trans_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
+ if ((num_param > 0xffff) || (max_param > 0xffff)
+ || (num_data > 0xffff) || (max_data > 0xffff)) {
+ DEBUG(3, ("Attempt to send invalid trans2 request "
+ "(setup %u, params %u/%u, data %u/%u)\n",
+ (unsigned)num_setup,
+ (unsigned)num_param, (unsigned)max_param,
+ (unsigned)num_data, (unsigned)max_data));
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ /*
+ * The largest wct will be for nttrans (19+num_setup). Make sure we
+ * don't overflow state->vwv in smb1cli_trans_format.
+ */
+
+ if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ state->conn = conn;
+ state->ev = ev;
+ state->cmd = cmd;
+ state->additional_flags = additional_flags;
+ state->clear_flags = clear_flags;
+ state->additional_flags2 = additional_flags2;
+ state->clear_flags2 = clear_flags2;
+ state->timeout_msec = timeout_msec;
+ state->flags = flags;
+ state->num_rsetup = 0;
+ state->rsetup = NULL;
+ state->pid = pid;
+ state->tcon = tcon;
+ state->session = session;
+ ZERO_STRUCT(state->rparam);
+ ZERO_STRUCT(state->rdata);
+
+ if (smbXcli_conn_use_unicode(conn)) {
+ charset = CH_UTF16LE;
+ } else {
+ charset = CH_DOS;
+ }
+
+ if ((pipe_name != NULL)
+ && (!convert_string_talloc(state, CH_UNIX, charset,
+ pipe_name, strlen(pipe_name) + 1,
+ &state->pipe_name_conv,
+ &state->pipe_name_conv_len))) {
+ tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+ return tevent_req_post(req, ev);
+ }
+ state->fid = fid; /* trans2 */
+ state->function = function; /* nttrans */
+
+ state->setup = setup;
+ state->num_setup = num_setup;
+ state->max_setup = max_setup;
+
+ state->param = param;
+ state->num_param = num_param;
+ state->param_sent = 0;
+ state->rparam.max = max_param;
+
+ state->data = data;
+ state->num_data = num_data;
+ state->data_sent = 0;
+ state->rdata.max = max_data;
+
+ smb1cli_trans_format(state, &wct, &iov_count);
+
+ subreq = smb1cli_req_create(state, ev, conn, cmd,
+ state->additional_flags,
+ state->clear_flags,
+ state->additional_flags2,
+ state->clear_flags2,
+ state->timeout_msec,
+ state->pid,
+ state->tcon,
+ state->session,
+ wct, state->vwv,
+ iov_count, state->iov);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, state->ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_trans_done, req);
+
+ /*
+ * Now get the MID of the primary request
+ * and mark it as persistent. This means
+ * we will able to send and receive multiple
+ * SMB pdus using this MID in both directions
+ * (including correct SMB signing).
+ */
+ state->mid = smb1cli_req_mid(subreq);
+ smb1cli_req_set_mid(subreq, state->mid);
+ state->primary_subreq = subreq;
+ talloc_set_destructor(state, smb1cli_trans_state_destructor);
+
+ tevent_req_set_cancel_fn(req, smb1cli_trans_cancel);
+
+ return req;
+}
+
+static bool smb1cli_trans_cancel(struct tevent_req *req)
+{
+ struct smb1cli_trans_state *state =
+ tevent_req_data(req,
+ struct smb1cli_trans_state);
+
+ if (state->primary_subreq == NULL) {
+ return false;
+ }
+
+ return tevent_req_cancel(state->primary_subreq);
+}
+
+static void smb1cli_trans_done2(struct tevent_req *subreq);
+
+static void smb1cli_trans_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb1cli_trans_state *state =
+ tevent_req_data(req,
+ struct smb1cli_trans_state);
+ NTSTATUS status;
+ bool sent_all;
+ struct iovec *recv_iov = NULL;
+ uint8_t *inhdr;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t vwv_ofs;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ uint32_t bytes_ofs;
+ uint8_t num_setup = 0;
+ uint16_t *setup = NULL;
+ uint32_t total_param = 0;
+ uint32_t num_param = 0;
+ uint32_t param_disp = 0;
+ uint32_t total_data = 0;
+ uint32_t num_data = 0;
+ uint32_t data_disp = 0;
+ uint8_t *param = NULL;
+ uint8_t *data = NULL;
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ &vwv_ofs,
+ &num_bytes,
+ &bytes,
+ &bytes_ofs,
+ NULL, /* pinbuf */
+ NULL, 0); /* expected */
+ /*
+ * Do not TALLOC_FREE(subreq) here, we might receive more than
+ * one response for the same mid.
+ */
+
+ /*
+ * We can receive something like STATUS_MORE_ENTRIES, so don't use
+ * !NT_STATUS_IS_OK(status) here.
+ */
+
+ if (NT_STATUS_IS_ERR(status)) {
+ goto fail;
+ }
+
+ if (recv_iov == NULL) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ goto fail;
+ }
+ state->status = status;
+
+ sent_all = ((state->param_sent == state->num_param)
+ && (state->data_sent == state->num_data));
+
+ status = smb1cli_pull_trans(
+ inhdr, wct, vwv, vwv_ofs,
+ num_bytes, bytes, bytes_ofs,
+ state->cmd, !sent_all, &num_setup, &setup,
+ &total_param, &num_param, &param_disp, &param,
+ &total_data, &num_data, &data_disp, &data);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ if (!sent_all) {
+ int iov_count;
+ struct tevent_req *subreq2;
+
+ smb1cli_trans_format(state, &wct, &iov_count);
+
+ subreq2 = smb1cli_req_create(state, state->ev, state->conn,
+ state->cmd + 1,
+ state->additional_flags,
+ state->clear_flags,
+ state->additional_flags2,
+ state->clear_flags2,
+ state->timeout_msec,
+ state->pid,
+ state->tcon,
+ state->session,
+ wct, state->vwv,
+ iov_count, state->iov);
+ if (tevent_req_nomem(subreq2, req)) {
+ return;
+ }
+ smb1cli_req_set_mid(subreq2, state->mid);
+
+ status = smb1cli_req_chain_submit(&subreq2, 1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
+
+ return;
+ }
+
+ status = smb1cli_trans_pull_blob(
+ state, &state->rparam, total_param, num_param, param,
+ param_disp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ status = smb1cli_trans_pull_blob(
+ state, &state->rdata, total_data, num_data, data,
+ data_disp);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ if ((state->rparam.total == state->rparam.received)
+ && (state->rdata.total == state->rdata.received)) {
+ state->recv_flags2 = SVAL(inhdr, HDR_FLG2);
+ smb1cli_trans_cleanup_primary(state);
+ tevent_req_done(req);
+ return;
+ }
+
+ TALLOC_FREE(recv_iov);
+
+ return;
+
+ fail:
+ smb1cli_trans_cleanup_primary(state);
+ tevent_req_nterror(req, status);
+}
+
+static void smb1cli_trans_done2(struct tevent_req *subreq2)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq2,
+ struct tevent_req);
+ struct smb1cli_trans_state *state =
+ tevent_req_data(req,
+ struct smb1cli_trans_state);
+ NTSTATUS status;
+ bool sent_all;
+ uint32_t seqnum;
+
+ /*
+ * First backup the seqnum of the secondary request
+ * and attach it to the primary request.
+ */
+ seqnum = smb1cli_req_seqnum(subreq2);
+ smb1cli_req_set_seqnum(state->primary_subreq, seqnum);
+
+ /* This was a one way request */
+ status = smb1cli_req_recv(subreq2, state,
+ NULL, /* recv_iov */
+ NULL, /* phdr */
+ NULL, /* pwct */
+ NULL, /* pvwv */
+ NULL, /* pvwv_offset */
+ NULL, /* pnum_bytes */
+ NULL, /* pbytes */
+ NULL, /* pbytes_offset */
+ NULL, /* pinbuf */
+ NULL, 0); /* expected */
+ TALLOC_FREE(subreq2);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+
+ sent_all = ((state->param_sent == state->num_param)
+ && (state->data_sent == state->num_data));
+
+ if (!sent_all) {
+ uint8_t wct;
+ int iov_count;
+
+ smb1cli_trans_format(state, &wct, &iov_count);
+
+ subreq2 = smb1cli_req_create(state, state->ev, state->conn,
+ state->cmd + 1,
+ state->additional_flags,
+ state->clear_flags,
+ state->additional_flags2,
+ state->clear_flags2,
+ state->timeout_msec,
+ state->pid,
+ state->tcon,
+ state->session,
+ wct, state->vwv,
+ iov_count, state->iov);
+ if (tevent_req_nomem(subreq2, req)) {
+ return;
+ }
+ smb1cli_req_set_mid(subreq2, state->mid);
+
+ status = smb1cli_req_chain_submit(&subreq2, 1);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
+ return;
+ }
+
+ return;
+
+ fail:
+ smb1cli_trans_cleanup_primary(state);
+ tevent_req_nterror(req, status);
+}
+
+NTSTATUS smb1cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint16_t *recv_flags2,
+ uint16_t **setup, uint8_t min_setup,
+ uint8_t *num_setup,
+ uint8_t **param, uint32_t min_param,
+ uint32_t *num_param,
+ uint8_t **data, uint32_t min_data,
+ uint32_t *num_data)
+{
+ struct smb1cli_trans_state *state =
+ tevent_req_data(req,
+ struct smb1cli_trans_state);
+ NTSTATUS status;
+
+ smb1cli_trans_cleanup_primary(state);
+
+ if (tevent_req_is_nterror(req, &status)) {
+ if (!NT_STATUS_IS_ERR(status)) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ tevent_req_received(req);
+ return status;
+ }
+
+ if ((state->num_rsetup < min_setup)
+ || (state->rparam.total < min_param)
+ || (state->rdata.total < min_data)) {
+ tevent_req_received(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (recv_flags2 != NULL) {
+ *recv_flags2 = state->recv_flags2;
+ }
+
+ if (setup != NULL) {
+ *setup = talloc_move(mem_ctx, &state->rsetup);
+ *num_setup = state->num_rsetup;
+ } else {
+ TALLOC_FREE(state->rsetup);
+ }
+
+ if (param != NULL) {
+ *param = talloc_move(mem_ctx, &state->rparam.data);
+ *num_param = state->rparam.total;
+ } else {
+ TALLOC_FREE(state->rparam.data);
+ }
+
+ if (data != NULL) {
+ *data = talloc_move(mem_ctx, &state->rdata.data);
+ *num_data = state->rdata.total;
+ } else {
+ TALLOC_FREE(state->rdata.data);
+ }
+
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
+
+NTSTATUS smb1cli_trans(TALLOC_CTX *mem_ctx, struct smbXcli_conn *conn,
+ uint8_t trans_cmd,
+ uint8_t additional_flags, uint8_t clear_flags,
+ uint16_t additional_flags2, uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *pipe_name, uint16_t fid, uint16_t function,
+ int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data,
+ uint16_t *recv_flags2,
+ uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
+ uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
+ uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = smb1cli_trans_send(frame, ev, conn, trans_cmd,
+ additional_flags, clear_flags,
+ additional_flags2, clear_flags2,
+ timeout_msec,
+ pid, tcon, session,
+ pipe_name, fid, function, flags,
+ setup, num_setup, max_setup,
+ param, num_param, max_param,
+ data, num_data, max_data);
+ if (req == NULL) {
+ goto fail;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+
+ status = smb1cli_trans_recv(req, mem_ctx, recv_flags2,
+ rsetup, min_rsetup, num_rsetup,
+ rparam, min_rparam, num_rparam,
+ rdata, min_rdata, num_rdata);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb1cli_write.c b/libcli/smb/smb1cli_write.c
new file mode 100644
index 0000000..d5bc57a
--- /dev/null
+++ b/libcli/smb/smb1cli_write.c
@@ -0,0 +1,284 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Gregor Beck 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb1cli_writex_state {
+ uint32_t size;
+ uint16_t vwv[14];
+ uint32_t written;
+ uint16_t available;
+ uint8_t pad;
+ struct iovec iov[2];
+};
+
+static void smb1cli_writex_done(struct tevent_req *subreq);
+
+/**
+ * Send an asynchrounus SMB_COM_WRITE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441954.aspx">MS-CIFS 2.2.4.43.1</a>
+ * @see smb1cli_writex_recv(), smb1cli_writex()
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ * @param[in] ev The event context to work on.
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file the data should be written to.
+ * @param[in] mode A bitfield containing the write mode.
+ * @param[in] buf The data to be written to the file.
+ * @param[in] offset The offset in bytes from the begin of file where to write.
+ * @param[in] size The number of bytes to write.
+ *
+ * @return a tevent_req or NULL
+ */
+struct tevent_req *smb1cli_writex_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint16_t mode,
+ const uint8_t *buf,
+ uint64_t offset,
+ uint32_t size)
+{
+ struct tevent_req *req, *subreq;
+ struct smb1cli_writex_state *state;
+ bool bigoffset = ((smb1cli_conn_capabilities(conn) & CAP_LARGE_FILES) != 0);
+ uint8_t wct = bigoffset ? 14 : 12;
+ uint16_t *vwv;
+ uint16_t data_offset =
+ smb1cli_req_wct_ofs(NULL, 0) /* reqs_before */
+ + 1 /* the wct field */
+ + wct * 2 /* vwv */
+ + 2 /* num_bytes field */
+ + 1; /* pad */
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb1cli_writex_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->size = size;
+
+ vwv = state->vwv;
+
+ SCVAL(vwv+0, 0, 0xFF);
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, 0);
+ SSVAL(vwv+2, 0, fnum);
+ SIVAL(vwv+3, 0, offset);
+ SIVAL(vwv+5, 0, 0);
+ SSVAL(vwv+7, 0, mode);
+ SSVAL(vwv+8, 0, 0);
+ SSVAL(vwv+9, 0, (state->size>>16));
+ SSVAL(vwv+10, 0, state->size);
+ SSVAL(vwv+11, 0, data_offset);
+
+ if (bigoffset) {
+ SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff);
+ }
+
+ state->pad = 0;
+ state->iov[0].iov_base = (void *)&state->pad;
+ state->iov[0].iov_len = 1;
+ state->iov[1].iov_base = discard_const_p(void, buf);
+ state->iov[1].iov_len = state->size;
+
+ subreq = smb1cli_req_create(state, ev, conn, SMBwriteX,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ timeout_msec, pid, tcon, session,
+ wct, vwv,
+ ARRAY_SIZE(state->iov), state->iov);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb1cli_writex_done, req);
+
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void smb1cli_writex_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb1cli_writex_state *state = tevent_req_data(
+ req, struct smb1cli_writex_state);
+ struct iovec *recv_iov = NULL;
+ uint8_t wct;
+ uint16_t *vwv;
+ NTSTATUS status;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x06
+ },
+ };
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ NULL, /* phdr */
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ NULL, /* num_bytes */
+ NULL, /* bytes */
+ NULL, /* pbytes_offset */
+ NULL, /* inbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->written = SVAL(vwv+2, 0);
+ if (state->size > UINT16_MAX) {
+ /*
+ * It is important that we only set the
+ * high bits only if we asked for a large write.
+ *
+ * OS/2 print shares get this wrong and may send
+ * invalid values.
+ *
+ * See bug #5326.
+ */
+ state->written |= SVAL(vwv+4, 0)<<16;
+ }
+ state->available = SVAL(vwv+3, 0);
+
+ tevent_req_done(req);
+}
+
+/**
+ * Receive the response to an asynchronous SMB_COM_WRITE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441673.aspx">MS-CIFS:2.2.4.43.2</a>
+ *
+ *
+ * @param[in] req req A tevent request created with smb1cli_writex_send()
+ * @param[out] pwritten The number of bytes written to the file.
+ * @param[out] pavailable Valid if writing to a named pipe or IO device.
+ *
+ * @return NT_STATUS_OK on success.
+ */
+NTSTATUS smb1cli_writex_recv(struct tevent_req *req, uint32_t *pwritten, uint16_t *pavailable)
+{
+ struct smb1cli_writex_state *state = tevent_req_data(
+ req, struct smb1cli_writex_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ if (pwritten != NULL) {
+ *pwritten = state->written;
+ }
+ if (pavailable != NULL) {
+ *pavailable = state->available;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Send an synchrounus SMB_COM_WRITE_ANDX request.
+ * <a href="http://msdn.microsoft.com/en-us/library/ee441848.aspx">MS-CIFS 2.2.4.43</a>
+ * @see smb1cli_writex_send(), smb1cli_writex_recv()
+ *
+ * @param[in] conn The smb connection.
+ * @param[in] timeout_msec If positive a timeout for the request.
+ * @param[in] pid The process identifier
+ * @param[in] tcon The smb tree connect.
+ * @param[in] session The smb session.
+ * @param[in] fnum The file id of the file the data should be written to.
+ * @param[in] mode A bitfield containing the write mode.
+ * @param[in] buf The data to be written to the file.
+ * @param[in] offset The offset in bytes from the begin of file where to write.
+ * @param[in] size The number of bytes to write.
+ * @param[out] pwritten The number of bytes written to the file.
+ * @param[out] pavailable Valid if writing to a named pipe or IO device.
+ *
+ * @return NT_STATUS_OK on success.
+ */
+NTSTATUS smb1cli_writex(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint16_t mode,
+ const uint8_t *buf,
+ uint64_t offset,
+ uint32_t size,
+ uint32_t *pwritten,
+ uint16_t *pavailable)
+{
+ TALLOC_CTX *frame = NULL;
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_OK;
+
+ frame = talloc_stackframe();
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ req = smb1cli_writex_send(frame, ev, conn,
+ timeout_msec,
+ pid, tcon, session,
+ fnum, mode, buf, offset, size);
+ if (req == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto done;
+ }
+
+ status = smb1cli_writex_recv(req, pwritten, pavailable);
+done:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2_constants.h b/libcli/smb/smb2_constants.h
new file mode 100644
index 0000000..a41be63
--- /dev/null
+++ b/libcli/smb/smb2_constants.h
@@ -0,0 +1,317 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 client library header
+
+ Copyright (C) Andrew Tridgell 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 __LIBCLI_SMB2_SMB2_CONSTANTS_H__
+#define __LIBCLI_SMB2_SMB2_CONSTANTS_H__
+
+/* offsets into SMB2_TRANSFORM header elements */
+#define SMB2_TF_PROTOCOL_ID 0x00 /* 4 bytes */
+#define SMB2_TF_SIGNATURE 0x04 /* 16 bytes */
+#define SMB2_TF_NONCE 0x14 /* 16 bytes */
+#define SMB2_TF_MSG_SIZE 0x24 /* 4 bytes */
+#define SMB2_TF_RESERVED 0x28 /* 2 bytes */
+#define SMB2_TF_FLAGS 0x2A /* 2 bytes */
+#define SMB2_TF_SESSION_ID 0x2C /* 8 bytes */
+
+#define SMB2_TF_HDR_SIZE 0x34 /* 52 bytes */
+
+#define SMB2_TF_MAGIC 0x424D53FD /* 0xFD 'S' 'M' 'B' */
+
+#define SMB2_TF_FLAGS_ENCRYPTED 0x0001
+
+/* offsets into header elements for a sync SMB2 request */
+#define SMB2_HDR_PROTOCOL_ID 0x00
+#define SMB2_HDR_LENGTH 0x04
+#define SMB2_HDR_CREDIT_CHARGE 0x06
+#define SMB2_HDR_EPOCH SMB2_HDR_CREDIT_CHARGE /* TODO: remove this */
+#define SMB2_HDR_STATUS 0x08
+#define SMB2_HDR_CHANNEL_SEQUENCE SMB2_HDR_STATUS /* in requests */
+#define SMB2_HDR_OPCODE 0x0c
+#define SMB2_HDR_CREDIT 0x0e
+#define SMB2_HDR_FLAGS 0x10
+#define SMB2_HDR_NEXT_COMMAND 0x14
+#define SMB2_HDR_MESSAGE_ID 0x18
+#define SMB2_HDR_PID 0x20
+#define SMB2_HDR_TID 0x24
+#define SMB2_HDR_SESSION_ID 0x28
+#define SMB2_HDR_SIGNATURE 0x30 /* 16 bytes */
+#define SMB2_HDR_BODY 0x40
+
+/* offsets into header elements for an async SMB2 request */
+#define SMB2_HDR_ASYNC_ID 0x20
+
+/* header flags */
+#define SMB2_HDR_FLAG_REDIRECT 0x01
+#define SMB2_HDR_FLAG_ASYNC 0x02
+#define SMB2_HDR_FLAG_CHAINED 0x04
+#define SMB2_HDR_FLAG_SIGNED 0x08
+#define SMB2_HDR_FLAG_PRIORITY_MASK 0x70
+#define SMB2_HDR_FLAG_DFS 0x10000000
+#define SMB2_HDR_FLAG_REPLAY_OPERATION 0x20000000
+
+#define SMB2_PRIORITY_MASK_TO_VALUE(__m) (((__m) & SMB2_HDR_FLAG_PRIORITY_MASK) >> 4)
+#define SMB2_PRIORITY_VALUE_TO_MASK(__v) (((__v) << 4) & SMB2_HDR_FLAG_PRIORITY_MASK)
+
+/* SMB2 opcodes */
+#define SMB2_OP_NEGPROT 0x00
+#define SMB2_OP_SESSSETUP 0x01
+#define SMB2_OP_LOGOFF 0x02
+#define SMB2_OP_TCON 0x03
+#define SMB2_OP_TDIS 0x04
+#define SMB2_OP_CREATE 0x05
+#define SMB2_OP_CLOSE 0x06
+#define SMB2_OP_FLUSH 0x07
+#define SMB2_OP_READ 0x08
+#define SMB2_OP_WRITE 0x09
+#define SMB2_OP_LOCK 0x0a
+#define SMB2_OP_IOCTL 0x0b
+#define SMB2_OP_CANCEL 0x0c
+#define SMB2_OP_KEEPALIVE 0x0d
+#define SMB2_OP_QUERY_DIRECTORY 0x0e
+#define SMB2_OP_NOTIFY 0x0f
+#define SMB2_OP_GETINFO 0x10
+#define SMB2_OP_SETINFO 0x11
+#define SMB2_OP_BREAK 0x12
+
+#define SMB2_MAGIC 0x424D53FE /* 0xFE 'S' 'M' 'B' */
+
+/* SMB2 negotiate dialects */
+#define SMB2_DIALECT_REVISION_000 0x0000 /* early beta dialect */
+#define SMB2_DIALECT_REVISION_202 0x0202
+#define SMB2_DIALECT_REVISION_210 0x0210
+#define SMB2_DIALECT_REVISION_222 0x0222
+#define SMB2_DIALECT_REVISION_224 0x0224
+#define SMB3_DIALECT_REVISION_300 0x0300
+#define SMB3_DIALECT_REVISION_302 0x0302
+#define SMB3_DIALECT_REVISION_310 0x0310
+#define SMB3_DIALECT_REVISION_311 0x0311
+#define SMB2_DIALECT_REVISION_2FF 0x02FF
+
+/* SMB2 negotiate security_mode */
+#define SMB2_NEGOTIATE_SIGNING_ENABLED 0x01
+#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x02
+
+/* SMB2 global capabilities */
+#define SMB2_CAP_DFS 0x00000001
+#define SMB2_CAP_LEASING 0x00000002 /* only in dialect >= 0x210 */
+#define SMB2_CAP_LARGE_MTU 0x00000004 /* only in dialect >= 0x210 */
+#define SMB2_CAP_MULTI_CHANNEL 0x00000008 /* only in dialect >= 0x222 */
+#define SMB2_CAP_PERSISTENT_HANDLES 0x00000010 /* only in dialect >= 0x222 */
+#define SMB2_CAP_DIRECTORY_LEASING 0x00000020 /* only in dialect >= 0x222 */
+#define SMB2_CAP_ENCRYPTION 0x00000040 /* only in dialect >= 0x222 */
+
+/* so we can spot new caps as added */
+#define SMB2_CAP_ALL (\
+ SMB2_CAP_DFS | \
+ SMB2_CAP_LEASING | \
+ SMB2_CAP_LARGE_MTU | \
+ SMB2_CAP_MULTI_CHANNEL | \
+ SMB2_CAP_PERSISTENT_HANDLES | \
+ SMB2_CAP_DIRECTORY_LEASING | \
+ SMB2_CAP_ENCRYPTION)
+
+/* Types of SMB2 Negotiate Contexts - only in dialect >= 0x310 */
+#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES 0x0001
+#define SMB2_ENCRYPTION_CAPABILITIES 0x0002
+#define SMB2_COMPRESSION_CAPABILITIES 0x0003
+#define SMB2_NETNAME_NEGOTIATE_CONTEXT_ID 0x0005
+#define SMB2_TRANSPORT_CAPABILITIES 0x0006
+#define SMB2_RDMA_TRANSFORM_CAPABILITIES 0x0007
+#define SMB2_SIGNING_CAPABILITIES 0x0008
+#define SMB2_POSIX_EXTENSIONS_AVAILABLE 0x0100
+
+/* Values for the SMB2_PREAUTH_INTEGRITY_CAPABILITIES Context (>= 0x310) */
+#define SMB2_PREAUTH_INTEGRITY_SHA512 0x0001
+
+/* Values for the SMB2_SIGNING_CAPABILITIES Context (>= 0x311) */
+#define SMB2_SIGNING_INVALID_ALGO 0xffff /* only used internally */
+#define SMB2_SIGNING_MD5_SMB1 0xfffe /* internally for SMB1 */
+#define SMB2_SIGNING_HMAC_SHA256 0x0000 /* default <= 0x210 */
+#define SMB2_SIGNING_AES128_CMAC 0x0001 /* default >= 0x224 */
+#define SMB2_SIGNING_AES128_GMAC 0x0002 /* only in dialect >= 0x311 */
+
+/* Values for the SMB2_ENCRYPTION_CAPABILITIES Context (>= 0x311) */
+#define SMB2_ENCRYPTION_INVALID_ALGO 0xffff /* only used internally */
+#define SMB2_ENCRYPTION_NONE 0x0000 /* only used internally */
+#define SMB2_ENCRYPTION_AES128_CCM 0x0001 /* only in dialect >= 0x224 */
+#define SMB2_ENCRYPTION_AES128_GCM 0x0002 /* only in dialect >= 0x311 */
+#define SMB2_ENCRYPTION_AES256_CCM 0x0003 /* only in dialect >= 0x311 */
+#define SMB2_ENCRYPTION_AES256_GCM 0x0004 /* only in dialect >= 0x311 */
+#define SMB2_NONCE_HIGH_MAX(nonce_len_bytes) ((uint64_t)(\
+ ((nonce_len_bytes) >= 16) ? UINT64_MAX : \
+ ((nonce_len_bytes) <= 8) ? 0 : \
+ (((uint64_t)1 << (((nonce_len_bytes) - 8)*8)) - 1) \
+ ))
+
+/* Values for the SMB2_TRANSPORT_CAPABILITIES Context (>= 0x311) */
+#define SMB2_ACCEPT_TRANSPORT_LEVEL_SECURITY 0x0001
+
+/* Values for the SMB2_RDMA_TRANSFORM_CAPABILITIES Context (>= 0x311) */
+#define SMB2_RDMA_TRANSFORM_NONE 0x0000
+#define SMB2_RDMA_TRANSFORM_ENCRYPTION 0x0001
+#define SMB2_RDMA_TRANSFORM_SIGNING 0x0002
+
+/* SMB2 session (request) flags */
+#define SMB2_SESSION_FLAG_BINDING 0x01
+/* SMB2_SESSION_FLAG_ENCRYPT_DATA 0x04 only in dialect >= 0x310 */
+
+/* SMB2 session (response) flags */
+#define SMB2_SESSION_FLAG_IS_GUEST 0x0001
+#define SMB2_SESSION_FLAG_IS_NULL 0x0002
+#define SMB2_SESSION_FLAG_ENCRYPT_DATA 0x0004 /* in dialect >= 0x224 */
+
+/* SMB2 tree connect (request) flags */
+#define SMB2_SHAREFLAG_CLUSTER_RECONNECT 0x0001 /* only in dialect >= 0x310 */
+
+/* SMB2 sharetype flags */
+#define SMB2_SHARE_TYPE_DISK 0x1
+#define SMB2_SHARE_TYPE_PIPE 0x2
+#define SMB2_SHARE_TYPE_PRINT 0x3
+
+/* SMB2 share flags */
+#define SMB2_SHAREFLAG_MANUAL_CACHING 0x0000
+#define SMB2_SHAREFLAG_AUTO_CACHING 0x0010
+#define SMB2_SHAREFLAG_VDO_CACHING 0x0020
+#define SMB2_SHAREFLAG_NO_CACHING 0x0030
+#define SMB2_SHAREFLAG_DFS 0x0001
+#define SMB2_SHAREFLAG_DFS_ROOT 0x0002
+#define SMB2_SHAREFLAG_RESTRICT_EXCLUSIVE_OPENS 0x0100
+#define SMB2_SHAREFLAG_FORCE_SHARED_DELETE 0x0200
+#define SMB2_SHAREFLAG_ALLOW_NAMESPACE_CACHING 0x0400
+#define SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM 0x0800
+#define SMB2_SHAREFLAG_FORCE_LEVELII_OPLOCKS 0x1000
+#define SMB2_SHAREFLAG_ENABLE_HASH_V1 0x2000
+#define SMB2_SHAREFLAG_ENABLE_HASH_V2 0x4000
+#define SMB2_SHAREFLAG_ENCRYPT_DATA 0x8000
+#define SMB2_SHAREFLAG_IDENTITY_REMOTING 0x00040000
+#define SMB2_SHAREFLAG_COMPRESS_DATA 0x00100000
+#define SMB2_SHAREFLAG_ISOLATED_TRANSPORT 0x00200000
+
+/* SMB2 share capabilities */
+#define SMB2_SHARE_CAP_DFS 0x8
+#define SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY 0x10 /* in dialect >= 0x222 */
+#define SMB2_SHARE_CAP_SCALEOUT 0x20 /* in dialect >= 0x222 */
+#define SMB2_SHARE_CAP_CLUSTER 0x40 /* in dialect >= 0x222 */
+#define SMB2_SHARE_CAP_ASYMMETRIC 0x80 /* in dialect >= 0x302 */
+
+/* SMB2 create security flags */
+#define SMB2_SECURITY_DYNAMIC_TRACKING 0x01
+#define SMB2_SECURITY_EFFECTIVE_ONLY 0x02
+
+/* SMB2 lock flags */
+#define SMB2_LOCK_FLAG_NONE 0x00000000
+#define SMB2_LOCK_FLAG_SHARED 0x00000001
+#define SMB2_LOCK_FLAG_EXCLUSIVE 0x00000002
+#define SMB2_LOCK_FLAG_UNLOCK 0x00000004
+#define SMB2_LOCK_FLAG_FAIL_IMMEDIATELY 0x00000010
+#define SMB2_LOCK_FLAG_ALL_MASK 0x00000017
+
+/* SMB2 requested oplock levels */
+#define SMB2_OPLOCK_LEVEL_NONE 0x00
+#define SMB2_OPLOCK_LEVEL_II 0x01
+#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
+#define SMB2_OPLOCK_LEVEL_BATCH 0x09
+#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
+
+/* SMB2 lease bits */
+#define SMB2_LEASE_NONE 0x00
+
+/* SMB2 lease flags */
+#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS 0x00000002
+#define SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET 0x00000004
+
+/* SMB2 lease break flags */
+#define SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED 0x01
+
+/* SMB2 impersonation levels */
+#define SMB2_IMPERSONATION_ANONYMOUS 0x00
+#define SMB2_IMPERSONATION_IDENTIFICATION 0x01
+#define SMB2_IMPERSONATION_IMPERSONATION 0x02
+#define SMB2_IMPERSONATION_DELEGATE 0x03
+
+/* SMB2 create tags */
+#define SMB2_CREATE_TAG_EXTA "ExtA"
+#define SMB2_CREATE_TAG_MXAC "MxAc"
+#define SMB2_CREATE_TAG_SECD "SecD"
+#define SMB2_CREATE_TAG_DHNQ "DHnQ"
+#define SMB2_CREATE_TAG_DHNC "DHnC"
+#define SMB2_CREATE_TAG_ALSI "AlSi"
+#define SMB2_CREATE_TAG_TWRP "TWrp"
+#define SMB2_CREATE_TAG_QFID "QFid"
+#define SMB2_CREATE_TAG_RQLS "RqLs"
+#define SMB2_CREATE_TAG_DH2Q "DH2Q"
+#define SMB2_CREATE_TAG_DH2C "DH2C"
+#define SMB2_CREATE_TAG_AAPL "AAPL"
+#define SMB2_CREATE_TAG_APP_INSTANCE_ID "\x45\xBC\xA6\x6A\xEF\xA7\xF7\x4A\x90\x08\xFA\x46\x2E\x14\x4D\x74"
+#define SVHDX_OPEN_DEVICE_CONTEXT "\x9C\xCB\xCF\x9E\x04\xC1\xE6\x43\x98\x0E\x15\x8D\xA1\xF6\xEC\x83"
+#define SMB2_CREATE_TAG_POSIX "\x93\xAD\x25\x50\x9C\xB4\x11\xE7\xB4\x23\x83\xDE\x96\x8B\xCD\x7C"
+
+/* SMB2 notify flags */
+#define SMB2_WATCH_TREE 0x0001
+
+/* SMB2 Create ignore some more create_options */
+#define SMB2_CREATE_OPTIONS_NOT_SUPPORTED_MASK (NTCREATEX_OPTIONS_TREE_CONNECTION | \
+ NTCREATEX_OPTIONS_OPFILTER)
+
+/*
+ SMB2 uses different level numbers for the same old SMB trans2 search levels
+*/
+#define SMB2_FIND_DIRECTORY_INFO 0x01
+#define SMB2_FIND_FULL_DIRECTORY_INFO 0x02
+#define SMB2_FIND_BOTH_DIRECTORY_INFO 0x03
+#define SMB2_FIND_NAME_INFO 0x0C
+#define SMB2_FIND_ID_BOTH_DIRECTORY_INFO 0x25
+#define SMB2_FIND_ID_FULL_DIRECTORY_INFO 0x26
+
+/* SMB2 UNIX Extensions. */
+#define SMB2_FIND_POSIX_INFORMATION 0x64
+
+/* flags for SMB2 find */
+#define SMB2_CONTINUE_FLAG_RESTART 0x01
+#define SMB2_CONTINUE_FLAG_SINGLE 0x02
+#define SMB2_CONTINUE_FLAG_INDEX 0x04
+#define SMB2_CONTINUE_FLAG_REOPEN 0x10
+
+/* get/setinfo classes, see [MS-SMB2] 2.2.37 and 2.2.39 */
+#define SMB2_0_INFO_FILE 0x01
+#define SMB2_0_INFO_FILESYSTEM 0x02
+#define SMB2_0_INFO_SECURITY 0x03
+#define SMB2_0_INFO_QUOTA 0x04
+
+#define SMB2_CLOSE_FLAGS_FULL_INFORMATION (0x01)
+
+#define SMB2_READFLAG_READ_UNBUFFERED 0x01
+
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+#define SMB2_WRITEFLAG_WRITE_UNBUFFERED 0x00000002
+
+/* 2.2.31 SMB2 IOCTL Request */
+#define SMB2_IOCTL_FLAG_IS_FSCTL 0x00000001
+
+/*
+ * Flags for durable handle v2 requests
+ */
+#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002
+
+/* The AES CCM nonce N of 15 - L octets. Where L=4 */
+#define SMB2_AES_128_CCM_NONCE_SIZE 11
+
+#endif
diff --git a/libcli/smb/smb2_create_blob.c b/libcli/smb/smb2_create_blob.c
new file mode 100644
index 0000000..57c7a9d
--- /dev/null
+++ b/libcli/smb/smb2_create_blob.c
@@ -0,0 +1,227 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 Create Context Blob handling
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Stefan Metzmacher 2008-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 "../libcli/smb/smb_common.h"
+
+static size_t smb2_create_blob_padding(uint32_t offset, size_t n)
+{
+ if ((offset & (n-1)) == 0) return 0;
+ return n - (offset & (n-1));
+}
+
+/*
+ parse a set of SMB2 create blobs
+*/
+NTSTATUS smb2_create_blob_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer,
+ struct smb2_create_blobs *blobs)
+{
+ const uint8_t *data = buffer.data;
+ uint32_t remaining = buffer.length;
+
+ while (remaining > 0) {
+ uint32_t next;
+ uint32_t name_offset, name_length;
+ uint32_t data_offset;
+ uint32_t data_length;
+ char *tag;
+ DATA_BLOB b;
+ NTSTATUS status;
+
+ if (remaining < 16) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ next = IVAL(data, 0);
+ name_offset = SVAL(data, 4);
+ name_length = SVAL(data, 6);
+#if 0
+ reserved = SVAL(data, 8);
+#endif
+ data_offset = SVAL(data, 10);
+ data_length = IVAL(data, 12);
+
+ if ((next & 0x7) != 0 ||
+ next > remaining ||
+ name_offset != 16 ||
+ name_length < 4 ||
+ name_offset + name_length > remaining ||
+ (data_offset & 0x7) != 0 ||
+ (data_offset && (data_offset < name_offset + name_length)) ||
+ (data_offset > remaining) ||
+ (data_offset + (uint64_t)data_length > remaining)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ tag = talloc_strndup(mem_ctx, (const char *)data + name_offset, name_length);
+ if (tag == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ b = data_blob_const(data+data_offset, data_length);
+ status = smb2_create_blob_add(mem_ctx, blobs, tag, b);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ talloc_free(tag);
+
+ if (next == 0) break;
+
+ remaining -= next;
+ data += next;
+
+ if (remaining < 16) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ add a blob to a smb2_create attribute blob
+*/
+static NTSTATUS smb2_create_blob_push_one(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_create_blob *blob,
+ bool last)
+{
+ uint32_t ofs = buffer->length;
+ size_t tag_length = strlen(blob->tag);
+ size_t blob_offset = 0;
+ size_t blob_pad = 0;
+ size_t next_offset = 0;
+ size_t next_pad = 0;
+ bool ok;
+
+ blob_offset = 0x10 + tag_length;
+ blob_pad = smb2_create_blob_padding(blob_offset, 8);
+ next_offset = blob_offset + blob_pad + blob->data.length;
+ if (!last) {
+ next_pad = smb2_create_blob_padding(next_offset, 8);
+ }
+
+ ok = data_blob_realloc(mem_ctx, buffer,
+ buffer->length + next_offset + next_pad);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (last) {
+ SIVAL(buffer->data, ofs+0x00, 0);
+ } else {
+ SIVAL(buffer->data, ofs+0x00, next_offset + next_pad);
+ }
+ SSVAL(buffer->data, ofs+0x04, 0x10); /* offset of tag */
+ SIVAL(buffer->data, ofs+0x06, tag_length); /* tag length */
+ SSVAL(buffer->data, ofs+0x0A, blob_offset + blob_pad); /* offset of data */
+ SIVAL(buffer->data, ofs+0x0C, blob->data.length);
+ memcpy(buffer->data+ofs+0x10, blob->tag, tag_length);
+ if (blob_pad > 0) {
+ memset(buffer->data+ofs+blob_offset, 0, blob_pad);
+ blob_offset += blob_pad;
+ }
+ memcpy(buffer->data+ofs+blob_offset, blob->data.data, blob->data.length);
+ if (next_pad > 0) {
+ memset(buffer->data+ofs+next_offset, 0, next_pad);
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ create a buffer of a set of create blobs
+*/
+NTSTATUS smb2_create_blob_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_create_blobs blobs)
+{
+ uint32_t i;
+ NTSTATUS status;
+
+ *buffer = (DATA_BLOB) { 0 };
+ for (i=0; i < blobs.num_blobs; i++) {
+ bool last = false;
+ const struct smb2_create_blob *c;
+
+ if ((i + 1) == blobs.num_blobs) {
+ last = true;
+ }
+
+ c = &blobs.blobs[i];
+ status = smb2_create_blob_push_one(mem_ctx, buffer, c, last);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, struct smb2_create_blobs *b,
+ const char *tag, DATA_BLOB data)
+{
+ struct smb2_create_blob *array;
+
+ array = talloc_realloc(mem_ctx, b->blobs,
+ struct smb2_create_blob,
+ b->num_blobs + 1);
+ NT_STATUS_HAVE_NO_MEMORY(array);
+ b->blobs = array;
+
+ b->blobs[b->num_blobs].tag = talloc_strdup(b->blobs, tag);
+ NT_STATUS_HAVE_NO_MEMORY(b->blobs[b->num_blobs].tag);
+
+ if (data.data) {
+ b->blobs[b->num_blobs].data = data_blob_talloc(b->blobs,
+ data.data,
+ data.length);
+ NT_STATUS_HAVE_NO_MEMORY(b->blobs[b->num_blobs].data.data);
+ } else {
+ b->blobs[b->num_blobs].data = data_blob_null;
+ }
+
+ b->num_blobs += 1;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * return the first blob with the given tag
+ */
+struct smb2_create_blob *smb2_create_blob_find(const struct smb2_create_blobs *b,
+ const char *tag)
+{
+ uint32_t i;
+
+ if (b == NULL) {
+ return NULL;
+ }
+
+ for (i=0; i < b->num_blobs; i++) {
+ if (strcmp(b->blobs[i].tag, tag) == 0) {
+ return &b->blobs[i];
+ }
+ }
+
+ return NULL;
+}
diff --git a/libcli/smb/smb2_create_blob.h b/libcli/smb/smb2_create_blob.h
new file mode 100644
index 0000000..642695a
--- /dev/null
+++ b/libcli/smb/smb2_create_blob.h
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 Create Context Blob handling
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Stefan Metzmacher 2008-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 _LIBCLI_SMB_SMB2_CREATE_BLOB_H_
+#define _LIBCLI_SMB_SMB2_CREATE_BLOB_H_
+
+#include "replace.h"
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "libcli/util/ntstatus.h"
+
+struct smb2_create_blob {
+ char *tag;
+ DATA_BLOB data;
+};
+
+struct smb2_create_blobs {
+ uint32_t num_blobs;
+ struct smb2_create_blob *blobs;
+};
+
+struct smb_create_returns {
+ uint8_t oplock_level;
+ uint8_t flags;
+ uint32_t create_action;
+ NTTIME creation_time;
+ NTTIME last_access_time;
+ NTTIME last_write_time;
+ NTTIME change_time;
+ uint64_t allocation_size;
+ uint64_t end_of_file;
+ uint32_t file_attributes;
+};
+
+/*
+ parse a set of SMB2 create blobs
+*/
+NTSTATUS smb2_create_blob_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer,
+ struct smb2_create_blobs *blobs);
+
+/*
+ create a buffer of a set of create blobs
+*/
+NTSTATUS smb2_create_blob_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_create_blobs blobs);
+
+NTSTATUS smb2_create_blob_add(TALLOC_CTX *mem_ctx, struct smb2_create_blobs *b,
+ const char *tag, DATA_BLOB data);
+
+/*
+ * return the first blob with the given tag
+ */
+struct smb2_create_blob *smb2_create_blob_find(const struct smb2_create_blobs *b,
+ const char *tag);
+
+#endif /* _LIBCLI_SMB_SMB2_CREATE_BLOB_H_ */
diff --git a/libcli/smb/smb2_create_ctx.h b/libcli/smb/smb2_create_ctx.h
new file mode 100644
index 0000000..7e7bf22
--- /dev/null
+++ b/libcli/smb/smb2_create_ctx.h
@@ -0,0 +1,47 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 create context specific stuff
+
+ Copyright (C) Ralph Boehme 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 __LIBCLI_SMB2_CREATE_CTX_H__
+#define __LIBCLI_SMB2_CREATE_CTX_H__
+
+/* http://opensource.apple.com/source/smb/smb-697.1.1/kernel/netsmb/smb_2.h */
+
+/* "AAPL" Context Command Codes */
+#define SMB2_CRTCTX_AAPL_SERVER_QUERY 1
+#define SMB2_CRTCTX_AAPL_RESOLVE_ID 2
+
+/* "AAPL" Server Query request/response bitmap */
+#define SMB2_CRTCTX_AAPL_SERVER_CAPS 1
+#define SMB2_CRTCTX_AAPL_VOLUME_CAPS 2
+#define SMB2_CRTCTX_AAPL_MODEL_INFO 4
+
+/* "AAPL" Client/Server Capabilities bitmap */
+#define SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR 1
+#define SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE 2
+#define SMB2_CRTCTX_AAPL_UNIX_BASED 4
+#define SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE 8
+
+/* "AAPL" Volume Capabilities bitmap */
+#define SMB2_CRTCTX_AAPL_SUPPORT_RESOLVE_ID 1
+#define SMB2_CRTCTX_AAPL_CASE_SENSITIVE 2
+#define SMB2_CRTCTX_AAPL_FULL_SYNC 4
+
+#endif
diff --git a/libcli/smb/smb2_lease.c b/libcli/smb/smb2_lease.c
new file mode 100644
index 0000000..fc641ff
--- /dev/null
+++ b/libcli/smb/smb2_lease.c
@@ -0,0 +1,102 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 Lease context handling
+
+ Copyright (C) Stefan Metzmacher 2012
+ Copyright (C) Volker Lendecke 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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/smb/smb_common.h"
+
+ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
+ struct smb2_lease *lease)
+{
+ int version;
+
+ switch (len) {
+ case 32:
+ version = 1;
+ break;
+ case 52:
+ version = 2;
+ break;
+ default:
+ return -1;
+ }
+
+ memcpy(&lease->lease_key, buf, 16);
+ lease->lease_state = IVAL(buf, 16);
+ lease->lease_flags = IVAL(buf, 20);
+ lease->lease_duration = BVAL(buf, 24);
+ lease->lease_version = version;
+
+ switch (version) {
+ case 1:
+ ZERO_STRUCT(lease->parent_lease_key);
+ lease->lease_epoch = 0;
+ break;
+ case 2:
+ memcpy(&lease->parent_lease_key, buf+32, 16);
+ lease->lease_epoch = SVAL(buf, 48);
+ break;
+ }
+
+ return len;
+}
+
+bool smb2_lease_push(const struct smb2_lease *lease, uint8_t *buf, size_t len)
+{
+ int version;
+
+ switch (len) {
+ case 32:
+ version = 1;
+ break;
+ case 52:
+ version = 2;
+ break;
+ default:
+ return false;
+ }
+
+ memcpy(&buf[0], &lease->lease_key, 16);
+ SIVAL(buf, 16, lease->lease_state);
+ SIVAL(buf, 20, lease->lease_flags);
+ SBVAL(buf, 24, lease->lease_duration);
+
+ if (version == 2) {
+ memcpy(&buf[32], &lease->parent_lease_key, 16);
+ SIVAL(buf, 48, lease->lease_epoch);
+ }
+
+ return true;
+}
+
+bool smb2_lease_key_equal(const struct smb2_lease_key *k1,
+ const struct smb2_lease_key *k2)
+{
+ return ((k1->data[0] == k2->data[0]) && (k1->data[1] == k2->data[1]));
+}
+
+bool smb2_lease_equal(const struct GUID *g1,
+ const struct smb2_lease_key *k1,
+ const struct GUID *g2,
+ const struct smb2_lease_key *k2)
+{
+ return GUID_equal(g1, g2) && smb2_lease_key_equal(k1, k2);
+}
diff --git a/libcli/smb/smb2_lease.h b/libcli/smb/smb2_lease.h
new file mode 100644
index 0000000..2e6faf7
--- /dev/null
+++ b/libcli/smb/smb2_lease.h
@@ -0,0 +1,43 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB2 Lease context handling
+
+ Copyright (C) Stefan Metzmacher 2012
+ Copyright (C) Volker Lendecke 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 _LIBCLI_SMB_SMB2_LEASE_H_
+#define _LIBCLI_SMB_SMB2_LEASE_H_
+
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/smb2_lease_struct.h"
+
+/*
+ * Parse a smb2 lease create context. Return -1 on error, buffer.length on
+ * success. V1 and V2 differ only by length of buffer.length
+ */
+ssize_t smb2_lease_pull(const uint8_t *buf, size_t len,
+ struct smb2_lease *lease);
+bool smb2_lease_push(const struct smb2_lease *lease, uint8_t *buf, size_t len);
+bool smb2_lease_key_equal(const struct smb2_lease_key *k1,
+ const struct smb2_lease_key *k2);
+bool smb2_lease_equal(const struct GUID *g1,
+ const struct smb2_lease_key *k1,
+ const struct GUID *g2,
+ const struct smb2_lease_key *k2);
+
+#endif /* _LIBCLI_SMB_SMB2_LEASE_H_ */
diff --git a/libcli/smb/smb2_lock.h b/libcli/smb/smb2_lock.h
new file mode 100644
index 0000000..f0e0535
--- /dev/null
+++ b/libcli/smb/smb2_lock.h
@@ -0,0 +1,32 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Volker Lendecke 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 __LIBCLI_SMB_SMB2_LOCK_H__
+#define __LIBCLI_SMB_SMB2_LOCK_H__
+
+#include "replace.h"
+
+struct smb2_lock_element {
+ uint64_t offset;
+ uint64_t length;
+ uint32_t flags;
+ uint32_t reserved;
+};
+
+#endif
diff --git a/libcli/smb/smb2_negotiate_context.c b/libcli/smb/smb2_negotiate_context.c
new file mode 100644
index 0000000..9ec20bc
--- /dev/null
+++ b/libcli/smb/smb2_negotiate_context.c
@@ -0,0 +1,203 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 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 "includes.h"
+#include "../libcli/smb/smb_common.h"
+#include "libcli/smb/smb2_negotiate_context.h"
+
+static size_t smb2_negotiate_context_padding(uint32_t offset, size_t n)
+{
+ if ((offset & (n-1)) == 0) return 0;
+ return n - (offset & (n-1));
+}
+
+/*
+ parse a set of SMB2 create contexts
+*/
+NTSTATUS smb2_negotiate_context_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer,
+ uint16_t expected_count,
+ struct smb2_negotiate_contexts *contexts)
+{
+ const uint8_t *data = buffer.data;
+ uint32_t remaining = buffer.length;
+ uint16_t idx;
+
+ for (idx = 0; idx < expected_count; idx++) {
+ uint16_t data_length;
+ uint16_t type;
+ NTSTATUS status;
+ size_t pad;
+ uint32_t next_offset;
+
+ if (remaining < 8) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ type = SVAL(data, 0x00);
+ data_length = SVAL(data, 0x02);
+#if 0
+ reserved = IVAL(data, 0x04);
+#endif
+
+ next_offset = 0x08 + data_length;
+ if (remaining < next_offset) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = smb2_negotiate_context_add(
+ mem_ctx, contexts, type, data+0x08, data_length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (contexts->num_contexts == expected_count) {
+ break;
+ }
+
+ remaining -= next_offset;
+ data += next_offset;
+
+ if (remaining == 0) {
+ break;
+ }
+
+ pad = smb2_negotiate_context_padding(next_offset, 8);
+ if (remaining < pad) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ remaining -= pad;
+ data += pad;
+ }
+
+ if (contexts->num_contexts != expected_count) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ add a context to a smb2_negotiate attribute context
+*/
+static NTSTATUS smb2_negotiate_context_push_one(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_negotiate_context *context,
+ bool last)
+{
+ uint32_t ofs = buffer->length;
+ size_t next_offset = 0;
+ size_t next_pad = 0;
+ bool ok;
+
+ if (context->data.length > UINT16_MAX) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ next_offset = 0x08 + context->data.length;
+ if (!last) {
+ next_pad = smb2_negotiate_context_padding(next_offset, 8);
+ }
+
+ ok = data_blob_realloc(mem_ctx, buffer,
+ buffer->length + next_offset + next_pad);
+ if (!ok) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ SSVAL(buffer->data, ofs+0x00, context->type);
+ SIVAL(buffer->data, ofs+0x02, context->data.length);
+ SIVAL(buffer->data, ofs+0x04, 0);
+ memcpy(buffer->data+ofs+0x08, context->data.data, context->data.length);
+ if (next_pad > 0) {
+ memset(buffer->data+ofs+next_offset, 0, next_pad);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ create a buffer of a set of create contexts
+*/
+NTSTATUS smb2_negotiate_context_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_negotiate_contexts contexts)
+{
+ uint32_t i;
+ NTSTATUS status;
+
+ *buffer = data_blob(NULL, 0);
+ for (i=0; i < contexts.num_contexts; i++) {
+ bool last = false;
+ const struct smb2_negotiate_context *c;
+
+ if ((i + 1) == contexts.num_contexts) {
+ last = true;
+ }
+
+ c = &contexts.contexts[i];
+ status = smb2_negotiate_context_push_one(mem_ctx, buffer, c, last);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2_negotiate_context_add(TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts *c,
+ uint16_t type,
+ const uint8_t *buf,
+ size_t buflen)
+{
+ struct smb2_negotiate_context *array;
+
+ array = talloc_realloc(mem_ctx, c->contexts,
+ struct smb2_negotiate_context,
+ c->num_contexts + 1);
+ NT_STATUS_HAVE_NO_MEMORY(array);
+ c->contexts = array;
+
+ c->contexts[c->num_contexts].type = type;
+
+ if (buf != NULL) {
+ c->contexts[c->num_contexts].data = data_blob_talloc(
+ c->contexts, buf, buflen);
+ NT_STATUS_HAVE_NO_MEMORY(c->contexts[c->num_contexts].data.data);
+ } else {
+ c->contexts[c->num_contexts].data = data_blob_null;
+ }
+
+ c->num_contexts += 1;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ * return the first blob with the given tag
+ */
+struct smb2_negotiate_context *smb2_negotiate_context_find(const struct smb2_negotiate_contexts *c,
+ uint16_t type)
+{
+ uint32_t i;
+
+ for (i=0; i < c->num_contexts; i++) {
+ if (c->contexts[i].type == type) {
+ return &c->contexts[i];
+ }
+ }
+
+ return NULL;
+}
diff --git a/libcli/smb/smb2_negotiate_context.h b/libcli/smb/smb2_negotiate_context.h
new file mode 100644
index 0000000..645fb64
--- /dev/null
+++ b/libcli/smb/smb2_negotiate_context.h
@@ -0,0 +1,92 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 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 _LIBCLI_SMB_SMB2_NEGOTIATE_BLOB_H_
+#define _LIBCLI_SMB_SMB2_NEGOTIATE_BLOB_H_
+
+struct smb2_negotiate_context {
+ uint16_t type;
+ DATA_BLOB data;
+};
+
+struct smb2_negotiate_contexts {
+ uint16_t num_contexts;
+ struct smb2_negotiate_context *contexts;
+};
+
+/*
+ parse a set of SMB2 negotiate contexts
+*/
+NTSTATUS smb2_negotiate_context_parse(TALLOC_CTX *mem_ctx, const DATA_BLOB buffer,
+ uint16_t expected_count,
+ struct smb2_negotiate_contexts *contexts);
+
+/*
+ negotiate a buffer of a set of negotiate contexts
+*/
+NTSTATUS smb2_negotiate_context_push(TALLOC_CTX *mem_ctx, DATA_BLOB *buffer,
+ const struct smb2_negotiate_contexts contexts);
+
+NTSTATUS smb2_negotiate_context_add(TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts *c,
+ uint16_t type,
+ const uint8_t *buf,
+ size_t buflen);
+
+/*
+ * return the first context with the given tag
+ */
+struct smb2_negotiate_context *smb2_negotiate_context_find(const struct smb2_negotiate_contexts *b,
+ uint16_t type);
+#define WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK 31
+
+struct smb3_signing_capabilities {
+#define SMB3_SIGNING_CAPABILITIES_MAX_ALGOS 3
+ uint16_t num_algos;
+ uint16_t algos[SMB3_SIGNING_CAPABILITIES_MAX_ALGOS];
+};
+
+struct smb3_encryption_capabilities {
+#define SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS 4
+ uint16_t num_algos;
+ uint16_t algos[SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS];
+};
+
+struct smb311_capabilities {
+ struct smb3_signing_capabilities signing;
+ struct smb3_encryption_capabilities encryption;
+};
+
+const char *smb3_signing_algorithm_name(uint16_t algo);
+const char *smb3_encryption_algorithm_name(uint16_t algo);
+
+struct smb311_capabilities smb311_capabilities_parse(const char *role,
+ const char * const *signing_algos,
+ const char * const *encryption_algos);
+
+NTSTATUS smb311_capabilities_check(const struct smb311_capabilities *c,
+ const char *debug_prefix,
+ int debug_lvl,
+ NTSTATUS error_status,
+ const char *role,
+ enum protocol_types protocol,
+ uint16_t sign_algo,
+ uint16_t cipher_algo);
+
+#endif /* _LIBCLI_SMB_SMB2_NEGOTIATE_BLOB_H_ */
diff --git a/libcli/smb/smb2_posix.c b/libcli/smb/smb2_posix.c
new file mode 100644
index 0000000..60be321
--- /dev/null
+++ b/libcli/smb/smb2_posix.c
@@ -0,0 +1,51 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * SMB2 Posix context handling
+ *
+ * Copyright (C) Jeremy Allison 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 "libcli/smb/smb2_posix.h"
+#include "libcli/smb/smb2_constants.h"
+#include "lib/util/byteorder.h"
+
+NTSTATUS make_smb2_posix_create_ctx(
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs **crb,
+ mode_t mode)
+{
+ struct smb2_create_blobs *cblobs = NULL;
+ uint8_t linear_mode[4];
+ DATA_BLOB blob = { .data=linear_mode, .length=sizeof(linear_mode) };
+ NTSTATUS status;
+
+ cblobs = talloc_zero(mem_ctx, struct smb2_create_blobs);
+ if (cblobs == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ SIVAL(&linear_mode,0, unix_perms_to_wire(mode & ~S_IFMT));
+
+ status = smb2_create_blob_add(
+ cblobs, cblobs, SMB2_CREATE_TAG_POSIX, blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(cblobs);
+ return status;
+ }
+ *crb = cblobs;
+ return NT_STATUS_OK;
+}
diff --git a/libcli/smb/smb2_posix.h b/libcli/smb/smb2_posix.h
new file mode 100644
index 0000000..0751814
--- /dev/null
+++ b/libcli/smb/smb2_posix.h
@@ -0,0 +1,36 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * SMB2 Posix context handling
+ *
+ * Copyright (C) Jeremy Allison 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 _LIBCLI_SMB_SMB2_POSIX_H_
+#define _LIBCLI_SMB_SMB2_POSIX_H_
+
+#include "replace.h"
+#include "system/filesys.h"
+#include <talloc.h>
+#include "libcli/smb/smb2_create_blob.h"
+#include "libcli/smb/smb_util.h"
+
+NTSTATUS make_smb2_posix_create_ctx(
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs **crb,
+ mode_t mode);
+
+#endif /* _LIBCLI_SMB_SMB2_POSIX_H_ */
diff --git a/libcli/smb/smb2_signing.c b/libcli/smb/smb2_signing.c
new file mode 100644
index 0000000..94ff51f
--- /dev/null
+++ b/libcli/smb/smb2_signing.c
@@ -0,0 +1,1110 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB2 signing
+
+ Copyright (C) Stefan Metzmacher 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 <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#define SMB2_SIGNING_KEY_GNUTLS_TYPES 1
+#include "../libcli/smb/smb_common.h"
+#include "../lib/crypto/crypto.h"
+#include "lib/util/iov_buf.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+
+void smb2_signing_derivations_fill_const_stack(struct smb2_signing_derivations *ds,
+ enum protocol_types protocol,
+ const DATA_BLOB preauth_hash)
+{
+ *ds = (struct smb2_signing_derivations) { .signing = NULL, };
+
+ if (protocol >= PROTOCOL_SMB3_11) {
+ struct smb2_signing_derivation *d = NULL;
+
+ SMB_ASSERT(preauth_hash.length != 0);
+
+ d = &ds->__signing;
+ ds->signing = d;
+ d->label = data_blob_string_const_null("SMBSigningKey");
+ d->context = preauth_hash;
+
+ d = &ds->__cipher_c2s;
+ ds->cipher_c2s = d;
+ d->label = data_blob_string_const_null("SMBC2SCipherKey");
+ d->context = preauth_hash;
+
+ d = &ds->__cipher_s2c;
+ ds->cipher_s2c = d;
+ d->label = data_blob_string_const_null("SMBS2CCipherKey");
+ d->context = preauth_hash;
+
+ d = &ds->__application;
+ ds->application = d;
+ d->label = data_blob_string_const_null("SMBAppKey");
+ d->context = preauth_hash;
+
+ } else if (protocol >= PROTOCOL_SMB3_00) {
+ struct smb2_signing_derivation *d = NULL;
+
+ d = &ds->__signing;
+ ds->signing = d;
+ d->label = data_blob_string_const_null("SMB2AESCMAC");
+ d->context = data_blob_string_const_null("SmbSign");
+
+ d = &ds->__cipher_c2s;
+ ds->cipher_c2s = d;
+ d->label = data_blob_string_const_null("SMB2AESCCM");
+ d->context = data_blob_string_const_null("ServerIn ");
+
+ d = &ds->__cipher_s2c;
+ ds->cipher_s2c = d;
+ d->label = data_blob_string_const_null("SMB2AESCCM");
+ d->context = data_blob_string_const_null("ServerOut");
+
+ d = &ds->__application;
+ ds->application = d;
+ d->label = data_blob_string_const_null("SMB2APP");
+ d->context = data_blob_string_const_null("SmbRpc");
+ }
+}
+
+static int smb2_signing_key_destructor(struct smb2_signing_key *key)
+{
+ if (key->hmac_hnd != NULL) {
+ gnutls_hmac_deinit(key->hmac_hnd, NULL);
+ key->hmac_hnd = NULL;
+ }
+
+ if (key->cipher_hnd != NULL) {
+ gnutls_aead_cipher_deinit(key->cipher_hnd);
+ key->cipher_hnd = NULL;
+ }
+
+ return 0;
+}
+
+NTSTATUS smb2_signing_key_copy(TALLOC_CTX *mem_ctx,
+ const struct smb2_signing_key *src,
+ struct smb2_signing_key **_dst)
+{
+ struct smb2_signing_key *dst = NULL;
+
+ dst = talloc_zero(mem_ctx, struct smb2_signing_key);
+ if (dst == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_set_destructor(dst, smb2_signing_key_destructor);
+
+ dst->sign_algo_id = src->sign_algo_id;
+ dst->cipher_algo_id = src->cipher_algo_id;
+
+ if (src->blob.length == 0) {
+ *_dst = dst;
+ return NT_STATUS_OK;
+ }
+
+ dst->blob = data_blob_talloc_zero(dst, src->blob.length);
+ if (dst->blob.length == 0) {
+ TALLOC_FREE(dst);
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_keep_secret(dst->blob.data);
+ memcpy(dst->blob.data, src->blob.data, dst->blob.length);
+
+ *_dst = dst;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smb2_signing_key_create(TALLOC_CTX *mem_ctx,
+ uint16_t sign_algo_id,
+ uint16_t cipher_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key)
+{
+ struct smb2_signing_key *key = NULL;
+ size_t in_key_length = 16;
+ size_t out_key_length = 16;
+ NTSTATUS status;
+
+ if (sign_algo_id != SMB2_SIGNING_INVALID_ALGO) {
+ SMB_ASSERT(cipher_algo_id == SMB2_ENCRYPTION_INVALID_ALGO);
+ }
+ if (cipher_algo_id != SMB2_ENCRYPTION_INVALID_ALGO) {
+ SMB_ASSERT(sign_algo_id == SMB2_SIGNING_INVALID_ALGO);
+ }
+
+ key = talloc_zero(mem_ctx, struct smb2_signing_key);
+ if (key == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_set_destructor(key, smb2_signing_key_destructor);
+
+ key->sign_algo_id = sign_algo_id;
+ key->cipher_algo_id = cipher_algo_id;
+
+ if (master_key == NULL) {
+ SMB_ASSERT(d == NULL);
+
+ *_key = key;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Per default use the full key.
+ */
+ in_key_length = out_key_length = master_key->length;
+ switch (sign_algo_id) {
+ case SMB2_SIGNING_INVALID_ALGO:
+ /*
+ * This means we're processing cipher_algo_id below
+ */
+ break;
+ case SMB2_SIGNING_MD5_SMB1:
+ SMB_ASSERT(d == NULL);
+ break;
+ case SMB2_SIGNING_HMAC_SHA256:
+ case SMB2_SIGNING_AES128_CMAC:
+ case SMB2_SIGNING_AES128_GMAC:
+ /*
+ * signing keys are padded or truncated to
+ * 16 bytes.
+ *
+ * Even with master_key->length = 0,
+ * we need to use 16 zeros.
+ */
+ in_key_length = out_key_length = 16;
+ break;
+ default:
+ DBG_ERR("sign_algo_id[%u] not supported\n", sign_algo_id);
+ return NT_STATUS_HMAC_NOT_SUPPORTED;
+ }
+ switch (cipher_algo_id) {
+ case SMB2_ENCRYPTION_INVALID_ALGO:
+ /*
+ * This means we're processing sign_algo_id above
+ */
+ break;
+ case SMB2_ENCRYPTION_NONE:
+ /*
+ * No encryption negotiated.
+ */
+ break;
+ case SMB2_ENCRYPTION_AES128_CCM:
+ case SMB2_ENCRYPTION_AES128_GCM:
+ /*
+ * encryption keys are padded or truncated to
+ * 16 bytes.
+ */
+ if (master_key->length == 0) {
+ DBG_ERR("cipher_algo_id[%u] without key\n",
+ cipher_algo_id);
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ in_key_length = out_key_length = 16;
+ break;
+ case SMB2_ENCRYPTION_AES256_CCM:
+ case SMB2_ENCRYPTION_AES256_GCM:
+ /*
+ * AES256 uses the available input and
+ * generated a 32 byte encryption key.
+ */
+ if (master_key->length == 0) {
+ DBG_ERR("cipher_algo_id[%u] without key\n",
+ cipher_algo_id);
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ out_key_length = 32;
+ break;
+ default:
+ DBG_ERR("cipher_algo_id[%u] not supported\n", cipher_algo_id);
+ return NT_STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG;
+ }
+
+ if (out_key_length == 0) {
+ *_key = key;
+ return NT_STATUS_OK;
+ }
+
+ key->blob = data_blob_talloc_zero(key, out_key_length);
+ if (key->blob.length == 0) {
+ TALLOC_FREE(key);
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_keep_secret(key->blob.data);
+ memcpy(key->blob.data,
+ master_key->data,
+ MIN(key->blob.length, master_key->length));
+
+ if (d == NULL) {
+ *_key = key;
+ return NT_STATUS_OK;
+ }
+
+ status = samba_gnutls_sp800_108_derive_key(key->blob.data,
+ in_key_length,
+ NULL,
+ 0,
+ d->label.data,
+ d->label.length,
+ d->context.data,
+ d->context.length,
+ GNUTLS_MAC_SHA256,
+ key->blob.data,
+ out_key_length);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(key);
+ return status;
+ }
+
+ *_key = key;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2_signing_key_sign_create(TALLOC_CTX *mem_ctx,
+ uint16_t sign_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key)
+{
+ return smb2_signing_key_create(mem_ctx,
+ sign_algo_id,
+ SMB2_ENCRYPTION_INVALID_ALGO,
+ master_key,
+ d,
+ _key);
+}
+
+NTSTATUS smb2_signing_key_cipher_create(TALLOC_CTX *mem_ctx,
+ uint16_t cipher_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key)
+{
+ return smb2_signing_key_create(mem_ctx,
+ SMB2_SIGNING_INVALID_ALGO,
+ cipher_algo_id,
+ master_key,
+ d,
+ _key);
+}
+
+bool smb2_signing_key_valid(const struct smb2_signing_key *key)
+{
+ if (key == NULL) {
+ return false;
+ }
+
+ if (key->blob.length == 0 || key->blob.data == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+static NTSTATUS smb2_signing_gmac(gnutls_aead_cipher_hd_t cipher_hnd,
+ const uint8_t *iv, size_t iv_size,
+ const giovec_t *auth_iov, uint8_t auth_iovcnt,
+ uint8_t *tag, size_t _tag_size)
+{
+ size_t tag_size = _tag_size;
+ int rc;
+
+ rc = gnutls_aead_cipher_encryptv2(cipher_hnd,
+ iv, iv_size,
+ auth_iov, auth_iovcnt,
+ NULL, 0,
+ tag, &tag_size);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smb2_signing_calc_signature(struct smb2_signing_key *signing_key,
+ uint16_t sign_algo_id,
+ const struct iovec *vector,
+ int count,
+ uint8_t signature[16])
+{
+ const uint8_t *hdr = (uint8_t *)vector[0].iov_base;
+ uint16_t opcode;
+ uint32_t flags;
+ uint64_t msg_id;
+ static const uint8_t zero_sig[16] = { 0, };
+ gnutls_mac_algorithm_t hmac_algo = GNUTLS_MAC_UNKNOWN;
+ int i;
+
+ /*
+ * We expect
+ * - SMB2 HDR
+ * - SMB2 BODY FIXED
+ * - (optional) SMB2 BODY DYN
+ * - (optional) PADDING
+ */
+ SMB_ASSERT(count >= 2);
+ SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
+ SMB_ASSERT(count <= 4);
+
+ opcode = SVAL(hdr, SMB2_HDR_OPCODE);
+ flags = IVAL(hdr, SMB2_HDR_FLAGS);
+ if (flags & SMB2_HDR_FLAG_REDIRECT) {
+ NTSTATUS pdu_status = NT_STATUS(IVAL(hdr, SMB2_HDR_STATUS));
+ if (NT_STATUS_EQUAL(pdu_status, NT_STATUS_PENDING)) {
+ DBG_ERR("opcode[%u] NT_STATUS_PENDING\n", opcode);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ if (opcode == SMB2_OP_CANCEL) {
+ DBG_ERR("SMB2_OP_CANCEL response should not be signed\n");
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+ msg_id = BVAL(hdr, SMB2_HDR_MESSAGE_ID);
+ if (msg_id == 0) {
+ if (opcode != SMB2_OP_CANCEL ||
+ sign_algo_id >= SMB2_SIGNING_AES128_GMAC)
+ {
+ DBG_ERR("opcode[%u] msg_id == 0\n", opcode);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ /*
+ * Legacy algorithms allow MID 0
+ * for cancel requests
+ */
+ }
+ if (msg_id == UINT64_MAX) {
+ DBG_ERR("opcode[%u] msg_id == UINT64_MAX\n", opcode);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ switch (sign_algo_id) {
+ case SMB2_SIGNING_AES128_GMAC: {
+ gnutls_cipher_algorithm_t algo = GNUTLS_CIPHER_AES_128_GCM;
+ uint32_t key_size = gnutls_cipher_get_key_size(algo);
+ uint32_t iv_size = gnutls_cipher_get_iv_size(algo);
+ size_t tag_size = gnutls_cipher_get_tag_size(algo);
+ gnutls_datum_t key = {
+ .data = signing_key->blob.data,
+ .size = MIN(signing_key->blob.length, key_size),
+ };
+ uint64_t high_bits = 0;
+ uint8_t iv[AES_BLOCK_SIZE] = {0};
+ giovec_t auth_iov[count+1];
+ size_t auth_iovcnt = 0;
+ NTSTATUS status;
+ int rc;
+
+ high_bits = flags & SMB2_HDR_FLAG_REDIRECT;
+ if (opcode == SMB2_OP_CANCEL) {
+ high_bits |= SMB2_HDR_FLAG_ASYNC;
+ }
+ SBVAL(iv, 0, msg_id);
+ SBVAL(iv, 8, high_bits);
+
+ if (signing_key->cipher_hnd == NULL) {
+ rc = gnutls_aead_cipher_init(&signing_key->cipher_hnd,
+ algo,
+ &key);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ }
+
+ SMB_ASSERT(key_size == 16);
+ SMB_ASSERT(iv_size == 12);
+ SMB_ASSERT(tag_size == 16);
+
+ auth_iov[auth_iovcnt++] = (giovec_t) {
+ .iov_base = discard_const_p(uint8_t, hdr),
+ .iov_len = SMB2_HDR_SIGNATURE,
+ };
+ auth_iov[auth_iovcnt++] = (giovec_t) {
+ .iov_base = discard_const_p(uint8_t, zero_sig),
+ .iov_len = 16,
+ };
+ for (i=1; i < count; i++) {
+ auth_iov[auth_iovcnt++] = (giovec_t) {
+ .iov_base = discard_const_p(uint8_t, vector[i].iov_base),
+ .iov_len = vector[i].iov_len,
+ };
+ }
+
+ status = smb2_signing_gmac(signing_key->cipher_hnd,
+ iv,
+ iv_size,
+ auth_iov,
+ auth_iovcnt,
+ signature,
+ tag_size);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+ } break;
+
+ case SMB2_SIGNING_AES128_CMAC:
+ hmac_algo = GNUTLS_MAC_AES_CMAC_128;
+ break;
+ case SMB2_SIGNING_HMAC_SHA256:
+ hmac_algo = GNUTLS_MAC_SHA256;
+ break;
+
+ default:
+ return NT_STATUS_HMAC_NOT_SUPPORTED;
+ }
+
+ if (hmac_algo != GNUTLS_MAC_UNKNOWN) {
+ uint8_t digest[gnutls_hmac_get_len(hmac_algo)];
+ gnutls_datum_t key = {
+ .data = signing_key->blob.data,
+ .size = MIN(signing_key->blob.length, 16),
+ };
+ int rc;
+
+ if (signing_key->hmac_hnd == NULL) {
+ rc = gnutls_hmac_init(&signing_key->hmac_hnd,
+ hmac_algo,
+ key.data,
+ key.size);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ }
+
+ rc = gnutls_hmac(signing_key->hmac_hnd, hdr, SMB2_HDR_SIGNATURE);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ rc = gnutls_hmac(signing_key->hmac_hnd, zero_sig, 16);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+ for (i = 1; i < count; i++) {
+ rc = gnutls_hmac(signing_key->hmac_hnd,
+ vector[i].iov_base,
+ vector[i].iov_len);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+ }
+ gnutls_hmac_output(signing_key->hmac_hnd, digest);
+ memcpy(signature, digest, 16);
+ ZERO_ARRAY(digest);
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_HMAC_NOT_SUPPORTED;
+}
+
+NTSTATUS smb2_signing_sign_pdu(struct smb2_signing_key *signing_key,
+ struct iovec *vector,
+ int count)
+{
+ uint16_t sign_algo_id;
+ uint8_t *hdr;
+ uint64_t session_id;
+ uint8_t res[16];
+ NTSTATUS status;
+
+ /*
+ * We expect
+ * - SMB2 HDR
+ * - SMB2 BODY FIXED
+ * - (optional) SMB2 BODY DYN
+ * - (optional) PADDING
+ */
+ SMB_ASSERT(count >= 2);
+ SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
+ SMB_ASSERT(count <= 4);
+
+ hdr = (uint8_t *)vector[0].iov_base;
+
+ session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
+ if (session_id == 0) {
+ /*
+ * do not sign messages with a zero session_id.
+ * See MS-SMB2 3.2.4.1.1
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (!smb2_signing_key_valid(signing_key)) {
+ DBG_WARNING("No signing key for SMB2 signing\n");
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ memset(hdr + SMB2_HDR_SIGNATURE, 0, 16);
+
+ SIVAL(hdr, SMB2_HDR_FLAGS, IVAL(hdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_SIGNED);
+
+ sign_algo_id = signing_key->sign_algo_id;
+
+ status = smb2_signing_calc_signature(signing_key,
+ sign_algo_id,
+ vector,
+ count,
+ res);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
+ (unsigned)sign_algo_id, nt_errstr(status));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) {
+ smb_panic(__location__);
+ }
+ return status;
+ }
+
+ DEBUG(5,("signed SMB2 message (sign_algo_id=%u)\n",
+ (unsigned)sign_algo_id));
+
+ memcpy(hdr + SMB2_HDR_SIGNATURE, res, 16);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key,
+ const struct iovec *vector,
+ int count)
+{
+ uint16_t sign_algo_id;
+ const uint8_t *hdr;
+ const uint8_t *sig;
+ uint64_t session_id;
+ uint8_t res[16];
+ NTSTATUS status;
+
+ /*
+ * We expect
+ * - SMB2 HDR
+ * - SMB2 BODY FIXED
+ * - (optional) SMB2 BODY DYN
+ * - (optional) PADDING
+ */
+ SMB_ASSERT(count >= 2);
+ SMB_ASSERT(vector[0].iov_len == SMB2_HDR_BODY);
+ SMB_ASSERT(count <= 4);
+
+ hdr = (const uint8_t *)vector[0].iov_base;
+
+ session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
+ if (session_id == 0) {
+ /*
+ * do not sign messages with a zero session_id.
+ * See MS-SMB2 3.2.4.1.1
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (!smb2_signing_key_valid(signing_key)) {
+ /* we don't have the session key yet */
+ return NT_STATUS_OK;
+ }
+
+ sig = hdr+SMB2_HDR_SIGNATURE;
+
+ sign_algo_id = signing_key->sign_algo_id;
+
+ status = smb2_signing_calc_signature(signing_key,
+ sign_algo_id,
+ vector,
+ count,
+ res);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("smb2_signing_calc_signature(sign_algo_id=%u) - %s\n",
+ (unsigned)sign_algo_id, nt_errstr(status));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_ERROR)) {
+ status = NT_STATUS_ACCESS_DENIED;
+ }
+ return status;
+ }
+
+ if (!mem_equal_const_time(res, sig, 16)) {
+ DEBUG(0,("Bad SMB2 (sign_algo_id=%u) signature for message\n",
+ (unsigned)sign_algo_id));
+ dump_data(0, sig, 16);
+ dump_data(0, res, 16);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2_signing_encrypt_pdu(struct smb2_signing_key *encryption_key,
+ struct iovec *vector,
+ int count)
+{
+ bool use_encryptv2 = false;
+ uint16_t cipher_id;
+ uint8_t *tf;
+ size_t a_total;
+ ssize_t m_total;
+ uint32_t iv_size = 0;
+ uint32_t key_size = 0;
+ size_t tag_size = 0;
+ gnutls_cipher_algorithm_t algo = 0;
+ gnutls_datum_t key;
+ gnutls_datum_t iv;
+ NTSTATUS status;
+ int rc;
+
+ if (count < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ tf = (uint8_t *)vector[0].iov_base;
+
+ if (!smb2_signing_key_valid(encryption_key)) {
+ DBG_WARNING("No encryption key for SMB2 signing\n");
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ cipher_id = encryption_key->cipher_algo_id;
+
+ a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
+
+ m_total = iov_buflen(&vector[1], count-1);
+ if (m_total == -1) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ SSVAL(tf, SMB2_TF_FLAGS, SMB2_TF_FLAGS_ENCRYPTED);
+ SIVAL(tf, SMB2_TF_MSG_SIZE, m_total);
+
+ switch (cipher_id) {
+ case SMB2_ENCRYPTION_AES128_CCM:
+ algo = GNUTLS_CIPHER_AES_128_CCM;
+ iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
+#ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
+ use_encryptv2 = true;
+#endif
+ break;
+ case SMB2_ENCRYPTION_AES128_GCM:
+ algo = GNUTLS_CIPHER_AES_128_GCM;
+ iv_size = gnutls_cipher_get_iv_size(algo);
+ use_encryptv2 = true;
+ break;
+ case SMB2_ENCRYPTION_AES256_CCM:
+ algo = GNUTLS_CIPHER_AES_256_CCM;
+ iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
+#ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
+ use_encryptv2 = true;
+#endif
+ break;
+ case SMB2_ENCRYPTION_AES256_GCM:
+ algo = GNUTLS_CIPHER_AES_256_GCM;
+ iv_size = gnutls_cipher_get_iv_size(algo);
+ use_encryptv2 = true;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ key_size = gnutls_cipher_get_key_size(algo);
+ tag_size = gnutls_cipher_get_tag_size(algo);
+
+ if (key_size != encryption_key->blob.length) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (tag_size != 16) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ key = (gnutls_datum_t) {
+ .data = encryption_key->blob.data,
+ .size = key_size,
+ };
+
+ iv = (gnutls_datum_t) {
+ .data = tf + SMB2_TF_NONCE,
+ .size = iv_size,
+ };
+
+ if (encryption_key->cipher_hnd == NULL) {
+ rc = gnutls_aead_cipher_init(&encryption_key->cipher_hnd,
+ algo,
+ &key);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+ }
+
+ memset(tf + SMB2_TF_NONCE + iv_size,
+ 0,
+ 16 - iv_size);
+
+ if (use_encryptv2) {
+ uint8_t tag[tag_size];
+ giovec_t auth_iov[1];
+
+ auth_iov[0] = (giovec_t) {
+ .iov_base = tf + SMB2_TF_NONCE,
+ .iov_len = a_total,
+ };
+
+ rc = gnutls_aead_cipher_encryptv2(encryption_key->cipher_hnd,
+ iv.data,
+ iv.size,
+ auth_iov,
+ 1,
+ &vector[1],
+ count - 1,
+ tag,
+ &tag_size);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+
+ memcpy(tf + SMB2_TF_SIGNATURE, tag, tag_size);
+ } else
+ {
+ size_t ptext_size = m_total;
+ uint8_t *ptext = NULL;
+ size_t ctext_size = m_total + tag_size;
+ uint8_t *ctext = NULL;
+ size_t len = 0;
+ int i;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ /*
+ * If we come from python bindings, we don't have a stackframe
+ * around, so use the NULL context.
+ *
+ * This is fine as we make sure we free the memory.
+ */
+ if (talloc_stackframe_exists()) {
+ tmp_ctx = talloc_tos();
+ }
+
+ ptext = talloc_size(tmp_ctx, ptext_size);
+ if (ptext == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ctext = talloc_size(tmp_ctx, ctext_size);
+ if (ctext == NULL) {
+ TALLOC_FREE(ptext);
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ for (i = 1; i < count; i++) {
+ if (vector[i].iov_base != NULL) {
+ memcpy(ptext + len,
+ vector[i].iov_base,
+ vector[i].iov_len);
+ }
+
+ len += vector[i].iov_len;
+ if (len > ptext_size) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto out;
+ }
+ }
+
+ rc = gnutls_aead_cipher_encrypt(encryption_key->cipher_hnd,
+ iv.data,
+ iv.size,
+ tf + SMB2_TF_NONCE,
+ a_total,
+ tag_size,
+ ptext,
+ ptext_size,
+ ctext,
+ &ctext_size);
+ if (rc < 0 || ctext_size != m_total + tag_size) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+
+ len = 0;
+ for (i = 1; i < count; i++) {
+ if (vector[i].iov_base != NULL) {
+ memcpy(vector[i].iov_base,
+ ctext + len,
+ vector[i].iov_len);
+ }
+
+ len += vector[i].iov_len;
+ }
+
+ memcpy(tf + SMB2_TF_SIGNATURE, ctext + m_total, tag_size);
+
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ }
+
+ DBG_INFO("Encrypted SMB2 message\n");
+
+ status = NT_STATUS_OK;
+out:
+ return status;
+}
+
+NTSTATUS smb2_signing_decrypt_pdu(struct smb2_signing_key *decryption_key,
+ struct iovec *vector,
+ int count)
+{
+ bool use_encryptv2 = false;
+ uint16_t cipher_id;
+ uint8_t *tf;
+ uint16_t flags;
+ size_t a_total;
+ ssize_t m_total;
+ uint32_t msg_size = 0;
+ uint32_t iv_size = 0;
+ uint32_t key_size = 0;
+ size_t tag_size = 0;
+ gnutls_cipher_algorithm_t algo = 0;
+ gnutls_datum_t key;
+ gnutls_datum_t iv;
+ NTSTATUS status;
+ int rc;
+
+ if (count < 1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (vector[0].iov_len != SMB2_TF_HDR_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ tf = (uint8_t *)vector[0].iov_base;
+
+ if (!smb2_signing_key_valid(decryption_key)) {
+ DBG_WARNING("No decryption key for SMB2 signing\n");
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ cipher_id = decryption_key->cipher_algo_id;
+
+ a_total = SMB2_TF_HDR_SIZE - SMB2_TF_NONCE;
+
+ m_total = iov_buflen(&vector[1], count-1);
+ if (m_total == -1) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ flags = SVAL(tf, SMB2_TF_FLAGS);
+ msg_size = IVAL(tf, SMB2_TF_MSG_SIZE);
+
+ if (flags != SMB2_TF_FLAGS_ENCRYPTED) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (msg_size != m_total) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ switch (cipher_id) {
+ case SMB2_ENCRYPTION_AES128_CCM:
+ algo = GNUTLS_CIPHER_AES_128_CCM;
+ iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
+#ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
+ use_encryptv2 = true;
+#endif
+ break;
+ case SMB2_ENCRYPTION_AES128_GCM:
+ algo = GNUTLS_CIPHER_AES_128_GCM;
+ iv_size = gnutls_cipher_get_iv_size(algo);
+ use_encryptv2 = true;
+ break;
+ case SMB2_ENCRYPTION_AES256_CCM:
+ algo = GNUTLS_CIPHER_AES_256_CCM;
+ iv_size = SMB2_AES_128_CCM_NONCE_SIZE;
+#ifdef ALLOW_GNUTLS_AEAD_CIPHER_ENCRYPTV2_AES_CCM
+ use_encryptv2 = true;
+#endif
+ break;
+ case SMB2_ENCRYPTION_AES256_GCM:
+ algo = GNUTLS_CIPHER_AES_256_GCM;
+ iv_size = gnutls_cipher_get_iv_size(algo);
+ use_encryptv2 = true;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ key_size = gnutls_cipher_get_key_size(algo);
+ tag_size = gnutls_cipher_get_tag_size(algo);
+
+ if (key_size != decryption_key->blob.length) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (tag_size != 16) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ key = (gnutls_datum_t) {
+ .data = decryption_key->blob.data,
+ .size = key_size,
+ };
+
+ iv = (gnutls_datum_t) {
+ .data = tf + SMB2_TF_NONCE,
+ .size = iv_size,
+ };
+
+ if (decryption_key->cipher_hnd == NULL) {
+ rc = gnutls_aead_cipher_init(&decryption_key->cipher_hnd,
+ algo,
+ &key);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+ }
+
+ if (use_encryptv2) {
+ giovec_t auth_iov[1];
+
+ auth_iov[0] = (giovec_t) {
+ .iov_base = tf + SMB2_TF_NONCE,
+ .iov_len = a_total,
+ };
+
+ rc = gnutls_aead_cipher_decryptv2(decryption_key->cipher_hnd,
+ iv.data,
+ iv.size,
+ auth_iov,
+ 1,
+ &vector[1],
+ count - 1,
+ tf + SMB2_TF_SIGNATURE,
+ tag_size);
+ if (rc < 0) {
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+ } else
+ {
+ size_t ctext_size = m_total + tag_size;
+ uint8_t *ctext = NULL;
+ size_t ptext_size = m_total;
+ uint8_t *ptext = NULL;
+ size_t len = 0;
+ int i;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ /*
+ * If we come from python bindings, we don't have a stackframe
+ * around, so use the NULL context.
+ *
+ * This is fine as we make sure we free the memory.
+ */
+ if (talloc_stackframe_exists()) {
+ tmp_ctx = talloc_tos();
+ }
+
+ /* GnuTLS doesn't have a iovec API for decryption yet */
+
+ ptext = talloc_size(tmp_ctx, ptext_size);
+ if (ptext == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ ctext = talloc_size(tmp_ctx, ctext_size);
+ if (ctext == NULL) {
+ TALLOC_FREE(ptext);
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+
+ for (i = 1; i < count; i++) {
+ memcpy(ctext + len,
+ vector[i].iov_base,
+ vector[i].iov_len);
+
+ len += vector[i].iov_len;
+ }
+ if (len != m_total) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto out;
+ }
+
+ memcpy(ctext + len,
+ tf + SMB2_TF_SIGNATURE,
+ tag_size);
+
+ /* This function will verify the tag */
+ rc = gnutls_aead_cipher_decrypt(decryption_key->cipher_hnd,
+ iv.data,
+ iv.size,
+ tf + SMB2_TF_NONCE,
+ a_total,
+ tag_size,
+ ctext,
+ ctext_size,
+ ptext,
+ &ptext_size);
+ if (rc < 0) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+ if (ptext_size != m_total) {
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ rc = GNUTLS_E_SHORT_MEMORY_BUFFER;
+ status = gnutls_error_to_ntstatus(rc, NT_STATUS_INTERNAL_ERROR);
+ goto out;
+ }
+
+ len = 0;
+ for (i = 1; i < count; i++) {
+ memcpy(vector[i].iov_base,
+ ptext + len,
+ vector[i].iov_len);
+
+ len += vector[i].iov_len;
+ }
+
+ TALLOC_FREE(ptext);
+ TALLOC_FREE(ctext);
+ }
+
+ DBG_INFO("Decrypted SMB2 message\n");
+
+ status = NT_STATUS_OK;
+out:
+ return status;
+}
diff --git a/libcli/smb/smb2_signing.h b/libcli/smb/smb2_signing.h
new file mode 100644
index 0000000..2b8eef9
--- /dev/null
+++ b/libcli/smb/smb2_signing.h
@@ -0,0 +1,102 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB2 signing
+
+ Copyright (C) Stefan Metzmacher 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 _LIBCLI_SMB_SMB2_SIGNING_H_
+#define _LIBCLI_SMB_SMB2_SIGNING_H_
+
+#include <gnutls/gnutls.h>
+
+#include "lib/util/data_blob.h"
+
+#include "libcli/smb/smb_constants.h"
+#include "libcli/util/ntstatus.h"
+
+struct iovec;
+
+struct smb2_signing_derivation {
+ DATA_BLOB label;
+ DATA_BLOB context;
+};
+
+struct smb2_signing_derivations {
+ struct smb2_signing_derivation __signing;
+ const struct smb2_signing_derivation *signing;
+ struct smb2_signing_derivation __cipher_c2s;
+ const struct smb2_signing_derivation *cipher_c2s;
+ struct smb2_signing_derivation __cipher_s2c;
+ const struct smb2_signing_derivation *cipher_s2c;
+ struct smb2_signing_derivation __application;
+ const struct smb2_signing_derivation *application;
+};
+
+void smb2_signing_derivations_fill_const_stack(struct smb2_signing_derivations *ds,
+ enum protocol_types protocol,
+ const DATA_BLOB preauth_hash);
+
+struct smb2_signing_key {
+ DATA_BLOB blob;
+ uint16_t sign_algo_id;
+ union {
+#ifdef SMB2_SIGNING_KEY_GNUTLS_TYPES
+ gnutls_hmac_hd_t hmac_hnd;
+#endif
+ void *__hmac_hnd;
+ };
+ uint16_t cipher_algo_id;
+ union {
+#ifdef SMB2_SIGNING_KEY_GNUTLS_TYPES
+ gnutls_aead_cipher_hd_t cipher_hnd;
+#endif
+ void *__cipher_hnd;
+ };
+};
+
+NTSTATUS smb2_signing_key_copy(TALLOC_CTX *mem_ctx,
+ const struct smb2_signing_key *src,
+ struct smb2_signing_key **_dst);
+NTSTATUS smb2_signing_key_sign_create(TALLOC_CTX *mem_ctx,
+ uint16_t sign_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key);
+NTSTATUS smb2_signing_key_cipher_create(TALLOC_CTX *mem_ctx,
+ uint16_t cipher_algo_id,
+ const DATA_BLOB *master_key,
+ const struct smb2_signing_derivation *d,
+ struct smb2_signing_key **_key);
+
+bool smb2_signing_key_valid(const struct smb2_signing_key *key);
+
+NTSTATUS smb2_signing_sign_pdu(struct smb2_signing_key *signing_key,
+ struct iovec *vector,
+ int count);
+
+NTSTATUS smb2_signing_check_pdu(struct smb2_signing_key *signing_key,
+ const struct iovec *vector,
+ int count);
+
+NTSTATUS smb2_signing_encrypt_pdu(struct smb2_signing_key *encryption_key,
+ struct iovec *vector,
+ int count);
+NTSTATUS smb2_signing_decrypt_pdu(struct smb2_signing_key *decryption_key,
+ struct iovec *vector,
+ int count);
+
+#endif /* _LIBCLI_SMB_SMB2_SIGNING_H_ */
diff --git a/libcli/smb/smb2cli_close.c b/libcli/smb/smb2cli_close.c
new file mode 100644
index 0000000..5e31056
--- /dev/null
+++ b/libcli/smb/smb2cli_close.c
@@ -0,0 +1,136 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_close_state {
+ uint8_t fixed[24];
+};
+
+static void smb2cli_close_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_close_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_close_state *state;
+ uint8_t *fixed;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_close_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 24);
+ SSVAL(fixed, 2, flags);
+ SBVAL(fixed, 8, fid_persistent);
+ SBVAL(fixed, 16, fid_volatile);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_CLOSE,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_close_done, req);
+ return req;
+}
+
+static void smb2cli_close_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x3C
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_close_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_close(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_close_send(frame, ev, conn, timeout_msec,
+ session, tcon, flags,
+ fid_persistent, fid_volatile);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_close_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c
new file mode 100644
index 0000000..e740365
--- /dev/null
+++ b/libcli/smb/smb2cli_create.c
@@ -0,0 +1,580 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+#include "smb2_create_blob.h"
+#include "reparse.h"
+
+struct smb2cli_create_state {
+ enum protocol_types protocol; /* for symlink error response parser */
+ uint8_t *name_utf16;
+ size_t name_utf16_len;
+ uint8_t fixed[56];
+
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+ struct smb_create_returns cr;
+ struct smb2_create_blobs blobs;
+ struct symlink_reparse_struct *symlink;
+ struct tevent_req *subreq;
+};
+
+static void smb2cli_create_done(struct tevent_req *subreq);
+static bool smb2cli_create_cancel(struct tevent_req *req);
+
+struct tevent_req *smb2cli_create_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *filename,
+ uint8_t oplock_level, /* SMB2_OPLOCK_LEVEL_* */
+ uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ struct smb2_create_blobs *blobs)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_create_state *state;
+ uint8_t *fixed;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ size_t blobs_offset;
+ uint8_t *dyn;
+ size_t dyn_len;
+ size_t max_dyn_len;
+ uint32_t additional_flags = 0;
+ uint32_t clear_flags = 0;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_create_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->protocol = smbXcli_conn_protocol(conn);
+
+ ok = convert_string_talloc(
+ state,
+ CH_UNIX,
+ CH_UTF16,
+ filename,
+ strlen(filename),
+ &state->name_utf16,
+ &state->name_utf16_len);
+ if (!ok) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+
+ if (strlen(filename) == 0) {
+ TALLOC_FREE(state->name_utf16);
+ state->name_utf16_len = 0;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0, 57);
+ SCVAL(fixed, 3, oplock_level);
+ SIVAL(fixed, 4, impersonation_level);
+ SIVAL(fixed, 24, desired_access);
+ SIVAL(fixed, 28, file_attributes);
+ SIVAL(fixed, 32, share_access);
+ SIVAL(fixed, 36, create_disposition);
+ SIVAL(fixed, 40, create_options);
+
+ SSVAL(fixed, 44, SMB2_HDR_BODY + 56);
+ SSVAL(fixed, 46, state->name_utf16_len);
+
+ blob = data_blob_null;
+
+ if (blobs != NULL) {
+ status = smb2_create_blob_push(state, &blob, *blobs);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ blobs_offset = state->name_utf16_len;
+ blobs_offset = ((blobs_offset + 3) & ~3);
+
+ if (blob.length > 0) {
+ blobs_offset = ((blobs_offset + 7) & ~7);
+ SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56);
+ SIVAL(fixed, 52, blob.length);
+ }
+
+ dyn_len = MAX(1, blobs_offset + blob.length);
+ dyn = talloc_zero_array(state, uint8_t, dyn_len);
+ if (tevent_req_nomem(dyn, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (state->name_utf16 != NULL) {
+ memcpy(dyn, state->name_utf16, state->name_utf16_len);
+ }
+
+ if (blob.data != NULL) {
+ memcpy(dyn + blobs_offset,
+ blob.data, blob.length);
+ data_blob_free(&blob);
+ }
+
+ if (smbXcli_conn_dfs_supported(conn) &&
+ smbXcli_tcon_is_dfs_share(tcon))
+ {
+ additional_flags |= SMB2_HDR_FLAG_DFS;
+ }
+
+ /*
+ * We use max_dyn_len = 0
+ * as we don't explicitly ask for any output length.
+ *
+ * But it's still possible for the server to return
+ * large create blobs.
+ */
+ max_dyn_len = 0;
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_CREATE,
+ additional_flags, clear_flags,
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ max_dyn_len);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_create_done, req);
+
+ state->subreq = subreq;
+ tevent_req_set_cancel_fn(req, smb2cli_create_cancel);
+
+ return req;
+}
+
+static bool smb2cli_create_cancel(struct tevent_req *req)
+{
+ struct smb2cli_create_state *state = tevent_req_data(req,
+ struct smb2cli_create_state);
+ return tevent_req_cancel(state->subreq);
+}
+
+/*
+ * [MS-SMB2] 2.2.2.2.1 Symbolic Link Error Response
+ */
+
+static NTSTATUS smb2cli_parse_symlink_error_response(
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *buf,
+ size_t buflen,
+ struct symlink_reparse_struct **psymlink)
+{
+ struct symlink_reparse_struct *symlink = NULL;
+ struct reparse_data_buffer reparse_buf = {
+ .tag = 0,
+ };
+ uint32_t symlink_length, error_tag;
+ NTSTATUS status;
+
+ if (buflen < 8) {
+ DBG_DEBUG("buffer too short: %zu bytes\n", buflen);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ symlink_length = IVAL(buf, 0);
+ if (symlink_length != (buflen-4)) {
+ DBG_DEBUG("symlink_length=%"PRIu32", (buflen-4)=%zu\n",
+ symlink_length, buflen-4);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ error_tag = IVAL(buf, 4);
+ if (error_tag != SYMLINK_ERROR_TAG) {
+ DBG_DEBUG("error_tag=%"PRIu32", expected 0x%x\n",
+ error_tag,
+ SYMLINK_ERROR_TAG);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ symlink = talloc(mem_ctx, struct symlink_reparse_struct);
+ if (symlink == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = reparse_data_buffer_parse(symlink,
+ &reparse_buf,
+ buf + 8,
+ buflen - 8);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("reparse_data_buffer_parse() failed: %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(symlink);
+ return status;
+ }
+
+ if (reparse_buf.tag != IO_REPARSE_TAG_SYMLINK) {
+ DBG_DEBUG("Got tag 0x%" PRIx32 ", "
+ "expected IO_REPARSE_TAG_SYMLINK\n",
+ reparse_buf.tag);
+ TALLOC_FREE(symlink);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *symlink = reparse_buf.parsed.lnk;
+ *psymlink = symlink;
+ return NT_STATUS_OK;
+}
+
+/*
+ * [MS-SMB2] 2.2.2 ErrorData
+ *
+ * This is in theory a broad API, but as right now we only have a
+ * single [MS-SMB2] 2.2.2.2.1 symlink error response we can return
+ * just this.
+ */
+static NTSTATUS smb2cli_create_error_data_parse(
+ enum protocol_types protocol,
+ uint8_t error_context_count,
+ uint32_t byte_count,
+ const uint8_t *buf,
+ size_t buflen,
+ TALLOC_CTX *mem_ctx,
+ struct symlink_reparse_struct **_symlink)
+{
+ struct symlink_reparse_struct *symlink = NULL;
+ uint32_t error_data_length, error_id;
+ NTSTATUS status;
+
+ if (protocol != PROTOCOL_SMB3_11) {
+ if (error_context_count != 0) {
+ DBG_DEBUG("Got error_context_count=%"PRIu8"\n",
+ error_context_count);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ status = smb2cli_parse_symlink_error_response(
+ mem_ctx, buf, buflen, &symlink);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ *_symlink = symlink;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * The STOPPED_ON_SYMLINK that I've seen coming from W2k16 has
+ * just a single array element in the [MS-SMB2] 2.2.2
+ * ErrorData array. We'll need to adapt this if there actually
+ * comes an array of multiple ErrorData elements.
+ */
+
+ if (error_context_count != 1) {
+ DBG_DEBUG("Got error_context_count=%"PRIu8"\n",
+ error_context_count);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (byte_count != buflen) {
+ DBG_DEBUG("bytecount=%"PRIu32", "
+ "buflen=%zu\n",
+ byte_count,
+ buflen);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (buflen < 8) {
+ DBG_DEBUG("buflen=%zu\n", buflen);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ error_data_length = IVAL(buf, 0);
+ if (error_data_length != (buflen - 8)) {
+ DBG_DEBUG("error_data_length=%"PRIu32", expected %zu\n",
+ error_data_length,
+ buflen - 8);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ error_id = IVAL(buf, 4);
+ if (error_id != 0) {
+ DBG_DEBUG("error_id=%"PRIu32", expected 0\n", error_id);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ status = smb2cli_parse_symlink_error_response(
+ mem_ctx, buf + 8, buflen - 8, &symlink);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_DEBUG("smb2cli_parse_symlink_error_response failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ *_symlink = symlink;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smb2cli_create_unparsed_unix_len(
+ size_t unparsed_utf16_len,
+ uint8_t *name_utf16,
+ size_t name_utf16_len,
+ size_t *_unparsed_unix_len)
+{
+ uint8_t *unparsed_utf16 = NULL;
+ uint8_t *unparsed_unix = NULL;
+ size_t unparsed_unix_len = 0;
+ bool ok;
+
+ if (unparsed_utf16_len > name_utf16_len) {
+ DBG_DEBUG("unparsed_utf16_len=%zu, name_utf16_len=%zu\n",
+ unparsed_utf16_len,
+ name_utf16_len);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (unparsed_utf16_len == 0) {
+ *_unparsed_unix_len = 0;
+ return NT_STATUS_OK;
+ }
+
+ unparsed_utf16 = name_utf16 + name_utf16_len - unparsed_utf16_len;
+
+ ok = convert_string_talloc(
+ talloc_tos(),
+ CH_UTF16,
+ CH_UNIX,
+ unparsed_utf16,
+ unparsed_utf16_len,
+ &unparsed_unix,
+ &unparsed_unix_len);
+ if (!ok) {
+ NTSTATUS status = map_nt_error_from_unix_common(errno);
+ DBG_DEBUG("convert_string_talloc failed: %s\n",
+ strerror(errno));
+ return status;
+ }
+ *_unparsed_unix_len = unparsed_unix_len;
+ return NT_STATUS_OK;
+}
+
+static void smb2cli_create_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_create_state *state =
+ tevent_req_data(req,
+ struct smb2cli_create_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint8_t *body;
+ uint32_t offset, length;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x59
+ },
+ {
+ .status = NT_STATUS_STOPPED_ON_SYMLINK,
+ .body_size = 0x9,
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
+ uint16_t error_context_count = CVAL(iov[1].iov_base, 2);
+ uint32_t byte_count = IVAL(iov[1].iov_base, 4);
+ size_t unparsed_unix_len = 0;
+
+ NTSTATUS symlink_status;
+
+ symlink_status = smb2cli_create_error_data_parse(
+ state->protocol,
+ error_context_count,
+ byte_count,
+ iov[2].iov_base,
+ iov[2].iov_len,
+ state,
+ &state->symlink);
+ if (tevent_req_nterror(req, symlink_status)) {
+ return;
+ }
+
+ /*
+ * Our callers want to know the unparsed length in
+ * unix encoding.
+ */
+ symlink_status = smb2cli_create_unparsed_unix_len(
+ state->symlink->unparsed_path_length,
+ state->name_utf16,
+ state->name_utf16_len,
+ &unparsed_unix_len);
+ if (tevent_req_nterror(req, symlink_status)) {
+ return;
+ }
+ state->symlink->unparsed_path_length = unparsed_unix_len;
+ }
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ body = (uint8_t *)iov[1].iov_base;
+
+ state->cr.oplock_level = CVAL(body, 2);
+ state->cr.flags = CVAL(body, 3);
+ state->cr.create_action = IVAL(body, 4);
+ state->cr.creation_time = BVAL(body, 8);
+ state->cr.last_access_time = BVAL(body, 16);
+ state->cr.last_write_time = BVAL(body, 24);
+ state->cr.change_time = BVAL(body, 32);
+ state->cr.allocation_size = BVAL(body, 40);
+ state->cr.end_of_file = BVAL(body, 48);
+ state->cr.file_attributes = IVAL(body, 56);
+ state->fid_persistent = BVAL(body, 64);
+ state->fid_volatile = BVAL(body, 72);
+
+ offset = IVAL(body, 80);
+ length = IVAL(body, 84);
+
+ if ((offset != 0) && (length != 0)) {
+ if ((offset != SMB2_HDR_BODY + 88) ||
+ (length > iov[2].iov_len)) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ status = smb2_create_blob_parse(
+ state, data_blob_const(iov[2].iov_base, length),
+ &state->blobs);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_create_recv(struct tevent_req *req,
+ uint64_t *fid_persistent,
+ uint64_t *fid_volatile,
+ struct smb_create_returns *cr,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs *blobs,
+ struct symlink_reparse_struct **psymlink)
+{
+ struct smb2cli_create_state *state =
+ tevent_req_data(req,
+ struct smb2cli_create_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
+ (psymlink != NULL)) {
+ *psymlink = talloc_move(mem_ctx, &state->symlink);
+ }
+ tevent_req_received(req);
+ return status;
+ }
+ *fid_persistent = state->fid_persistent;
+ *fid_volatile = state->fid_volatile;
+ if (cr) {
+ *cr = state->cr;
+ }
+ if (blobs) {
+ blobs->num_blobs = state->blobs.num_blobs;
+ blobs->blobs = talloc_move(mem_ctx, &state->blobs.blobs);
+ }
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_create(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *filename,
+ uint8_t oplock_level, /* SMB2_OPLOCK_LEVEL_* */
+ uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ struct smb2_create_blobs *blobs,
+ uint64_t *fid_persistent,
+ uint64_t *fid_volatile,
+ struct smb_create_returns *cr,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs *ret_blobs,
+ struct symlink_reparse_struct **psymlink)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_create_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ filename, oplock_level,
+ impersonation_level, desired_access,
+ file_attributes, share_access,
+ create_disposition, create_options,
+ blobs);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_create_recv(
+ req,
+ fid_persistent,
+ fid_volatile,
+ cr,
+ mem_ctx,
+ ret_blobs,
+ psymlink);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_echo.c b/libcli/smb/smb2cli_echo.c
new file mode 100644
index 0000000..39c592c
--- /dev/null
+++ b/libcli/smb/smb2cli_echo.c
@@ -0,0 +1,122 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_echo_state {
+ uint8_t fixed[0x4];
+};
+
+static void smb2cli_echo_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_echo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_echo_state *state;
+ uint8_t *fixed;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_echo_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 4);
+ SSVAL(fixed, 2, 0);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_KEEPALIVE,
+ 0, 0, /* flags */
+ timeout_msec,
+ NULL, /* tcon */
+ NULL, /* session */
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_echo_done, req);
+ return req;
+}
+
+static void smb2cli_echo_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x04
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_echo_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_echo(struct smbXcli_conn *conn,
+ uint32_t timeout_msec)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_echo_send(frame, ev, conn, timeout_msec);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_echo_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_flush.c b/libcli/smb/smb2cli_flush.c
new file mode 100644
index 0000000..f014720
--- /dev/null
+++ b/libcli/smb/smb2cli_flush.c
@@ -0,0 +1,133 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_flush_state {
+ uint8_t fixed[24];
+};
+
+static void smb2cli_flush_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_flush_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_flush_state *state;
+ uint8_t *fixed;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_flush_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 24);
+ SBVAL(fixed, 8, fid_persistent);
+ SBVAL(fixed, 16, fid_volatile);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_FLUSH,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_flush_done, req);
+ return req;
+}
+
+static void smb2cli_flush_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x04
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_flush_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_flush(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_flush_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ fid_persistent, fid_volatile);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_flush_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_ioctl.c b/libcli/smb/smb2cli_ioctl.c
new file mode 100644
index 0000000..2c1d76c
--- /dev/null
+++ b/libcli/smb/smb2cli_ioctl.c
@@ -0,0 +1,519 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
+
+struct smb2cli_ioctl_state {
+ uint8_t fixed[0x38];
+ uint8_t dyn_pad[1];
+ uint32_t max_input_length;
+ uint32_t max_output_length;
+ struct iovec *recv_iov;
+ bool out_valid;
+ DATA_BLOB out_input_buffer;
+ DATA_BLOB out_output_buffer;
+ uint32_t ctl_code;
+};
+
+static void smb2cli_ioctl_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ uint32_t in_ctl_code,
+ uint32_t in_max_input_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_output_buffer,
+ uint32_t in_flags)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_ioctl_state *state;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint32_t input_buffer_offset = 0;
+ uint32_t input_buffer_length = 0;
+ uint32_t output_buffer_offset = 0;
+ uint32_t output_buffer_length = 0;
+ uint32_t pad_length = 0;
+ uint64_t tmp64;
+ uint32_t max_dyn_len = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_ioctl_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ctl_code = in_ctl_code;
+ state->max_input_length = in_max_input_length;
+ state->max_output_length = in_max_output_length;
+
+ tmp64 = in_max_input_length;
+ tmp64 += in_max_output_length;
+ if (tmp64 > UINT32_MAX) {
+ max_dyn_len = UINT32_MAX;
+ } else {
+ max_dyn_len = tmp64;
+ }
+
+ if (in_input_buffer) {
+ input_buffer_offset = SMB2_HDR_BODY+0x38;
+ input_buffer_length = in_input_buffer->length;
+ }
+
+ if (in_output_buffer) {
+ output_buffer_offset = SMB2_HDR_BODY+0x38;
+ output_buffer_length = in_output_buffer->length;
+ if (input_buffer_length > 0 && output_buffer_length > 0) {
+ uint32_t tmp;
+ output_buffer_offset += input_buffer_length;
+ tmp = output_buffer_offset;
+ output_buffer_offset = NDR_ROUND(output_buffer_offset, 8);
+ pad_length = output_buffer_offset - tmp;
+ }
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0x00, 0x39);
+ SSVAL(fixed, 0x02, 0); /* reserved */
+ SIVAL(fixed, 0x04, in_ctl_code);
+ SBVAL(fixed, 0x08, in_fid_persistent);
+ SBVAL(fixed, 0x10, in_fid_volatile);
+ SIVAL(fixed, 0x18, input_buffer_offset);
+ SIVAL(fixed, 0x1C, input_buffer_length);
+ SIVAL(fixed, 0x20, in_max_input_length);
+ SIVAL(fixed, 0x24, output_buffer_offset);
+ SIVAL(fixed, 0x28, output_buffer_length);
+ SIVAL(fixed, 0x2C, in_max_output_length);
+ SIVAL(fixed, 0x30, in_flags);
+ SIVAL(fixed, 0x34, 0); /* reserved */
+
+ if (input_buffer_length > 0 && output_buffer_length > 0) {
+ size_t avail = UINT32_MAX - (input_buffer_length + pad_length);
+ size_t ofs = output_buffer_offset - input_buffer_offset;
+
+ if (avail < output_buffer_length) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ dyn_len = input_buffer_length + output_buffer_length + pad_length;
+
+ dyn = talloc_zero_array(state, uint8_t, dyn_len);
+ if (tevent_req_nomem(dyn, req)) {
+ return tevent_req_post(req, ev);
+ }
+ memcpy(dyn, in_input_buffer->data,
+ in_input_buffer->length);
+ memcpy(dyn + ofs, in_output_buffer->data,
+ in_output_buffer->length);
+ } else if (input_buffer_length > 0) {
+ dyn = in_input_buffer->data;
+ dyn_len = in_input_buffer->length;
+ } else if (output_buffer_length > 0) {
+ dyn = in_output_buffer->data;
+ dyn_len = in_output_buffer->length;
+ } else {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_IOCTL,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ max_dyn_len);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_ioctl_done, req);
+ return req;
+}
+
+static void smb2cli_ioctl_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_ioctl_state *state =
+ tevent_req_data(req,
+ struct smb2cli_ioctl_state);
+ NTSTATUS status;
+ NTSTATUS error;
+ struct iovec *iov;
+ uint8_t *fixed;
+ DATA_BLOB dyn_buffer = data_blob_null;
+ uint32_t dyn_ofs = SMB2_HDR_BODY + 0x30;
+ uint32_t input_min_offset;
+ uint32_t input_buffer_offset;
+ uint32_t input_buffer_length;
+ uint32_t input_next_offset;
+ uint32_t output_min_offset;
+ uint32_t output_buffer_offset;
+ uint32_t output_buffer_length;
+ uint32_t output_next_offset;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x31
+ },
+ {
+ .status = STATUS_BUFFER_OVERFLOW,
+ .body_size = 0x31
+ },
+ {
+ /*
+ * We need to make sure that
+ * a response with NT_STATUS_FILE_CLOSED
+ * without signing generates NT_STATUS_ACCESS_DENIED
+ * if the request was signed.
+ */
+ .status = NT_STATUS_FILE_CLOSED,
+ .body_size = 0x09,
+ },
+ {
+ /*
+ * a normal error
+ */
+ .status = NT_STATUS_INVALID_PARAMETER,
+ .body_size = 0x09
+ },
+ {
+ /*
+ * a special case for FSCTL_SRV_COPYCHUNK_*
+ */
+ .status = NT_STATUS_INVALID_PARAMETER,
+ .body_size = 0x31
+ },
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ switch (state->ctl_code) {
+ case FSCTL_SRV_COPYCHUNK:
+ case FSCTL_SRV_COPYCHUNK_WRITE:
+ break;
+ default:
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (iov[1].iov_len != 0x30) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ } else if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /* no error */
+ } else {
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ /*
+ * At this stage we're sure that got a body size of 0x31,
+ * either with NT_STATUS_OK, STATUS_BUFFER_OVERFLOW or
+ * NT_STATUS_INVALID_PARAMETER.
+ */
+
+ state->recv_iov = iov;
+ fixed = (uint8_t *)iov[1].iov_base;
+ dyn_buffer = data_blob_const((uint8_t *)iov[2].iov_base,
+ iov[2].iov_len);
+
+ input_buffer_offset = IVAL(fixed, 0x18);
+ input_buffer_length = IVAL(fixed, 0x1C);
+ output_buffer_offset = IVAL(fixed, 0x20);
+ output_buffer_length = IVAL(fixed, 0x24);
+
+ input_min_offset = dyn_ofs;
+ input_next_offset = dyn_ofs;
+ error = smb2cli_parse_dyn_buffer(dyn_ofs,
+ dyn_buffer,
+ input_min_offset,
+ input_buffer_offset,
+ input_buffer_length,
+ state->max_input_length,
+ &input_next_offset,
+ &state->out_input_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
+ }
+
+ /*
+ * If output data is returned, the output offset MUST be set to
+ * InputOffset + InputCount rounded up to a multiple of 8.
+ */
+ output_min_offset = NDR_ROUND(input_next_offset, 8);
+ output_next_offset = 0; /* this variable is completely ignored */
+ error = smb2cli_parse_dyn_buffer(dyn_ofs,
+ dyn_buffer,
+ output_min_offset,
+ output_buffer_offset,
+ output_buffer_length,
+ state->max_output_length,
+ &output_next_offset,
+ &state->out_output_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
+ }
+
+ state->out_valid = true;
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_ioctl_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_input_buffer,
+ DATA_BLOB *out_output_buffer)
+{
+ struct smb2cli_ioctl_state *state =
+ tevent_req_data(req,
+ struct smb2cli_ioctl_state);
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+ if (out_input_buffer) {
+ *out_input_buffer = data_blob_null;
+ }
+ if (out_output_buffer) {
+ *out_output_buffer = data_blob_null;
+ }
+ tevent_req_received(req);
+ return status;
+ }
+
+ talloc_steal(mem_ctx, state->recv_iov);
+ if (out_input_buffer) {
+ *out_input_buffer = state->out_input_buffer;
+ }
+ if (out_output_buffer) {
+ *out_output_buffer = state->out_output_buffer;
+ }
+
+ tevent_req_received(req);
+ return status;
+}
+
+NTSTATUS smb2cli_ioctl(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ uint32_t in_ctl_code,
+ uint32_t in_max_input_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_output_buffer,
+ uint32_t in_flags,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_input_buffer,
+ DATA_BLOB *out_output_buffer)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_ioctl_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ in_fid_persistent,
+ in_fid_volatile,
+ in_ctl_code,
+ in_max_input_length,
+ in_input_buffer,
+ in_max_output_length,
+ in_output_buffer,
+ in_flags);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_ioctl_recv(req, mem_ctx,
+ out_input_buffer,
+ out_output_buffer);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct smb2cli_ioctl_pipe_wait_state {
+ DATA_BLOB in_blob;
+ DATA_BLOB out_blob;
+};
+
+static void smb2cli_ioctl_pipe_wait_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_ioctl_pipe_wait_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *pipe_name,
+ uint64_t pipe_wait_timeout)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct smb2cli_ioctl_pipe_wait_state *state = NULL;
+ struct fsctl_pipe_wait fsctl = {0};
+ enum ndr_err_code err;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_ioctl_pipe_wait_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->out_blob = data_blob_string_const("");
+
+ fsctl.pipe_name = pipe_name;
+ fsctl.timeout = pipe_wait_timeout;
+ fsctl.timeout_specified = pipe_wait_timeout > 0 ? 1 : 0;
+
+ err = ndr_push_struct_blob(&state->in_blob, mem_ctx, &fsctl,
+ (ndr_push_flags_fn_t)ndr_push_fsctl_pipe_wait);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ return NULL;
+ }
+
+ subreq = smb2cli_ioctl_send(mem_ctx, ev, conn, timeout_msec,
+ session, tcon,
+ UINT64_MAX, UINT64_MAX,
+ FSCTL_PIPE_WAIT,
+ 0, &state->in_blob,
+ 0, &state->out_blob,
+ SMB2_IOCTL_FLAG_IS_FSCTL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(subreq, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_ioctl_pipe_wait_done, req);
+
+ return req;
+}
+
+static void smb2cli_ioctl_pipe_wait_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_ioctl_pipe_wait_state *state = tevent_req_data(
+ req, struct smb2cli_ioctl_pipe_wait_state);
+ NTSTATUS status;
+
+ status = smb2cli_ioctl_recv(subreq, state, NULL, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+
+NTSTATUS smb2cli_ioctl_pipe_wait_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_ioctl_pipe_wait(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *pipe_name,
+ uint64_t pipe_wait_timeout)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ req = smb2cli_ioctl_pipe_wait_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ pipe_name, pipe_wait_timeout);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+
+ status = smb2cli_ioctl_pipe_wait_recv(req);
+
+fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_notify.c b/libcli/smb/smb2cli_notify.c
new file mode 100644
index 0000000..9026a6b
--- /dev/null
+++ b/libcli/smb/smb2cli_notify.c
@@ -0,0 +1,236 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+#include "librpc/gen_ndr/ndr_notify.h"
+
+struct smb2cli_notify_state {
+ uint8_t fixed[32];
+
+ struct iovec *recv_iov;
+ uint8_t *data;
+ uint32_t data_length;
+
+ struct tevent_req *subreq;
+ struct tevent_req *timeout_subreq;
+};
+
+static void smb2cli_notify_done(struct tevent_req *subreq);
+static void smb2cli_notify_timedout(struct tevent_req *subreq);
+static bool smb2cli_notify_cancel(struct tevent_req *req);
+
+struct tevent_req *smb2cli_notify_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t output_buffer_length,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t completion_filter,
+ bool recursive)
+{
+ struct tevent_req *req;
+ struct smb2cli_notify_state *state;
+ uint8_t *fixed;
+ uint16_t watch_tree;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_notify_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ watch_tree = recursive ? SMB2_WATCH_TREE : 0;
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 32);
+ SSVAL(fixed, 2, watch_tree);
+ SIVAL(fixed, 4, output_buffer_length);
+ SBVAL(fixed, 8, fid_persistent);
+ SBVAL(fixed, 16, fid_volatile);
+ SIVAL(fixed, 24, completion_filter);
+ SIVAL(fixed, 28, 0); /* reserved */
+
+ state->subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_NOTIFY,
+ 0, 0, /* flags */
+ 0, /* timeout_msec */
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(state->subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(state->subreq, smb2cli_notify_done, req);
+
+ if (timeout_msec != 0) {
+ state->timeout_subreq = tevent_wakeup_send(
+ state, ev, timeval_current_ofs_msec(timeout_msec));
+ if (tevent_req_nomem(state->timeout_subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(
+ state->timeout_subreq, smb2cli_notify_timedout, req);
+ }
+
+ tevent_req_set_cancel_fn(req, smb2cli_notify_cancel);
+
+ return req;
+}
+
+static bool smb2cli_notify_cancel(struct tevent_req *req)
+{
+ struct smb2cli_notify_state *state = tevent_req_data(
+ req, struct smb2cli_notify_state);
+ bool ok;
+
+ TALLOC_FREE(state->timeout_subreq);
+
+ ok = tevent_req_cancel(state->subreq);
+ return ok;
+}
+
+static void smb2cli_notify_timedout(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_notify_state *state = tevent_req_data(
+ req, struct smb2cli_notify_state);
+ bool ok;
+
+ ok = tevent_wakeup_recv(subreq);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ ok = tevent_req_cancel(state->subreq);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+}
+
+static void smb2cli_notify_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_notify_state *state = tevent_req_data(
+ req, struct smb2cli_notify_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint16_t data_offset;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x09
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) {
+ status = NT_STATUS_IO_TIMEOUT;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ data_offset = SVAL(iov[1].iov_base, 2);
+ state->data_length = IVAL(iov[1].iov_base, 4);
+
+ if ((data_offset != SMB2_HDR_BODY + 8) ||
+ (state->data_length > iov[2].iov_len)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->recv_iov = iov;
+ state->data = (uint8_t *)iov[2].iov_base;
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **data, uint32_t *data_length)
+{
+ struct smb2cli_notify_state *state = tevent_req_data(
+ req, struct smb2cli_notify_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ talloc_steal(mem_ctx, state->recv_iov);
+ *data_length = state->data_length;
+ *data = state->data;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_notify(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t output_buffer_length,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t completion_filter,
+ bool recursive,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_notify_send(frame, ev, conn, timeout_msec,
+ session, tcon, output_buffer_length,
+ fid_persistent, fid_volatile,
+ completion_filter, recursive);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_notify_recv(req, mem_ctx, data, data_length);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_query_directory.c b/libcli/smb/smb2cli_query_directory.c
new file mode 100644
index 0000000..e6321ff
--- /dev/null
+++ b/libcli/smb/smb2cli_query_directory.c
@@ -0,0 +1,210 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_query_directory_state {
+ uint8_t fixed[32];
+ uint8_t dyn_pad[1];
+ struct iovec *recv_iov;
+ uint8_t *data;
+ uint32_t data_length;
+};
+
+static void smb2cli_query_directory_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_query_directory_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t level,
+ uint8_t flags,
+ uint32_t file_index,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ const char *mask,
+ uint32_t outbuf_len)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_query_directory_state *state;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_query_directory_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (!convert_string_talloc(state, CH_UNIX, CH_UTF16,
+ mask, strlen(mask),
+ &dyn, &dyn_len)) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+
+ if (strlen(mask) == 0) {
+ TALLOC_FREE(dyn);
+ dyn_len = 0;
+ }
+
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 33);
+ SCVAL(fixed, 2, level);
+ SCVAL(fixed, 3, flags);
+ SIVAL(fixed, 4, file_index);
+ SBVAL(fixed, 8, fid_persistent);
+ SBVAL(fixed, 16, fid_volatile);
+ SSVAL(fixed, 24, SMB2_HDR_BODY + 32);
+ SSVAL(fixed, 26, dyn_len);
+ SIVAL(fixed, 28, outbuf_len);
+
+ if (dyn_len == 0) {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_QUERY_DIRECTORY,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ outbuf_len); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_query_directory_done, req);
+ return req;
+}
+
+static void smb2cli_query_directory_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_query_directory_state *state =
+ tevent_req_data(req,
+ struct smb2cli_query_directory_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint16_t data_offset;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x09
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ data_offset = SVAL(iov[1].iov_base, 2);
+ state->data_length = IVAL(iov[1].iov_base, 4);
+
+ if ((data_offset != SMB2_HDR_BODY + 8) ||
+ (state->data_length > iov[2].iov_len)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->recv_iov = iov;
+ state->data = (uint8_t *)iov[2].iov_base;
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_query_directory_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length)
+{
+ struct smb2cli_query_directory_state *state =
+ tevent_req_data(req,
+ struct smb2cli_query_directory_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ talloc_steal(mem_ctx, state->recv_iov);
+ *data_length = state->data_length;
+ *data = state->data;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_query_directory(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t level,
+ uint8_t flags,
+ uint32_t file_index,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ const char *mask,
+ uint32_t outbuf_len,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_query_directory_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ level, flags,
+ file_index, fid_persistent,
+ fid_volatile, mask, outbuf_len);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_query_directory_recv(req, mem_ctx,
+ data, data_length);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_query_info.c b/libcli/smb/smb2cli_query_info.c
new file mode 100644
index 0000000..d499611
--- /dev/null
+++ b/libcli/smb/smb2cli_query_info.c
@@ -0,0 +1,266 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_query_info_state {
+ uint8_t fixed[0x28];
+ uint8_t dyn_pad[1];
+ uint32_t max_output_length;
+ struct iovec *recv_iov;
+ DATA_BLOB out_output_buffer;
+ bool out_valid;
+};
+
+static void smb2cli_query_info_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_query_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint32_t in_flags,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_query_info_state *state;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint16_t input_buffer_offset = 0;
+ uint32_t input_buffer_length = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_query_info_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->max_output_length = in_max_output_length;
+
+ if (in_input_buffer) {
+ input_buffer_offset = SMB2_HDR_BODY+0x28;
+ input_buffer_length = in_input_buffer->length;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0x00, 0x29);
+ SCVAL(fixed, 0x02, in_info_type);
+ SCVAL(fixed, 0x03, in_file_info_class); /* reserved */
+ SIVAL(fixed, 0x04, in_max_output_length);
+ SSVAL(fixed, 0x08, input_buffer_offset);
+ SSVAL(fixed, 0x0A, 0); /* reserved */
+ SIVAL(fixed, 0x0C, input_buffer_length);
+ SIVAL(fixed, 0x10, in_additional_info);
+ SIVAL(fixed, 0x14, in_flags);
+ SBVAL(fixed, 0x18, in_fid_persistent);
+ SBVAL(fixed, 0x20, in_fid_volatile);
+
+ if (input_buffer_length > 0) {
+ dyn = in_input_buffer->data;
+ dyn_len = in_input_buffer->length;
+ } else {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_GETINFO,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ in_max_output_length); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_query_info_done, req);
+ return req;
+}
+
+static void smb2cli_query_info_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_query_info_state *state =
+ tevent_req_data(req,
+ struct smb2cli_query_info_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint32_t dyn_ofs = SMB2_HDR_BODY + 0x08;
+ uint32_t output_buffer_offset;
+ uint32_t output_buffer_length;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x09
+ },
+ {
+ .status = STATUS_BUFFER_OVERFLOW,
+ .body_size = 0x09
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /* no error */
+ } else {
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ state->recv_iov = iov;
+ fixed = (uint8_t *)iov[1].iov_base;
+ dyn = (uint8_t *)iov[2].iov_base;
+ dyn_len = iov[2].iov_len;
+
+ output_buffer_offset = SVAL(fixed, 0x02);
+ output_buffer_length = IVAL(fixed, 0x04);
+
+ if ((output_buffer_offset > 0) && (output_buffer_length > 0)) {
+ if (output_buffer_offset != dyn_ofs) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (output_buffer_length > dyn_len) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (output_buffer_length > state->max_output_length) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->out_output_buffer.data = dyn;
+ state->out_output_buffer.length = output_buffer_length;
+ }
+
+ state->out_valid = true;
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_query_info_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_output_buffer)
+{
+ struct smb2cli_query_info_state *state =
+ tevent_req_data(req,
+ struct smb2cli_query_info_state);
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+ if (out_output_buffer) {
+ *out_output_buffer = data_blob_null;
+ }
+ tevent_req_received(req);
+ return status;
+ }
+
+ talloc_steal(mem_ctx, state->recv_iov);
+ if (out_output_buffer) {
+ *out_output_buffer = state->out_output_buffer;
+ }
+
+ tevent_req_received(req);
+ return status;
+}
+
+NTSTATUS smb2cli_query_info(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint32_t in_flags,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_output_buffer)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_query_info_send(frame, ev,
+ conn, timeout_msec,
+ session, tcon,
+ in_info_type,
+ in_file_info_class,
+ in_max_output_length,
+ in_input_buffer,
+ in_additional_info,
+ in_flags,
+ in_fid_persistent,
+ in_fid_volatile);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_query_info_recv(req, mem_ctx,
+ out_output_buffer);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_read.c b/libcli/smb/smb2cli_read.c
new file mode 100644
index 0000000..c7f4874
--- /dev/null
+++ b/libcli/smb/smb2cli_read.c
@@ -0,0 +1,218 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_read_state {
+ uint8_t fixed[48];
+ uint8_t dyn_pad[1];
+ struct iovec *recv_iov;
+ uint8_t *data;
+ uint32_t data_length;
+ bool out_valid;
+};
+
+static void smb2cli_read_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_read_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint64_t minimum_count,
+ uint64_t remaining_bytes)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_read_state *state;
+ uint8_t *fixed;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0, 49);
+ SIVAL(fixed, 4, length);
+ SBVAL(fixed, 8, offset);
+ SBVAL(fixed, 16, fid_persistent);
+ SBVAL(fixed, 24, fid_volatile);
+ SBVAL(fixed, 32, minimum_count);
+ SBVAL(fixed, 40, remaining_bytes);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_READ,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ state->dyn_pad, sizeof(state->dyn_pad),
+ length); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_read_done, req);
+ return req;
+}
+
+static void smb2cli_read_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_read_state *state =
+ tevent_req_data(req,
+ struct smb2cli_read_state);
+ NTSTATUS status;
+ NTSTATUS error;
+ struct iovec *iov;
+ const uint8_t dyn_ofs = SMB2_HDR_BODY + 0x10;
+ DATA_BLOB dyn_buffer = data_blob_null;
+ uint8_t data_offset;
+ DATA_BLOB data_buffer = data_blob_null;
+ uint32_t next_offset = 0; /* this variable is completely ignored */
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = STATUS_BUFFER_OVERFLOW,
+ .body_size = 0x11
+ },
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x11
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /* no error */
+ } else {
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ data_offset = CVAL(iov[1].iov_base, 2);
+ state->data_length = IVAL(iov[1].iov_base, 4);
+
+ dyn_buffer = data_blob_const((uint8_t *)iov[2].iov_base,
+ iov[2].iov_len);
+
+ error = smb2cli_parse_dyn_buffer(dyn_ofs,
+ dyn_buffer,
+ dyn_ofs, /* min_offset */
+ data_offset,
+ state->data_length,
+ dyn_buffer.length, /* max_length */
+ &next_offset,
+ &data_buffer);
+ if (tevent_req_nterror(req, error)) {
+ return;
+ }
+
+ state->recv_iov = iov;
+ state->data = data_buffer.data;
+
+ state->out_valid = true;
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **data, uint32_t *data_length)
+{
+ struct smb2cli_read_state *state =
+ tevent_req_data(req,
+ struct smb2cli_read_state);
+ NTSTATUS status = NT_STATUS_OK;
+
+ if (tevent_req_is_nterror(req, &status) && !state->out_valid) {
+ *data_length = 0;
+ *data = NULL;
+ tevent_req_received(req);
+ return status;
+ }
+ talloc_steal(mem_ctx, state->recv_iov);
+ *data_length = state->data_length;
+ *data = state->data;
+ tevent_req_received(req);
+ return status;
+}
+
+NTSTATUS smb2cli_read(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint64_t minimum_count,
+ uint64_t remaining_bytes,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_read_send(frame, ev,
+ conn, timeout_msec, session, tcon,
+ length, offset,
+ fid_persistent, fid_volatile,
+ minimum_count, remaining_bytes);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_read_recv(req, mem_ctx, data, data_length);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_session.c b/libcli/smb/smb2cli_session.c
new file mode 100644
index 0000000..65a604a
--- /dev/null
+++ b/libcli/smb/smb2cli_session.c
@@ -0,0 +1,350 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+struct smb2cli_session_setup_state {
+ struct smbXcli_session *session;
+ uint8_t fixed[24];
+ uint8_t dyn_pad[1];
+ struct iovec *recv_iov;
+ DATA_BLOB out_security_buffer;
+ NTSTATUS status;
+};
+
+static void smb2cli_session_setup_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ uint8_t in_flags,
+ uint32_t in_capabilities,
+ uint32_t in_channel,
+ uint64_t in_previous_session_id,
+ const DATA_BLOB *in_security_buffer)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_session_setup_state *state;
+ uint8_t *buf;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint8_t security_mode;
+ uint16_t security_buffer_offset = 0;
+ uint16_t security_buffer_length = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_session_setup_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (session == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ state->session = session;
+ security_mode = smb2cli_session_security_mode(session);
+
+ if (in_security_buffer) {
+ if (in_security_buffer->length > UINT16_MAX) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+ security_buffer_offset = SMB2_HDR_BODY + 24;
+ security_buffer_length = in_security_buffer->length;
+ }
+
+ buf = state->fixed;
+
+ SSVAL(buf, 0, 25);
+ SCVAL(buf, 2, in_flags);
+ SCVAL(buf, 3, security_mode);
+ SIVAL(buf, 4, in_capabilities);
+ SIVAL(buf, 8, in_channel);
+ SSVAL(buf, 12, security_buffer_offset);
+ SSVAL(buf, 14, security_buffer_length);
+ SBVAL(buf, 16, in_previous_session_id);
+
+ if (security_buffer_length > 0) {
+ dyn = in_security_buffer->data;
+ dyn_len = in_security_buffer->length;
+ } else {
+ dyn = state->dyn_pad;;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev,
+ conn, SMB2_OP_SESSSETUP,
+ 0, 0, /* flags */
+ timeout_msec,
+ NULL, /* tcon */
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ UINT16_MAX); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_session_setup_done, req);
+ return req;
+}
+
+static void smb2cli_session_setup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_session_setup_state *state =
+ tevent_req_data(req,
+ struct smb2cli_session_setup_state);
+ NTSTATUS status;
+ NTSTATUS preauth_status;
+ uint64_t current_session_id;
+ uint64_t session_id;
+ uint16_t session_flags;
+ uint16_t expected_offset = 0;
+ uint16_t security_buffer_offset;
+ uint16_t security_buffer_length;
+ uint8_t *security_buffer_data = NULL;
+ struct iovec sent_iov[3];
+ const uint8_t *hdr;
+ const uint8_t *body;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_MORE_PROCESSING_REQUIRED,
+ .body_size = 0x09
+ },
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x09
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &state->recv_iov,
+ expected, ARRAY_SIZE(expected));
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ TALLOC_FREE(subreq);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ smb2cli_req_get_sent_iov(subreq, sent_iov);
+ preauth_status = smb2cli_session_update_preauth(state->session, sent_iov);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, preauth_status)) {
+ return;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ preauth_status = smb2cli_session_update_preauth(state->session,
+ state->recv_iov);
+ if (tevent_req_nterror(req, preauth_status)) {
+ return;
+ }
+ }
+
+ hdr = (const uint8_t *)state->recv_iov[0].iov_base;
+ body = (const uint8_t *)state->recv_iov[1].iov_base;
+
+ session_id = BVAL(hdr, SMB2_HDR_SESSION_ID);
+ session_flags = SVAL(body, 2);
+
+ security_buffer_offset = SVAL(body, 4);
+ security_buffer_length = SVAL(body, 6);
+
+ if (security_buffer_length > 0) {
+ expected_offset = SMB2_HDR_BODY + 8;
+ }
+ if (security_buffer_offset != 0) {
+ security_buffer_data = (uint8_t *)state->recv_iov[2].iov_base;
+ expected_offset = SMB2_HDR_BODY + 8;
+ }
+
+ if (security_buffer_offset != expected_offset) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ if (security_buffer_length > state->recv_iov[2].iov_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->out_security_buffer.data = security_buffer_data;
+ state->out_security_buffer.length = security_buffer_length;
+
+ current_session_id = smb2cli_session_current_id(state->session);
+ if (current_session_id == 0) {
+ /* A new session was requested */
+ current_session_id = session_id;
+ }
+
+ if (current_session_id != session_id) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ smb2cli_session_set_id_and_flags(state->session,
+ session_id, session_flags);
+
+ state->status = status;
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **recv_iov,
+ DATA_BLOB *out_security_buffer)
+{
+ struct smb2cli_session_setup_state *state =
+ tevent_req_data(req,
+ struct smb2cli_session_setup_state);
+ NTSTATUS status;
+ struct iovec *_tmp;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (recv_iov == NULL) {
+ recv_iov = &_tmp;
+ }
+
+ *recv_iov = talloc_move(mem_ctx, &state->recv_iov);
+
+ *out_security_buffer = state->out_security_buffer;
+
+ /*
+ * Return the status from the server:
+ * NT_STATUS_MORE_PROCESSING_REQUIRED or
+ * NT_STATUS_OK.
+ */
+ status = state->status;
+ tevent_req_received(req);
+ return status;
+}
+
+struct smb2cli_logoff_state {
+ uint8_t fixed[4];
+};
+
+static void smb2cli_logoff_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_logoff_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_logoff_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ SSVAL(state->fixed, 0, 4);
+
+ subreq = smb2cli_req_send(state, ev,
+ conn, SMB2_OP_LOGOFF,
+ 0, 0, /* flags */
+ timeout_msec,
+ NULL, /* tcon */
+ session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_logoff_done, req);
+ return req;
+}
+
+static void smb2cli_logoff_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_logoff_state *state =
+ tevent_req_data(req,
+ struct smb2cli_logoff_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x04
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_logoff_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_logoff_send(frame, ev, conn, timeout_msec, session);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_logoff_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_set_info.c b/libcli/smb/smb2cli_set_info.c
new file mode 100644
index 0000000..6871370
--- /dev/null
+++ b/libcli/smb/smb2cli_set_info.c
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_set_info_state {
+ uint8_t fixed[0x20];
+ uint8_t dyn_pad[1];
+};
+
+static void smb2cli_set_info_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_set_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_set_info_state *state;
+ uint8_t *fixed;
+ uint8_t *dyn;
+ size_t dyn_len;
+ uint16_t input_buffer_offset = 0;
+ uint32_t input_buffer_length = 0;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_set_info_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (in_input_buffer) {
+ input_buffer_offset = SMB2_HDR_BODY+0x20;
+ input_buffer_length = in_input_buffer->length;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0x00, 0x21);
+ SCVAL(fixed, 0x02, in_info_type);
+ SCVAL(fixed, 0x03, in_file_info_class);
+ SIVAL(fixed, 0x04, input_buffer_length);
+ SSVAL(fixed, 0x08, input_buffer_offset);
+ SSVAL(fixed, 0x0A, 0); /* reserved */
+ SIVAL(fixed, 0x0C, in_additional_info);
+ SBVAL(fixed, 0x10, in_fid_persistent);
+ SBVAL(fixed, 0x18, in_fid_volatile);
+
+ if (input_buffer_length > 0) {
+ dyn = in_input_buffer->data;
+ dyn_len = in_input_buffer->length;
+ } else {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_SETINFO,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_set_info_done, req);
+ return req;
+}
+
+static void smb2cli_set_info_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x02
+ },
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_set_info_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_set_info(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_set_info_send(frame, ev,
+ conn, timeout_msec,
+ session, tcon,
+ in_info_type,
+ in_file_info_class,
+ in_input_buffer,
+ in_additional_info,
+ in_fid_persistent,
+ in_fid_volatile);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_set_info_recv(req);
+
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_tcon.c b/libcli/smb/smb2cli_tcon.c
new file mode 100644
index 0000000..d5e4fc3
--- /dev/null
+++ b/libcli/smb/smb2cli_tcon.c
@@ -0,0 +1,461 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smbXcli_base.h"
+
+struct smb2cli_raw_tcon_state {
+ struct smbXcli_session *session;
+ struct smbXcli_tcon *tcon;
+ uint8_t fixed[8];
+ uint8_t dyn_pad[1];
+};
+
+static void smb2cli_raw_tcon_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_raw_tcon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t tcon_flags,
+ const char *unc)
+{
+ struct tevent_req *req = NULL;
+ struct smb2cli_raw_tcon_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ uint8_t *fixed = NULL;
+ uint8_t *dyn = NULL;
+ size_t dyn_len;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_raw_tcon_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->session = session;
+ state->tcon = tcon;
+
+ if (!convert_string_talloc(state, CH_UNIX, CH_UTF16,
+ unc, strlen(unc),
+ &dyn, &dyn_len)) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+
+ if (strlen(unc) == 0) {
+ TALLOC_FREE(dyn);
+ dyn_len = 0;
+ }
+
+ fixed = state->fixed;
+ SSVAL(fixed, 0, 9);
+ if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_11) {
+ SSVAL(fixed, 2, tcon_flags);
+ } else {
+ SSVAL(fixed, 2, 0); /* Reserved */
+ }
+ SSVAL(fixed, 4, SMB2_HDR_BODY + 8);
+ SSVAL(fixed, 6, dyn_len);
+
+ if (dyn_len == 0) {
+ dyn = state->dyn_pad;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TCON,
+ additional_flags, clear_flags,
+ timeout_msec,
+ NULL, /* tcon */
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_raw_tcon_done, req);
+
+ return req;
+}
+
+static void smb2cli_raw_tcon_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_raw_tcon_state *state = tevent_req_data(
+ req, struct smb2cli_raw_tcon_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ uint8_t *body;
+ uint32_t tcon_id;
+ uint8_t share_type;
+ uint32_t share_flags;
+ uint32_t share_capabilities;
+ uint32_t maximal_access;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x10
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tcon_id = IVAL(iov[0].iov_base, SMB2_HDR_TID);
+
+ body = (uint8_t *)iov[1].iov_base;
+ share_type = CVAL(body, 0x02);
+ share_flags = IVAL(body, 0x04);
+ share_capabilities = IVAL(body, 0x08);
+ maximal_access = IVAL(body, 0x0C);
+
+ smb2cli_tcon_set_values(state->tcon,
+ state->session,
+ tcon_id,
+ share_type,
+ share_flags,
+ share_capabilities,
+ maximal_access);
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_raw_tcon_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_raw_tcon(struct smbXcli_conn *conn,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t tcon_flags,
+ const char *unc)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_raw_tcon_send(frame, ev, conn,
+ additional_flags, clear_flags,
+ timeout_msec, session, tcon,
+ tcon_flags, unc);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_raw_tcon_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct smb2cli_tcon_state {
+ struct tevent_context *ev;
+ struct smbXcli_conn *conn;
+ uint32_t timeout_msec;
+ struct smbXcli_session *session;
+ struct smbXcli_tcon *tcon;
+ uint8_t fixed[8];
+ uint8_t dyn_pad[1];
+};
+
+static void smb2cli_tcon_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_tcon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ const char *unc)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_tcon_state *state;
+ uint32_t additional_flags = 0;
+ uint32_t clear_flags = 0;
+
+ req = tevent_req_create(mem_ctx, &state, struct smb2cli_tcon_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->conn = conn;
+ state->timeout_msec = timeout_msec;
+ state->session = session;
+ state->tcon = tcon;
+
+ if (smbXcli_session_is_authenticated(state->session)) {
+ additional_flags |= SMB2_HDR_FLAG_SIGNED;
+ }
+
+ subreq = smb2cli_raw_tcon_send(state,
+ state->ev,
+ state->conn,
+ additional_flags,
+ clear_flags,
+ state->timeout_msec,
+ state->session,
+ state->tcon,
+ flags,
+ unc);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_tcon_done, req);
+
+ return req;
+}
+
+static void smb2cli_tcon_validate(struct tevent_req *subreq);
+
+static void smb2cli_tcon_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_tcon_state *state = tevent_req_data(
+ req, struct smb2cli_tcon_state);
+ NTSTATUS status;
+
+ status = smb2cli_raw_tcon_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (!smbXcli_session_is_authenticated(state->session)) {
+ tevent_req_done(req);
+ return;
+ }
+
+ if (smbXcli_conn_protocol(state->conn) >= PROTOCOL_SMB3_11) {
+ tevent_req_done(req);
+ return;
+ }
+
+ subreq = smb2cli_validate_negotiate_info_send(state, state->ev,
+ state->conn,
+ state->timeout_msec,
+ state->session,
+ state->tcon);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, smb2cli_tcon_validate, req);
+}
+
+static void smb2cli_tcon_validate(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smb2cli_tcon_state *state = tevent_req_data(
+ req, struct smb2cli_tcon_state);
+ NTSTATUS status;
+
+ status = smb2cli_validate_negotiate_info_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ smb2cli_tcon_set_values(state->tcon, NULL,
+ UINT32_MAX, 0, 0, 0, 0);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_tcon_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_tcon(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ const char *unc)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_tcon_send(frame, ev, conn,
+ timeout_msec, session, tcon,
+ flags, unc);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_tcon_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct smb2cli_tdis_state {
+ struct smbXcli_tcon *tcon;
+ uint8_t fixed[4];
+};
+
+static void smb2cli_tdis_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_tdis_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_tdis_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_tdis_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->tcon = tcon;
+
+ SSVAL(state->fixed, 0, 4);
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TDIS,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon, session,
+ state->fixed, sizeof(state->fixed),
+ NULL, 0, /* dyn* */
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_tdis_done, req);
+ return req;
+}
+
+static void smb2cli_tdis_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_tdis_state *state =
+ tevent_req_data(req,
+ struct smb2cli_tdis_state);
+ NTSTATUS status;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x04
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, NULL, NULL,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ smb2cli_tcon_set_values(state->tcon, NULL,
+ UINT32_MAX, 0, 0, 0, 0);
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_tdis_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smb2cli_tdis(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_tdis_send(frame, ev, conn,
+ timeout_msec, session, tcon);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_tdis_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smb2cli_write.c b/libcli/smb/smb2cli_write.c
new file mode 100644
index 0000000..6d0a0aa
--- /dev/null
+++ b/libcli/smb/smb2cli_write.c
@@ -0,0 +1,183 @@
+/*
+ Unix SMB/CIFS implementation.
+ smb2 lib
+ Copyright (C) Volker Lendecke 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 "system/network.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+
+struct smb2cli_write_state {
+ uint8_t fixed[48];
+ uint8_t dyn_pad[1];
+ uint32_t written;
+};
+
+static void smb2cli_write_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_write_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t remaining_bytes,
+ uint32_t flags,
+ const uint8_t *data)
+{
+ struct tevent_req *req, *subreq;
+ struct smb2cli_write_state *state;
+ uint8_t *fixed;
+ const uint8_t *dyn;
+ size_t dyn_len;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_write_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ fixed = state->fixed;
+
+ SSVAL(fixed, 0, 49);
+ SSVAL(fixed, 2, SMB2_HDR_BODY + 48);
+ SIVAL(fixed, 4, length);
+ SBVAL(fixed, 8, offset);
+ SBVAL(fixed, 16, fid_persistent);
+ SBVAL(fixed, 24, fid_volatile);
+ SIVAL(fixed, 36, remaining_bytes);
+ SIVAL(fixed, 44, flags);
+
+ if (length > 0) {
+ dyn = data;
+ dyn_len = length;
+ } else {
+ dyn = state->dyn_pad;;
+ dyn_len = sizeof(state->dyn_pad);
+ }
+
+ subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_WRITE,
+ 0, 0, /* flags */
+ timeout_msec,
+ tcon,
+ session,
+ state->fixed, sizeof(state->fixed),
+ dyn, dyn_len,
+ 0); /* max_dyn_len */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smb2cli_write_done, req);
+ return req;
+}
+
+static void smb2cli_write_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_write_state *state =
+ tevent_req_data(req,
+ struct smb2cli_write_state);
+ NTSTATUS status;
+ struct iovec *iov;
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x11
+ }
+ };
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ state->written = IVAL(iov[1].iov_base, 4);
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_write_recv(struct tevent_req *req, uint32_t *written)
+{
+ struct smb2cli_write_state *state =
+ tevent_req_data(req,
+ struct smb2cli_write_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ if (written) {
+ *written = state->written;
+ }
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_write(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t remaining_bytes,
+ uint32_t flags,
+ const uint8_t *data,
+ uint32_t *written)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smb2cli_write_send(frame, ev, conn, timeout_msec,
+ session, tcon,
+ length, offset,
+ fid_persistent, fid_volatile,
+ remaining_bytes, flags, data);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = smb2cli_write_recv(req, written);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
new file mode 100644
index 0000000..a52a615
--- /dev/null
+++ b/libcli/smb/smbXcli_base.c
@@ -0,0 +1,7034 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 2008
+ 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 "system/network.h"
+#include "../lib/async_req/async_sock.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../lib/util/tevent_unix.h"
+#include "lib/util/util_net.h"
+#include "lib/util/dlinklist.h"
+#include "lib/util/iov_buf.h"
+#include "../libcli/smb/smb_common.h"
+#include "../libcli/smb/smb_seal.h"
+#include "../libcli/smb/smb_signing.h"
+#include "../libcli/smb/read_smb.h"
+#include "smbXcli_base.h"
+#include "librpc/ndr/libndr.h"
+#include "libcli/smb/smb2_negotiate_context.h"
+#include "libcli/smb/smb2_signing.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+struct smbXcli_conn;
+struct smbXcli_req;
+struct smbXcli_session;
+struct smbXcli_tcon;
+
+struct smbXcli_conn {
+ int sock_fd;
+ struct sockaddr_storage local_ss;
+ struct sockaddr_storage remote_ss;
+ const char *remote_name;
+
+ struct tevent_queue *outgoing;
+ struct tevent_req **pending;
+ struct tevent_req *read_smb_req;
+ struct tevent_req *suicide_req;
+
+ enum protocol_types min_protocol;
+ enum protocol_types max_protocol;
+ enum protocol_types protocol;
+ bool allow_signing;
+ bool desire_signing;
+ bool mandatory_signing;
+
+ /*
+ * The incoming dispatch function should return:
+ * - NT_STATUS_RETRY, if more incoming PDUs are expected.
+ * - NT_STATUS_OK, if no more processing is desired, e.g.
+ * the dispatch function called
+ * tevent_req_done().
+ * - All other return values disconnect the connection.
+ */
+ NTSTATUS (*dispatch_incoming)(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf);
+
+ struct {
+ struct {
+ uint32_t capabilities;
+ uint32_t max_xmit;
+ } client;
+
+ struct {
+ uint32_t capabilities;
+ uint32_t max_xmit;
+ uint16_t max_mux;
+ uint16_t security_mode;
+ bool readbraw;
+ bool writebraw;
+ bool lockread;
+ bool writeunlock;
+ uint32_t session_key;
+ struct GUID guid;
+ DATA_BLOB gss_blob;
+ uint8_t challenge[8];
+ const char *workgroup;
+ const char *name;
+ int time_zone;
+ NTTIME system_time;
+ } server;
+
+ uint32_t capabilities;
+ uint32_t max_xmit;
+
+ uint16_t mid;
+
+ struct smb1_signing_state *signing;
+ struct smb_trans_enc_state *trans_enc;
+
+ struct tevent_req *read_braw_req;
+ } smb1;
+
+ struct {
+ struct {
+ uint32_t capabilities;
+ uint16_t security_mode;
+ struct GUID guid;
+ struct smb311_capabilities smb3_capabilities;
+ } client;
+
+ struct {
+ uint32_t capabilities;
+ uint16_t security_mode;
+ struct GUID guid;
+ uint32_t max_trans_size;
+ uint32_t max_read_size;
+ uint32_t max_write_size;
+ NTTIME system_time;
+ NTTIME start_time;
+ DATA_BLOB gss_blob;
+ uint16_t sign_algo;
+ uint16_t cipher;
+ bool smb311_posix;
+ } server;
+
+ uint64_t mid;
+ uint16_t cur_credits;
+ uint16_t max_credits;
+
+ uint32_t cc_chunk_len;
+ uint32_t cc_max_chunks;
+
+ uint8_t io_priority;
+
+ bool force_channel_sequence;
+
+ uint8_t preauth_sha512[64];
+ } smb2;
+
+ struct smbXcli_session *sessions;
+};
+
+struct smb2cli_session {
+ uint64_t session_id;
+ uint16_t session_flags;
+ struct smb2_signing_key *application_key;
+ struct smb2_signing_key *signing_key;
+ bool should_sign;
+ bool should_encrypt;
+ struct smb2_signing_key *encryption_key;
+ struct smb2_signing_key *decryption_key;
+ uint64_t nonce_high_random;
+ uint64_t nonce_high_max;
+ uint64_t nonce_high;
+ uint64_t nonce_low;
+ uint16_t channel_sequence;
+ bool replay_active;
+ bool require_signed_response;
+};
+
+struct smbXcli_session {
+ struct smbXcli_session *prev, *next;
+ struct smbXcli_conn *conn;
+
+ struct {
+ uint16_t session_id;
+ uint16_t action;
+ DATA_BLOB application_key;
+ bool protected_key;
+ } smb1;
+
+ struct smb2cli_session *smb2;
+
+ struct {
+ struct smb2_signing_key *signing_key;
+ uint8_t preauth_sha512[64];
+ } smb2_channel;
+
+ /*
+ * this should be a short term hack
+ * until the upper layers have implemented
+ * re-authentication.
+ */
+ bool disconnect_expired;
+};
+
+struct smbXcli_tcon {
+ bool is_smb1;
+ uint32_t fs_attributes;
+
+ struct {
+ uint16_t tcon_id;
+ uint16_t optional_support;
+ uint32_t maximal_access;
+ uint32_t guest_maximal_access;
+ char *service;
+ char *fs_type;
+ } smb1;
+
+ struct {
+ uint32_t tcon_id;
+ uint8_t type;
+ uint32_t flags;
+ uint32_t capabilities;
+ uint32_t maximal_access;
+ bool should_sign;
+ bool should_encrypt;
+ } smb2;
+};
+
+struct smbXcli_req_state {
+ struct tevent_context *ev;
+ struct smbXcli_conn *conn;
+ struct smbXcli_session *session; /* maybe NULL */
+ struct smbXcli_tcon *tcon; /* maybe NULL */
+
+ uint8_t length_hdr[4];
+
+ bool one_way;
+
+ uint8_t *inbuf;
+
+ struct tevent_req *write_req;
+
+ struct timeval endtime;
+
+ struct {
+ /* Space for the header including the wct */
+ uint8_t hdr[HDR_VWV];
+
+ /*
+ * For normal requests, smb1cli_req_send chooses a mid.
+ * SecondaryV trans requests need to use the mid of the primary
+ * request, so we need a place to store it.
+ * Assume it is set if != 0.
+ */
+ uint16_t mid;
+
+ uint16_t *vwv;
+ uint8_t bytecount_buf[2];
+
+#define MAX_SMB_IOV 10
+ /* length_hdr, hdr, words, byte_count, buffers */
+ struct iovec iov[1 + 3 + MAX_SMB_IOV];
+ int iov_count;
+
+ bool one_way_seqnum;
+ uint32_t seqnum;
+ struct tevent_req **chained_requests;
+
+ uint8_t recv_cmd;
+ NTSTATUS recv_status;
+ /* always an array of 3 talloc elements */
+ struct iovec *recv_iov;
+ } smb1;
+
+ struct {
+ const uint8_t *fixed;
+ uint16_t fixed_len;
+ const uint8_t *dyn;
+ uint32_t dyn_len;
+
+ uint8_t transform[SMB2_TF_HDR_SIZE];
+ uint8_t hdr[SMB2_HDR_BODY];
+ uint8_t pad[7]; /* padding space for compounding */
+
+ /*
+ * always an array of 3 talloc elements
+ * (without a SMB2_TRANSFORM header!)
+ *
+ * HDR, BODY, DYN
+ */
+ struct iovec *recv_iov;
+
+ /*
+ * the expected max for the response dyn_len
+ */
+ uint32_t max_dyn_len;
+
+ uint16_t credit_charge;
+
+ bool should_sign;
+ bool should_encrypt;
+ uint64_t encryption_session_id;
+
+ bool signing_skipped;
+ bool require_signed_response;
+ bool notify_async;
+ bool got_async;
+ uint16_t cancel_flags;
+ uint64_t cancel_mid;
+ uint64_t cancel_aid;
+ } smb2;
+};
+
+static int smbXcli_conn_destructor(struct smbXcli_conn *conn)
+{
+ /*
+ * NT_STATUS_OK, means we do not notify the callers
+ */
+ smbXcli_conn_disconnect(conn, NT_STATUS_OK);
+
+ while (conn->sessions) {
+ conn->sessions->conn = NULL;
+ DLIST_REMOVE(conn->sessions, conn->sessions);
+ }
+
+ if (conn->smb1.trans_enc) {
+ TALLOC_FREE(conn->smb1.trans_enc);
+ }
+
+ return 0;
+}
+
+struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
+ int fd,
+ const char *remote_name,
+ enum smb_signing_setting signing_state,
+ uint32_t smb1_capabilities,
+ struct GUID *client_guid,
+ uint32_t smb2_capabilities,
+ const struct smb311_capabilities *smb3_capabilities)
+{
+ struct smbXcli_conn *conn = NULL;
+ void *ss = NULL;
+ struct sockaddr *sa = NULL;
+ socklen_t sa_length;
+ int ret;
+
+ if (smb3_capabilities != NULL) {
+ const struct smb3_signing_capabilities *sign_algos =
+ &smb3_capabilities->signing;
+ const struct smb3_encryption_capabilities *ciphers =
+ &smb3_capabilities->encryption;
+
+ SMB_ASSERT(sign_algos->num_algos <= SMB3_SIGNING_CAPABILITIES_MAX_ALGOS);
+ SMB_ASSERT(ciphers->num_algos <= SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS);
+ }
+
+ conn = talloc_zero(mem_ctx, struct smbXcli_conn);
+ if (!conn) {
+ return NULL;
+ }
+
+ ret = set_blocking(fd, false);
+ if (ret < 0) {
+ goto error;
+ }
+ conn->sock_fd = fd;
+
+ conn->remote_name = talloc_strdup(conn, remote_name);
+ if (conn->remote_name == NULL) {
+ goto error;
+ }
+
+ ss = (void *)&conn->local_ss;
+ sa = (struct sockaddr *)ss;
+ sa_length = sizeof(conn->local_ss);
+ ret = getsockname(fd, sa, &sa_length);
+ if (ret == -1) {
+ goto error;
+ }
+ ss = (void *)&conn->remote_ss;
+ sa = (struct sockaddr *)ss;
+ sa_length = sizeof(conn->remote_ss);
+ ret = getpeername(fd, sa, &sa_length);
+ if (ret == -1) {
+ goto error;
+ }
+
+ conn->outgoing = tevent_queue_create(conn, "smbXcli_outgoing");
+ if (conn->outgoing == NULL) {
+ goto error;
+ }
+ conn->pending = NULL;
+
+ conn->min_protocol = PROTOCOL_NONE;
+ conn->max_protocol = PROTOCOL_NONE;
+ conn->protocol = PROTOCOL_NONE;
+
+ switch (signing_state) {
+ case SMB_SIGNING_OFF:
+ /* never */
+ conn->allow_signing = false;
+ conn->desire_signing = false;
+ conn->mandatory_signing = false;
+ break;
+ case SMB_SIGNING_DEFAULT:
+ case SMB_SIGNING_IF_REQUIRED:
+ /* if the server requires it */
+ conn->allow_signing = true;
+ conn->desire_signing = false;
+ conn->mandatory_signing = false;
+ break;
+ case SMB_SIGNING_DESIRED:
+ /* if the server desires it */
+ conn->allow_signing = true;
+ conn->desire_signing = true;
+ conn->mandatory_signing = false;
+ break;
+ case SMB_SIGNING_IPC_DEFAULT:
+ case SMB_SIGNING_REQUIRED:
+ /* always */
+ conn->allow_signing = true;
+ conn->desire_signing = true;
+ conn->mandatory_signing = true;
+ break;
+ }
+
+ conn->smb1.client.capabilities = smb1_capabilities;
+ conn->smb1.client.max_xmit = UINT16_MAX;
+
+ conn->smb1.capabilities = conn->smb1.client.capabilities;
+ conn->smb1.max_xmit = 1024;
+
+ conn->smb1.mid = 1;
+
+ /* initialise signing */
+ conn->smb1.signing = smb1_signing_init(conn,
+ conn->allow_signing,
+ conn->desire_signing,
+ conn->mandatory_signing);
+ if (!conn->smb1.signing) {
+ goto error;
+ }
+
+ conn->smb2.client.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ if (conn->mandatory_signing) {
+ conn->smb2.client.security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ }
+ if (client_guid) {
+ conn->smb2.client.guid = *client_guid;
+ }
+ conn->smb2.client.capabilities = smb2_capabilities;
+ if (smb3_capabilities != NULL) {
+ conn->smb2.client.smb3_capabilities = *smb3_capabilities;
+ }
+
+ conn->smb2.cur_credits = 1;
+ conn->smb2.max_credits = 0;
+ conn->smb2.io_priority = 1;
+
+ /*
+ * Samba and Windows servers accept a maximum of 16 MiB with a maximum
+ * chunk length of 1 MiB.
+ */
+ conn->smb2.cc_chunk_len = 1024 * 1024;
+ conn->smb2.cc_max_chunks = 16;
+
+ talloc_set_destructor(conn, smbXcli_conn_destructor);
+ return conn;
+
+ error:
+ TALLOC_FREE(conn);
+ return NULL;
+}
+
+bool smbXcli_conn_is_connected(struct smbXcli_conn *conn)
+{
+ if (conn == NULL) {
+ return false;
+ }
+
+ if (conn->sock_fd == -1) {
+ return false;
+ }
+
+ return true;
+}
+
+enum protocol_types smbXcli_conn_protocol(struct smbXcli_conn *conn)
+{
+ return conn->protocol;
+}
+
+bool smbXcli_conn_use_unicode(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return true;
+ }
+
+ if (conn->smb1.capabilities & CAP_UNICODE) {
+ return true;
+ }
+
+ return false;
+}
+
+bool smbXcli_conn_signing_mandatory(struct smbXcli_conn *conn)
+{
+ return conn->mandatory_signing;
+}
+
+bool smbXcli_conn_have_posix(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ return conn->smb2.server.smb311_posix;
+ }
+ if (conn->protocol <= PROTOCOL_NT1) {
+ return (conn->smb1.capabilities & CAP_UNIX);
+ }
+ return false;
+}
+
+/*
+ * [MS-SMB] 2.2.2.3.5 - SMB1 support for passing through
+ * query/set commands to the file system
+ */
+bool smbXcli_conn_support_passthrough(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return true;
+ }
+
+ if (conn->smb1.capabilities & CAP_W2K_SMBS) {
+ return true;
+ }
+
+ return false;
+}
+
+void smbXcli_conn_set_sockopt(struct smbXcli_conn *conn, const char *options)
+{
+ set_socket_options(conn->sock_fd, options);
+}
+
+const struct sockaddr_storage *smbXcli_conn_local_sockaddr(struct smbXcli_conn *conn)
+{
+ return &conn->local_ss;
+}
+
+const struct sockaddr_storage *smbXcli_conn_remote_sockaddr(struct smbXcli_conn *conn)
+{
+ return &conn->remote_ss;
+}
+
+const char *smbXcli_conn_remote_name(struct smbXcli_conn *conn)
+{
+ return conn->remote_name;
+}
+
+uint16_t smbXcli_conn_max_requests(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ /*
+ * TODO...
+ */
+ return 1;
+ }
+
+ return conn->smb1.server.max_mux;
+}
+
+NTTIME smbXcli_conn_server_system_time(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return conn->smb2.server.system_time;
+ }
+
+ return conn->smb1.server.system_time;
+}
+
+const DATA_BLOB *smbXcli_conn_server_gss_blob(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return &conn->smb2.server.gss_blob;
+ }
+
+ return &conn->smb1.server.gss_blob;
+}
+
+const struct GUID *smbXcli_conn_server_guid(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return &conn->smb2.server.guid;
+ }
+
+ return &conn->smb1.server.guid;
+}
+
+bool smbXcli_conn_get_force_channel_sequence(struct smbXcli_conn *conn)
+{
+ return conn->smb2.force_channel_sequence;
+}
+
+void smbXcli_conn_set_force_channel_sequence(struct smbXcli_conn *conn,
+ bool v)
+{
+ conn->smb2.force_channel_sequence = v;
+}
+
+struct smbXcli_conn_samba_suicide_state {
+ struct smbXcli_conn *conn;
+ struct iovec iov;
+ uint8_t buf[9];
+ struct tevent_req *write_req;
+};
+
+static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
+static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq);
+
+struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t exitcode)
+{
+ struct tevent_req *req, *subreq;
+ struct smbXcli_conn_samba_suicide_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbXcli_conn_samba_suicide_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->conn = conn;
+ SIVAL(state->buf, 4, SMB_SUICIDE_PACKET);
+ SCVAL(state->buf, 8, exitcode);
+ _smb_setlen_nbt(state->buf, sizeof(state->buf)-4);
+
+ if (conn->suicide_req != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->iov.iov_base = state->buf;
+ state->iov.iov_len = sizeof(state->buf);
+
+ subreq = writev_send(state, ev, conn->outgoing, conn->sock_fd,
+ false, &state->iov, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smbXcli_conn_samba_suicide_done, req);
+ state->write_req = subreq;
+
+ tevent_req_set_cleanup_fn(req, smbXcli_conn_samba_suicide_cleanup);
+
+ /*
+ * We need to use tevent_req_defer_callback()
+ * in order to allow smbXcli_conn_disconnect()
+ * to do a safe cleanup.
+ */
+ tevent_req_defer_callback(req, ev);
+ conn->suicide_req = req;
+
+ return req;
+}
+
+static void smbXcli_conn_samba_suicide_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct smbXcli_conn_samba_suicide_state *state = tevent_req_data(
+ req, struct smbXcli_conn_samba_suicide_state);
+
+ TALLOC_FREE(state->write_req);
+
+ if (state->conn == NULL) {
+ return;
+ }
+
+ if (state->conn->suicide_req == req) {
+ state->conn->suicide_req = NULL;
+ }
+ state->conn = NULL;
+}
+
+static void smbXcli_conn_samba_suicide_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct smbXcli_conn_samba_suicide_state *state = tevent_req_data(
+ req, struct smbXcli_conn_samba_suicide_state);
+ ssize_t nwritten;
+ int err;
+
+ state->write_req = NULL;
+
+ nwritten = writev_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (nwritten == -1) {
+ /* here, we need to notify all pending requests */
+ NTSTATUS status = map_nt_error_from_unix_common(err);
+ smbXcli_conn_disconnect(state->conn, status);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+NTSTATUS smbXcli_conn_samba_suicide_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS smbXcli_conn_samba_suicide(struct smbXcli_conn *conn,
+ uint8_t exitcode)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ bool ok;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smbXcli_conn_samba_suicide_send(frame, ev, conn, exitcode);
+ if (req == NULL) {
+ goto fail;
+ }
+ ok = tevent_req_poll_ntstatus(req, ev, &status);
+ if (!ok) {
+ goto fail;
+ }
+ status = smbXcli_conn_samba_suicide_recv(req);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+uint32_t smb1cli_conn_capabilities(struct smbXcli_conn *conn)
+{
+ return conn->smb1.capabilities;
+}
+
+uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn)
+{
+ return conn->smb1.max_xmit;
+}
+
+bool smb1cli_conn_req_possible(struct smbXcli_conn *conn)
+{
+ size_t pending = talloc_array_length(conn->pending);
+ uint16_t possible = conn->smb1.server.max_mux;
+
+ if (pending >= possible) {
+ return false;
+ }
+
+ return true;
+}
+
+uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.session_key;
+}
+
+const uint8_t *smb1cli_conn_server_challenge(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.challenge;
+}
+
+uint16_t smb1cli_conn_server_security_mode(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.security_mode;
+}
+
+bool smb1cli_conn_server_readbraw(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.readbraw;
+}
+
+bool smb1cli_conn_server_writebraw(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.writebraw;
+}
+
+bool smb1cli_conn_server_lockread(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.lockread;
+}
+
+bool smb1cli_conn_server_writeunlock(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.writeunlock;
+}
+
+int smb1cli_conn_server_time_zone(struct smbXcli_conn *conn)
+{
+ return conn->smb1.server.time_zone;
+}
+
+bool smb1cli_conn_activate_signing(struct smbXcli_conn *conn,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response)
+{
+ return smb1_signing_activate(conn->smb1.signing,
+ user_session_key,
+ response);
+}
+
+bool smb1cli_conn_check_signing(struct smbXcli_conn *conn,
+ const uint8_t *buf, uint32_t seqnum)
+{
+ const uint8_t *hdr = buf + NBT_HDR_SIZE;
+ size_t len = smb_len_nbt(buf);
+
+ return smb1_signing_check_pdu(conn->smb1.signing, hdr, len, seqnum);
+}
+
+bool smb1cli_conn_signing_is_active(struct smbXcli_conn *conn)
+{
+ return smb1_signing_is_active(conn->smb1.signing);
+}
+
+void smb1cli_conn_set_encryption(struct smbXcli_conn *conn,
+ struct smb_trans_enc_state *es)
+{
+ /* Replace the old state, if any. */
+ if (conn->smb1.trans_enc) {
+ TALLOC_FREE(conn->smb1.trans_enc);
+ }
+ conn->smb1.trans_enc = es;
+}
+
+bool smb1cli_conn_encryption_on(struct smbXcli_conn *conn)
+{
+ return common_encryption_on(conn->smb1.trans_enc);
+}
+
+
+static NTSTATUS smb1cli_pull_raw_error(const uint8_t *hdr)
+{
+ uint32_t flags2 = SVAL(hdr, HDR_FLG2);
+ NTSTATUS status = NT_STATUS(IVAL(hdr, HDR_RCLS));
+
+ if (NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_OK;
+ }
+
+ if (flags2 & FLAGS2_32_BIT_ERROR_CODES) {
+ return status;
+ }
+
+ return NT_STATUS_DOS(CVAL(hdr, HDR_RCLS), SVAL(hdr, HDR_ERR));
+}
+
+/**
+ * Is the SMB command able to hold an AND_X successor
+ * @param[in] cmd The SMB command in question
+ * @retval Can we add a chained request after "cmd"?
+ */
+bool smb1cli_is_andx_req(uint8_t cmd)
+{
+ switch (cmd) {
+ case SMBtconX:
+ case SMBlockingX:
+ case SMBopenX:
+ case SMBreadX:
+ case SMBwriteX:
+ case SMBsesssetupX:
+ case SMBulogoffX:
+ case SMBntcreateX:
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static uint16_t smb1cli_alloc_mid(struct smbXcli_conn *conn)
+{
+ size_t num_pending = talloc_array_length(conn->pending);
+ uint16_t result;
+
+ if (conn->protocol == PROTOCOL_NONE) {
+ /*
+ * This is what windows sends on the SMB1 Negprot request
+ * and some vendors reuse the SMB1 MID as SMB2 sequence number.
+ */
+ return 0;
+ }
+
+ while (true) {
+ size_t i;
+
+ result = conn->smb1.mid++;
+ if ((result == 0) || (result == 0xffff)) {
+ continue;
+ }
+
+ for (i=0; i<num_pending; i++) {
+ if (result == smb1cli_req_mid(conn->pending[i])) {
+ break;
+ }
+ }
+
+ if (i == num_pending) {
+ return result;
+ }
+ }
+}
+
+static NTSTATUS smbXcli_req_cancel_write_req(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_conn *conn = state->conn;
+ size_t num_pending = talloc_array_length(conn->pending);
+ ssize_t ret;
+ int err;
+ bool ok;
+
+ if (state->write_req == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Check if it's possible to cancel the request.
+ * If the result is true it's not too late.
+ * See writev_cancel().
+ */
+ ok = tevent_req_cancel(state->write_req);
+ if (ok) {
+ TALLOC_FREE(state->write_req);
+
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ /*
+ * SMB2 has a sane signing state.
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (num_pending > 1) {
+ /*
+ * We have more pending requests following us. This
+ * means the signing state will be broken for them.
+ *
+ * As a solution we could add the requests directly to
+ * our outgoing queue and do the signing in the trigger
+ * function and then use writev_send() without passing a
+ * queue. That way we'll only sign packets we're most
+ * likely send to the wire.
+ */
+ return NT_STATUS_REQUEST_OUT_OF_SEQUENCE;
+ }
+
+ /*
+ * If we're the only request that's
+ * pending, we're able to recover the signing
+ * state.
+ */
+ smb1_signing_cancel_reply(conn->smb1.signing,
+ state->smb1.one_way_seqnum);
+ return NT_STATUS_OK;
+ }
+
+ ret = writev_recv(state->write_req, &err);
+ TALLOC_FREE(state->write_req);
+ if (ret == -1) {
+ return map_nt_error_from_unix_common(err);
+ }
+
+ return NT_STATUS_OK;
+}
+
+void smbXcli_req_unset_pending(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_conn *conn = state->conn;
+ size_t num_pending = talloc_array_length(conn->pending);
+ size_t i;
+ NTSTATUS cancel_status;
+
+ cancel_status = smbXcli_req_cancel_write_req(req);
+
+ if (state->smb1.mid != 0) {
+ /*
+ * This is a [nt]trans[2] request which waits
+ * for more than one reply.
+ */
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+ }
+
+ tevent_req_set_cleanup_fn(req, NULL);
+
+ if (num_pending == 1) {
+ /*
+ * The pending read_smb tevent_req is a child of
+ * conn->pending. So if nothing is pending anymore, we need to
+ * delete the socket read fde.
+ */
+ /* TODO: smbXcli_conn_cancel_read_req */
+ TALLOC_FREE(conn->pending);
+ conn->read_smb_req = NULL;
+
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+ }
+
+ for (i=0; i<num_pending; i++) {
+ if (req == conn->pending[i]) {
+ break;
+ }
+ }
+ if (i == num_pending) {
+ /*
+ * Something's seriously broken. Just returning here is the
+ * right thing nevertheless, the point of this routine is to
+ * remove ourselves from conn->pending.
+ */
+
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+ }
+
+ /*
+ * Remove ourselves from the conn->pending array
+ */
+ for (; i < (num_pending - 1); i++) {
+ conn->pending[i] = conn->pending[i+1];
+ }
+
+ /*
+ * No NULL check here, we're shrinking by sizeof(void *), and
+ * talloc_realloc just adjusts the size for this.
+ */
+ conn->pending = talloc_realloc(NULL, conn->pending, struct tevent_req *,
+ num_pending - 1);
+
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+}
+
+static void smbXcli_req_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_conn *conn = state->conn;
+ NTSTATUS cancel_status;
+
+ switch (req_state) {
+ case TEVENT_REQ_RECEIVED:
+ /*
+ * Make sure we really remove it from
+ * the pending array on destruction.
+ *
+ * smbXcli_req_unset_pending() calls
+ * smbXcli_req_cancel_write_req() internal
+ */
+ state->smb1.mid = 0;
+ smbXcli_req_unset_pending(req);
+ return;
+ default:
+ cancel_status = smbXcli_req_cancel_write_req(req);
+ if (!NT_STATUS_IS_OK(cancel_status)) {
+ /*
+ * If the write_req cancel didn't work
+ * we can't use the connection anymore.
+ */
+ smbXcli_conn_disconnect(conn, cancel_status);
+ return;
+ }
+ return;
+ }
+}
+
+static bool smb1cli_req_cancel(struct tevent_req *req);
+static bool smb2cli_req_cancel(struct tevent_req *req);
+
+static bool smbXcli_req_cancel(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ if (!smbXcli_conn_is_connected(state->conn)) {
+ return false;
+ }
+
+ if (state->conn->protocol == PROTOCOL_NONE) {
+ return false;
+ }
+
+ if (state->conn->protocol >= PROTOCOL_SMB2_02) {
+ return smb2cli_req_cancel(req);
+ }
+
+ return smb1cli_req_cancel(req);
+}
+
+static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn);
+
+bool smbXcli_req_set_pending(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_conn *conn;
+ struct tevent_req **pending;
+ size_t num_pending;
+
+ conn = state->conn;
+
+ if (!smbXcli_conn_is_connected(conn)) {
+ return false;
+ }
+
+ num_pending = talloc_array_length(conn->pending);
+
+ pending = talloc_realloc(conn, conn->pending, struct tevent_req *,
+ num_pending+1);
+ if (pending == NULL) {
+ return false;
+ }
+ pending[num_pending] = req;
+ conn->pending = pending;
+ tevent_req_set_cleanup_fn(req, smbXcli_req_cleanup);
+ tevent_req_set_cancel_fn(req, smbXcli_req_cancel);
+
+ if (!smbXcli_conn_receive_next(conn)) {
+ /*
+ * the caller should notify the current request
+ *
+ * And all other pending requests get notified
+ * by smbXcli_conn_disconnect().
+ */
+ smbXcli_req_unset_pending(req);
+ smbXcli_conn_disconnect(conn, NT_STATUS_NO_MEMORY);
+ return false;
+ }
+
+ return true;
+}
+
+static void smbXcli_conn_received(struct tevent_req *subreq);
+
+static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn)
+{
+ size_t num_pending = talloc_array_length(conn->pending);
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+
+ if (conn->read_smb_req != NULL) {
+ return true;
+ }
+
+ if (num_pending == 0) {
+ if (conn->smb2.mid < UINT64_MAX) {
+ /* no more pending requests, so we are done for now */
+ return true;
+ }
+
+ /*
+ * If there are no more SMB2 requests possible,
+ * because we are out of message ids,
+ * we need to disconnect.
+ */
+ smbXcli_conn_disconnect(conn, NT_STATUS_CONNECTION_ABORTED);
+ return true;
+ }
+
+ req = conn->pending[0];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ /*
+ * We're the first ones, add the read_smb request that waits for the
+ * answer from the server
+ */
+ conn->read_smb_req = read_smb_send(conn->pending,
+ state->ev,
+ conn->sock_fd);
+ if (conn->read_smb_req == NULL) {
+ return false;
+ }
+ tevent_req_set_callback(conn->read_smb_req, smbXcli_conn_received, conn);
+ return true;
+}
+
+void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status)
+{
+ struct smbXcli_session *session;
+ int sock_fd = conn->sock_fd;
+
+ tevent_queue_stop(conn->outgoing);
+
+ conn->sock_fd = -1;
+
+ session = conn->sessions;
+ if (talloc_array_length(conn->pending) == 0) {
+ /*
+ * if we do not have pending requests
+ * there is no need to update the channel_sequence
+ */
+ session = NULL;
+ }
+ for (; session; session = session->next) {
+ smb2cli_session_increment_channel_sequence(session);
+ }
+
+ if (conn->suicide_req != NULL) {
+ /*
+ * smbXcli_conn_samba_suicide_send()
+ * used tevent_req_defer_callback() already.
+ */
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(conn->suicide_req, status);
+ }
+ conn->suicide_req = NULL;
+ }
+
+ /*
+ * Cancel all pending requests. We do not do a for-loop walking
+ * conn->pending because that array changes in
+ * smbXcli_req_unset_pending.
+ */
+ while (conn->pending != NULL &&
+ talloc_array_length(conn->pending) > 0) {
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+ struct tevent_req **chain;
+ size_t num_chained;
+ size_t i;
+
+ req = conn->pending[0];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ if (state->smb1.chained_requests == NULL) {
+ bool in_progress;
+
+ /*
+ * We're dead. No point waiting for trans2
+ * replies.
+ */
+ state->smb1.mid = 0;
+
+ smbXcli_req_unset_pending(req);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* do not notify the callers */
+ continue;
+ }
+
+ in_progress = tevent_req_is_in_progress(req);
+ if (!in_progress) {
+ /*
+ * already finished
+ */
+ continue;
+ }
+
+ /*
+ * we need to defer the callback, because we may notify
+ * more then one caller.
+ */
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_nterror(req, status);
+ continue;
+ }
+
+ chain = talloc_move(conn, &state->smb1.chained_requests);
+ num_chained = talloc_array_length(chain);
+
+ for (i=0; i<num_chained; i++) {
+ bool in_progress;
+
+ req = chain[i];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ /*
+ * We're dead. No point waiting for trans2
+ * replies.
+ */
+ state->smb1.mid = 0;
+
+ smbXcli_req_unset_pending(req);
+
+ if (NT_STATUS_IS_OK(status)) {
+ /* do not notify the callers */
+ continue;
+ }
+
+ in_progress = tevent_req_is_in_progress(req);
+ if (!in_progress) {
+ /*
+ * already finished
+ */
+ continue;
+ }
+
+ /*
+ * we need to defer the callback, because we may notify
+ * more than one caller.
+ */
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_nterror(req, status);
+ }
+ TALLOC_FREE(chain);
+ }
+
+ if (sock_fd != -1) {
+ close(sock_fd);
+ }
+}
+
+/*
+ * Fetch a smb request's mid. Only valid after the request has been sent by
+ * smb1cli_req_send().
+ */
+uint16_t smb1cli_req_mid(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ if (state->smb1.mid != 0) {
+ return state->smb1.mid;
+ }
+
+ return SVAL(state->smb1.hdr, HDR_MID);
+}
+
+void smb1cli_req_set_mid(struct tevent_req *req, uint16_t mid)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ state->smb1.mid = mid;
+}
+
+uint32_t smb1cli_req_seqnum(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ return state->smb1.seqnum;
+}
+
+void smb1cli_req_set_seqnum(struct tevent_req *req, uint32_t seqnum)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ state->smb1.seqnum = seqnum;
+}
+
+static size_t smbXcli_iov_len(const struct iovec *iov, int count)
+{
+ ssize_t ret = iov_buflen(iov, count);
+
+ /* Ignore the overflow case for now ... */
+ return ret;
+}
+
+static void smb1cli_req_flags(enum protocol_types protocol,
+ uint32_t smb1_capabilities,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint8_t *_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint16_t *_flags2)
+{
+ uint8_t flags = 0;
+ uint16_t flags2 = 0;
+
+ if (protocol >= PROTOCOL_LANMAN1) {
+ flags |= FLAG_CASELESS_PATHNAMES;
+ flags |= FLAG_CANONICAL_PATHNAMES;
+ }
+
+ if (protocol >= PROTOCOL_LANMAN2) {
+ flags2 |= FLAGS2_LONG_PATH_COMPONENTS;
+ flags2 |= FLAGS2_EXTENDED_ATTRIBUTES;
+ }
+
+ if (protocol >= PROTOCOL_NT1) {
+ flags2 |= FLAGS2_IS_LONG_NAME;
+
+ if (smb1_capabilities & CAP_UNICODE) {
+ flags2 |= FLAGS2_UNICODE_STRINGS;
+ }
+ if (smb1_capabilities & CAP_STATUS32) {
+ flags2 |= FLAGS2_32_BIT_ERROR_CODES;
+ }
+ if (smb1_capabilities & CAP_EXTENDED_SECURITY) {
+ flags2 |= FLAGS2_EXTENDED_SECURITY;
+ }
+ }
+
+ flags |= additional_flags;
+ flags &= ~clear_flags;
+ flags2 |= additional_flags2;
+ flags2 &= ~clear_flags2;
+
+ *_flags = flags;
+ *_flags2 = flags2;
+}
+
+static void smb1cli_req_cancel_done(struct tevent_req *subreq);
+
+static bool smb1cli_req_cancel(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ uint8_t flags;
+ uint16_t flags2;
+ uint32_t pid;
+ uint16_t mid;
+ struct tevent_req *subreq;
+ NTSTATUS status;
+
+ flags = CVAL(state->smb1.hdr, HDR_FLG);
+ flags2 = SVAL(state->smb1.hdr, HDR_FLG2);
+ pid = SVAL(state->smb1.hdr, HDR_PID);
+ pid |= SVAL(state->smb1.hdr, HDR_PIDHIGH)<<16;
+ mid = SVAL(state->smb1.hdr, HDR_MID);
+
+ subreq = smb1cli_req_create(state, state->ev,
+ state->conn,
+ SMBntcancel,
+ flags, 0,
+ flags2, 0,
+ 0, /* timeout */
+ pid,
+ state->tcon,
+ state->session,
+ 0, NULL, /* vwv */
+ 0, NULL); /* bytes */
+ if (subreq == NULL) {
+ return false;
+ }
+ smb1cli_req_set_mid(subreq, mid);
+
+ status = smb1cli_req_chain_submit(&subreq, 1);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ return false;
+ }
+ smb1cli_req_set_mid(subreq, 0);
+
+ tevent_req_set_callback(subreq, smb1cli_req_cancel_done, NULL);
+
+ return true;
+}
+
+static void smb1cli_req_cancel_done(struct tevent_req *subreq)
+{
+ /* we do not care about the result */
+ TALLOC_FREE(subreq);
+}
+
+struct tevent_req *smb1cli_req_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint8_t wct, uint16_t *vwv,
+ int iov_count,
+ struct iovec *bytes_iov)
+{
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+ uint8_t flags = 0;
+ uint16_t flags2 = 0;
+ uint16_t uid = 0;
+ uint16_t tid = 0;
+ ssize_t num_bytes;
+
+ if (iov_count > MAX_SMB_IOV) {
+ /*
+ * Should not happen :-)
+ */
+ return NULL;
+ }
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbXcli_req_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->conn = conn;
+ state->session = session;
+ state->tcon = tcon;
+
+ if (session) {
+ uid = session->smb1.session_id;
+ }
+
+ if (tcon) {
+ tid = tcon->smb1.tcon_id;
+
+ if (tcon->fs_attributes & FILE_CASE_SENSITIVE_SEARCH) {
+ clear_flags |= FLAG_CASELESS_PATHNAMES;
+ } else {
+ /* Default setting, case insensitive. */
+ additional_flags |= FLAG_CASELESS_PATHNAMES;
+ }
+
+ if (smbXcli_conn_dfs_supported(conn) &&
+ smbXcli_tcon_is_dfs_share(tcon))
+ {
+ additional_flags2 |= FLAGS2_DFS_PATHNAMES;
+ }
+ }
+
+ state->smb1.recv_cmd = 0xFF;
+ state->smb1.recv_status = NT_STATUS_INTERNAL_ERROR;
+ state->smb1.recv_iov = talloc_zero_array(state, struct iovec, 3);
+ if (state->smb1.recv_iov == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ smb1cli_req_flags(conn->protocol,
+ conn->smb1.capabilities,
+ smb_command,
+ additional_flags,
+ clear_flags,
+ &flags,
+ additional_flags2,
+ clear_flags2,
+ &flags2);
+
+ SIVAL(state->smb1.hdr, 0, SMB_MAGIC);
+ SCVAL(state->smb1.hdr, HDR_COM, smb_command);
+ SIVAL(state->smb1.hdr, HDR_RCLS, NT_STATUS_V(NT_STATUS_OK));
+ SCVAL(state->smb1.hdr, HDR_FLG, flags);
+ SSVAL(state->smb1.hdr, HDR_FLG2, flags2);
+ SSVAL(state->smb1.hdr, HDR_PIDHIGH, pid >> 16);
+ SSVAL(state->smb1.hdr, HDR_TID, tid);
+ SSVAL(state->smb1.hdr, HDR_PID, pid);
+ SSVAL(state->smb1.hdr, HDR_UID, uid);
+ SSVAL(state->smb1.hdr, HDR_MID, 0); /* this comes later */
+ SCVAL(state->smb1.hdr, HDR_WCT, wct);
+
+ state->smb1.vwv = vwv;
+
+ num_bytes = iov_buflen(bytes_iov, iov_count);
+ if (num_bytes == -1) {
+ /*
+ * I'd love to add a check for num_bytes<=UINT16_MAX here, but
+ * the smbclient->samba connections can lie and transfer more.
+ */
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ SSVAL(state->smb1.bytecount_buf, 0, num_bytes);
+
+ state->smb1.iov[0].iov_base = (void *)state->length_hdr;
+ state->smb1.iov[0].iov_len = sizeof(state->length_hdr);
+ state->smb1.iov[1].iov_base = (void *)state->smb1.hdr;
+ state->smb1.iov[1].iov_len = sizeof(state->smb1.hdr);
+ state->smb1.iov[2].iov_base = (void *)state->smb1.vwv;
+ state->smb1.iov[2].iov_len = wct * sizeof(uint16_t);
+ state->smb1.iov[3].iov_base = (void *)state->smb1.bytecount_buf;
+ state->smb1.iov[3].iov_len = sizeof(uint16_t);
+
+ if (iov_count != 0) {
+ memcpy(&state->smb1.iov[4], bytes_iov,
+ iov_count * sizeof(*bytes_iov));
+ }
+ state->smb1.iov_count = iov_count + 4;
+
+ if (timeout_msec > 0) {
+ state->endtime = timeval_current_ofs_msec(timeout_msec);
+ if (!tevent_req_set_endtime(req, ev, state->endtime)) {
+ return req;
+ }
+ }
+
+ switch (smb_command) {
+ case SMBtranss:
+ case SMBtranss2:
+ case SMBnttranss:
+ state->one_way = true;
+ break;
+ case SMBntcancel:
+ state->one_way = true;
+ state->smb1.one_way_seqnum = true;
+ break;
+ case SMBlockingX:
+ if ((wct == 8) &&
+ (CVAL(vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) {
+ state->one_way = true;
+ }
+ break;
+ }
+
+ return req;
+}
+
+static NTSTATUS smb1cli_conn_signv(struct smbXcli_conn *conn,
+ struct iovec *iov, int iov_count,
+ uint32_t *seqnum,
+ bool one_way_seqnum)
+{
+ TALLOC_CTX *frame = NULL;
+ NTSTATUS status;
+ uint8_t *buf;
+
+ /*
+ * Obvious optimization: Make cli_calculate_sign_mac work with struct
+ * iovec directly. MD5Update would do that just fine.
+ */
+
+ if (iov_count < 4) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[0].iov_len != NBT_HDR_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[1].iov_len != (MIN_SMB_SIZE-sizeof(uint16_t))) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[2].iov_len > (0xFF * sizeof(uint16_t))) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[3].iov_len != sizeof(uint16_t)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ frame = talloc_stackframe();
+
+ buf = iov_concat(frame, &iov[1], iov_count - 1);
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *seqnum = smb1_signing_next_seqnum(conn->smb1.signing,
+ one_way_seqnum);
+ status = smb1_signing_sign_pdu(conn->smb1.signing,
+ buf,
+ talloc_get_size(buf),
+ *seqnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ memcpy(iov[1].iov_base, buf, iov[1].iov_len);
+
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+static void smb1cli_req_writev_done(struct tevent_req *subreq);
+static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf);
+
+static NTSTATUS smb1cli_req_writev_submit(struct tevent_req *req,
+ struct smbXcli_req_state *state,
+ struct iovec *iov, int iov_count)
+{
+ struct tevent_req *subreq;
+ NTSTATUS status;
+ uint8_t cmd;
+ uint16_t mid;
+ ssize_t nbtlen;
+
+ if (!smbXcli_conn_is_connected(state->conn)) {
+ return NT_STATUS_CONNECTION_DISCONNECTED;
+ }
+
+ if (state->conn->protocol > PROTOCOL_NT1) {
+ DBG_ERR("called for dialect[%s] server[%s]\n",
+ smb_protocol_types_string(state->conn->protocol),
+ smbXcli_conn_remote_name(state->conn));
+ return NT_STATUS_REVISION_MISMATCH;
+ }
+
+ if (iov_count < 4) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[0].iov_len != NBT_HDR_SIZE) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[1].iov_len != (MIN_SMB_SIZE-sizeof(uint16_t))) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[2].iov_len > (0xFF * sizeof(uint16_t))) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ if (iov[3].iov_len != sizeof(uint16_t)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ cmd = CVAL(iov[1].iov_base, HDR_COM);
+ if (cmd == SMBreadBraw) {
+ if (smbXcli_conn_has_async_calls(state->conn)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ state->conn->smb1.read_braw_req = req;
+ }
+
+ if (state->smb1.mid != 0) {
+ mid = state->smb1.mid;
+ } else {
+ mid = smb1cli_alloc_mid(state->conn);
+ }
+ SSVAL(iov[1].iov_base, HDR_MID, mid);
+
+ nbtlen = iov_buflen(&iov[1], iov_count-1);
+ if ((nbtlen == -1) || (nbtlen > 0x1FFFF)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ _smb_setlen_nbt(iov[0].iov_base, nbtlen);
+
+ status = smb1cli_conn_signv(state->conn, iov, iov_count,
+ &state->smb1.seqnum,
+ state->smb1.one_way_seqnum);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * If we supported multiple encryption contexts
+ * here we'd look up based on tid.
+ */
+ if (common_encryption_on(state->conn->smb1.trans_enc)) {
+ char *buf, *enc_buf;
+
+ buf = (char *)iov_concat(talloc_tos(), iov, iov_count);
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ status = common_encrypt_buffer(state->conn->smb1.trans_enc,
+ (char *)buf, &enc_buf);
+ TALLOC_FREE(buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Error in encrypting client message: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ buf = (char *)talloc_memdup(state, enc_buf,
+ smb_len_nbt(enc_buf)+4);
+ SAFE_FREE(enc_buf);
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov[0].iov_base = (void *)buf;
+ iov[0].iov_len = talloc_get_size(buf);
+ iov_count = 1;
+ }
+
+ if (state->conn->dispatch_incoming == NULL) {
+ state->conn->dispatch_incoming = smb1cli_conn_dispatch_incoming;
+ }
+
+ if (!smbXcli_req_set_pending(req)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ tevent_req_set_cancel_fn(req, smbXcli_req_cancel);
+
+ subreq = writev_send(state, state->ev, state->conn->outgoing,
+ state->conn->sock_fd, false, iov, iov_count);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, smb1cli_req_writev_done, req);
+ state->write_req = subreq;
+
+ return NT_STATUS_OK;
+}
+
+struct tevent_req *smb1cli_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint8_t wct, uint16_t *vwv,
+ uint32_t num_bytes,
+ const uint8_t *bytes)
+{
+ struct tevent_req *req;
+ struct iovec iov;
+ NTSTATUS status;
+
+ iov.iov_base = discard_const_p(void, bytes);
+ iov.iov_len = num_bytes;
+
+ req = smb1cli_req_create(mem_ctx, ev, conn, smb_command,
+ additional_flags, clear_flags,
+ additional_flags2, clear_flags2,
+ timeout_msec,
+ pid, tcon, session,
+ wct, vwv, 1, &iov);
+ if (req == NULL) {
+ return NULL;
+ }
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+ status = smb1cli_req_chain_submit(&req, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void smb1cli_req_writev_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ ssize_t nwritten;
+ int err;
+
+ state->write_req = NULL;
+
+ nwritten = writev_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (nwritten == -1) {
+ /* here, we need to notify all pending requests */
+ NTSTATUS status = map_nt_error_from_unix_common(err);
+ smbXcli_conn_disconnect(state->conn, status);
+ return;
+ }
+
+ if (state->one_way) {
+ state->inbuf = NULL;
+ tevent_req_done(req);
+ return;
+ }
+}
+
+static void smbXcli_conn_received(struct tevent_req *subreq)
+{
+ struct smbXcli_conn *conn =
+ tevent_req_callback_data(subreq,
+ struct smbXcli_conn);
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ uint8_t *inbuf;
+ ssize_t received;
+ int err;
+
+ if (subreq != conn->read_smb_req) {
+ DEBUG(1, ("Internal error: cli_smb_received called with "
+ "unexpected subreq\n"));
+ smbXcli_conn_disconnect(conn, NT_STATUS_INTERNAL_ERROR);
+ TALLOC_FREE(frame);
+ return;
+ }
+ conn->read_smb_req = NULL;
+
+ received = read_smb_recv(subreq, frame, &inbuf, &err);
+ TALLOC_FREE(subreq);
+ if (received == -1) {
+ status = map_nt_error_from_unix_common(err);
+ smbXcli_conn_disconnect(conn, status);
+ TALLOC_FREE(frame);
+ return;
+ }
+
+ status = conn->dispatch_incoming(conn, frame, inbuf);
+ TALLOC_FREE(frame);
+ if (NT_STATUS_IS_OK(status)) {
+ /*
+ * We should not do any more processing
+ * as the dispatch function called
+ * tevent_req_done().
+ */
+ return;
+ }
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
+ /*
+ * We got an error, so notify all pending requests
+ */
+ smbXcli_conn_disconnect(conn, status);
+ return;
+ }
+
+ /*
+ * We got NT_STATUS_RETRY, so we may ask for a
+ * next incoming pdu.
+ */
+ if (!smbXcli_conn_receive_next(conn)) {
+ smbXcli_conn_disconnect(conn, NT_STATUS_NO_MEMORY);
+ }
+}
+
+static NTSTATUS smb1cli_inbuf_parse_chain(uint8_t *buf, TALLOC_CTX *mem_ctx,
+ struct iovec **piov, int *pnum_iov)
+{
+ struct iovec *iov;
+ size_t num_iov;
+ size_t buflen;
+ size_t taken;
+ size_t remaining;
+ uint8_t *hdr;
+ uint8_t cmd;
+ uint32_t wct_ofs;
+ NTSTATUS status;
+ size_t min_size = MIN_SMB_SIZE;
+
+ buflen = smb_len_tcp(buf);
+ taken = 0;
+
+ hdr = buf + NBT_HDR_SIZE;
+
+ status = smb1cli_pull_raw_error(hdr);
+ if (NT_STATUS_IS_ERR(status)) {
+ /*
+ * This is an ugly hack to support OS/2
+ * which skips the byte_count in the DATA block
+ * on some error responses.
+ *
+ * See bug #9096
+ */
+ min_size -= sizeof(uint16_t);
+ }
+
+ if (buflen < min_size) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * This returns iovec elements in the following order:
+ *
+ * - SMB header
+ *
+ * - Parameter Block
+ * - Data Block
+ *
+ * - Parameter Block
+ * - Data Block
+ *
+ * - Parameter Block
+ * - Data Block
+ */
+ num_iov = 1;
+
+ iov = talloc_array(mem_ctx, struct iovec, num_iov);
+ if (iov == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov[0].iov_base = hdr;
+ iov[0].iov_len = HDR_WCT;
+ taken += HDR_WCT;
+
+ cmd = CVAL(hdr, HDR_COM);
+ wct_ofs = HDR_WCT;
+
+ while (true) {
+ size_t len = buflen - taken;
+ struct iovec *cur;
+ struct iovec *iov_tmp;
+ uint8_t wct;
+ uint32_t bcc_ofs;
+ uint16_t bcc;
+ size_t needed;
+
+ /*
+ * we need at least WCT
+ */
+ needed = sizeof(uint8_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ /*
+ * Now we check if the specified words are there
+ */
+ wct = CVAL(hdr, wct_ofs);
+ needed += wct * sizeof(uint16_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ if ((num_iov == 1) &&
+ (len == needed) &&
+ NT_STATUS_IS_ERR(status))
+ {
+ /*
+ * This is an ugly hack to support OS/2
+ * which skips the byte_count in the DATA block
+ * on some error responses.
+ *
+ * See bug #9096
+ */
+ iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
+ num_iov + 2);
+ if (iov_tmp == NULL) {
+ TALLOC_FREE(iov);
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov = iov_tmp;
+ cur = &iov[num_iov];
+ num_iov += 2;
+
+ cur[0].iov_len = 0;
+ cur[0].iov_base = hdr + (wct_ofs + sizeof(uint8_t));
+ cur[1].iov_len = 0;
+ cur[1].iov_base = cur[0].iov_base;
+
+ taken += needed;
+ break;
+ }
+
+ /*
+ * we need at least BCC
+ */
+ needed += sizeof(uint16_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ /*
+ * Now we check if the specified bytes are there
+ */
+ bcc_ofs = wct_ofs + sizeof(uint8_t) + wct * sizeof(uint16_t);
+ bcc = SVAL(hdr, bcc_ofs);
+ needed += bcc * sizeof(uint8_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ /*
+ * we allocate 2 iovec structures for words and bytes
+ */
+ iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
+ num_iov + 2);
+ if (iov_tmp == NULL) {
+ TALLOC_FREE(iov);
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov = iov_tmp;
+ cur = &iov[num_iov];
+ num_iov += 2;
+
+ cur[0].iov_len = wct * sizeof(uint16_t);
+ cur[0].iov_base = hdr + (wct_ofs + sizeof(uint8_t));
+ cur[1].iov_len = bcc * sizeof(uint8_t);
+ cur[1].iov_base = hdr + (bcc_ofs + sizeof(uint16_t));
+
+ taken += needed;
+
+ if (!smb1cli_is_andx_req(cmd)) {
+ /*
+ * If the current command does not have AndX chanining
+ * we are done.
+ */
+ break;
+ }
+
+ if (wct == 0 && bcc == 0) {
+ /*
+ * An empty response also ends the chain,
+ * most likely with an error.
+ */
+ break;
+ }
+
+ if (wct < 2) {
+ DEBUG(10, ("%s: wct[%d] < 2 for cmd[0x%02X]\n",
+ __location__, (int)wct, (int)cmd));
+ goto inval;
+ }
+ cmd = CVAL(cur[0].iov_base, 0);
+ if (cmd == 0xFF) {
+ /*
+ * If it is the end of the chain we are also done.
+ */
+ break;
+ }
+ wct_ofs = SVAL(cur[0].iov_base, 2);
+
+ if (wct_ofs < taken) {
+ goto inval;
+ }
+ if (wct_ofs > buflen) {
+ goto inval;
+ }
+
+ /*
+ * we consumed everything up to the start of the next
+ * parameter block.
+ */
+ taken = wct_ofs;
+ }
+
+ remaining = buflen - taken;
+
+ if (remaining > 0 && num_iov >= 3) {
+ /*
+ * The last DATA block gets the remaining
+ * bytes, this is needed to support
+ * CAP_LARGE_WRITEX and CAP_LARGE_READX.
+ */
+ iov[num_iov-1].iov_len += remaining;
+ }
+
+ *piov = iov;
+ *pnum_iov = num_iov;
+ return NT_STATUS_OK;
+
+inval:
+ TALLOC_FREE(iov);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf)
+{
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+ NTSTATUS status;
+ size_t num_pending;
+ size_t i;
+ uint8_t cmd;
+ uint16_t mid;
+ bool oplock_break;
+ uint8_t *inhdr = inbuf + NBT_HDR_SIZE;
+ size_t len = smb_len_tcp(inbuf);
+ struct iovec *iov = NULL;
+ int num_iov = 0;
+ struct tevent_req **chain = NULL;
+ size_t num_chained = 0;
+ size_t num_responses = 0;
+
+ if (conn->smb1.read_braw_req != NULL) {
+ req = conn->smb1.read_braw_req;
+ conn->smb1.read_braw_req = NULL;
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ smbXcli_req_unset_pending(req);
+
+ if (state->smb1.recv_iov == NULL) {
+ /*
+ * For requests with more than
+ * one response, we have to readd the
+ * recv_iov array.
+ */
+ state->smb1.recv_iov = talloc_zero_array(state,
+ struct iovec,
+ 3);
+ if (tevent_req_nomem(state->smb1.recv_iov, req)) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ state->smb1.recv_iov[0].iov_base = (void *)(inhdr);
+ state->smb1.recv_iov[0].iov_len = len;
+ ZERO_STRUCT(state->smb1.recv_iov[1]);
+ ZERO_STRUCT(state->smb1.recv_iov[2]);
+
+ state->smb1.recv_cmd = SMBreadBraw;
+ state->smb1.recv_status = NT_STATUS_OK;
+ state->inbuf = talloc_move(state->smb1.recv_iov, &inbuf);
+
+ tevent_req_done(req);
+ return NT_STATUS_OK;
+ }
+
+ if ((IVAL(inhdr, 0) != SMB_MAGIC) /* 0xFF"SMB" */
+ && (SVAL(inhdr, 0) != 0x45ff)) /* 0xFF"E" */ {
+ DEBUG(10, ("Got non-SMB PDU\n"));
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * If we supported multiple encryption contexts
+ * here we'd look up based on tid.
+ */
+ if (common_encryption_on(conn->smb1.trans_enc)
+ && (CVAL(inbuf, 0) == 0)) {
+ uint16_t enc_ctx_num;
+
+ status = get_enc_ctx_num(inbuf, &enc_ctx_num);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("get_enc_ctx_num returned %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ if (enc_ctx_num != conn->smb1.trans_enc->enc_ctx_num) {
+ DEBUG(10, ("wrong enc_ctx %d, expected %d\n",
+ enc_ctx_num,
+ conn->smb1.trans_enc->enc_ctx_num));
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ status = common_decrypt_buffer(conn->smb1.trans_enc,
+ (char *)inbuf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("common_decrypt_buffer returned %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ inhdr = inbuf + NBT_HDR_SIZE;
+ len = smb_len_nbt(inbuf);
+ }
+
+ mid = SVAL(inhdr, HDR_MID);
+ num_pending = talloc_array_length(conn->pending);
+
+ for (i=0; i<num_pending; i++) {
+ if (mid == smb1cli_req_mid(conn->pending[i])) {
+ break;
+ }
+ }
+ if (i == num_pending) {
+ /* Dump unexpected reply */
+ return NT_STATUS_RETRY;
+ }
+
+ oplock_break = false;
+
+ if (mid == 0xffff) {
+ /*
+ * Paranoia checks that this is really an oplock break request.
+ */
+ oplock_break = (len == 51); /* hdr + 8 words */
+ oplock_break &= ((CVAL(inhdr, HDR_FLG) & FLAG_REPLY) == 0);
+ oplock_break &= (CVAL(inhdr, HDR_COM) == SMBlockingX);
+ oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(6)) == 0);
+ oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(7)) == 0);
+
+ if (!oplock_break) {
+ /* Dump unexpected reply */
+ return NT_STATUS_RETRY;
+ }
+ }
+
+ req = conn->pending[i];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ if (!oplock_break /* oplock breaks are not signed */
+ && !smb1_signing_check_pdu(conn->smb1.signing,
+ inhdr, len, state->smb1.seqnum+1)) {
+ DEBUG(10, ("cli_check_sign_mac failed\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ status = smb1cli_inbuf_parse_chain(inbuf, tmp_mem,
+ &iov, &num_iov);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("smb1cli_inbuf_parse_chain - %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ cmd = CVAL(inhdr, HDR_COM);
+ status = smb1cli_pull_raw_error(inhdr);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED) &&
+ (state->session != NULL) && state->session->disconnect_expired)
+ {
+ /*
+ * this should be a short term hack
+ * until the upper layers have implemented
+ * re-authentication.
+ */
+ return status;
+ }
+
+ if (state->smb1.chained_requests == NULL) {
+ if (num_iov != 3) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ smbXcli_req_unset_pending(req);
+
+ if (state->smb1.recv_iov == NULL) {
+ /*
+ * For requests with more than
+ * one response, we have to readd the
+ * recv_iov array.
+ */
+ state->smb1.recv_iov = talloc_zero_array(state,
+ struct iovec,
+ 3);
+ if (tevent_req_nomem(state->smb1.recv_iov, req)) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ state->smb1.recv_cmd = cmd;
+ state->smb1.recv_status = status;
+ state->inbuf = talloc_move(state->smb1.recv_iov, &inbuf);
+
+ state->smb1.recv_iov[0] = iov[0];
+ state->smb1.recv_iov[1] = iov[1];
+ state->smb1.recv_iov[2] = iov[2];
+
+ if (talloc_array_length(conn->pending) == 0) {
+ tevent_req_done(req);
+ return NT_STATUS_OK;
+ }
+
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_done(req);
+ return NT_STATUS_RETRY;
+ }
+
+ chain = talloc_move(tmp_mem, &state->smb1.chained_requests);
+ num_chained = talloc_array_length(chain);
+ num_responses = (num_iov - 1)/2;
+
+ if (num_responses > num_chained) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ for (i=0; i<num_chained; i++) {
+ size_t iov_idx = 1 + (i*2);
+ struct iovec *cur = &iov[iov_idx];
+ uint8_t *inbuf_ref;
+
+ req = chain[i];
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ smbXcli_req_unset_pending(req);
+
+ /*
+ * as we finish multiple requests here
+ * we need to defer the callbacks as
+ * they could destroy our current stack state.
+ */
+ tevent_req_defer_callback(req, state->ev);
+
+ if (i >= num_responses) {
+ tevent_req_nterror(req, NT_STATUS_REQUEST_ABORTED);
+ continue;
+ }
+
+ if (state->smb1.recv_iov == NULL) {
+ /*
+ * For requests with more than
+ * one response, we have to readd the
+ * recv_iov array.
+ */
+ state->smb1.recv_iov = talloc_zero_array(state,
+ struct iovec,
+ 3);
+ if (tevent_req_nomem(state->smb1.recv_iov, req)) {
+ continue;
+ }
+ }
+
+ state->smb1.recv_cmd = cmd;
+
+ if (i == (num_responses - 1)) {
+ /*
+ * The last request in the chain gets the status
+ */
+ state->smb1.recv_status = status;
+ } else {
+ cmd = CVAL(cur[0].iov_base, 0);
+ state->smb1.recv_status = NT_STATUS_OK;
+ }
+
+ state->inbuf = inbuf;
+
+ /*
+ * Note: here we use talloc_reference() in a way
+ * that does not expose it to the caller.
+ */
+ inbuf_ref = talloc_reference(state->smb1.recv_iov, inbuf);
+ if (tevent_req_nomem(inbuf_ref, req)) {
+ continue;
+ }
+
+ /* copy the related buffers */
+ state->smb1.recv_iov[0] = iov[0];
+ state->smb1.recv_iov[1] = cur[0];
+ state->smb1.recv_iov[2] = cur[1];
+
+ tevent_req_done(req);
+ }
+
+ return NT_STATUS_RETRY;
+}
+
+NTSTATUS smb1cli_req_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ uint8_t **phdr,
+ uint8_t *pwct,
+ uint16_t **pvwv,
+ uint32_t *pvwv_offset,
+ uint32_t *pnum_bytes,
+ uint8_t **pbytes,
+ uint32_t *pbytes_offset,
+ uint8_t **pinbuf,
+ const struct smb1cli_req_expected_response *expected,
+ size_t num_expected)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ NTSTATUS status = NT_STATUS_OK;
+ struct iovec *recv_iov = NULL;
+ uint8_t *hdr = NULL;
+ uint8_t wct = 0;
+ uint32_t vwv_offset = 0;
+ uint16_t *vwv = NULL;
+ uint32_t num_bytes = 0;
+ uint32_t bytes_offset = 0;
+ uint8_t *bytes = NULL;
+ size_t i;
+ bool found_status = false;
+ bool found_size = false;
+
+ if (piov != NULL) {
+ *piov = NULL;
+ }
+ if (phdr != NULL) {
+ *phdr = 0;
+ }
+ if (pwct != NULL) {
+ *pwct = 0;
+ }
+ if (pvwv != NULL) {
+ *pvwv = NULL;
+ }
+ if (pvwv_offset != NULL) {
+ *pvwv_offset = 0;
+ }
+ if (pnum_bytes != NULL) {
+ *pnum_bytes = 0;
+ }
+ if (pbytes != NULL) {
+ *pbytes = NULL;
+ }
+ if (pbytes_offset != NULL) {
+ *pbytes_offset = 0;
+ }
+ if (pinbuf != NULL) {
+ *pinbuf = NULL;
+ }
+
+ if (state->inbuf != NULL) {
+ recv_iov = state->smb1.recv_iov;
+ state->smb1.recv_iov = NULL;
+ if (state->smb1.recv_cmd != SMBreadBraw) {
+ hdr = (uint8_t *)recv_iov[0].iov_base;
+ wct = recv_iov[1].iov_len/2;
+ vwv = (uint16_t *)recv_iov[1].iov_base;
+ vwv_offset = PTR_DIFF(vwv, hdr);
+ num_bytes = recv_iov[2].iov_len;
+ bytes = (uint8_t *)recv_iov[2].iov_base;
+ bytes_offset = PTR_DIFF(bytes, hdr);
+ }
+ }
+
+ if (tevent_req_is_nterror(req, &status)) {
+ for (i=0; i < num_expected; i++) {
+ if (NT_STATUS_EQUAL(status, expected[i].status)) {
+ found_status = true;
+ break;
+ }
+ }
+
+ if (found_status) {
+ return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+
+ return status;
+ }
+
+ if (num_expected == 0) {
+ found_status = true;
+ found_size = true;
+ }
+
+ status = state->smb1.recv_status;
+
+ for (i=0; i < num_expected; i++) {
+ if (!NT_STATUS_EQUAL(status, expected[i].status)) {
+ continue;
+ }
+
+ found_status = true;
+ if (expected[i].wct == 0) {
+ found_size = true;
+ break;
+ }
+
+ if (expected[i].wct == wct) {
+ found_size = true;
+ break;
+ }
+ }
+
+ if (!found_status) {
+ return status;
+ }
+
+ if (!found_size) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (piov != NULL) {
+ *piov = talloc_move(mem_ctx, &recv_iov);
+ }
+
+ if (phdr != NULL) {
+ *phdr = hdr;
+ }
+ if (pwct != NULL) {
+ *pwct = wct;
+ }
+ if (pvwv != NULL) {
+ *pvwv = vwv;
+ }
+ if (pvwv_offset != NULL) {
+ *pvwv_offset = vwv_offset;
+ }
+ if (pnum_bytes != NULL) {
+ *pnum_bytes = num_bytes;
+ }
+ if (pbytes != NULL) {
+ *pbytes = bytes;
+ }
+ if (pbytes_offset != NULL) {
+ *pbytes_offset = bytes_offset;
+ }
+ if (pinbuf != NULL) {
+ *pinbuf = state->inbuf;
+ }
+
+ return status;
+}
+
+size_t smb1cli_req_wct_ofs(struct tevent_req **reqs, int num_reqs)
+{
+ size_t wct_ofs;
+ int i;
+
+ wct_ofs = HDR_WCT;
+
+ for (i=0; i<num_reqs; i++) {
+ struct smbXcli_req_state *state;
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+ wct_ofs += smbXcli_iov_len(state->smb1.iov+2,
+ state->smb1.iov_count-2);
+ wct_ofs = (wct_ofs + 3) & ~3;
+ }
+ return wct_ofs;
+}
+
+NTSTATUS smb1cli_req_chain_submit(struct tevent_req **reqs, int num_reqs)
+{
+ struct smbXcli_req_state *first_state =
+ tevent_req_data(reqs[0],
+ struct smbXcli_req_state);
+ struct smbXcli_req_state *state;
+ size_t wct_offset;
+ size_t chain_padding = 0;
+ int i, iovlen;
+ struct iovec *iov = NULL;
+ struct iovec *this_iov;
+ NTSTATUS status;
+ ssize_t nbt_len;
+
+ if (num_reqs == 1) {
+ return smb1cli_req_writev_submit(reqs[0], first_state,
+ first_state->smb1.iov,
+ first_state->smb1.iov_count);
+ }
+
+ iovlen = 0;
+ for (i=0; i<num_reqs; i++) {
+ if (!tevent_req_is_in_progress(reqs[i])) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+
+ if (state->smb1.iov_count < 4) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (i == 0) {
+ /*
+ * The NBT and SMB header
+ */
+ iovlen += 2;
+ } else {
+ /*
+ * Chain padding
+ */
+ iovlen += 1;
+ }
+
+ /*
+ * words and bytes
+ */
+ iovlen += state->smb1.iov_count - 2;
+ }
+
+ iov = talloc_zero_array(first_state, struct iovec, iovlen);
+ if (iov == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ first_state->smb1.chained_requests = (struct tevent_req **)talloc_memdup(
+ first_state, reqs, sizeof(*reqs) * num_reqs);
+ if (first_state->smb1.chained_requests == NULL) {
+ TALLOC_FREE(iov);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ wct_offset = HDR_WCT;
+ this_iov = iov;
+
+ for (i=0; i<num_reqs; i++) {
+ size_t next_padding = 0;
+ uint16_t *vwv;
+
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+
+ if (i < num_reqs-1) {
+ if (!smb1cli_is_andx_req(CVAL(state->smb1.hdr, HDR_COM))
+ || CVAL(state->smb1.hdr, HDR_WCT) < 2) {
+ TALLOC_FREE(iov);
+ TALLOC_FREE(first_state->smb1.chained_requests);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ }
+
+ wct_offset += smbXcli_iov_len(state->smb1.iov+2,
+ state->smb1.iov_count-2) + 1;
+ if ((wct_offset % 4) != 0) {
+ next_padding = 4 - (wct_offset % 4);
+ }
+ wct_offset += next_padding;
+ vwv = state->smb1.vwv;
+
+ if (i < num_reqs-1) {
+ struct smbXcli_req_state *next_state =
+ tevent_req_data(reqs[i+1],
+ struct smbXcli_req_state);
+ SCVAL(vwv+0, 0, CVAL(next_state->smb1.hdr, HDR_COM));
+ SCVAL(vwv+0, 1, 0);
+ SSVAL(vwv+1, 0, wct_offset);
+ } else if (smb1cli_is_andx_req(CVAL(state->smb1.hdr, HDR_COM))) {
+ /* properly end the chain */
+ SCVAL(vwv+0, 0, 0xff);
+ SCVAL(vwv+0, 1, 0xff);
+ SSVAL(vwv+1, 0, 0);
+ }
+
+ if (i == 0) {
+ /*
+ * The NBT and SMB header
+ */
+ this_iov[0] = state->smb1.iov[0];
+ this_iov[1] = state->smb1.iov[1];
+ this_iov += 2;
+ } else {
+ /*
+ * This one is a bit subtle. We have to add
+ * chain_padding bytes between the requests, and we
+ * have to also include the wct field of the
+ * subsequent requests. We use the subsequent header
+ * for the padding, it contains the wct field in its
+ * last byte.
+ */
+ this_iov[0].iov_len = chain_padding+1;
+ this_iov[0].iov_base = (void *)&state->smb1.hdr[
+ sizeof(state->smb1.hdr) - this_iov[0].iov_len];
+ memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1);
+ this_iov += 1;
+ }
+
+ /*
+ * copy the words and bytes
+ */
+ memcpy(this_iov, state->smb1.iov+2,
+ sizeof(struct iovec) * (state->smb1.iov_count-2));
+ this_iov += state->smb1.iov_count - 2;
+ chain_padding = next_padding;
+ }
+
+ nbt_len = iov_buflen(&iov[1], iovlen-1);
+ if ((nbt_len == -1) || (nbt_len > first_state->conn->smb1.max_xmit)) {
+ TALLOC_FREE(iov);
+ TALLOC_FREE(first_state->smb1.chained_requests);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ status = smb1cli_req_writev_submit(reqs[0], first_state, iov, iovlen);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(iov);
+ TALLOC_FREE(first_state->smb1.chained_requests);
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct tevent_queue *smbXcli_conn_send_queue(struct smbXcli_conn *conn)
+{
+ return conn->outgoing;
+}
+
+bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn)
+{
+ return ((tevent_queue_length(conn->outgoing) != 0)
+ || (talloc_array_length(conn->pending) != 0));
+}
+
+bool smbXcli_conn_dfs_supported(struct smbXcli_conn *conn)
+{
+ if (conn->protocol >= PROTOCOL_SMB2_02) {
+ return (smb2cli_conn_server_capabilities(conn) & SMB2_CAP_DFS);
+ }
+
+ return (smb1cli_conn_capabilities(conn) & CAP_DFS);
+}
+
+bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len)
+{
+ uint16_t credits = 1;
+
+ if (conn->smb2.cur_credits == 0) {
+ if (max_dyn_len != NULL) {
+ *max_dyn_len = 0;
+ }
+ return false;
+ }
+
+ if (conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) {
+ credits = conn->smb2.cur_credits;
+ }
+
+ if (max_dyn_len != NULL) {
+ *max_dyn_len = credits * 65536;
+ }
+
+ return true;
+}
+
+uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.capabilities;
+}
+
+uint16_t smb2cli_conn_server_security_mode(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.security_mode;
+}
+
+uint16_t smb2cli_conn_server_signing_algo(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.sign_algo;
+}
+
+uint16_t smb2cli_conn_server_encryption_algo(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.cipher;
+}
+
+uint32_t smb2cli_conn_max_trans_size(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.max_trans_size;
+}
+
+uint32_t smb2cli_conn_max_read_size(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.max_read_size;
+}
+
+uint32_t smb2cli_conn_max_write_size(struct smbXcli_conn *conn)
+{
+ return conn->smb2.server.max_write_size;
+}
+
+void smb2cli_conn_set_max_credits(struct smbXcli_conn *conn,
+ uint16_t max_credits)
+{
+ conn->smb2.max_credits = max_credits;
+}
+
+uint16_t smb2cli_conn_get_cur_credits(struct smbXcli_conn *conn)
+{
+ return conn->smb2.cur_credits;
+}
+
+uint8_t smb2cli_conn_get_io_priority(struct smbXcli_conn *conn)
+{
+ if (conn->protocol < PROTOCOL_SMB3_11) {
+ return 0;
+ }
+
+ return conn->smb2.io_priority;
+}
+
+void smb2cli_conn_set_io_priority(struct smbXcli_conn *conn,
+ uint8_t io_priority)
+{
+ conn->smb2.io_priority = io_priority;
+}
+
+uint32_t smb2cli_conn_cc_chunk_len(struct smbXcli_conn *conn)
+{
+ return conn->smb2.cc_chunk_len;
+}
+
+void smb2cli_conn_set_cc_chunk_len(struct smbXcli_conn *conn,
+ uint32_t chunk_len)
+{
+ conn->smb2.cc_chunk_len = chunk_len;
+}
+
+uint32_t smb2cli_conn_cc_max_chunks(struct smbXcli_conn *conn)
+{
+ return conn->smb2.cc_max_chunks;
+}
+
+void smb2cli_conn_set_cc_max_chunks(struct smbXcli_conn *conn,
+ uint32_t max_chunks)
+{
+ conn->smb2.cc_max_chunks = max_chunks;
+}
+
+static void smb2cli_req_cancel_done(struct tevent_req *subreq);
+
+static bool smb2cli_req_cancel(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ struct smbXcli_tcon *tcon = state->tcon;
+ struct smbXcli_session *session = state->session;
+ uint8_t *fixed = state->smb2.pad;
+ uint16_t fixed_len = 4;
+ struct tevent_req *subreq;
+ struct smbXcli_req_state *substate;
+ NTSTATUS status;
+
+ if (state->smb2.cancel_mid == UINT64_MAX) {
+ /*
+ * We already send a cancel,
+ * make sure we don't do it
+ * twice, otherwise we may
+ * expose the same NONCE for
+ * AES-128-GMAC signing
+ */
+ return true;
+ }
+
+ SSVAL(fixed, 0, 0x04);
+ SSVAL(fixed, 2, 0);
+
+ subreq = smb2cli_req_create(state, state->ev,
+ state->conn,
+ SMB2_OP_CANCEL,
+ 0, 0, /* flags */
+ 0, /* timeout */
+ tcon, session,
+ fixed, fixed_len,
+ NULL, 0, 0);
+ if (subreq == NULL) {
+ return false;
+ }
+ substate = tevent_req_data(subreq, struct smbXcli_req_state);
+
+ substate->smb2.cancel_mid = BVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID);
+
+ SIVAL(substate->smb2.hdr, SMB2_HDR_FLAGS, state->smb2.cancel_flags);
+ SBVAL(substate->smb2.hdr, SMB2_HDR_MESSAGE_ID, state->smb2.cancel_mid);
+ SBVAL(substate->smb2.hdr, SMB2_HDR_ASYNC_ID, state->smb2.cancel_aid);
+
+ /*
+ * remember that we don't send a cancel again
+ */
+ state->smb2.cancel_mid = UINT64_MAX;
+
+ status = smb2cli_req_compound_submit(&subreq, 1);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ return false;
+ }
+
+ tevent_req_set_callback(subreq, smb2cli_req_cancel_done, NULL);
+
+ return true;
+}
+
+static void smb2cli_req_cancel_done(struct tevent_req *subreq)
+{
+ /* we do not care about the result */
+ TALLOC_FREE(subreq);
+}
+
+struct timeval smbXcli_req_endtime(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state = tevent_req_data(
+ req, struct smbXcli_req_state);
+
+ return state->endtime;
+}
+
+struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint16_t cmd,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const uint8_t *fixed,
+ uint16_t fixed_len,
+ const uint8_t *dyn,
+ uint32_t dyn_len,
+ uint32_t max_dyn_len)
+{
+ struct tevent_req *req;
+ struct smbXcli_req_state *state;
+ uint32_t flags = 0;
+ uint32_t tid = 0;
+ uint64_t uid = 0;
+ bool use_channel_sequence = conn->smb2.force_channel_sequence;
+ uint16_t channel_sequence = 0;
+ bool use_replay_flag = false;
+ enum protocol_types proto = smbXcli_conn_protocol(conn);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbXcli_req_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if ((proto > PROTOCOL_NONE) && (proto < PROTOCOL_SMB2_02)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return req;
+ }
+
+ state->ev = ev;
+ state->conn = conn;
+ state->session = session;
+ state->tcon = tcon;
+
+ if (conn->smb2.server.capabilities & SMB2_CAP_PERSISTENT_HANDLES) {
+ use_channel_sequence = true;
+ } else if (conn->smb2.server.capabilities & SMB2_CAP_MULTI_CHANNEL) {
+ use_channel_sequence = true;
+ }
+
+ if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_00) {
+ use_replay_flag = true;
+ }
+
+ if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_11) {
+ flags |= SMB2_PRIORITY_VALUE_TO_MASK(conn->smb2.io_priority);
+ }
+
+ if (session) {
+ uid = session->smb2->session_id;
+
+ if (use_channel_sequence) {
+ channel_sequence = session->smb2->channel_sequence;
+ }
+
+ if (use_replay_flag && session->smb2->replay_active) {
+ additional_flags |= SMB2_HDR_FLAG_REPLAY_OPERATION;
+ }
+
+ state->smb2.should_sign = session->smb2->should_sign;
+ state->smb2.should_encrypt = session->smb2->should_encrypt;
+ state->smb2.require_signed_response =
+ session->smb2->require_signed_response;
+
+ if (cmd == SMB2_OP_SESSSETUP &&
+ !smb2_signing_key_valid(session->smb2_channel.signing_key) &&
+ smb2_signing_key_valid(session->smb2->signing_key))
+ {
+ /*
+ * a session bind needs to be signed
+ */
+ state->smb2.should_sign = true;
+ }
+
+ if (cmd == SMB2_OP_SESSSETUP &&
+ !smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ state->smb2.should_encrypt = false;
+ }
+
+ if (additional_flags & SMB2_HDR_FLAG_SIGNED) {
+ if (!smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ tevent_req_nterror(req, NT_STATUS_NO_USER_SESSION_KEY);
+ return req;
+ }
+
+ additional_flags &= ~SMB2_HDR_FLAG_SIGNED;
+ state->smb2.should_sign = true;
+ }
+ }
+
+ if (tcon) {
+ tid = tcon->smb2.tcon_id;
+
+ if (tcon->smb2.should_sign) {
+ state->smb2.should_sign = true;
+ }
+ if (tcon->smb2.should_encrypt) {
+ state->smb2.should_encrypt = true;
+ }
+ }
+
+ if (state->smb2.should_encrypt) {
+ state->smb2.should_sign = false;
+ }
+
+ state->smb2.recv_iov = talloc_zero_array(state, struct iovec, 3);
+ if (tevent_req_nomem(state->smb2.recv_iov, req)) {
+ return req;
+ }
+
+ flags |= additional_flags;
+ flags &= ~clear_flags;
+
+ state->smb2.fixed = fixed;
+ state->smb2.fixed_len = fixed_len;
+ state->smb2.dyn = dyn;
+ state->smb2.dyn_len = dyn_len;
+ state->smb2.max_dyn_len = max_dyn_len;
+
+ if (state->smb2.should_encrypt) {
+ SIVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
+ SBVAL(state->smb2.transform, SMB2_TF_SESSION_ID, uid);
+ }
+
+ SIVAL(state->smb2.hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
+ SSVAL(state->smb2.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
+ SSVAL(state->smb2.hdr, SMB2_HDR_OPCODE, cmd);
+ SSVAL(state->smb2.hdr, SMB2_HDR_CHANNEL_SEQUENCE, channel_sequence);
+ SIVAL(state->smb2.hdr, SMB2_HDR_FLAGS, flags);
+ SIVAL(state->smb2.hdr, SMB2_HDR_PID, 0); /* reserved */
+ SIVAL(state->smb2.hdr, SMB2_HDR_TID, tid);
+ SBVAL(state->smb2.hdr, SMB2_HDR_SESSION_ID, uid);
+
+ switch (cmd) {
+ case SMB2_OP_CANCEL:
+ state->one_way = true;
+ break;
+ case SMB2_OP_BREAK:
+ /*
+ * If this is a dummy request, it will have
+ * UINT64_MAX as message id.
+ * If we send on break acknowledgement,
+ * this gets overwritten later.
+ */
+ SBVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
+ break;
+ }
+
+ if (timeout_msec > 0) {
+ state->endtime = timeval_current_ofs_msec(timeout_msec);
+ if (!tevent_req_set_endtime(req, ev, state->endtime)) {
+ return req;
+ }
+ }
+
+ return req;
+}
+
+void smb2cli_req_set_notify_async(struct tevent_req *req)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ state->smb2.notify_async = true;
+}
+
+static void smb2cli_req_writev_done(struct tevent_req *subreq);
+static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf);
+
+NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
+ int num_reqs)
+{
+ struct smbXcli_req_state *state;
+ struct tevent_req *subreq;
+ struct iovec *iov;
+ int i, num_iov, nbt_len;
+ int tf_iov = -1;
+ struct smb2_signing_key *encryption_key = NULL;
+ uint64_t encryption_session_id = 0;
+ uint64_t nonce_high = UINT64_MAX;
+ uint64_t nonce_low = UINT64_MAX;
+
+ /*
+ * 1 for the nbt length, optional TRANSFORM
+ * per request: HDR, fixed, dyn, padding
+ * -1 because the last one does not need padding
+ */
+
+ iov = talloc_array(reqs[0], struct iovec, 1 + 1 + 4*num_reqs - 1);
+ if (iov == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ num_iov = 1;
+ nbt_len = 0;
+
+ /*
+ * the session of the first request that requires encryption
+ * specifies the encryption key.
+ */
+ for (i=0; i<num_reqs; i++) {
+ if (!tevent_req_is_in_progress(reqs[i])) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+
+ if (!smbXcli_conn_is_connected(state->conn)) {
+ return NT_STATUS_CONNECTION_DISCONNECTED;
+ }
+
+ if ((state->conn->protocol != PROTOCOL_NONE) &&
+ (state->conn->protocol < PROTOCOL_SMB2_02)) {
+ return NT_STATUS_REVISION_MISMATCH;
+ }
+
+ if (state->session == NULL) {
+ continue;
+ }
+
+ if (!state->smb2.should_encrypt) {
+ continue;
+ }
+
+ encryption_key = state->session->smb2->encryption_key;
+ if (!smb2_signing_key_valid(encryption_key)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ encryption_session_id = state->session->smb2->session_id;
+
+ state->session->smb2->nonce_low += 1;
+ if (state->session->smb2->nonce_low == 0) {
+ state->session->smb2->nonce_high += 1;
+ state->session->smb2->nonce_low += 1;
+ }
+
+ /*
+ * CCM and GCM algorithms must never have their
+ * nonce wrap, or the security of the whole
+ * communication and the keys is destroyed.
+ * We must drop the connection once we have
+ * transferred too much data.
+ *
+ * NOTE: We assume nonces greater than 8 bytes.
+ */
+ if (state->session->smb2->nonce_high >=
+ state->session->smb2->nonce_high_max)
+ {
+ return NT_STATUS_ENCRYPTION_FAILED;
+ }
+
+ nonce_high = state->session->smb2->nonce_high_random;
+ nonce_high += state->session->smb2->nonce_high;
+ nonce_low = state->session->smb2->nonce_low;
+
+ tf_iov = num_iov;
+ iov[num_iov].iov_base = state->smb2.transform;
+ iov[num_iov].iov_len = sizeof(state->smb2.transform);
+ num_iov += 1;
+
+ SBVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
+ SBVAL(state->smb2.transform, SMB2_TF_NONCE,
+ nonce_low);
+ SBVAL(state->smb2.transform, SMB2_TF_NONCE+8,
+ nonce_high);
+ SBVAL(state->smb2.transform, SMB2_TF_SESSION_ID,
+ encryption_session_id);
+
+ nbt_len += SMB2_TF_HDR_SIZE;
+ break;
+ }
+
+ for (i=0; i<num_reqs; i++) {
+ int hdr_iov;
+ size_t reqlen;
+ bool ret;
+ uint16_t opcode;
+ uint64_t avail;
+ uint16_t charge;
+ uint16_t credits;
+ uint64_t mid;
+ struct smb2_signing_key *signing_key = NULL;
+
+ if (!tevent_req_is_in_progress(reqs[i])) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ state = tevent_req_data(reqs[i], struct smbXcli_req_state);
+
+ if (!smbXcli_conn_is_connected(state->conn)) {
+ return NT_STATUS_CONNECTION_DISCONNECTED;
+ }
+
+ if ((state->conn->protocol != PROTOCOL_NONE) &&
+ (state->conn->protocol < PROTOCOL_SMB2_02)) {
+ return NT_STATUS_REVISION_MISMATCH;
+ }
+
+ opcode = SVAL(state->smb2.hdr, SMB2_HDR_OPCODE);
+ if (opcode == SMB2_OP_CANCEL) {
+ goto skip_credits;
+ }
+
+ avail = UINT64_MAX - state->conn->smb2.mid;
+ if (avail < 1) {
+ return NT_STATUS_CONNECTION_ABORTED;
+ }
+
+ if (state->conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) {
+ uint32_t max_dyn_len = 1;
+
+ max_dyn_len = MAX(max_dyn_len, state->smb2.dyn_len);
+ max_dyn_len = MAX(max_dyn_len, state->smb2.max_dyn_len);
+
+ charge = (max_dyn_len - 1)/ 65536 + 1;
+ } else {
+ charge = 1;
+ }
+
+ charge = MAX(state->smb2.credit_charge, charge);
+
+ avail = MIN(avail, state->conn->smb2.cur_credits);
+ if (avail < charge) {
+ DBG_ERR("Insufficient credits. "
+ "%"PRIu64" available, %"PRIu16" needed\n",
+ avail, charge);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ credits = 0;
+ if (state->conn->smb2.max_credits > state->conn->smb2.cur_credits) {
+ credits = state->conn->smb2.max_credits -
+ state->conn->smb2.cur_credits;
+ }
+ if (state->conn->smb2.max_credits >= state->conn->smb2.cur_credits) {
+ credits += 1;
+ }
+
+ mid = state->conn->smb2.mid;
+ state->conn->smb2.mid += charge;
+ state->conn->smb2.cur_credits -= charge;
+
+ if (state->conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) {
+ SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT_CHARGE, charge);
+ }
+ SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT, credits);
+ SBVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID, mid);
+
+ state->smb2.cancel_flags = SVAL(state->smb2.hdr, SMB2_HDR_FLAGS);
+ state->smb2.cancel_flags &= ~SMB2_HDR_FLAG_CHAINED;
+ if (state->conn->smb2.server.sign_algo >= SMB2_SIGNING_AES128_GMAC) {
+ state->smb2.cancel_mid = mid;
+ } else {
+ state->smb2.cancel_mid = 0;
+ }
+ state->smb2.cancel_aid = 0;
+
+skip_credits:
+ if (state->session && encryption_key == NULL) {
+ /*
+ * We prefer the channel signing key if it is
+ * already there.
+ */
+ if (state->smb2.should_sign) {
+ signing_key = state->session->smb2_channel.signing_key;
+ }
+
+ /*
+ * If it is a channel binding, we already have the main
+ * signing key and try that one.
+ */
+ if (signing_key != NULL &&
+ !smb2_signing_key_valid(signing_key)) {
+ signing_key = state->session->smb2->signing_key;
+ }
+
+ /*
+ * If we do not have any session key yet, we skip the
+ * signing of SMB2_OP_SESSSETUP requests.
+ */
+ if (signing_key != NULL &&
+ !smb2_signing_key_valid(signing_key)) {
+ signing_key = NULL;
+ }
+ }
+
+ hdr_iov = num_iov;
+ iov[num_iov].iov_base = state->smb2.hdr;
+ iov[num_iov].iov_len = sizeof(state->smb2.hdr);
+ num_iov += 1;
+
+ iov[num_iov].iov_base = discard_const(state->smb2.fixed);
+ iov[num_iov].iov_len = state->smb2.fixed_len;
+ num_iov += 1;
+
+ if (state->smb2.dyn != NULL) {
+ iov[num_iov].iov_base = discard_const(state->smb2.dyn);
+ iov[num_iov].iov_len = state->smb2.dyn_len;
+ num_iov += 1;
+ }
+
+ reqlen = sizeof(state->smb2.hdr);
+ reqlen += state->smb2.fixed_len;
+ reqlen += state->smb2.dyn_len;
+
+ if (i < num_reqs-1) {
+ if ((reqlen % 8) > 0) {
+ uint8_t pad = 8 - (reqlen % 8);
+ iov[num_iov].iov_base = state->smb2.pad;
+ iov[num_iov].iov_len = pad;
+ num_iov += 1;
+ reqlen += pad;
+ }
+ SIVAL(state->smb2.hdr, SMB2_HDR_NEXT_COMMAND, reqlen);
+ }
+
+ state->smb2.encryption_session_id = encryption_session_id;
+
+ if (signing_key != NULL) {
+ NTSTATUS status;
+
+ status = smb2_signing_sign_pdu(signing_key,
+ &iov[hdr_iov], num_iov - hdr_iov);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ nbt_len += reqlen;
+
+ ret = smbXcli_req_set_pending(reqs[i]);
+ if (!ret) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ state = tevent_req_data(reqs[0], struct smbXcli_req_state);
+ _smb_setlen_tcp(state->length_hdr, nbt_len);
+ iov[0].iov_base = state->length_hdr;
+ iov[0].iov_len = sizeof(state->length_hdr);
+
+ if (encryption_key != NULL) {
+ NTSTATUS status;
+ size_t buflen = nbt_len - SMB2_TF_HDR_SIZE;
+ uint8_t *buf;
+ int vi;
+
+ buf = talloc_array(iov, uint8_t, buflen);
+ if (buf == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * We copy the buffers before encrypting them,
+ * this is at least currently needed for the
+ * to keep state->smb2.hdr.
+ *
+ * Also the callers may expect there buffers
+ * to be const.
+ */
+ for (vi = tf_iov + 1; vi < num_iov; vi++) {
+ struct iovec *v = &iov[vi];
+ const uint8_t *o = (const uint8_t *)v->iov_base;
+
+ memcpy(buf, o, v->iov_len);
+ v->iov_base = (void *)buf;
+ buf += v->iov_len;
+ }
+
+ status = smb2_signing_encrypt_pdu(encryption_key,
+ &iov[tf_iov], num_iov - tf_iov);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ if (state->conn->dispatch_incoming == NULL) {
+ state->conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
+ }
+
+ subreq = writev_send(state, state->ev, state->conn->outgoing,
+ state->conn->sock_fd, false, iov, num_iov);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, smb2cli_req_writev_done, reqs[0]);
+ state->write_req = subreq;
+
+ return NT_STATUS_OK;
+}
+
+void smb2cli_req_set_credit_charge(struct tevent_req *req, uint16_t charge)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ state->smb2.credit_charge = charge;
+}
+
+struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint16_t cmd,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const uint8_t *fixed,
+ uint16_t fixed_len,
+ const uint8_t *dyn,
+ uint32_t dyn_len,
+ uint32_t max_dyn_len)
+{
+ struct tevent_req *req;
+ NTSTATUS status;
+
+ req = smb2cli_req_create(mem_ctx, ev, conn, cmd,
+ additional_flags, clear_flags,
+ timeout_msec,
+ tcon, session,
+ fixed, fixed_len,
+ dyn, dyn_len,
+ max_dyn_len);
+ if (req == NULL) {
+ return NULL;
+ }
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+ status = smb2cli_req_compound_submit(&req, 1);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void smb2cli_req_writev_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ ssize_t nwritten;
+ int err;
+
+ state->write_req = NULL;
+
+ nwritten = writev_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (nwritten == -1) {
+ /* here, we need to notify all pending requests */
+ NTSTATUS status = map_nt_error_from_unix_common(err);
+ smbXcli_conn_disconnect(state->conn, status);
+ return;
+ }
+}
+
+static struct smbXcli_session* smbXcli_session_by_uid(struct smbXcli_conn *conn,
+ uint64_t uid)
+{
+ struct smbXcli_session *s = conn->sessions;
+
+ for (; s; s = s->next) {
+ if (s->smb2->session_id != uid) {
+ continue;
+ }
+ break;
+ }
+
+ return s;
+}
+
+static NTSTATUS smb2cli_inbuf_parse_compound(struct smbXcli_conn *conn,
+ uint8_t *buf,
+ size_t buflen,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ size_t *pnum_iov)
+{
+ struct iovec *iov;
+ int num_iov = 0;
+ size_t taken = 0;
+ uint8_t *first_hdr = buf;
+ size_t verified_buflen = 0;
+ uint8_t *tf = NULL;
+ size_t tf_len = 0;
+
+ iov = talloc_array(mem_ctx, struct iovec, num_iov);
+ if (iov == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while (taken < buflen) {
+ size_t len = buflen - taken;
+ uint8_t *hdr = first_hdr + taken;
+ struct iovec *cur;
+ size_t full_size;
+ size_t next_command_ofs;
+ uint16_t body_size;
+ struct iovec *iov_tmp;
+
+ if (verified_buflen > taken) {
+ len = verified_buflen - taken;
+ } else {
+ tf = NULL;
+ tf_len = 0;
+ }
+
+ if (len < 4) {
+ DEBUG(10, ("%d bytes left, expected at least %d\n",
+ (int)len, 4));
+ goto inval;
+ }
+ if (IVAL(hdr, 0) == SMB2_TF_MAGIC) {
+ struct smbXcli_session *s;
+ uint64_t uid;
+ struct iovec tf_iov[2];
+ size_t enc_len;
+ NTSTATUS status;
+
+ if (len < SMB2_TF_HDR_SIZE) {
+ DEBUG(10, ("%d bytes left, expected at least %d\n",
+ (int)len, SMB2_TF_HDR_SIZE));
+ goto inval;
+ }
+ tf = hdr;
+ tf_len = SMB2_TF_HDR_SIZE;
+ taken += tf_len;
+
+ hdr = first_hdr + taken;
+ enc_len = IVAL(tf, SMB2_TF_MSG_SIZE);
+ uid = BVAL(tf, SMB2_TF_SESSION_ID);
+
+ if (len < SMB2_TF_HDR_SIZE + enc_len) {
+ DEBUG(10, ("%d bytes left, expected at least %d\n",
+ (int)len,
+ (int)(SMB2_TF_HDR_SIZE + enc_len)));
+ goto inval;
+ }
+
+ s = smbXcli_session_by_uid(conn, uid);
+ if (s == NULL) {
+ DEBUG(10, ("unknown session_id %llu\n",
+ (unsigned long long)uid));
+ goto inval;
+ }
+
+ tf_iov[0].iov_base = (void *)tf;
+ tf_iov[0].iov_len = tf_len;
+ tf_iov[1].iov_base = (void *)hdr;
+ tf_iov[1].iov_len = enc_len;
+
+ status = smb2_signing_decrypt_pdu(s->smb2->decryption_key,
+ tf_iov, 2);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(iov);
+ return status;
+ }
+
+ verified_buflen = taken + enc_len;
+ len = enc_len;
+ }
+
+ /*
+ * We need the header plus the body length field
+ */
+
+ if (len < SMB2_HDR_BODY + 2) {
+ DEBUG(10, ("%d bytes left, expected at least %d\n",
+ (int)len, SMB2_HDR_BODY));
+ goto inval;
+ }
+ if (IVAL(hdr, 0) != SMB2_MAGIC) {
+ DEBUG(10, ("Got non-SMB2 PDU: %x\n",
+ IVAL(hdr, 0)));
+ goto inval;
+ }
+ if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
+ DEBUG(10, ("Got HDR len %d, expected %d\n",
+ SVAL(hdr, 4), SMB2_HDR_BODY));
+ goto inval;
+ }
+
+ full_size = len;
+ next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
+ body_size = SVAL(hdr, SMB2_HDR_BODY);
+
+ if (next_command_ofs != 0) {
+ if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
+ goto inval;
+ }
+ if (next_command_ofs > full_size) {
+ goto inval;
+ }
+ full_size = next_command_ofs;
+ }
+ if (body_size < 2) {
+ goto inval;
+ }
+ body_size &= 0xfffe;
+
+ if (body_size > (full_size - SMB2_HDR_BODY)) {
+ goto inval;
+ }
+
+ iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
+ num_iov + 4);
+ if (iov_tmp == NULL) {
+ TALLOC_FREE(iov);
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov = iov_tmp;
+ cur = &iov[num_iov];
+ num_iov += 4;
+
+ cur[0].iov_base = tf;
+ cur[0].iov_len = tf_len;
+ cur[1].iov_base = hdr;
+ cur[1].iov_len = SMB2_HDR_BODY;
+ cur[2].iov_base = hdr + SMB2_HDR_BODY;
+ cur[2].iov_len = body_size;
+ cur[3].iov_base = hdr + SMB2_HDR_BODY + body_size;
+ cur[3].iov_len = full_size - (SMB2_HDR_BODY + body_size);
+
+ taken += full_size;
+ }
+
+ *piov = iov;
+ *pnum_iov = num_iov;
+ return NT_STATUS_OK;
+
+inval:
+ TALLOC_FREE(iov);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+static struct tevent_req *smb2cli_conn_find_pending(struct smbXcli_conn *conn,
+ uint64_t mid)
+{
+ size_t num_pending = talloc_array_length(conn->pending);
+ size_t i;
+
+ for (i=0; i<num_pending; i++) {
+ struct tevent_req *req = conn->pending[i];
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ if (mid == BVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID)) {
+ return req;
+ }
+ }
+ return NULL;
+}
+
+static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf)
+{
+ struct tevent_req *req;
+ struct smbXcli_req_state *state = NULL;
+ struct iovec *iov = NULL;
+ size_t i, num_iov = 0;
+ NTSTATUS status;
+ bool defer = true;
+ struct smbXcli_session *last_session = NULL;
+ size_t inbuf_len = smb_len_tcp(inbuf);
+
+ status = smb2cli_inbuf_parse_compound(conn,
+ inbuf + NBT_HDR_SIZE,
+ inbuf_len,
+ tmp_mem,
+ &iov, &num_iov);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (i=0; i<num_iov; i+=4) {
+ uint8_t *inbuf_ref = NULL;
+ struct iovec *cur = &iov[i];
+ uint8_t *inhdr = (uint8_t *)cur[1].iov_base;
+ uint16_t opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
+ uint32_t flags = IVAL(inhdr, SMB2_HDR_FLAGS);
+ uint64_t mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
+ uint16_t req_opcode;
+ uint32_t req_flags;
+ uint16_t credits = SVAL(inhdr, SMB2_HDR_CREDIT);
+ uint32_t new_credits;
+ struct smbXcli_session *session = NULL;
+ struct smb2_signing_key *signing_key = NULL;
+ bool was_encrypted = false;
+
+ new_credits = conn->smb2.cur_credits;
+ new_credits += credits;
+ if (new_credits > UINT16_MAX) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ conn->smb2.cur_credits += credits;
+
+ req = smb2cli_conn_find_pending(conn, mid);
+ if (req == NULL) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ state = tevent_req_data(req, struct smbXcli_req_state);
+
+ req_opcode = SVAL(state->smb2.hdr, SMB2_HDR_OPCODE);
+ if (opcode != req_opcode) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ req_flags = SVAL(state->smb2.hdr, SMB2_HDR_FLAGS);
+
+ if (!(flags & SMB2_HDR_FLAG_REDIRECT)) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ status = NT_STATUS(IVAL(inhdr, SMB2_HDR_STATUS));
+ if ((flags & SMB2_HDR_FLAG_ASYNC) &&
+ NT_STATUS_EQUAL(status, NT_STATUS_PENDING)) {
+ uint64_t async_id = BVAL(inhdr, SMB2_HDR_ASYNC_ID);
+
+ if (state->smb2.got_async) {
+ /* We only expect one STATUS_PENDING response */
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ state->smb2.got_async = true;
+
+ /*
+ * async interim responses are not signed,
+ * even if the SMB2_HDR_FLAG_SIGNED flag
+ * is set.
+ */
+ state->smb2.cancel_flags |= SMB2_HDR_FLAG_ASYNC;
+ state->smb2.cancel_aid = async_id;
+
+ if (state->smb2.notify_async) {
+ tevent_req_defer_callback(req, state->ev);
+ tevent_req_notify_callback(req);
+ }
+ continue;
+ }
+
+ session = state->session;
+ if (req_flags & SMB2_HDR_FLAG_CHAINED) {
+ session = last_session;
+ }
+ last_session = session;
+
+ if (flags & SMB2_HDR_FLAG_SIGNED) {
+ uint64_t uid = BVAL(inhdr, SMB2_HDR_SESSION_ID);
+
+ if (session == NULL) {
+ session = smbXcli_session_by_uid(state->conn,
+ uid);
+ }
+
+ if (session == NULL) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ last_session = session;
+ signing_key = session->smb2_channel.signing_key;
+ }
+
+ if (opcode == SMB2_OP_SESSSETUP) {
+ /*
+ * We prefer the channel signing key, if it is
+ * already there.
+ *
+ * If we do not have a channel signing key yet,
+ * we try the main signing key, if it is not
+ * the final response.
+ */
+ if (signing_key != NULL &&
+ !smb2_signing_key_valid(signing_key) &&
+ !NT_STATUS_IS_OK(status)) {
+ signing_key = session->smb2->signing_key;
+ }
+
+ if (signing_key != NULL &&
+ !smb2_signing_key_valid(signing_key)) {
+ /*
+ * If we do not have a session key to
+ * verify the signature, we defer the
+ * signing check to the caller.
+ *
+ * The caller gets NT_STATUS_OK, it
+ * has to call
+ * smb2cli_session_set_session_key()
+ * or
+ * smb2cli_session_set_channel_key()
+ * which will check the signature
+ * with the channel signing key.
+ */
+ signing_key = NULL;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * Only check the signature of the last response
+ * of a successful session auth. This matches
+ * Windows behaviour for NTLM auth and reauth.
+ */
+ state->smb2.require_signed_response = false;
+ }
+ }
+
+ if (state->smb2.should_sign ||
+ state->smb2.require_signed_response)
+ {
+ if (!(flags & SMB2_HDR_FLAG_SIGNED)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (!smb2_signing_key_valid(signing_key) &&
+ state->smb2.require_signed_response) {
+ signing_key = session->smb2_channel.signing_key;
+ }
+
+ if (cur[0].iov_len == SMB2_TF_HDR_SIZE) {
+ const uint8_t *tf = (const uint8_t *)cur[0].iov_base;
+ uint64_t uid = BVAL(tf, SMB2_TF_SESSION_ID);
+
+ /*
+ * If the response was encrypted in a SMB2_TRANSFORM
+ * pdu, which belongs to the correct session,
+ * we do not need to do signing checks
+ *
+ * It could be the session the response belongs to
+ * or the session that was used to encrypt the
+ * SMB2_TRANSFORM request.
+ */
+ if ((session && session->smb2->session_id == uid) ||
+ (state->smb2.encryption_session_id == uid)) {
+ signing_key = NULL;
+ was_encrypted = true;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
+ /*
+ * if the server returns NT_STATUS_USER_SESSION_DELETED
+ * the response is not signed and we should
+ * propagate the NT_STATUS_USER_SESSION_DELETED
+ * status to the caller.
+ */
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_REQUEST_OUT_OF_SEQUENCE)) {
+ /*
+ * if the server returns
+ * NT_STATUS_REQUEST_OUT_OF_SEQUENCE for a session setup
+ * request, the response is not signed and we should
+ * propagate the NT_STATUS_REQUEST_OUT_OF_SEQUENCE
+ * status to the caller
+ */
+ if (opcode == SMB2_OP_SESSSETUP) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ /*
+ * if the server returns NT_STATUS_NOT_SUPPORTED
+ * for a session setup request, the response is not
+ * signed and we should propagate the NT_STATUS_NOT_SUPPORTED
+ * status to the caller.
+ */
+ if (opcode == SMB2_OP_SESSSETUP) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ /*
+ * if the server returns
+ * NT_STATUS_ACCESS_DENIED for a session setup
+ * request, the response is not signed and we should
+ * propagate the NT_STATUS_ACCESS_DENIED
+ * status to the caller without disconnecting
+ * the connection because we where not able to
+ * verify the response signature.
+ */
+ if (opcode == SMB2_OP_SESSSETUP) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /*
+ * if the server returns
+ * NT_STATUS_INVALID_PARAMETER
+ * the response might not be encrypted.
+ */
+ if (state->smb2.should_encrypt && !was_encrypted) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+
+ if (state->smb2.should_encrypt && !was_encrypted) {
+ if (!state->smb2.signing_skipped) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /*
+ * if the server returns
+ * NT_STATUS_NETWORK_NAME_DELETED
+ * NT_STATUS_FILE_CLOSED
+ * NT_STATUS_INVALID_PARAMETER
+ * the response might not be signed
+ * as this happens before the signing checks.
+ *
+ * If server echos the signature (or all zeros)
+ * we should report the status from the server
+ * to the caller.
+ */
+ if (signing_key) {
+ bool cmp;
+
+ cmp = mem_equal_const_time(inhdr+SMB2_HDR_SIGNATURE,
+ state->smb2.hdr+SMB2_HDR_SIGNATURE,
+ 16);
+ if (cmp) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+ if (signing_key) {
+ bool zero;
+ zero = all_zero(inhdr+SMB2_HDR_SIGNATURE, 16);
+ if (zero) {
+ state->smb2.signing_skipped = true;
+ signing_key = NULL;
+ }
+ }
+ }
+
+ if (signing_key) {
+ NTSTATUS signing_status;
+
+ signing_status = smb2_signing_check_pdu(signing_key,
+ &cur[1], 3);
+ if (!NT_STATUS_IS_OK(signing_status)) {
+ /*
+ * If the signing check fails, we disconnect
+ * the connection.
+ */
+ return signing_status;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED) &&
+ (session != NULL) && session->disconnect_expired)
+ {
+ /*
+ * this should be a short term hack
+ * until the upper layers have implemented
+ * re-authentication.
+ */
+ return status;
+ }
+
+ smbXcli_req_unset_pending(req);
+
+ /*
+ * There might be more than one response
+ * we need to defer the notifications
+ */
+ if ((num_iov == 5) && (talloc_array_length(conn->pending) == 0)) {
+ defer = false;
+ }
+
+ if (defer) {
+ tevent_req_defer_callback(req, state->ev);
+ }
+
+ /*
+ * Note: here we use talloc_reference() in a way
+ * that does not expose it to the caller.
+ */
+ inbuf_ref = talloc_reference(state->smb2.recv_iov, inbuf);
+ if (tevent_req_nomem(inbuf_ref, req)) {
+ continue;
+ }
+
+ /* copy the related buffers */
+ state->smb2.recv_iov[0] = cur[1];
+ state->smb2.recv_iov[1] = cur[2];
+ state->smb2.recv_iov[2] = cur[3];
+
+ tevent_req_done(req);
+ }
+
+ if (defer) {
+ return NT_STATUS_RETRY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ const struct smb2cli_req_expected_response *expected,
+ size_t num_expected)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+ NTSTATUS status;
+ size_t body_size;
+ bool found_status = false;
+ bool found_size = false;
+ size_t i;
+
+ if (piov != NULL) {
+ *piov = NULL;
+ }
+
+ if (tevent_req_is_in_progress(req) && state->smb2.got_async) {
+ return NT_STATUS_PENDING;
+ }
+
+ if (tevent_req_is_nterror(req, &status)) {
+ for (i=0; i < num_expected; i++) {
+ if (NT_STATUS_EQUAL(status, expected[i].status)) {
+ return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ }
+ }
+
+ return status;
+ }
+
+ if (num_expected == 0) {
+ found_status = true;
+ found_size = true;
+ }
+
+ status = NT_STATUS(IVAL(state->smb2.recv_iov[0].iov_base, SMB2_HDR_STATUS));
+ body_size = SVAL(state->smb2.recv_iov[1].iov_base, 0);
+
+ for (i=0; i < num_expected; i++) {
+ if (!NT_STATUS_EQUAL(status, expected[i].status)) {
+ continue;
+ }
+
+ found_status = true;
+ if (expected[i].body_size == 0) {
+ found_size = true;
+ break;
+ }
+
+ if (expected[i].body_size == body_size) {
+ found_size = true;
+ break;
+ }
+ }
+
+ if (!found_status) {
+ return status;
+ }
+
+ if (state->smb2.signing_skipped) {
+ if (num_expected > 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ if (!NT_STATUS_IS_ERR(status)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ if (!found_size) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (piov != NULL) {
+ *piov = talloc_move(mem_ctx, &state->smb2.recv_iov);
+ }
+
+ return status;
+}
+
+NTSTATUS smb2cli_req_get_sent_iov(struct tevent_req *req,
+ struct iovec *sent_iov)
+{
+ struct smbXcli_req_state *state =
+ tevent_req_data(req,
+ struct smbXcli_req_state);
+
+ if (tevent_req_is_in_progress(req)) {
+ return NT_STATUS_PENDING;
+ }
+
+ sent_iov[0].iov_base = state->smb2.hdr;
+ sent_iov[0].iov_len = sizeof(state->smb2.hdr);
+
+ sent_iov[1].iov_base = discard_const(state->smb2.fixed);
+ sent_iov[1].iov_len = state->smb2.fixed_len;
+
+ if (state->smb2.dyn != NULL) {
+ sent_iov[2].iov_base = discard_const(state->smb2.dyn);
+ sent_iov[2].iov_len = state->smb2.dyn_len;
+ } else {
+ sent_iov[2].iov_base = NULL;
+ sent_iov[2].iov_len = 0;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static const struct {
+ enum protocol_types proto;
+ const char *smb1_name;
+} smb1cli_prots[] = {
+ {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
+ {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
+ {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
+ {PROTOCOL_LANMAN1, "LANMAN1.0"},
+ {PROTOCOL_LANMAN2, "LM1.2X002"},
+ {PROTOCOL_LANMAN2, "DOS LANMAN2.1"},
+ {PROTOCOL_LANMAN2, "LANMAN2.1"},
+ {PROTOCOL_LANMAN2, "Samba"},
+ {PROTOCOL_NT1, "NT LANMAN 1.0"},
+ {PROTOCOL_NT1, "NT LM 0.12"},
+ {PROTOCOL_SMB2_02, "SMB 2.002"},
+ {PROTOCOL_SMB2_10, "SMB 2.???"},
+};
+
+static const struct {
+ enum protocol_types proto;
+ uint16_t smb2_dialect;
+} smb2cli_prots[] = {
+ {PROTOCOL_SMB2_02, SMB2_DIALECT_REVISION_202},
+ {PROTOCOL_SMB2_10, SMB2_DIALECT_REVISION_210},
+ {PROTOCOL_SMB3_00, SMB3_DIALECT_REVISION_300},
+ {PROTOCOL_SMB3_02, SMB3_DIALECT_REVISION_302},
+ {PROTOCOL_SMB3_11, SMB3_DIALECT_REVISION_311},
+};
+
+struct smbXcli_negprot_state {
+ struct smbXcli_conn *conn;
+ struct tevent_context *ev;
+ struct smb2_negotiate_contexts *in_ctx;
+ struct smb2_negotiate_contexts *out_ctx;
+ uint32_t timeout_msec;
+
+ struct {
+ uint8_t fixed[36];
+ } smb2;
+};
+
+static void smbXcli_negprot_invalid_done(struct tevent_req *subreq);
+static struct tevent_req *smbXcli_negprot_smb1_subreq(struct smbXcli_negprot_state *state);
+static void smbXcli_negprot_smb1_done(struct tevent_req *subreq);
+static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_state *state);
+static void smbXcli_negprot_smb2_done(struct tevent_req *subreq);
+static NTSTATUS smbXcli_negprot_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *frame,
+ uint8_t *inbuf);
+
+struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ enum protocol_types min_protocol,
+ enum protocol_types max_protocol,
+ uint16_t max_credits,
+ struct smb2_negotiate_contexts *in_ctx)
+{
+ struct tevent_req *req, *subreq;
+ struct smbXcli_negprot_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbXcli_negprot_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->conn = conn;
+ state->ev = ev;
+ state->in_ctx = in_ctx;
+ state->timeout_msec = timeout_msec;
+
+ if (min_protocol == PROTOCOL_NONE) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (max_protocol == PROTOCOL_NONE) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ if (min_protocol > max_protocol) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
+ return tevent_req_post(req, ev);
+ }
+
+ conn->min_protocol = min_protocol;
+ conn->max_protocol = max_protocol;
+ conn->protocol = PROTOCOL_NONE;
+
+ if (max_protocol >= PROTOCOL_SMB2_02) {
+ conn->smb2.max_credits = max_credits;
+ }
+
+ if ((min_protocol < PROTOCOL_SMB2_02) &&
+ (max_protocol < PROTOCOL_SMB2_02)) {
+ /*
+ * SMB1 only...
+ */
+ conn->dispatch_incoming = smb1cli_conn_dispatch_incoming;
+
+ subreq = smbXcli_negprot_smb1_subreq(state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb1_done, req);
+ return req;
+ }
+
+ if ((min_protocol >= PROTOCOL_SMB2_02) &&
+ (max_protocol >= PROTOCOL_SMB2_02)) {
+ /*
+ * SMB2 only...
+ */
+ conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
+
+ subreq = smbXcli_negprot_smb2_subreq(state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req);
+ return req;
+ }
+
+ /*
+ * We send an SMB1 negprot with the SMB2 dialects
+ * and expect a SMB1 or a SMB2 response.
+ *
+ * smbXcli_negprot_dispatch_incoming() will fix the
+ * callback to match protocol of the response.
+ */
+ conn->dispatch_incoming = smbXcli_negprot_dispatch_incoming;
+
+ subreq = smbXcli_negprot_smb1_subreq(state);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smbXcli_negprot_invalid_done, req);
+ return req;
+}
+
+static void smbXcli_negprot_invalid_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ NTSTATUS status;
+
+ /*
+ * we just want the low level error
+ */
+ status = tevent_req_simple_recv_ntstatus(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ /* this should never happen */
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+}
+
+static struct tevent_req *smbXcli_negprot_smb1_subreq(struct smbXcli_negprot_state *state)
+{
+ size_t i;
+ DATA_BLOB bytes = data_blob_null;
+ uint8_t flags;
+ uint16_t flags2;
+
+ /* setup the protocol strings */
+ for (i=0; i < ARRAY_SIZE(smb1cli_prots); i++) {
+ uint8_t c = 2;
+ bool ok;
+
+ if (smb1cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb1cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ ok = data_blob_append(state, &bytes, &c, sizeof(c));
+ if (!ok) {
+ return NULL;
+ }
+
+ /*
+ * We know it is already ascii and
+ * we want NULL termination.
+ */
+ ok = data_blob_append(state, &bytes,
+ smb1cli_prots[i].smb1_name,
+ strlen(smb1cli_prots[i].smb1_name)+1);
+ if (!ok) {
+ return NULL;
+ }
+ }
+
+ smb1cli_req_flags(state->conn->max_protocol,
+ state->conn->smb1.client.capabilities,
+ SMBnegprot,
+ 0, 0, &flags,
+ 0, 0, &flags2);
+
+ return smb1cli_req_send(state, state->ev, state->conn,
+ SMBnegprot,
+ flags, ~flags,
+ flags2, ~flags2,
+ state->timeout_msec,
+ 0xFFFE, 0, NULL, /* pid, tid, session */
+ 0, NULL, /* wct, vwv */
+ bytes.length, bytes.data);
+}
+
+static void smbXcli_negprot_smb1_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbXcli_negprot_state *state =
+ tevent_req_data(req,
+ struct smbXcli_negprot_state);
+ struct smbXcli_conn *conn = state->conn;
+ struct iovec *recv_iov = NULL;
+ uint8_t *inhdr = NULL;
+ uint8_t wct;
+ uint16_t *vwv;
+ uint32_t num_bytes;
+ uint8_t *bytes;
+ NTSTATUS status;
+ uint16_t protnum;
+ size_t i;
+ size_t num_prots = 0;
+ uint8_t flags;
+ uint32_t client_capabilities = conn->smb1.client.capabilities;
+ uint32_t both_capabilities;
+ uint32_t server_capabilities = 0;
+ uint32_t capabilities;
+ uint32_t client_max_xmit = conn->smb1.client.max_xmit;
+ uint32_t server_max_xmit = 0;
+ uint32_t max_xmit;
+ uint32_t server_max_mux = 0;
+ uint16_t server_security_mode = 0;
+ uint32_t server_session_key = 0;
+ bool server_readbraw = false;
+ bool server_writebraw = false;
+ bool server_lockread = false;
+ bool server_writeunlock = false;
+ struct GUID server_guid = GUID_zero();
+ DATA_BLOB server_gss_blob = data_blob_null;
+ uint8_t server_challenge[8];
+ char *server_workgroup = NULL;
+ char *server_name = NULL;
+ int server_time_zone = 0;
+ NTTIME server_system_time = 0;
+ static const struct smb1cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x11, /* NT1 */
+ },
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x0D, /* LM */
+ },
+ {
+ .status = NT_STATUS_OK,
+ .wct = 0x01, /* CORE */
+ }
+ };
+
+ ZERO_STRUCT(server_challenge);
+
+ status = smb1cli_req_recv(subreq, state,
+ &recv_iov,
+ &inhdr,
+ &wct,
+ &vwv,
+ NULL, /* pvwv_offset */
+ &num_bytes,
+ &bytes,
+ NULL, /* pbytes_offset */
+ NULL, /* pinbuf */
+ expected, ARRAY_SIZE(expected));
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ if (inhdr == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ flags = CVAL(inhdr, HDR_FLG);
+
+ protnum = SVAL(vwv, 0);
+
+ for (i=0; i < ARRAY_SIZE(smb1cli_prots); i++) {
+ if (smb1cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb1cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ if (protnum != num_prots) {
+ num_prots++;
+ continue;
+ }
+
+ conn->protocol = smb1cli_prots[i].proto;
+ break;
+ }
+
+ if (conn->protocol == PROTOCOL_NONE) {
+ DBG_ERR("No compatible protocol selected by server.\n");
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if ((conn->protocol < PROTOCOL_NT1) && conn->mandatory_signing) {
+ DEBUG(0,("smbXcli_negprot: SMB signing is mandatory "
+ "and the selected protocol level doesn't support it.\n"));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ if (flags & FLAG_SUPPORT_LOCKREAD) {
+ server_lockread = true;
+ server_writeunlock = true;
+ }
+
+ if (conn->protocol >= PROTOCOL_NT1) {
+ const char *client_signing = NULL;
+ bool server_mandatory = false;
+ bool server_allowed = false;
+ const char *server_signing = NULL;
+ bool ok;
+ uint8_t key_len;
+
+ if (wct != 0x11) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ /* NT protocol */
+ server_security_mode = CVAL(vwv + 1, 0);
+ server_max_mux = SVAL(vwv + 1, 1);
+ server_max_xmit = IVAL(vwv + 3, 1);
+ server_session_key = IVAL(vwv + 7, 1);
+ server_time_zone = SVALS(vwv + 15, 1);
+ server_time_zone *= 60;
+ /* this time arrives in real GMT */
+ server_system_time = BVAL(vwv + 11, 1);
+ server_capabilities = IVAL(vwv + 9, 1);
+
+ key_len = CVAL(vwv + 16, 1);
+
+ if (server_capabilities & CAP_RAW_MODE) {
+ server_readbraw = true;
+ server_writebraw = true;
+ }
+ if (server_capabilities & CAP_LOCK_AND_READ) {
+ server_lockread = true;
+ }
+
+ if (server_capabilities & CAP_EXTENDED_SECURITY) {
+ DATA_BLOB blob1, blob2;
+
+ if (num_bytes < 16) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ blob1 = data_blob_const(bytes, 16);
+ status = GUID_from_data_blob(&blob1, &server_guid);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ blob1 = data_blob_const(bytes+16, num_bytes-16);
+ blob2 = data_blob_dup_talloc(state, blob1);
+ if (blob1.length > 0 &&
+ tevent_req_nomem(blob2.data, req)) {
+ return;
+ }
+ server_gss_blob = blob2;
+ } else {
+ DATA_BLOB blob1, blob2;
+
+ if (num_bytes < key_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (key_len != 0 && key_len != 8) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (key_len == 8) {
+ memcpy(server_challenge, bytes, 8);
+ }
+
+ blob1 = data_blob_const(bytes+key_len, num_bytes-key_len);
+ blob2 = data_blob_const(bytes+key_len, num_bytes-key_len);
+ if (blob1.length > 0) {
+ size_t len;
+
+ len = utf16_null_terminated_len_n(blob1.data,
+ blob1.length);
+ blob1.length = len;
+
+ ok = convert_string_talloc(state,
+ CH_UTF16LE,
+ CH_UNIX,
+ blob1.data,
+ blob1.length,
+ &server_workgroup,
+ &len);
+ if (!ok) {
+ status = map_nt_error_from_unix_common(errno);
+ tevent_req_nterror(req, status);
+ return;
+ }
+ }
+
+ blob2.data += blob1.length;
+ blob2.length -= blob1.length;
+ if (blob2.length > 0) {
+ size_t len;
+
+ ok = convert_string_talloc(state,
+ CH_UTF16LE,
+ CH_UNIX,
+ blob2.data,
+ blob2.length,
+ &server_name,
+ &len);
+ if (!ok) {
+ status = map_nt_error_from_unix_common(errno);
+ tevent_req_nterror(req, status);
+ return;
+ }
+ }
+ }
+
+ client_signing = "disabled";
+ if (conn->allow_signing) {
+ client_signing = "allowed";
+ }
+ if (conn->mandatory_signing) {
+ client_signing = "required";
+ }
+
+ server_signing = "not supported";
+ if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
+ server_signing = "supported";
+ server_allowed = true;
+ } else if (conn->mandatory_signing) {
+ /*
+ * We have mandatory signing as client
+ * lets assume the server will look at our
+ * FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED
+ * flag in the session setup
+ */
+ server_signing = "not announced";
+ server_allowed = true;
+ }
+ if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
+ server_signing = "required";
+ server_mandatory = true;
+ }
+
+ ok = smb1_signing_set_negotiated(conn->smb1.signing,
+ server_allowed,
+ server_mandatory);
+ if (!ok) {
+ DEBUG(1,("cli_negprot: SMB signing is required, "
+ "but client[%s] and server[%s] mismatch\n",
+ client_signing, server_signing));
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ } else if (conn->protocol >= PROTOCOL_LANMAN1) {
+ DATA_BLOB blob1;
+ uint8_t key_len;
+ time_t t;
+
+ if (wct != 0x0D) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ server_security_mode = SVAL(vwv + 1, 0);
+ server_max_xmit = SVAL(vwv + 2, 0);
+ server_max_mux = SVAL(vwv + 3, 0);
+ server_readbraw = ((SVAL(vwv + 5, 0) & 0x1) != 0);
+ server_writebraw = ((SVAL(vwv + 5, 0) & 0x2) != 0);
+ server_session_key = IVAL(vwv + 6, 0);
+ server_time_zone = SVALS(vwv + 10, 0);
+ server_time_zone *= 60;
+ /* this time is converted to GMT by make_unix_date */
+ t = pull_dos_date((const uint8_t *)(vwv + 8), server_time_zone);
+ unix_to_nt_time(&server_system_time, t);
+ key_len = SVAL(vwv + 11, 0);
+
+ if (num_bytes < key_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (key_len != 0 && key_len != 8) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (key_len == 8) {
+ memcpy(server_challenge, bytes, 8);
+ }
+
+ blob1 = data_blob_const(bytes+key_len, num_bytes-key_len);
+ if (blob1.length > 0) {
+ size_t len;
+ bool ok;
+
+ len = utf16_null_terminated_len_n(blob1.data,
+ blob1.length);
+ blob1.length = len;
+
+ ok = convert_string_talloc(state,
+ CH_DOS,
+ CH_UNIX,
+ blob1.data,
+ blob1.length,
+ &server_workgroup,
+ &len);
+ if (!ok) {
+ status = map_nt_error_from_unix_common(errno);
+ tevent_req_nterror(req, status);
+ return;
+ }
+ }
+
+ } else {
+ /* the old core protocol */
+ server_time_zone = get_time_zone(time(NULL));
+ server_max_xmit = 1024;
+ server_max_mux = 1;
+ }
+
+ if (server_max_xmit < 1024) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (server_max_mux < 1) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ /*
+ * Now calculate the negotiated capabilities
+ * based on the mask for:
+ * - client only flags
+ * - flags used in both directions
+ * - server only flags
+ */
+ both_capabilities = client_capabilities & server_capabilities;
+ capabilities = client_capabilities & SMB_CAP_CLIENT_MASK;
+ capabilities |= both_capabilities & SMB_CAP_BOTH_MASK;
+ capabilities |= server_capabilities & SMB_CAP_SERVER_MASK;
+
+ max_xmit = MIN(client_max_xmit, server_max_xmit);
+
+ conn->smb1.server.capabilities = server_capabilities;
+ conn->smb1.capabilities = capabilities;
+
+ conn->smb1.server.max_xmit = server_max_xmit;
+ conn->smb1.max_xmit = max_xmit;
+
+ conn->smb1.server.max_mux = server_max_mux;
+
+ conn->smb1.server.security_mode = server_security_mode;
+
+ conn->smb1.server.readbraw = server_readbraw;
+ conn->smb1.server.writebraw = server_writebraw;
+ conn->smb1.server.lockread = server_lockread;
+ conn->smb1.server.writeunlock = server_writeunlock;
+
+ conn->smb1.server.session_key = server_session_key;
+
+ talloc_steal(conn, server_gss_blob.data);
+ conn->smb1.server.gss_blob = server_gss_blob;
+ conn->smb1.server.guid = server_guid;
+ memcpy(conn->smb1.server.challenge, server_challenge, 8);
+ conn->smb1.server.workgroup = talloc_move(conn, &server_workgroup);
+ conn->smb1.server.name = talloc_move(conn, &server_name);
+
+ conn->smb1.server.time_zone = server_time_zone;
+ conn->smb1.server.system_time = server_system_time;
+
+ tevent_req_done(req);
+}
+
+static size_t smbXcli_padding_helper(uint32_t offset, size_t n)
+{
+ if ((offset & (n-1)) == 0) return 0;
+ return n - (offset & (n-1));
+}
+
+static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_state *state)
+{
+ size_t i;
+ uint8_t *buf;
+ uint16_t dialect_count = 0;
+ DATA_BLOB dyn = data_blob_null;
+
+ for (i=0; i < ARRAY_SIZE(smb2cli_prots); i++) {
+ bool ok;
+ uint8_t val[2];
+
+ if (smb2cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ SSVAL(val, 0, smb2cli_prots[i].smb2_dialect);
+
+ ok = data_blob_append(state, &dyn, val, sizeof(val));
+ if (!ok) {
+ return NULL;
+ }
+
+ dialect_count++;
+ }
+
+ buf = state->smb2.fixed;
+ SSVAL(buf, 0, 36);
+ SSVAL(buf, 2, dialect_count);
+ SSVAL(buf, 4, state->conn->smb2.client.security_mode);
+ SSVAL(buf, 6, 0); /* Reserved */
+ if (state->conn->max_protocol >= PROTOCOL_SMB3_00) {
+ SIVAL(buf, 8, state->conn->smb2.client.capabilities);
+ } else {
+ SIVAL(buf, 8, 0); /* Capabilities */
+ }
+ if (state->conn->max_protocol >= PROTOCOL_SMB2_10) {
+ NTSTATUS status;
+ struct GUID_ndr_buf guid_buf = { .buf = {0}, };
+
+ status = GUID_to_ndr_buf(&state->conn->smb2.client.guid,
+ &guid_buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ memcpy(buf+12, guid_buf.buf, 16); /* ClientGuid */
+ } else {
+ memset(buf+12, 0, 16); /* ClientGuid */
+ }
+
+ if (state->conn->max_protocol >= PROTOCOL_SMB3_11) {
+ const struct smb3_signing_capabilities *client_sign_algos =
+ &state->conn->smb2.client.smb3_capabilities.signing;
+ const struct smb3_encryption_capabilities *client_ciphers =
+ &state->conn->smb2.client.smb3_capabilities.encryption;
+ NTSTATUS status;
+ struct smb2_negotiate_contexts c = { .num_contexts = 0, };
+ uint8_t *netname_utf16 = NULL;
+ size_t netname_utf16_len = 0;
+ uint32_t offset;
+ DATA_BLOB b;
+ uint8_t p[38];
+ const uint8_t zeros[8] = {0, };
+ size_t pad;
+ bool ok;
+
+ SSVAL(p, 0, 1); /* HashAlgorithmCount */
+ SSVAL(p, 2, 32); /* SaltLength */
+ SSVAL(p, 4, SMB2_PREAUTH_INTEGRITY_SHA512);
+ generate_random_buffer(p + 6, 32);
+
+ status = smb2_negotiate_context_add(
+ state, &c, SMB2_PREAUTH_INTEGRITY_CAPABILITIES, p, 38);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ if (client_ciphers->num_algos > 0) {
+ size_t ofs = 0;
+ SSVAL(p, ofs, client_ciphers->num_algos);
+ ofs += 2;
+
+ for (i = 0; i < client_ciphers->num_algos; i++) {
+ size_t next_ofs = ofs + 2;
+ SMB_ASSERT(next_ofs < ARRAY_SIZE(p));
+ SSVAL(p, ofs, client_ciphers->algos[i]);
+ ofs = next_ofs;
+ }
+
+ status = smb2_negotiate_context_add(
+ state, &c, SMB2_ENCRYPTION_CAPABILITIES, p, ofs);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+
+ if (client_sign_algos->num_algos > 0) {
+ size_t ofs = 0;
+ SSVAL(p, ofs, client_sign_algos->num_algos);
+ ofs += 2;
+
+ for (i = 0; i < client_sign_algos->num_algos; i++) {
+ size_t next_ofs = ofs + 2;
+ SMB_ASSERT(next_ofs < ARRAY_SIZE(p));
+ SSVAL(p, ofs, client_sign_algos->algos[i]);
+ ofs = next_ofs;
+ }
+
+ status = smb2_negotiate_context_add(
+ state, &c, SMB2_SIGNING_CAPABILITIES, p, ofs);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+
+ ok = convert_string_talloc(state, CH_UNIX, CH_UTF16,
+ state->conn->remote_name,
+ strlen(state->conn->remote_name),
+ &netname_utf16, &netname_utf16_len);
+ if (!ok) {
+ return NULL;
+ }
+
+ status = smb2_negotiate_context_add(state, &c,
+ SMB2_NETNAME_NEGOTIATE_CONTEXT_ID,
+ netname_utf16, netname_utf16_len);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ if (state->in_ctx != NULL) {
+ struct smb2_negotiate_contexts *ctxs = state->in_ctx;
+
+ for (i=0; i<ctxs->num_contexts; i++) {
+ struct smb2_negotiate_context *ctx =
+ &ctxs->contexts[i];
+
+ status = smb2_negotiate_context_add(
+ state,
+ &c,
+ ctx->type,
+ ctx->data.data,
+ ctx->data.length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+ }
+
+ status = smb2_negotiate_context_push(state, &b, c);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ offset = SMB2_HDR_BODY + sizeof(state->smb2.fixed) + dyn.length;
+ pad = smbXcli_padding_helper(offset, 8);
+
+ ok = data_blob_append(state, &dyn, zeros, pad);
+ if (!ok) {
+ return NULL;
+ }
+ offset += pad;
+
+ ok = data_blob_append(state, &dyn, b.data, b.length);
+ if (!ok) {
+ return NULL;
+ }
+
+ SIVAL(buf, 28, offset); /* NegotiateContextOffset */
+ SSVAL(buf, 32, c.num_contexts); /* NegotiateContextCount */
+ SSVAL(buf, 34, 0); /* Reserved */
+ } else {
+ SBVAL(buf, 28, 0); /* Reserved/ClientStartTime */
+ }
+
+ return smb2cli_req_send(state, state->ev,
+ state->conn, SMB2_OP_NEGPROT,
+ 0, 0, /* flags */
+ state->timeout_msec,
+ NULL, NULL, /* tcon, session */
+ state->smb2.fixed, sizeof(state->smb2.fixed),
+ dyn.data, dyn.length,
+ UINT16_MAX); /* max_dyn_len */
+}
+
+static NTSTATUS smbXcli_negprot_smb3_check_capabilities(struct tevent_req *req);
+
+static void smbXcli_negprot_smb2_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smbXcli_negprot_state *state =
+ tevent_req_data(req,
+ struct smbXcli_negprot_state);
+ struct smbXcli_conn *conn = state->conn;
+ size_t security_offset, security_length;
+ DATA_BLOB blob;
+ NTSTATUS status;
+ struct iovec *iov = NULL;
+ uint8_t *body;
+ size_t i;
+ uint16_t dialect_revision;
+ uint32_t negotiate_context_offset = 0;
+ uint16_t negotiate_context_count = 0;
+ DATA_BLOB negotiate_context_blob = data_blob_null;
+ size_t avail;
+ size_t ctx_ofs;
+ size_t needed;
+ struct smb2_negotiate_context *preauth = NULL;
+ uint16_t hash_count;
+ uint16_t salt_length;
+ uint16_t hash_selected;
+ gnutls_hash_hd_t hash_hnd = NULL;
+ struct smb2_negotiate_context *sign_algo = NULL;
+ struct smb2_negotiate_context *cipher = NULL;
+ struct smb2_negotiate_context *posix = NULL;
+ struct iovec sent_iov[3] = {{0}, {0}, {0}};
+ static const struct smb2cli_req_expected_response expected[] = {
+ {
+ .status = NT_STATUS_OK,
+ .body_size = 0x41
+ }
+ };
+ int rc;
+
+ status = smb2cli_req_recv(subreq, state, &iov,
+ expected, ARRAY_SIZE(expected));
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ if (iov == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return;
+ }
+
+ body = (uint8_t *)iov[1].iov_base;
+
+ dialect_revision = SVAL(body, 4);
+
+ for (i=0; i < ARRAY_SIZE(smb2cli_prots); i++) {
+ if (smb2cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].smb2_dialect != dialect_revision) {
+ continue;
+ }
+
+ conn->protocol = smb2cli_prots[i].proto;
+ break;
+ }
+
+ if (conn->protocol == PROTOCOL_NONE) {
+ TALLOC_FREE(subreq);
+
+ if (state->conn->min_protocol >= PROTOCOL_SMB2_02) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (dialect_revision != SMB2_DIALECT_REVISION_2FF) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ /* make sure we do not loop forever */
+ state->conn->min_protocol = PROTOCOL_SMB2_02;
+
+ /*
+ * send a SMB2 negprot, in order to negotiate
+ * the SMB2 dialect.
+ */
+ subreq = smbXcli_negprot_smb2_subreq(state);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req);
+ return;
+ }
+
+ conn->smb2.server.security_mode = SVAL(body, 2);
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ negotiate_context_count = SVAL(body, 6);
+ }
+
+ blob = data_blob_const(body + 8, 16);
+ status = GUID_from_data_blob(&blob, &conn->smb2.server.guid);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ conn->smb2.server.capabilities = IVAL(body, 24);
+ conn->smb2.server.max_trans_size= IVAL(body, 28);
+ conn->smb2.server.max_read_size = IVAL(body, 32);
+ conn->smb2.server.max_write_size= IVAL(body, 36);
+ conn->smb2.server.system_time = BVAL(body, 40);
+ conn->smb2.server.start_time = BVAL(body, 48);
+
+ if (conn->smb2.server.max_trans_size == 0 ||
+ conn->smb2.server.max_read_size == 0 ||
+ conn->smb2.server.max_write_size == 0) {
+ /*
+ * We can't connect to servers we can't
+ * do any operations on.
+ */
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ security_offset = SVAL(body, 56);
+ security_length = SVAL(body, 58);
+
+ if (security_offset == 0) {
+ /*
+ * Azure sends security_offset = 0 and security_length = 0
+ *
+ * We just set security_offset to the expected value
+ * in order to allow the further logic to work
+ * as before.
+ */
+ if (security_length != 0) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ security_offset = SMB2_HDR_BODY + iov[1].iov_len;
+ }
+
+ if (security_offset != SMB2_HDR_BODY + iov[1].iov_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (security_length > iov[2].iov_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ conn->smb2.server.gss_blob = data_blob_talloc(conn,
+ iov[2].iov_base,
+ security_length);
+ if (tevent_req_nomem(conn->smb2.server.gss_blob.data, req)) {
+ return;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_00) {
+ conn->smb2.server.sign_algo = SMB2_SIGNING_AES128_CMAC;
+ } else {
+ conn->smb2.server.sign_algo = SMB2_SIGNING_HMAC_SHA256;
+ }
+
+ if (conn->protocol < PROTOCOL_SMB3_11) {
+ TALLOC_FREE(subreq);
+
+ if (conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION) {
+ conn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM;
+ }
+
+ status = smbXcli_negprot_smb3_check_capabilities(req);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+ }
+
+ /*
+ * Here we are now at SMB3_11, so encryption should be
+ * negotiated via context, not capabilities.
+ */
+
+ if (conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION) {
+ /*
+ * Server set SMB2_CAP_ENCRYPTION capability,
+ * but *SHOULD* not, not *MUST* not. Just mask it off.
+ * NetApp seems to do this:
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13009
+ */
+ conn->smb2.server.capabilities &= ~SMB2_CAP_ENCRYPTION;
+ }
+
+ negotiate_context_offset = IVAL(body, 60);
+ if (negotiate_context_offset < security_offset) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ ctx_ofs = negotiate_context_offset - security_offset;
+ if (ctx_ofs > iov[2].iov_len) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ avail = iov[2].iov_len - security_length;
+ needed = iov[2].iov_len - ctx_ofs;
+ if (needed > avail) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ negotiate_context_blob.data = (uint8_t *)iov[2].iov_base;
+ negotiate_context_blob.length = iov[2].iov_len;
+
+ negotiate_context_blob.data += ctx_ofs;
+ negotiate_context_blob.length -= ctx_ofs;
+
+ state->out_ctx = talloc_zero(state, struct smb2_negotiate_contexts);
+ if (tevent_req_nomem(state->out_ctx, req)) {
+ return;
+ }
+
+ status = smb2_negotiate_context_parse(state->out_ctx,
+ negotiate_context_blob,
+ negotiate_context_count,
+ state->out_ctx);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ status = NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ preauth = smb2_negotiate_context_find(
+ state->out_ctx, SMB2_PREAUTH_INTEGRITY_CAPABILITIES);
+ if (preauth == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (preauth->data.length < 6) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ hash_count = SVAL(preauth->data.data, 0);
+ salt_length = SVAL(preauth->data.data, 2);
+ hash_selected = SVAL(preauth->data.data, 4);
+
+ if (hash_count != 1) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (preauth->data.length != (6 + salt_length)) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (hash_selected != SMB2_PREAUTH_INTEGRITY_SHA512) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ sign_algo = smb2_negotiate_context_find(
+ state->out_ctx, SMB2_SIGNING_CAPABILITIES);
+ if (sign_algo != NULL) {
+ const struct smb3_signing_capabilities *client_sign_algos =
+ &state->conn->smb2.client.smb3_capabilities.signing;
+ bool found_selected = false;
+ uint16_t sign_algo_count;
+ uint16_t sign_algo_selected;
+
+ if (client_sign_algos->num_algos == 0) {
+ /*
+ * We didn't ask for SMB2_ENCRYPTION_CAPABILITIES
+ */
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (sign_algo->data.length < 2) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ sign_algo_count = SVAL(sign_algo->data.data, 0);
+ if (sign_algo_count != 1) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (sign_algo->data.length < (2 + 2 * sign_algo_count)) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ sign_algo_selected = SVAL(sign_algo->data.data, 2);
+
+ for (i = 0; i < client_sign_algos->num_algos; i++) {
+ if (client_sign_algos->algos[i] == sign_algo_selected) {
+ /*
+ * We found a match
+ */
+ found_selected = true;
+ break;
+ }
+ }
+
+ if (!found_selected) {
+ /*
+ * The server send a sign_algo we didn't offer.
+ */
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ conn->smb2.server.sign_algo = sign_algo_selected;
+ }
+
+ cipher = smb2_negotiate_context_find(
+ state->out_ctx, SMB2_ENCRYPTION_CAPABILITIES);
+ if (cipher != NULL) {
+ const struct smb3_encryption_capabilities *client_ciphers =
+ &state->conn->smb2.client.smb3_capabilities.encryption;
+ bool found_selected = false;
+ uint16_t cipher_count;
+ uint16_t cipher_selected;
+
+ if (client_ciphers->num_algos == 0) {
+ /*
+ * We didn't ask for SMB2_ENCRYPTION_CAPABILITIES
+ */
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (cipher->data.length < 2) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ cipher_count = SVAL(cipher->data.data, 0);
+ if (cipher_count != 1) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ if (cipher->data.length < (2 + 2 * cipher_count)) {
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+ cipher_selected = SVAL(cipher->data.data, 2);
+
+ for (i = 0; i < client_ciphers->num_algos; i++) {
+ if (cipher_selected == SMB2_ENCRYPTION_NONE) {
+ /*
+ * encryption not supported
+ */
+ found_selected = true;
+ break;
+ }
+ if (client_ciphers->algos[i] == cipher_selected) {
+ /*
+ * We found a match
+ */
+ found_selected = true;
+ break;
+ }
+ }
+
+ if (!found_selected) {
+ /*
+ * The server send a cipher we didn't offer.
+ */
+ tevent_req_nterror(req,
+ NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ conn->smb2.server.cipher = cipher_selected;
+ }
+
+ posix = smb2_negotiate_context_find(
+ state->out_ctx, SMB2_POSIX_EXTENSIONS_AVAILABLE);
+ if (posix != NULL) {
+ DATA_BLOB posix_blob = data_blob_const(
+ SMB2_CREATE_TAG_POSIX, strlen(SMB2_CREATE_TAG_POSIX));
+ int cmp = data_blob_cmp(&posix->data, &posix_blob);
+
+ conn->smb2.server.smb311_posix = (cmp == 0);
+ }
+
+
+ /* First we hash the request */
+ smb2cli_req_get_sent_iov(subreq, sent_iov);
+
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_SHA512);
+ if (rc < 0) {
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+
+ rc = gnutls_hash(hash_hnd,
+ conn->smb2.preauth_sha512,
+ sizeof(conn->smb2.preauth_sha512));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+ for (i = 0; i < 3; i++) {
+ rc = gnutls_hash(hash_hnd,
+ sent_iov[i].iov_base,
+ sent_iov[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+ }
+
+ /* This resets the hash state */
+ gnutls_hash_output(hash_hnd, conn->smb2.preauth_sha512);
+ TALLOC_FREE(subreq);
+
+ /* And now we hash the response */
+ rc = gnutls_hash(hash_hnd,
+ conn->smb2.preauth_sha512,
+ sizeof(conn->smb2.preauth_sha512));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+ for (i = 0; i < 3; i++) {
+ rc = gnutls_hash(hash_hnd,
+ iov[i].iov_base,
+ iov[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ tevent_req_nterror(req,
+ gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED));
+ return;
+ }
+ }
+ gnutls_hash_deinit(hash_hnd, conn->smb2.preauth_sha512);
+ if (rc < 0) {
+ tevent_req_nterror(req,
+ NT_STATUS_UNSUCCESSFUL);
+ return;
+ }
+
+ status = smbXcli_negprot_smb3_check_capabilities(req);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS smbXcli_negprot_smb3_check_capabilities(struct tevent_req *req)
+{
+ struct smbXcli_negprot_state *state =
+ tevent_req_data(req,
+ struct smbXcli_negprot_state);
+ struct smbXcli_conn *conn = state->conn;
+
+ return smb311_capabilities_check(&conn->smb2.client.smb3_capabilities,
+ "smbXcli_negprot",
+ DBGLVL_ERR,
+ NT_STATUS_ACCESS_DENIED,
+ "client",
+ conn->protocol,
+ conn->smb2.server.sign_algo,
+ conn->smb2.server.cipher);
+}
+
+static NTSTATUS smbXcli_negprot_dispatch_incoming(struct smbXcli_conn *conn,
+ TALLOC_CTX *tmp_mem,
+ uint8_t *inbuf)
+{
+ size_t num_pending = talloc_array_length(conn->pending);
+ struct tevent_req *subreq;
+ struct smbXcli_req_state *substate;
+ struct tevent_req *req;
+ uint32_t protocol_magic;
+ size_t inbuf_len = smb_len_nbt(inbuf);
+
+ if (num_pending != 1) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (inbuf_len < 4) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ subreq = conn->pending[0];
+ substate = tevent_req_data(subreq, struct smbXcli_req_state);
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+
+ protocol_magic = IVAL(inbuf, 4);
+
+ switch (protocol_magic) {
+ case SMB_MAGIC:
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb1_done, req);
+ conn->dispatch_incoming = smb1cli_conn_dispatch_incoming;
+ return smb1cli_conn_dispatch_incoming(conn, tmp_mem, inbuf);
+
+ case SMB2_MAGIC:
+ if (substate->smb2.recv_iov == NULL) {
+ /*
+ * For the SMB1 negprot we have move it.
+ */
+ substate->smb2.recv_iov = substate->smb1.recv_iov;
+ substate->smb1.recv_iov = NULL;
+ }
+
+ /*
+ * we got an SMB2 answer, which consumed sequence number 0
+ * so we need to use 1 as the next one.
+ *
+ * we also need to set the current credits to 0
+ * as we consumed the initial one. The SMB2 answer
+ * hopefully grant us a new credit.
+ */
+ conn->smb2.mid = 1;
+ conn->smb2.cur_credits = 0;
+ tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req);
+ conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
+ return smb2cli_conn_dispatch_incoming(conn, tmp_mem, inbuf);
+ }
+
+ DEBUG(10, ("Got non-SMB PDU\n"));
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+NTSTATUS smbXcli_negprot_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts **out_ctx)
+{
+ struct smbXcli_negprot_state *state = tevent_req_data(
+ req, struct smbXcli_negprot_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ if (out_ctx != NULL) {
+ *out_ctx = talloc_move(mem_ctx, &state->out_ctx);
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smbXcli_negprot(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ enum protocol_types min_protocol,
+ enum protocol_types max_protocol,
+ struct smb2_negotiate_contexts *in_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts **out_ctx)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ bool ok;
+
+ if (smbXcli_conn_has_async_calls(conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER_MIX;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = smbXcli_negprot_send(
+ frame,
+ ev,
+ conn,
+ timeout_msec,
+ min_protocol,
+ max_protocol,
+ WINDOWS_CLIENT_PURE_SMB2_NEGPROT_INITIAL_CREDIT_ASK,
+ in_ctx);
+ if (req == NULL) {
+ goto fail;
+ }
+ ok = tevent_req_poll_ntstatus(req, ev, &status);
+ if (!ok) {
+ goto fail;
+ }
+ status = smbXcli_negprot_recv(req, mem_ctx, out_ctx);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct smb2cli_validate_negotiate_info_state {
+ struct smbXcli_conn *conn;
+ DATA_BLOB in_input_buffer;
+ DATA_BLOB in_output_buffer;
+ DATA_BLOB out_input_buffer;
+ DATA_BLOB out_output_buffer;
+ uint16_t dialect;
+};
+
+static void smb2cli_validate_negotiate_info_done(struct tevent_req *subreq);
+
+struct tevent_req *smb2cli_validate_negotiate_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon)
+{
+ struct tevent_req *req;
+ struct smb2cli_validate_negotiate_info_state *state;
+ uint8_t *buf;
+ uint16_t dialect_count = 0;
+ struct tevent_req *subreq;
+ bool _save_should_sign;
+ size_t i;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smb2cli_validate_negotiate_info_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->conn = conn;
+
+ state->in_input_buffer = data_blob_talloc_zero(state,
+ 4 + 16 + 1 + 1 + 2);
+ if (tevent_req_nomem(state->in_input_buffer.data, req)) {
+ return tevent_req_post(req, ev);
+ }
+ buf = state->in_input_buffer.data;
+
+ if (state->conn->max_protocol >= PROTOCOL_SMB3_00) {
+ SIVAL(buf, 0, conn->smb2.client.capabilities);
+ } else {
+ SIVAL(buf, 0, 0); /* Capabilities */
+ }
+ if (state->conn->max_protocol >= PROTOCOL_SMB2_10) {
+ NTSTATUS status;
+ struct GUID_ndr_buf guid_buf = { .buf = {0}, };
+
+ status = GUID_to_ndr_buf(&conn->smb2.client.guid,
+ &guid_buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ memcpy(buf+4, guid_buf.buf, 16); /* ClientGuid */
+ } else {
+ memset(buf+4, 0, 16); /* ClientGuid */
+ }
+ if (state->conn->min_protocol >= PROTOCOL_SMB2_02) {
+ SCVAL(buf, 20, conn->smb2.client.security_mode);
+ } else {
+ SCVAL(buf, 20, 0);
+ }
+ SCVAL(buf, 21, 0); /* reserved */
+
+ for (i=0; i < ARRAY_SIZE(smb2cli_prots); i++) {
+ bool ok;
+ size_t ofs;
+
+ if (smb2cli_prots[i].proto < state->conn->min_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].proto > state->conn->max_protocol) {
+ continue;
+ }
+
+ if (smb2cli_prots[i].proto == state->conn->protocol) {
+ state->dialect = smb2cli_prots[i].smb2_dialect;
+ }
+
+ ofs = state->in_input_buffer.length;
+ ok = data_blob_realloc(state, &state->in_input_buffer,
+ ofs + 2);
+ if (!ok) {
+ tevent_req_oom(req);
+ return tevent_req_post(req, ev);
+ }
+
+ buf = state->in_input_buffer.data;
+ SSVAL(buf, ofs, smb2cli_prots[i].smb2_dialect);
+
+ dialect_count++;
+ }
+ buf = state->in_input_buffer.data;
+ SSVAL(buf, 22, dialect_count);
+
+ _save_should_sign = smb2cli_tcon_is_signing_on(tcon);
+ smb2cli_tcon_should_sign(tcon, true);
+ subreq = smb2cli_ioctl_send(state, ev, conn,
+ timeout_msec, session, tcon,
+ UINT64_MAX, /* in_fid_persistent */
+ UINT64_MAX, /* in_fid_volatile */
+ FSCTL_VALIDATE_NEGOTIATE_INFO,
+ 0, /* in_max_input_length */
+ &state->in_input_buffer,
+ 24, /* in_max_output_length */
+ &state->in_output_buffer,
+ SMB2_IOCTL_FLAG_IS_FSCTL);
+ smb2cli_tcon_should_sign(tcon, _save_should_sign);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq,
+ smb2cli_validate_negotiate_info_done,
+ req);
+
+ return req;
+}
+
+static void smb2cli_validate_negotiate_info_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct smb2cli_validate_negotiate_info_state *state =
+ tevent_req_data(req,
+ struct smb2cli_validate_negotiate_info_state);
+ NTSTATUS status;
+ const uint8_t *buf;
+ uint32_t capabilities;
+ DATA_BLOB guid_blob;
+ struct GUID server_guid;
+ uint16_t security_mode;
+ uint16_t dialect;
+
+ status = smb2cli_ioctl_recv(subreq, state,
+ &state->out_input_buffer,
+ &state->out_output_buffer);
+ TALLOC_FREE(subreq);
+
+ /*
+ * This response must be signed correctly for
+ * these "normal" error codes to be processed.
+ * If the packet wasn't signed correctly we will get
+ * NT_STATUS_ACCESS_DENIED or NT_STATUS_HMAC_NOT_SUPPORTED,
+ * or NT_STATUS_INVALID_NETWORK_RESPONSE
+ * from smb2_signing_check_pdu().
+ *
+ * We must never ignore the above errors here.
+ */
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * Older Windows and Samba releases return
+ * NT_STATUS_FILE_CLOSED.
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_DEVICE_REQUEST)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * This is returned by the NTVFS based Samba 4.x file server
+ * for file shares.
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_FS_DRIVER_REQUIRED)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * This is returned by the NTVFS based Samba 4.x file server
+ * for ipc shares.
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * This might be returned by older Windows versions or by
+ * NetApp SMB server implementations.
+ *
+ * See
+ *
+ * https://blogs.msdn.microsoft.com/openspecification/2012/06/28/smb3-secure-dialect-negotiation/
+ *
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+ /*
+ * The response was signed, but not supported
+ *
+ * This might be returned by NetApp Ontap 7.3.7 SMB server
+ * implementations.
+ *
+ * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14607
+ *
+ */
+ tevent_req_done(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->out_output_buffer.length != 24) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ buf = state->out_output_buffer.data;
+
+ capabilities = IVAL(buf, 0);
+ guid_blob = data_blob_const(buf + 4, 16);
+ status = GUID_from_data_blob(&guid_blob, &server_guid);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ security_mode = CVAL(buf, 20);
+ dialect = SVAL(buf, 22);
+
+ if (capabilities != state->conn->smb2.server.capabilities) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ if (!GUID_equal(&server_guid, &state->conn->smb2.server.guid)) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ if (security_mode != state->conn->smb2.server.security_mode) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ if (dialect != state->dialect) {
+ tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS smb2cli_validate_negotiate_info_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static int smbXcli_session_destructor(struct smbXcli_session *session)
+{
+ if (session->conn == NULL) {
+ return 0;
+ }
+
+ DLIST_REMOVE(session->conn->sessions, session);
+ return 0;
+}
+
+struct smbXcli_session *smbXcli_session_create(TALLOC_CTX *mem_ctx,
+ struct smbXcli_conn *conn)
+{
+ struct smbXcli_session *session;
+ NTSTATUS status;
+
+ session = talloc_zero(mem_ctx, struct smbXcli_session);
+ if (session == NULL) {
+ return NULL;
+ }
+ session->smb2 = talloc_zero(session, struct smb2cli_session);
+ if (session->smb2 == NULL) {
+ talloc_free(session);
+ return NULL;
+ }
+ talloc_set_destructor(session, smbXcli_session_destructor);
+
+ status = smb2_signing_key_sign_create(session->smb2,
+ conn->smb2.server.sign_algo,
+ NULL, /* no master key */
+ NULL, /* derivations */
+ &session->smb2->signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(session);
+ return NULL;
+ }
+
+ DLIST_ADD_END(conn->sessions, session);
+ session->conn = conn;
+
+ status = smb2_signing_key_sign_create(session,
+ conn->smb2.server.sign_algo,
+ NULL, /* no master key */
+ NULL, /* derivations */
+ &session->smb2_channel.signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(session);
+ return NULL;
+ }
+
+ memcpy(session->smb2_channel.preauth_sha512,
+ conn->smb2.preauth_sha512,
+ sizeof(session->smb2_channel.preauth_sha512));
+
+ return session;
+}
+
+struct smbXcli_session *smbXcli_session_shallow_copy(TALLOC_CTX *mem_ctx,
+ struct smbXcli_session *src)
+{
+ struct smbXcli_session *session;
+ struct timespec ts;
+ NTTIME nt;
+
+ session = talloc_zero(mem_ctx, struct smbXcli_session);
+ if (session == NULL) {
+ return NULL;
+ }
+ session->smb2 = talloc_zero(session, struct smb2cli_session);
+ if (session->smb2 == NULL) {
+ talloc_free(session);
+ return NULL;
+ }
+
+ /*
+ * Note we keep a pointer to the session keys of the
+ * main session and rely on the caller to free the
+ * shallow copy first!
+ */
+ session->conn = src->conn;
+ *session->smb2 = *src->smb2;
+ session->smb2_channel = src->smb2_channel;
+ session->disconnect_expired = src->disconnect_expired;
+
+ /*
+ * This is only supposed to be called in test code
+ * but we should not reuse nonces!
+ *
+ * Add the current timestamp as NTTIME to nonce_high
+ * and set nonce_low to a value we can recognize in captures.
+ */
+ clock_gettime_mono(&ts);
+ nt = unix_timespec_to_nt_time(ts);
+ nt &= session->smb2->nonce_high_max;
+ if (nt == session->smb2->nonce_high_max || nt < UINT8_MAX) {
+ talloc_free(session);
+ return NULL;
+ }
+ session->smb2->nonce_high += nt;
+ session->smb2->nonce_low = UINT32_MAX;
+
+ DLIST_ADD_END(src->conn->sessions, session);
+ talloc_set_destructor(session, smbXcli_session_destructor);
+
+ return session;
+}
+
+bool smbXcli_session_is_guest(struct smbXcli_session *session)
+{
+ if (session == NULL) {
+ return false;
+ }
+
+ if (session->conn == NULL) {
+ return false;
+ }
+
+ if (session->conn->mandatory_signing) {
+ return false;
+ }
+
+ if (session->conn->protocol >= PROTOCOL_SMB2_02) {
+ if (session->smb2->session_flags & SMB2_SESSION_FLAG_IS_GUEST) {
+ return true;
+ }
+ return false;
+ }
+
+ if (session->smb1.action & SMB_SETUP_GUEST) {
+ return true;
+ }
+
+ return false;
+}
+
+bool smbXcli_session_is_authenticated(struct smbXcli_session *session)
+{
+ const DATA_BLOB *application_key;
+
+ if (session == NULL) {
+ return false;
+ }
+
+ if (session->conn == NULL) {
+ return false;
+ }
+
+ /*
+ * If we have an application key we had a session key negotiated
+ * at auth time.
+ */
+ if (session->conn->protocol >= PROTOCOL_SMB2_02) {
+ if (!smb2_signing_key_valid(session->smb2->application_key)) {
+ return false;
+ }
+ application_key = &session->smb2->application_key->blob;
+ } else {
+ application_key = &session->smb1.application_key;
+ }
+
+ if (application_key->length == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+NTSTATUS smb2cli_session_signing_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key)
+{
+ const struct smb2_signing_key *sig = NULL;
+
+ if (session->conn == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ /*
+ * Use channel signing key if there is one, otherwise fallback
+ * to session.
+ */
+
+ if (smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ sig = session->smb2_channel.signing_key;
+ } else if (smb2_signing_key_valid(session->smb2->signing_key)) {
+ sig = session->smb2->signing_key;
+ } else {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ *key = data_blob_dup_talloc(mem_ctx, sig->blob);
+ if (key->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_encryption_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key)
+{
+ if (session->conn == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (session->conn->protocol < PROTOCOL_SMB3_00) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (!smb2_signing_key_valid(session->smb2->encryption_key)) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ *key = data_blob_dup_talloc(mem_ctx, session->smb2->encryption_key->blob);
+ if (key->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_decryption_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key)
+{
+ if (session->conn == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (session->conn->protocol < PROTOCOL_SMB3_00) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (!smb2_signing_key_valid(session->smb2->decryption_key)) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ *key = data_blob_dup_talloc(mem_ctx, session->smb2->decryption_key->blob);
+ if (key->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smbXcli_session_application_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key)
+{
+ const DATA_BLOB *application_key;
+
+ *key = data_blob_null;
+
+ if (session->conn == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (session->conn->protocol >= PROTOCOL_SMB2_02) {
+ if (!smb2_signing_key_valid(session->smb2->application_key)) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+ application_key = &session->smb2->application_key->blob;
+ } else {
+ application_key = &session->smb1.application_key;
+ }
+
+ if (application_key->length == 0) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ *key = data_blob_dup_talloc(mem_ctx, *application_key);
+ if (key->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+void smbXcli_session_set_disconnect_expired(struct smbXcli_session *session)
+{
+ session->disconnect_expired = true;
+}
+
+uint16_t smb1cli_session_current_id(struct smbXcli_session *session)
+{
+ return session->smb1.session_id;
+}
+
+void smb1cli_session_set_id(struct smbXcli_session *session,
+ uint16_t session_id)
+{
+ session->smb1.session_id = session_id;
+}
+
+void smb1cli_session_set_action(struct smbXcli_session *session,
+ uint16_t action)
+{
+ session->smb1.action = action;
+}
+
+NTSTATUS smb1cli_session_set_session_key(struct smbXcli_session *session,
+ const DATA_BLOB _session_key)
+{
+ struct smbXcli_conn *conn = session->conn;
+ uint8_t session_key[16];
+
+ if (conn == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (session->smb1.application_key.length != 0) {
+ /*
+ * TODO: do not allow this...
+ *
+ * return NT_STATUS_INVALID_PARAMETER_MIX;
+ */
+ data_blob_clear_free(&session->smb1.application_key);
+ session->smb1.protected_key = false;
+ }
+
+ if (_session_key.length == 0) {
+ return NT_STATUS_OK;
+ }
+
+ ZERO_STRUCT(session_key);
+ memcpy(session_key, _session_key.data,
+ MIN(_session_key.length, sizeof(session_key)));
+
+ session->smb1.application_key = data_blob_talloc(session,
+ session_key,
+ sizeof(session_key));
+ ZERO_STRUCT(session_key);
+ if (session->smb1.application_key.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ session->smb1.protected_key = false;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb1cli_session_protect_session_key(struct smbXcli_session *session)
+{
+ NTSTATUS status;
+
+ if (session->smb1.protected_key) {
+ /* already protected */
+ return NT_STATUS_OK;
+ }
+
+ if (session->smb1.application_key.length != 16) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ status = smb1_key_derivation(session->smb1.application_key.data,
+ session->smb1.application_key.length,
+ session->smb1.application_key.data);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ session->smb1.protected_key = true;
+
+ return NT_STATUS_OK;
+}
+
+uint8_t smb2cli_session_security_mode(struct smbXcli_session *session)
+{
+ struct smbXcli_conn *conn = session->conn;
+ uint8_t security_mode = 0;
+
+ if (conn == NULL) {
+ return security_mode;
+ }
+
+ security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ if (conn->mandatory_signing) {
+ security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ }
+ if (session->smb2->should_sign) {
+ security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ }
+
+ return security_mode;
+}
+
+uint64_t smb2cli_session_current_id(struct smbXcli_session *session)
+{
+ return session->smb2->session_id;
+}
+
+uint16_t smb2cli_session_get_flags(struct smbXcli_session *session)
+{
+ return session->smb2->session_flags;
+}
+
+void smb2cli_session_set_id_and_flags(struct smbXcli_session *session,
+ uint64_t session_id,
+ uint16_t session_flags)
+{
+ session->smb2->session_id = session_id;
+ session->smb2->session_flags = session_flags;
+}
+
+void smb2cli_session_increment_channel_sequence(struct smbXcli_session *session)
+{
+ session->smb2->channel_sequence += 1;
+}
+
+uint16_t smb2cli_session_reset_channel_sequence(struct smbXcli_session *session,
+ uint16_t channel_sequence)
+{
+ uint16_t prev_cs;
+
+ prev_cs = session->smb2->channel_sequence;
+ session->smb2->channel_sequence = channel_sequence;
+
+ return prev_cs;
+}
+
+uint16_t smb2cli_session_current_channel_sequence(struct smbXcli_session *session)
+{
+ return session->smb2->channel_sequence;
+}
+
+void smb2cli_session_start_replay(struct smbXcli_session *session)
+{
+ session->smb2->replay_active = true;
+}
+
+void smb2cli_session_stop_replay(struct smbXcli_session *session)
+{
+ session->smb2->replay_active = false;
+}
+
+void smb2cli_session_require_signed_response(struct smbXcli_session *session,
+ bool require_signed_response)
+{
+ session->smb2->require_signed_response = require_signed_response;
+}
+
+NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
+ const struct iovec *iov)
+{
+ gnutls_hash_hd_t hash_hnd = NULL;
+ size_t i;
+ int rc;
+
+ if (session->conn == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (session->conn->protocol < PROTOCOL_SMB3_11) {
+ return NT_STATUS_OK;
+ }
+
+ if (smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ return NT_STATUS_OK;
+ }
+
+ rc = gnutls_hash_init(&hash_hnd,
+ GNUTLS_DIG_SHA512);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ rc = gnutls_hash(hash_hnd,
+ session->smb2_channel.preauth_sha512,
+ sizeof(session->smb2_channel.preauth_sha512));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ for (i = 0; i < 3; i++) {
+ rc = gnutls_hash(hash_hnd,
+ iov[i].iov_base,
+ iov[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ }
+ gnutls_hash_deinit(hash_hnd, session->smb2_channel.preauth_sha512);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
+ const DATA_BLOB _session_key,
+ const struct iovec *recv_iov)
+{
+ struct smbXcli_conn *conn = session->conn;
+ uint16_t no_sign_flags = 0;
+ bool check_signature = true;
+ uint32_t hdr_flags;
+ NTSTATUS status;
+ struct smb2_signing_derivations derivations = {
+ .signing = NULL,
+ };
+ DATA_BLOB preauth_hash = data_blob_null;
+ size_t nonce_size = 0;
+
+ if (conn == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (recv_iov[0].iov_len != SMB2_HDR_BODY) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (!conn->mandatory_signing) {
+ /*
+ * only allow guest sessions without
+ * mandatory signing.
+ *
+ * If we try an authentication with username != ""
+ * and the server let us in without verifying the
+ * password we don't have a negotiated session key
+ * for signing.
+ */
+ no_sign_flags = SMB2_SESSION_FLAG_IS_GUEST;
+ }
+
+ if (session->smb2->session_flags & no_sign_flags) {
+ session->smb2->should_sign = false;
+ return NT_STATUS_OK;
+ }
+
+ if (smb2_signing_key_valid(session->smb2->signing_key)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ preauth_hash = data_blob_const(session->smb2_channel.preauth_sha512,
+ sizeof(session->smb2_channel.preauth_sha512));
+ }
+
+ smb2_signing_derivations_fill_const_stack(&derivations,
+ conn->protocol,
+ preauth_hash);
+
+ status = smb2_signing_key_sign_create(session->smb2,
+ conn->smb2.server.sign_algo,
+ &_session_key,
+ derivations.signing,
+ &session->smb2->signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2_signing_key_cipher_create(session->smb2,
+ conn->smb2.server.cipher,
+ &_session_key,
+ derivations.cipher_c2s,
+ &session->smb2->encryption_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2_signing_key_cipher_create(session->smb2,
+ conn->smb2.server.cipher,
+ &_session_key,
+ derivations.cipher_s2c,
+ &session->smb2->decryption_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2_signing_key_sign_create(session->smb2,
+ conn->smb2.server.sign_algo,
+ &_session_key,
+ derivations.application,
+ &session->smb2->application_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = smb2_signing_key_copy(session,
+ session->smb2->signing_key,
+ &session->smb2_channel.signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ check_signature = conn->mandatory_signing;
+
+ hdr_flags = IVAL(recv_iov[0].iov_base, SMB2_HDR_FLAGS);
+ if (hdr_flags & SMB2_HDR_FLAG_SIGNED) {
+ /*
+ * Sadly some vendors don't sign the
+ * final SMB2 session setup response
+ *
+ * At least Windows and Samba are always doing this
+ * if there's a session key available.
+ *
+ * We only check the signature if it's mandatory
+ * or SMB2_HDR_FLAG_SIGNED is provided.
+ */
+ check_signature = true;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ check_signature = true;
+ }
+
+ if (check_signature) {
+ status = smb2_signing_check_pdu(session->smb2_channel.signing_key,
+ recv_iov, 3);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ session->smb2->should_sign = false;
+ session->smb2->should_encrypt = false;
+
+ if (conn->desire_signing) {
+ session->smb2->should_sign = true;
+ }
+
+ if (conn->smb2.server.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+ session->smb2->should_sign = true;
+ }
+
+ if (session->smb2->session_flags & SMB2_SESSION_FLAG_ENCRYPT_DATA) {
+ session->smb2->should_encrypt = true;
+ }
+
+ if (conn->protocol < PROTOCOL_SMB3_00) {
+ session->smb2->should_encrypt = false;
+ }
+
+ if (conn->smb2.server.cipher == 0) {
+ session->smb2->should_encrypt = false;
+ }
+
+ /*
+ * CCM and GCM algorithms must never have their
+ * nonce wrap, or the security of the whole
+ * communication and the keys is destroyed.
+ * We must drop the connection once we have
+ * transferred too much data.
+ *
+ * NOTE: We assume nonces greater than 8 bytes.
+ */
+ generate_nonce_buffer((uint8_t *)&session->smb2->nonce_high_random,
+ sizeof(session->smb2->nonce_high_random));
+ switch (conn->smb2.server.cipher) {
+ case SMB2_ENCRYPTION_AES128_CCM:
+ nonce_size = SMB2_AES_128_CCM_NONCE_SIZE;
+ break;
+ case SMB2_ENCRYPTION_AES128_GCM:
+ nonce_size = gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_GCM);
+ break;
+ case SMB2_ENCRYPTION_AES256_CCM:
+ nonce_size = SMB2_AES_128_CCM_NONCE_SIZE;
+ break;
+ case SMB2_ENCRYPTION_AES256_GCM:
+ nonce_size = gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_256_GCM);
+ break;
+ default:
+ nonce_size = 0;
+ break;
+ }
+ session->smb2->nonce_high_max = SMB2_NONCE_HIGH_MAX(nonce_size);
+ session->smb2->nonce_high = 0;
+ session->smb2->nonce_low = 0;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_create_channel(TALLOC_CTX *mem_ctx,
+ struct smbXcli_session *session1,
+ struct smbXcli_conn *conn,
+ struct smbXcli_session **_session2)
+{
+ struct smbXcli_session *session2;
+ NTSTATUS status;
+
+ if (!smb2_signing_key_valid(session1->smb2->signing_key)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (conn == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ session2 = talloc_zero(mem_ctx, struct smbXcli_session);
+ if (session2 == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ session2->smb2 = talloc_reference(session2, session1->smb2);
+ if (session2->smb2 == NULL) {
+ talloc_free(session2);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ talloc_set_destructor(session2, smbXcli_session_destructor);
+ DLIST_ADD_END(conn->sessions, session2);
+ session2->conn = conn;
+
+ status = smb2_signing_key_sign_create(session2,
+ conn->smb2.server.sign_algo,
+ NULL, /* no master key */
+ NULL, /* derivations */
+ &session2->smb2_channel.signing_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(session2);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(session2->smb2_channel.preauth_sha512,
+ conn->smb2.preauth_sha512,
+ sizeof(session2->smb2_channel.preauth_sha512));
+
+ *_session2 = session2;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
+ const DATA_BLOB _channel_key,
+ const struct iovec *recv_iov)
+{
+ struct smbXcli_conn *conn = session->conn;
+ uint8_t channel_key[16];
+ NTSTATUS status;
+ struct _derivation {
+ DATA_BLOB label;
+ DATA_BLOB context;
+ };
+ struct {
+ struct _derivation signing;
+ } derivation = {
+ .signing.label.length = 0,
+ };
+
+ if (conn == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_11) {
+ struct _derivation *d;
+ DATA_BLOB p;
+
+ p = data_blob_const(session->smb2_channel.preauth_sha512,
+ sizeof(session->smb2_channel.preauth_sha512));
+
+ d = &derivation.signing;
+ d->label = data_blob_string_const_null("SMBSigningKey");
+ d->context = p;
+ } else if (conn->protocol >= PROTOCOL_SMB3_00) {
+ struct _derivation *d;
+
+ d = &derivation.signing;
+ d->label = data_blob_string_const_null("SMB2AESCMAC");
+ d->context = data_blob_string_const_null("SmbSign");
+ }
+
+ ZERO_STRUCT(channel_key);
+ memcpy(channel_key, _channel_key.data,
+ MIN(_channel_key.length, sizeof(channel_key)));
+
+ session->smb2_channel.signing_key->blob =
+ data_blob_talloc(session->smb2_channel.signing_key,
+ channel_key,
+ sizeof(channel_key));
+ if (!smb2_signing_key_valid(session->smb2_channel.signing_key)) {
+ ZERO_STRUCT(channel_key);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (conn->protocol >= PROTOCOL_SMB3_00) {
+ struct _derivation *d = &derivation.signing;
+
+ status = samba_gnutls_sp800_108_derive_key(
+ channel_key,
+ sizeof(channel_key),
+ NULL,
+ 0,
+ d->label.data,
+ d->label.length,
+ d->context.data,
+ d->context.length,
+ GNUTLS_MAC_SHA256,
+ session->smb2_channel.signing_key->blob.data,
+ session->smb2_channel.signing_key->blob.length);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ ZERO_STRUCT(channel_key);
+
+ status = smb2_signing_check_pdu(session->smb2_channel.signing_key,
+ recv_iov, 3);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session)
+{
+ if (!session->smb2->should_sign) {
+ /*
+ * We need required signing on the session
+ * in order to prevent man in the middle attacks.
+ */
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (session->smb2->should_encrypt) {
+ return NT_STATUS_OK;
+ }
+
+ if (session->conn->protocol < PROTOCOL_SMB3_00) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (session->conn->smb2.server.cipher == 0) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (!smb2_signing_key_valid(session->smb2->signing_key)) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+ session->smb2->should_encrypt = true;
+ return NT_STATUS_OK;
+}
+
+uint16_t smb2cli_session_get_encryption_cipher(struct smbXcli_session *session)
+{
+ if (session->conn->protocol < PROTOCOL_SMB3_00) {
+ return 0;
+ }
+
+ if (!session->smb2->should_encrypt) {
+ return 0;
+ }
+
+ return session->conn->smb2.server.cipher;
+}
+
+struct smbXcli_tcon *smbXcli_tcon_create(TALLOC_CTX *mem_ctx)
+{
+ struct smbXcli_tcon *tcon;
+
+ tcon = talloc_zero(mem_ctx, struct smbXcli_tcon);
+ if (tcon == NULL) {
+ return NULL;
+ }
+
+ return tcon;
+}
+
+/*
+ * Return a deep structure copy of a struct smbXcli_tcon *
+ */
+
+struct smbXcli_tcon *smbXcli_tcon_copy(TALLOC_CTX *mem_ctx,
+ const struct smbXcli_tcon *tcon_in)
+{
+ struct smbXcli_tcon *tcon;
+
+ tcon = talloc_memdup(mem_ctx, tcon_in, sizeof(struct smbXcli_tcon));
+ if (tcon == NULL) {
+ return NULL;
+ }
+
+ /* Deal with the SMB1 strings. */
+ if (tcon_in->smb1.service != NULL) {
+ tcon->smb1.service = talloc_strdup(tcon, tcon_in->smb1.service);
+ if (tcon->smb1.service == NULL) {
+ TALLOC_FREE(tcon);
+ return NULL;
+ }
+ }
+ if (tcon->smb1.fs_type != NULL) {
+ tcon->smb1.fs_type = talloc_strdup(tcon, tcon_in->smb1.fs_type);
+ if (tcon->smb1.fs_type == NULL) {
+ TALLOC_FREE(tcon);
+ return NULL;
+ }
+ }
+ return tcon;
+}
+
+void smbXcli_tcon_set_fs_attributes(struct smbXcli_tcon *tcon,
+ uint32_t fs_attributes)
+{
+ tcon->fs_attributes = fs_attributes;
+}
+
+uint32_t smbXcli_tcon_get_fs_attributes(struct smbXcli_tcon *tcon)
+{
+ return tcon->fs_attributes;
+}
+
+bool smbXcli_tcon_is_dfs_share(struct smbXcli_tcon *tcon)
+{
+ if (tcon == NULL) {
+ return false;
+ }
+
+ if (tcon->is_smb1) {
+ if (tcon->smb1.optional_support & SMB_SHARE_IN_DFS) {
+ return true;
+ }
+
+ return false;
+ }
+
+ if (tcon->smb2.capabilities & SMB2_SHARE_CAP_DFS) {
+ return true;
+ }
+
+ return false;
+}
+
+uint16_t smb1cli_tcon_current_id(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb1.tcon_id;
+}
+
+void smb1cli_tcon_set_id(struct smbXcli_tcon *tcon, uint16_t tcon_id)
+{
+ tcon->is_smb1 = true;
+ tcon->smb1.tcon_id = tcon_id;
+}
+
+bool smb1cli_tcon_set_values(struct smbXcli_tcon *tcon,
+ uint16_t tcon_id,
+ uint16_t optional_support,
+ uint32_t maximal_access,
+ uint32_t guest_maximal_access,
+ const char *service,
+ const char *fs_type)
+{
+ tcon->is_smb1 = true;
+ tcon->fs_attributes = 0;
+ tcon->smb1.tcon_id = tcon_id;
+ tcon->smb1.optional_support = optional_support;
+ tcon->smb1.maximal_access = maximal_access;
+ tcon->smb1.guest_maximal_access = guest_maximal_access;
+
+ TALLOC_FREE(tcon->smb1.service);
+ tcon->smb1.service = talloc_strdup(tcon, service);
+ if (service != NULL && tcon->smb1.service == NULL) {
+ return false;
+ }
+
+ TALLOC_FREE(tcon->smb1.fs_type);
+ tcon->smb1.fs_type = talloc_strdup(tcon, fs_type);
+ if (fs_type != NULL && tcon->smb1.fs_type == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+uint32_t smb2cli_tcon_current_id(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb2.tcon_id;
+}
+
+void smb2cli_tcon_set_id(struct smbXcli_tcon *tcon, uint32_t tcon_id)
+{
+ tcon->smb2.tcon_id = tcon_id;
+}
+
+uint32_t smb2cli_tcon_capabilities(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb2.capabilities;
+}
+
+uint32_t smb2cli_tcon_flags(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb2.flags;
+}
+
+void smb2cli_tcon_set_values(struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint32_t tcon_id,
+ uint8_t type,
+ uint32_t flags,
+ uint32_t capabilities,
+ uint32_t maximal_access)
+{
+ tcon->is_smb1 = false;
+ tcon->fs_attributes = 0;
+ tcon->smb2.tcon_id = tcon_id;
+ tcon->smb2.type = type;
+ tcon->smb2.flags = flags;
+ tcon->smb2.capabilities = capabilities;
+ tcon->smb2.maximal_access = maximal_access;
+
+ tcon->smb2.should_sign = false;
+ tcon->smb2.should_encrypt = false;
+
+ if (session == NULL) {
+ return;
+ }
+
+ tcon->smb2.should_sign = session->smb2->should_sign;
+ tcon->smb2.should_encrypt = session->smb2->should_encrypt;
+
+ if (flags & SMB2_SHAREFLAG_ENCRYPT_DATA) {
+ tcon->smb2.should_encrypt = true;
+ }
+}
+
+void smb2cli_tcon_should_sign(struct smbXcli_tcon *tcon,
+ bool should_sign)
+{
+ tcon->smb2.should_sign = should_sign;
+}
+
+bool smb2cli_tcon_is_signing_on(struct smbXcli_tcon *tcon)
+{
+ if (tcon->smb2.should_encrypt) {
+ return true;
+ }
+
+ return tcon->smb2.should_sign;
+}
+
+void smb2cli_tcon_should_encrypt(struct smbXcli_tcon *tcon,
+ bool should_encrypt)
+{
+ tcon->smb2.should_encrypt = should_encrypt;
+}
+
+bool smb2cli_tcon_is_encryption_on(struct smbXcli_tcon *tcon)
+{
+ return tcon->smb2.should_encrypt;
+}
+
+void smb2cli_conn_set_mid(struct smbXcli_conn *conn, uint64_t mid)
+{
+ conn->smb2.mid = mid;
+}
+
+uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn)
+{
+ return conn->smb2.mid;
+}
+
+NTSTATUS smb2cli_parse_dyn_buffer(uint32_t dyn_offset,
+ const DATA_BLOB dyn_buffer,
+ uint32_t min_offset,
+ uint32_t buffer_offset,
+ uint32_t buffer_length,
+ uint32_t max_length,
+ uint32_t *next_offset,
+ DATA_BLOB *buffer)
+{
+ uint32_t offset;
+ bool oob;
+
+ *buffer = data_blob_null;
+ *next_offset = dyn_offset;
+
+ if (buffer_offset == 0) {
+ /*
+ * If the offset is 0, we better ignore
+ * the buffer_length field.
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (buffer_length == 0) {
+ /*
+ * If the length is 0, we better ignore
+ * the buffer_offset field.
+ */
+ return NT_STATUS_OK;
+ }
+
+ if ((buffer_offset % 8) != 0) {
+ /*
+ * The offset needs to be 8 byte aligned.
+ */
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * We used to enforce buffer_offset to be
+ * an exact match of the expected minimum,
+ * but the NetApp Ontap 7.3.7 SMB server
+ * gets the padding wrong and aligns the
+ * input_buffer_offset by a value of 8.
+ *
+ * So we just enforce that the offset is
+ * not lower than the expected value.
+ */
+ SMB_ASSERT(min_offset >= dyn_offset);
+ if (buffer_offset < min_offset) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * Make [input|output]_buffer_offset relative to "dyn_buffer"
+ */
+ offset = buffer_offset - dyn_offset;
+ oob = smb_buffer_oob(dyn_buffer.length, offset, buffer_length);
+ if (oob) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * Give the caller a hint what we consumed,
+ * the caller may need to add possible padding.
+ */
+ *next_offset = buffer_offset + buffer_length;
+
+ if (max_length == 0) {
+ /*
+ * If max_input_length is 0 we ignore the
+ * input_buffer_length, because Windows 2008 echos the
+ * DCERPC request from the requested input_buffer to
+ * the response input_buffer.
+ *
+ * We just use the same logic also for max_output_length...
+ */
+ buffer_length = 0;
+ }
+
+ if (buffer_length > max_length) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ *buffer = (DATA_BLOB) {
+ .data = dyn_buffer.data + offset,
+ .length = buffer_length,
+ };
+ return NT_STATUS_OK;
+}
diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h
new file mode 100644
index 0000000..25ccd84
--- /dev/null
+++ b/libcli/smb/smbXcli_base.h
@@ -0,0 +1,969 @@
+/*
+ Unix SMB/CIFS implementation.
+ Infrastructure for async SMB client requests
+ Copyright (C) Volker Lendecke 2008
+ 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/>.
+*/
+
+#ifndef _SMBXCLI_BASE_H_
+#define _SMBXCLI_BASE_H_
+
+#define SMB_SUICIDE_PACKET 0x74697865
+
+#include "replace.h"
+#include <tevent.h>
+#include "libcli/smb/smb_constants.h"
+#include "libcli/util/ntstatus.h"
+#include "lib/util/time.h"
+#include "lib/util/data_blob.h"
+
+struct smbXcli_conn;
+struct smbXcli_session;
+struct smbXcli_tcon;
+struct smb_trans_enc_state;
+struct GUID;
+struct iovec;
+struct smb2_create_blobs;
+struct smb_create_returns;
+struct smb311_capabilities;
+
+struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
+ int fd,
+ const char *remote_name,
+ enum smb_signing_setting signing_state,
+ uint32_t smb1_capabilities,
+ struct GUID *client_guid,
+ uint32_t smb2_capabilities,
+ const struct smb311_capabilities *smb3_capabilities);
+
+bool smbXcli_conn_is_connected(struct smbXcli_conn *conn);
+void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status);
+
+struct tevent_queue *smbXcli_conn_send_queue(struct smbXcli_conn *conn);
+bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn);
+
+bool smbXcli_conn_dfs_supported(struct smbXcli_conn *conn);
+
+enum protocol_types smbXcli_conn_protocol(struct smbXcli_conn *conn);
+bool smbXcli_conn_use_unicode(struct smbXcli_conn *conn);
+bool smbXcli_conn_signing_mandatory(struct smbXcli_conn *conn);
+bool smbXcli_conn_have_posix(struct smbXcli_conn *conn);
+bool smbXcli_conn_support_passthrough(struct smbXcli_conn *conn);
+
+void smbXcli_conn_set_sockopt(struct smbXcli_conn *conn, const char *options);
+const struct sockaddr_storage *smbXcli_conn_local_sockaddr(struct smbXcli_conn *conn);
+const struct sockaddr_storage *smbXcli_conn_remote_sockaddr(struct smbXcli_conn *conn);
+const char *smbXcli_conn_remote_name(struct smbXcli_conn *conn);
+
+uint16_t smbXcli_conn_max_requests(struct smbXcli_conn *conn);
+NTTIME smbXcli_conn_server_system_time(struct smbXcli_conn *conn);
+const DATA_BLOB *smbXcli_conn_server_gss_blob(struct smbXcli_conn *conn);
+const struct GUID *smbXcli_conn_server_guid(struct smbXcli_conn *conn);
+bool smbXcli_conn_get_force_channel_sequence(struct smbXcli_conn *conn);
+void smbXcli_conn_set_force_channel_sequence(struct smbXcli_conn *conn,
+ bool v);
+
+
+struct tevent_req *smbXcli_conn_samba_suicide_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t exitcode);
+NTSTATUS smbXcli_conn_samba_suicide_recv(struct tevent_req *req);
+NTSTATUS smbXcli_conn_samba_suicide(struct smbXcli_conn *conn,
+ uint8_t exitcode);
+
+void smbXcli_req_unset_pending(struct tevent_req *req);
+bool smbXcli_req_set_pending(struct tevent_req *req);
+struct timeval smbXcli_req_endtime(struct tevent_req *req);
+
+uint32_t smb1cli_conn_capabilities(struct smbXcli_conn *conn);
+uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn);
+bool smb1cli_conn_req_possible(struct smbXcli_conn *conn);
+uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn);
+const uint8_t *smb1cli_conn_server_challenge(struct smbXcli_conn *conn);
+uint16_t smb1cli_conn_server_security_mode(struct smbXcli_conn *conn);
+bool smb1cli_conn_server_readbraw(struct smbXcli_conn *conn);
+bool smb1cli_conn_server_writebraw(struct smbXcli_conn *conn);
+bool smb1cli_conn_server_lockread(struct smbXcli_conn *conn);
+bool smb1cli_conn_server_writeunlock(struct smbXcli_conn *conn);
+int smb1cli_conn_server_time_zone(struct smbXcli_conn *conn);
+
+bool smb1cli_conn_activate_signing(struct smbXcli_conn *conn,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response);
+bool smb1cli_conn_check_signing(struct smbXcli_conn *conn,
+ const uint8_t *buf, uint32_t seqnum);
+bool smb1cli_conn_signing_is_active(struct smbXcli_conn *conn);
+
+void smb1cli_conn_set_encryption(struct smbXcli_conn *conn,
+ struct smb_trans_enc_state *es);
+bool smb1cli_conn_encryption_on(struct smbXcli_conn *conn);
+
+bool smb1cli_is_andx_req(uint8_t cmd);
+size_t smb1cli_req_wct_ofs(struct tevent_req **reqs, int num_reqs);
+
+uint16_t smb1cli_req_mid(struct tevent_req *req);
+void smb1cli_req_set_mid(struct tevent_req *req, uint16_t mid);
+
+uint32_t smb1cli_req_seqnum(struct tevent_req *req);
+void smb1cli_req_set_seqnum(struct tevent_req *req, uint32_t seqnum);
+
+struct smb1cli_req_expected_response {
+ NTSTATUS status;
+ uint8_t wct;
+};
+
+struct tevent_req *smb1cli_req_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint8_t wct, uint16_t *vwv,
+ int iov_count,
+ struct iovec *bytes_iov);
+NTSTATUS smb1cli_req_chain_submit(struct tevent_req **reqs, int num_reqs);
+
+struct tevent_req *smb1cli_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint8_t smb_command,
+ uint8_t additional_flags,
+ uint8_t clear_flags,
+ uint16_t additional_flags2,
+ uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint8_t wct, uint16_t *vwv,
+ uint32_t num_bytes,
+ const uint8_t *bytes);
+NTSTATUS smb1cli_req_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ uint8_t **phdr,
+ uint8_t *pwct,
+ uint16_t **pvwv,
+ uint32_t *pvwv_offset,
+ uint32_t *pnum_bytes,
+ uint8_t **pbytes,
+ uint32_t *pbytes_offset,
+ uint8_t **pinbuf,
+ const struct smb1cli_req_expected_response *expected,
+ size_t num_expected);
+
+struct tevent_req *smb1cli_trans_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct smbXcli_conn *conn, uint8_t cmd,
+ uint8_t additional_flags, uint8_t clear_flags,
+ uint16_t additional_flags2, uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *pipe_name, uint16_t fid, uint16_t function, int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data);
+NTSTATUS smb1cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint16_t *recv_flags2,
+ uint16_t **setup, uint8_t min_setup,
+ uint8_t *num_setup,
+ uint8_t **param, uint32_t min_param,
+ uint32_t *num_param,
+ uint8_t **data, uint32_t min_data,
+ uint32_t *num_data);
+NTSTATUS smb1cli_trans(TALLOC_CTX *mem_ctx, struct smbXcli_conn *conn,
+ uint8_t trans_cmd,
+ uint8_t additional_flags, uint8_t clear_flags,
+ uint16_t additional_flags2, uint16_t clear_flags2,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *pipe_name, uint16_t fid, uint16_t function,
+ int flags,
+ uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
+ uint8_t *param, uint32_t num_param, uint32_t max_param,
+ uint8_t *data, uint32_t num_data, uint32_t max_data,
+ uint16_t *recv_flags2,
+ uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
+ uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
+ uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata);
+
+struct tevent_req *smb1cli_echo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint16_t num_echos,
+ DATA_BLOB data);
+NTSTATUS smb1cli_echo_recv(struct tevent_req *req);
+NTSTATUS smb1cli_echo(struct smbXcli_conn *conn, uint32_t timeout_msec,
+ uint16_t num_echos, DATA_BLOB data);
+
+struct tevent_req *smb1cli_session_setup_lm21_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const char *in_user,
+ const char *in_domain,
+ const DATA_BLOB in_password,
+ const char *in_native_os,
+ const char *in_native_lm);
+NTSTATUS smb1cli_session_setup_lm21_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ char **out_native_os,
+ char **out_native_lm);
+struct tevent_req *smb1cli_session_setup_nt1_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const char *in_user,
+ const char *in_domain,
+ const DATA_BLOB in_apassword,
+ const DATA_BLOB in_upassword,
+ uint32_t in_capabilities,
+ const char *in_native_os,
+ const char *in_native_lm);
+NTSTATUS smb1cli_session_setup_nt1_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **precv_iov,
+ const uint8_t **precv_inbuf,
+ char **out_native_os,
+ char **out_native_lm,
+ char **out_primary_domain);
+struct tevent_req *smb1cli_session_setup_ext_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_session *session,
+ uint16_t in_buf_size,
+ uint16_t in_mpx_max,
+ uint16_t in_vc_num,
+ uint32_t in_sess_key,
+ const DATA_BLOB in_security_blob,
+ uint32_t in_capabilities,
+ const char *in_native_os,
+ const char *in_native_lm);
+NTSTATUS smb1cli_session_setup_ext_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **precv_iov,
+ const uint8_t **precv_inbuf,
+ DATA_BLOB *out_security_blob,
+ char **out_native_os,
+ char **out_native_lm);
+
+struct tevent_req *smb1cli_ntcreatex_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *fname,
+ uint32_t CreatFlags,
+ uint32_t RootDirectoryFid,
+ uint32_t DesiredAccess,
+ uint64_t AllocationSize,
+ uint32_t FileAttributes,
+ uint32_t ShareAccess,
+ uint32_t CreateDisposition,
+ uint32_t CreateOptions,
+ uint32_t ImpersonationLevel,
+ uint8_t SecurityFlags);
+NTSTATUS smb1cli_ntcreatex_recv(struct tevent_req *req, uint16_t *pfnum);
+NTSTATUS smb1cli_ntcreatex(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const char *fname,
+ uint32_t CreatFlags,
+ uint32_t RootDirectoryFid,
+ uint32_t DesiredAccess,
+ uint64_t AllocationSize,
+ uint32_t FileAttributes,
+ uint32_t ShareAccess,
+ uint32_t CreateDisposition,
+ uint32_t CreateOptions,
+ uint32_t ImpersonationLevel,
+ uint8_t SecurityFlags,
+ uint16_t *pfnum);
+struct tevent_req *smb1cli_close_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint32_t last_modified);
+NTSTATUS smb1cli_close_recv(struct tevent_req *req);
+NTSTATUS smb1cli_close(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint32_t last_modified);
+struct tevent_req *smb1cli_writex_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint16_t mode,
+ const uint8_t *buf,
+ uint64_t offset,
+ uint32_t size);
+NTSTATUS smb1cli_writex_recv(struct tevent_req *req,
+ uint32_t *pwritten,
+ uint16_t *pavailable);
+NTSTATUS smb1cli_writex(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint16_t mode,
+ const uint8_t *buf,
+ uint64_t offset,
+ uint32_t size,
+ uint32_t *pwritten,
+ uint16_t *pavailable);
+struct tevent_req *smb1cli_readx_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ uint32_t pid,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint16_t fnum,
+ uint64_t offset,
+ uint32_t size);
+NTSTATUS smb1cli_readx_recv(struct tevent_req *req,
+ uint32_t *received,
+ uint8_t **rcvbuf);
+
+bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len);
+uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn);
+uint16_t smb2cli_conn_server_security_mode(struct smbXcli_conn *conn);
+uint16_t smb2cli_conn_server_signing_algo(struct smbXcli_conn *conn);
+uint16_t smb2cli_conn_server_encryption_algo(struct smbXcli_conn *conn);
+uint32_t smb2cli_conn_max_trans_size(struct smbXcli_conn *conn);
+uint32_t smb2cli_conn_max_read_size(struct smbXcli_conn *conn);
+uint32_t smb2cli_conn_max_write_size(struct smbXcli_conn *conn);
+void smb2cli_conn_set_max_credits(struct smbXcli_conn *conn,
+ uint16_t max_credits);
+uint16_t smb2cli_conn_get_cur_credits(struct smbXcli_conn *conn);
+uint8_t smb2cli_conn_get_io_priority(struct smbXcli_conn *conn);
+void smb2cli_conn_set_io_priority(struct smbXcli_conn *conn,
+ uint8_t io_priority);
+uint32_t smb2cli_conn_cc_chunk_len(struct smbXcli_conn *conn);
+void smb2cli_conn_set_cc_chunk_len(struct smbXcli_conn *conn,
+ uint32_t chunk_len);
+uint32_t smb2cli_conn_cc_max_chunks(struct smbXcli_conn *conn);
+void smb2cli_conn_set_cc_max_chunks(struct smbXcli_conn *conn,
+ uint32_t max_chunks);
+void smb2cli_conn_set_mid(struct smbXcli_conn *conn, uint64_t mid);
+uint64_t smb2cli_conn_get_mid(struct smbXcli_conn *conn);
+
+NTSTATUS smb2cli_parse_dyn_buffer(uint32_t dyn_offset,
+ const DATA_BLOB dyn_buffer,
+ uint32_t min_offset,
+ uint32_t buffer_offset,
+ uint32_t buffer_length,
+ uint32_t max_length,
+ uint32_t *next_offset,
+ DATA_BLOB *buffer);
+
+struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint16_t cmd,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const uint8_t *fixed,
+ uint16_t fixed_len,
+ const uint8_t *dyn,
+ uint32_t dyn_len,
+ uint32_t max_dyn_len);
+void smb2cli_req_set_notify_async(struct tevent_req *req);
+NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
+ int num_reqs);
+void smb2cli_req_set_credit_charge(struct tevent_req *req, uint16_t charge);
+
+struct smb2cli_req_expected_response {
+ NTSTATUS status;
+ uint16_t body_size;
+};
+
+struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint16_t cmd,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ const uint8_t *fixed,
+ uint16_t fixed_len,
+ const uint8_t *dyn,
+ uint32_t dyn_len,
+ uint32_t max_dyn_len);
+NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct iovec **piov,
+ const struct smb2cli_req_expected_response *expected,
+ size_t num_expected);
+
+/*
+ * This expects an iov[3] array, that is filled with references to
+ * the buffers used for the sending the requests into the socket.
+ *
+ * This can only be called after smb2cli_req_recv(subreq) before
+ * the TALLOC_FREE(subreq).
+ */
+NTSTATUS smb2cli_req_get_sent_iov(struct tevent_req *req,
+ struct iovec *sent_iov);
+
+struct smb2_negotiate_contexts;
+struct tevent_req *smbXcli_negprot_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ enum protocol_types min_protocol,
+ enum protocol_types max_protocol,
+ uint16_t max_credits,
+ struct smb2_negotiate_contexts *in_ctx);
+NTSTATUS smbXcli_negprot_recv(
+ struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts **out_ctx);
+NTSTATUS smbXcli_negprot(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ enum protocol_types min_protocol,
+ enum protocol_types max_protocol,
+ struct smb2_negotiate_contexts *in_ctx,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_negotiate_contexts **out_ctx);
+
+struct tevent_req *smb2cli_validate_negotiate_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon);
+NTSTATUS smb2cli_validate_negotiate_info_recv(struct tevent_req *req);
+
+struct smbXcli_session *smbXcli_session_create(TALLOC_CTX *mem_ctx,
+ struct smbXcli_conn *conn);
+struct smbXcli_session *smbXcli_session_shallow_copy(TALLOC_CTX *mem_ctx,
+ struct smbXcli_session *src);
+bool smbXcli_session_is_guest(struct smbXcli_session *session);
+bool smbXcli_session_is_authenticated(struct smbXcli_session *session);
+NTSTATUS smb2cli_session_signing_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key);
+NTSTATUS smb2cli_session_encryption_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key);
+NTSTATUS smb2cli_session_decryption_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key);
+NTSTATUS smbXcli_session_application_key(struct smbXcli_session *session,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *key);
+void smbXcli_session_set_disconnect_expired(struct smbXcli_session *session);
+uint16_t smb1cli_session_current_id(struct smbXcli_session* session);
+void smb1cli_session_set_id(struct smbXcli_session* session,
+ uint16_t session_id);
+void smb1cli_session_set_action(struct smbXcli_session *session,
+ uint16_t action);
+NTSTATUS smb1cli_session_set_session_key(struct smbXcli_session *session,
+ const DATA_BLOB _session_key);
+NTSTATUS smb1cli_session_protect_session_key(struct smbXcli_session *session);
+uint8_t smb2cli_session_security_mode(struct smbXcli_session *session);
+uint64_t smb2cli_session_current_id(struct smbXcli_session *session);
+uint16_t smb2cli_session_get_flags(struct smbXcli_session *session);
+void smb2cli_session_set_id_and_flags(struct smbXcli_session *session,
+ uint64_t session_id,
+ uint16_t session_flags);
+void smb2cli_session_increment_channel_sequence(struct smbXcli_session *session);
+uint16_t smb2cli_session_reset_channel_sequence(struct smbXcli_session *session,
+ uint16_t channel_sequence);
+uint16_t smb2cli_session_current_channel_sequence(struct smbXcli_session *session);
+void smb2cli_session_start_replay(struct smbXcli_session *session);
+void smb2cli_session_stop_replay(struct smbXcli_session *session);
+void smb2cli_session_require_signed_response(struct smbXcli_session *session,
+ bool require_signed_response);
+NTSTATUS smb2cli_session_update_preauth(struct smbXcli_session *session,
+ const struct iovec *iov);
+NTSTATUS smb2cli_session_set_session_key(struct smbXcli_session *session,
+ const DATA_BLOB session_key,
+ const struct iovec *recv_iov);
+NTSTATUS smb2cli_session_create_channel(TALLOC_CTX *mem_ctx,
+ struct smbXcli_session *session1,
+ struct smbXcli_conn *conn,
+ struct smbXcli_session **_session2);
+NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session,
+ const DATA_BLOB channel_key,
+ const struct iovec *recv_iov);
+NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session);
+uint16_t smb2cli_session_get_encryption_cipher(struct smbXcli_session *session);
+
+struct smbXcli_tcon *smbXcli_tcon_create(TALLOC_CTX *mem_ctx);
+struct smbXcli_tcon *smbXcli_tcon_copy(TALLOC_CTX *mem_ctx,
+ const struct smbXcli_tcon *tcon_in);
+void smbXcli_tcon_set_fs_attributes(struct smbXcli_tcon *tcon,
+ uint32_t fs_attributes);
+uint32_t smbXcli_tcon_get_fs_attributes(struct smbXcli_tcon *tcon);
+bool smbXcli_tcon_is_dfs_share(struct smbXcli_tcon *tcon);
+uint16_t smb1cli_tcon_current_id(struct smbXcli_tcon *tcon);
+void smb1cli_tcon_set_id(struct smbXcli_tcon *tcon, uint16_t tcon_id);
+bool smb1cli_tcon_set_values(struct smbXcli_tcon *tcon,
+ uint16_t tcon_id,
+ uint16_t optional_support,
+ uint32_t maximal_access,
+ uint32_t guest_maximal_access,
+ const char *service,
+ const char *fs_type);
+uint32_t smb2cli_tcon_current_id(struct smbXcli_tcon *tcon);
+void smb2cli_tcon_set_id(struct smbXcli_tcon *tcon, uint32_t tcon_id);
+uint32_t smb2cli_tcon_capabilities(struct smbXcli_tcon *tcon);
+uint32_t smb2cli_tcon_flags(struct smbXcli_tcon *tcon);
+void smb2cli_tcon_set_values(struct smbXcli_tcon *tcon,
+ struct smbXcli_session *session,
+ uint32_t tcon_id,
+ uint8_t type,
+ uint32_t flags,
+ uint32_t capabilities,
+ uint32_t maximal_access);
+void smb2cli_tcon_should_sign(struct smbXcli_tcon *tcon,
+ bool should_sign);
+bool smb2cli_tcon_is_signing_on(struct smbXcli_tcon *tcon);
+void smb2cli_tcon_should_encrypt(struct smbXcli_tcon *tcon,
+ bool should_encrypt);
+bool smb2cli_tcon_is_encryption_on(struct smbXcli_tcon *tcon);
+
+struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ uint8_t in_flags,
+ uint32_t in_capabilities,
+ uint32_t in_channel,
+ uint64_t in_previous_session_id,
+ const DATA_BLOB *in_security_buffer);
+NTSTATUS smb2cli_session_setup_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **recv_iov,
+ DATA_BLOB *out_security_buffer);
+
+struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session);
+NTSTATUS smb2cli_logoff_recv(struct tevent_req *req);
+NTSTATUS smb2cli_logoff(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session);
+
+/* smb2cli_raw_tcon* should only be used in tests! */
+struct tevent_req *smb2cli_raw_tcon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t tcon_flags,
+ const char *unc);
+NTSTATUS smb2cli_raw_tcon_recv(struct tevent_req *req);
+NTSTATUS smb2cli_raw_tcon(struct smbXcli_conn *conn,
+ uint32_t additional_flags,
+ uint32_t clear_flags,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t tcon_flags,
+ const char *unc);
+struct tevent_req *smb2cli_tcon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ const char *unc);
+NTSTATUS smb2cli_tcon_recv(struct tevent_req *req);
+NTSTATUS smb2cli_tcon(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ const char *unc);
+
+struct tevent_req *smb2cli_tdis_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon);
+NTSTATUS smb2cli_tdis_recv(struct tevent_req *req);
+NTSTATUS smb2cli_tdis(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon);
+
+struct symlink_reparse_struct;
+
+struct tevent_req *smb2cli_create_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *filename,
+ uint8_t oplock_level, /* SMB2_OPLOCK_LEVEL_* */
+ uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ struct smb2_create_blobs *blobs);
+NTSTATUS smb2cli_create_recv(struct tevent_req *req,
+ uint64_t *fid_persistent,
+ uint64_t *fid_volatile,
+ struct smb_create_returns *cr,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs *blobs,
+ struct symlink_reparse_struct **psymlink);
+NTSTATUS smb2cli_create(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *filename,
+ uint8_t oplock_level, /* SMB2_OPLOCK_LEVEL_* */
+ uint32_t impersonation_level, /* SMB2_IMPERSONATION_* */
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ struct smb2_create_blobs *blobs,
+ uint64_t *fid_persistent,
+ uint64_t *fid_volatile,
+ struct smb_create_returns *cr,
+ TALLOC_CTX *mem_ctx,
+ struct smb2_create_blobs *ret_blobs,
+ struct symlink_reparse_struct **psymlink);
+
+struct tevent_req *smb2cli_close_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile);
+NTSTATUS smb2cli_close_recv(struct tevent_req *req);
+NTSTATUS smb2cli_close(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t flags,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile);
+
+struct tevent_req *smb2cli_read_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint64_t minimum_count,
+ uint64_t remaining_bytes);
+NTSTATUS smb2cli_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **data, uint32_t *data_length);
+NTSTATUS smb2cli_read(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint64_t minimum_count,
+ uint64_t remaining_bytes,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length);
+
+struct tevent_req *smb2cli_write_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t remaining_bytes,
+ uint32_t flags,
+ const uint8_t *data);
+NTSTATUS smb2cli_write_recv(struct tevent_req *req,
+ uint32_t *written);
+NTSTATUS smb2cli_write(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t length,
+ uint64_t offset,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t remaining_bytes,
+ uint32_t flags,
+ const uint8_t *data,
+ uint32_t *written);
+
+struct tevent_req *smb2cli_flush_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile);
+NTSTATUS smb2cli_flush_recv(struct tevent_req *req);
+NTSTATUS smb2cli_flush(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile);
+
+struct tevent_req *smb2cli_set_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile);
+NTSTATUS smb2cli_set_info_recv(struct tevent_req *req);
+NTSTATUS smb2cli_set_info(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile);
+
+struct tevent_req *smb2cli_query_info_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint32_t in_flags,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile);
+NTSTATUS smb2cli_query_info_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_output_buffer);
+NTSTATUS smb2cli_query_info(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t in_info_type,
+ uint8_t in_file_info_class,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_additional_info,
+ uint32_t in_flags,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_output_buffer);
+
+struct tevent_req *smb2cli_query_directory_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t level,
+ uint8_t flags,
+ uint32_t file_index,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ const char *mask,
+ uint32_t outbuf_len);
+NTSTATUS smb2cli_query_directory_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length);
+NTSTATUS smb2cli_query_directory(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t level,
+ uint8_t flags,
+ uint32_t file_index,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ const char *mask,
+ uint32_t outbuf_len,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length);
+
+struct tevent_req *smb2cli_notify_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t output_buffer_length,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t completion_filter,
+ bool recursive);
+NTSTATUS smb2cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **data, uint32_t *data_length);
+NTSTATUS smb2cli_notify(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint32_t output_buffer_length,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ uint32_t completion_filter,
+ bool recursive,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **data,
+ uint32_t *data_length);
+
+struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ uint32_t in_ctl_code,
+ uint32_t in_max_input_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_output_buffer,
+ uint32_t in_flags);
+NTSTATUS smb2cli_ioctl_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_input_buffer,
+ DATA_BLOB *out_output_buffer);
+NTSTATUS smb2cli_ioctl(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint64_t in_fid_persistent,
+ uint64_t in_fid_volatile,
+ uint32_t in_ctl_code,
+ uint32_t in_max_input_length,
+ const DATA_BLOB *in_input_buffer,
+ uint32_t in_max_output_length,
+ const DATA_BLOB *in_output_buffer,
+ uint32_t in_flags,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out_input_buffer,
+ DATA_BLOB *out_output_buffer);
+
+struct tevent_req *smb2cli_echo_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec);
+NTSTATUS smb2cli_echo_recv(struct tevent_req *req);
+NTSTATUS smb2cli_echo(struct smbXcli_conn *conn,
+ uint32_t timeout_msec);
+
+struct tevent_req *smb2cli_ioctl_pipe_wait_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *pipe_name,
+ uint64_t pipe_wait_timeout);
+
+NTSTATUS smb2cli_ioctl_pipe_wait_recv(struct tevent_req *req);
+
+NTSTATUS smb2cli_ioctl_pipe_wait(struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ const char *pipe_name,
+ uint64_t pipe_wait_timeout);
+
+#endif /* _SMBXCLI_BASE_H_ */
diff --git a/libcli/smb/smb_common.h b/libcli/smb/smb_common.h
new file mode 100644
index 0000000..0117570
--- /dev/null
+++ b/libcli/smb/smb_common.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB and SMB2 common header
+
+ Copyright (C) Stefan Metzmacher 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 __LIBCLI_SMB_SMB_COMMON_H__
+#define __LIBCLI_SMB_SMB_COMMON_H__
+
+#include "libcli/smb/smb_constants.h"
+#include "libcli/smb/smb2_constants.h"
+#include "libcli/smb/smb2_create_blob.h"
+#include "libcli/smb/smb2_lease.h"
+#include "libcli/smb/smb2_lock.h"
+#include "libcli/smb/smb2_signing.h"
+#include "libcli/smb/smb_util.h"
+#include "libcli/smb/smb_unix_ext.h"
+
+#endif
diff --git a/libcli/smb/smb_constants.h b/libcli/smb/smb_constants.h
new file mode 100644
index 0000000..1d55a55
--- /dev/null
+++ b/libcli/smb/smb_constants.h
@@ -0,0 +1,649 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB parameters and setup, plus a whole lot more.
+
+ Copyright (C) Andrew Tridgell 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 _SMB_CONSTANTS_H
+#define _SMB_CONSTANTS_H
+
+/*
+ * Netbios over TCP (rfc 1002)
+ */
+#define NBSSmessage 0x00 /* session message */
+#define NBSSrequest 0x81 /* session request */
+#define NBSSpositive 0x82 /* positive session response */
+#define NBSSnegative 0x83 /* negative session response */
+#define NBSSretarget 0x84 /* retarget session response */
+#define NBSSkeepalive 0x85 /* keepalive */
+
+#define SMB_MAGIC 0x424D53FF /* 0xFF 'S' 'M' 'B' */
+
+/* the basic packet size, assuming no words or bytes. Does not include the NBT header */
+#define MIN_SMB_SIZE 35
+
+/* when using NBT encapsulation every packet has a 4 byte header */
+#define NBT_HDR_SIZE 4
+
+/* offsets into message header for common items - NOTE: These have
+ changed from being offsets from the base of the NBT packet to the base of the SMB packet.
+ this has reduced all these values by 4
+*/
+#define HDR_COM 4
+#define HDR_RCLS 5
+#define HDR_REH 6
+#define HDR_ERR 7
+#define HDR_FLG 9
+#define HDR_FLG2 10
+#define HDR_PIDHIGH 12
+#define HDR_SS_FIELD 14
+#define HDR_TID 24
+#define HDR_PID 26
+#define HDR_UID 28
+#define HDR_MID 30
+#define HDR_WCT 32
+#define HDR_VWV 33
+
+/* Macros for accessing SMB protocol elements */
+#define VWV(vwv) ((vwv)*2)
+
+#define smb_len_nbt(buf) (RIVAL(buf, 0) & 0x1FFFF)
+#define _smb_setlen_nbt(buf,len) RSIVAL(buf, 0, (len) & 0x1FFFF)
+#define smb_setlen_nbt(buf, len) do { \
+ _smb_setlen_nbt(buf, len); \
+ SIVAL(buf, 4, SMB_MAGIC); \
+} while (0)
+
+#define smb_len_tcp(buf) (RIVAL(buf, 0) & 0xFFFFFF)
+#define _smb_setlen_tcp(buf,len) RSIVAL(buf, 0, (len) & 0xFFFFFF)
+#define smb_setlen_tcp(buf, len) do { \
+ _smb_setlen_tcp(buf, len); \
+ SIVAL(buf, 4, SMB_MAGIC); \
+} while (0)
+
+/* protocol types. It assumes that higher protocols include lower protocols
+ as subsets. */
+enum protocol_types {
+ PROTOCOL_DEFAULT=-1,
+ PROTOCOL_NONE=0,
+ PROTOCOL_CORE,
+ PROTOCOL_COREPLUS,
+ PROTOCOL_LANMAN1,
+ PROTOCOL_LANMAN2,
+ PROTOCOL_NT1,
+ PROTOCOL_SMB2_02,
+ PROTOCOL_SMB2_10,
+ PROTOCOL_SMB3_00,
+ PROTOCOL_SMB3_02,
+ PROTOCOL_SMB3_11
+};
+#define PROTOCOL_LATEST PROTOCOL_SMB3_11
+
+enum smb_signing_setting {
+ SMB_SIGNING_IPC_DEFAULT = -2, /* Only used in C code */
+ SMB_SIGNING_DEFAULT = -1,
+ SMB_SIGNING_OFF = 0,
+ SMB_SIGNING_IF_REQUIRED = 1,
+ SMB_SIGNING_DESIRED = 2,
+ SMB_SIGNING_REQUIRED = 3,
+};
+
+/* This MUST align with 'enum smb_signing_setting' */
+enum smb_encryption_setting {
+ SMB_ENCRYPTION_DEFAULT = SMB_SIGNING_DEFAULT,
+ SMB_ENCRYPTION_OFF = SMB_SIGNING_OFF,
+ SMB_ENCRYPTION_IF_REQUIRED = SMB_SIGNING_IF_REQUIRED,
+ SMB_ENCRYPTION_DESIRED = SMB_SIGNING_DESIRED,
+ SMB_ENCRYPTION_REQUIRED = SMB_SIGNING_REQUIRED,
+};
+
+/* types of buffers in core SMB protocol */
+#define SMB_DATA_BLOCK 0x1
+#define SMB_ASCII4 0x4
+
+/* flag defines. CIFS spec 3.1.1 */
+#define FLAG_SUPPORT_LOCKREAD 0x01
+#define FLAG_CLIENT_BUF_AVAIL 0x02
+#define FLAG_RESERVED 0x04
+#define FLAG_CASELESS_PATHNAMES 0x08
+#define FLAG_CANONICAL_PATHNAMES 0x10
+#define FLAG_REQUEST_OPLOCK 0x20
+#define FLAG_REQUEST_BATCH_OPLOCK 0x40
+#define FLAG_REPLY 0x80
+
+/* the complete */
+#define SMBmkdir 0x00 /* create directory */
+#define SMBrmdir 0x01 /* delete directory */
+#define SMBopen 0x02 /* open file */
+#define SMBcreate 0x03 /* create file */
+#define SMBclose 0x04 /* close file */
+#define SMBflush 0x05 /* flush file */
+#define SMBunlink 0x06 /* delete file */
+#define SMBmv 0x07 /* rename file */
+#define SMBgetatr 0x08 /* get file attributes */
+#define SMBsetatr 0x09 /* set file attributes */
+#define SMBread 0x0A /* read from file */
+#define SMBwrite 0x0B /* write to file */
+#define SMBlock 0x0C /* lock byte range */
+#define SMBunlock 0x0D /* unlock byte range */
+#define SMBctemp 0x0E /* create temporary file */
+#define SMBmknew 0x0F /* make new file */
+#define SMBcheckpath 0x10 /* check directory path */
+#define SMBexit 0x11 /* process exit */
+#define SMBlseek 0x12 /* seek */
+#define SMBtcon 0x70 /* tree connect */
+#define SMBtconX 0x75 /* tree connect and X*/
+#define SMBtdis 0x71 /* tree disconnect */
+#define SMBnegprot 0x72 /* negotiate protocol */
+#define SMBdskattr 0x80 /* get disk attributes */
+#define SMBsearch 0x81 /* search directory */
+#define SMBsplopen 0xC0 /* open print spool file */
+#define SMBsplwr 0xC1 /* write to print spool file */
+#define SMBsplclose 0xC2 /* close print spool file */
+#define SMBsplretq 0xC3 /* return print queue */
+#define SMBsends 0xD0 /* send single block message */
+#define SMBsendb 0xD1 /* send broadcast message */
+#define SMBfwdname 0xD2 /* forward user name */
+#define SMBcancelf 0xD3 /* cancel forward */
+#define SMBgetmac 0xD4 /* get machine name */
+#define SMBsendstrt 0xD5 /* send start of multi-block message */
+#define SMBsendend 0xD6 /* send end of multi-block message */
+#define SMBsendtxt 0xD7 /* send text of multi-block message */
+
+/* Core+ protocol */
+#define SMBlockread 0x13 /* Lock a range and read */
+#define SMBwriteunlock 0x14 /* Unlock a range then write */
+#define SMBreadbraw 0x1a /* read a block of data with no smb header */
+#define SMBwritebraw 0x1d /* write a block of data with no smb header */
+#define SMBwritec 0x20 /* secondary write request */
+#define SMBwriteclose 0x2c /* write a file then close it */
+
+/* dos extended protocol */
+#define SMBreadBraw 0x1A /* read block raw */
+#define SMBreadBmpx 0x1B /* read block multiplexed */
+#define SMBreadBs 0x1C /* read block (secondary response) */
+#define SMBwriteBraw 0x1D /* write block raw */
+#define SMBwriteBmpx 0x1E /* write block multiplexed */
+#define SMBwriteBs 0x1F /* write block (secondary request) */
+#define SMBwriteC 0x20 /* write complete response */
+#define SMBsetattrE 0x22 /* set file attributes expanded */
+#define SMBgetattrE 0x23 /* get file attributes expanded */
+#define SMBlockingX 0x24 /* lock/unlock byte ranges and X */
+#define SMBtrans 0x25 /* transaction - name, bytes in/out */
+#define SMBtranss 0x26 /* transaction (secondary request/response) */
+#define SMBioctl 0x27 /* IOCTL */
+#define SMBioctls 0x28 /* IOCTL (secondary request/response) */
+#define SMBcopy 0x29 /* copy */
+#define SMBmove 0x2A /* move */
+#define SMBecho 0x2B /* echo */
+#define SMBopenX 0x2D /* open and X */
+#define SMBreadX 0x2E /* read and X */
+#define SMBwriteX 0x2F /* write and X */
+#define SMBsesssetupX 0x73 /* Session Set Up & X (including User Logon) */
+#define SMBffirst 0x82 /* find first */
+#define SMBfunique 0x83 /* find unique */
+#define SMBfclose 0x84 /* find close */
+#define SMBinvalid 0xFE /* invalid command */
+
+/* Extended 2.0 protocol */
+#define SMBtrans2 0x32 /* TRANS2 protocol set */
+#define SMBtranss2 0x33 /* TRANS2 protocol set, secondary command */
+#define SMBfindclose 0x34 /* Terminate a TRANSACT2_FINDFIRST */
+#define SMBfindnclose 0x35 /* Terminate a TRANSACT2_FINDNOTIFYFIRST */
+#define SMBulogoffX 0x74 /* user logoff */
+
+/* NT SMB extensions. */
+#define SMBnttrans 0xA0 /* NT transact */
+#define SMBnttranss 0xA1 /* NT transact secondary */
+#define SMBntcreateX 0xA2 /* NT create and X */
+#define SMBntcancel 0xA4 /* NT cancel */
+#define SMBntrename 0xA5 /* NT rename */
+
+/* used to indicate end of chain */
+#define SMB_CHAIN_NONE 0xFF
+
+/* Sercurity mode bits. */
+#define NEGOTIATE_SECURITY_USER_LEVEL 0x01
+#define NEGOTIATE_SECURITY_CHALLENGE_RESPONSE 0x02
+#define NEGOTIATE_SECURITY_SIGNATURES_ENABLED 0x04
+#define NEGOTIATE_SECURITY_SIGNATURES_REQUIRED 0x08
+
+/*
+ * The negotiated buffer size for non LARGE_READX/WRITEX
+ * should be limited to uint16_t and has to be at least
+ * 500, which is the default for MinClientBufferSize on Windows.
+ */
+#define SMB_BUFFER_SIZE_MIN 500
+#define SMB_BUFFER_SIZE_MAX 65535
+
+/* Capabilities. see ftp.microsoft.com/developr/drg/cifs/cifs/cifs4.txt */
+
+#define CAP_RAW_MODE 0x00000001
+#define CAP_MPX_MODE 0x00000002
+#define CAP_UNICODE 0x00000004
+#define CAP_LARGE_FILES 0x00000008
+#define CAP_NT_SMBS 0x00000010
+#define CAP_RPC_REMOTE_APIS 0x00000020
+#define CAP_STATUS32 0x00000040
+#define CAP_LEVEL_II_OPLOCKS 0x00000080
+#define CAP_LOCK_AND_READ 0x00000100
+#define CAP_NT_FIND 0x00000200
+#define CAP_DFS 0x00001000
+#define CAP_W2K_SMBS 0x00002000
+#define CAP_LARGE_READX 0x00004000
+#define CAP_LARGE_WRITEX 0x00008000
+#define CAP_LWIO 0x00010000
+#define CAP_UNIX 0x00800000 /* Capabilities for UNIX extensions. Created by HP. */
+#define CAP_DYNAMIC_REAUTH 0x20000000
+#define CAP_EXTENDED_SECURITY 0x80000000
+
+#define SMB_CAP_BOTH_MASK ( \
+ CAP_UNICODE | \
+ CAP_NT_SMBS | \
+ CAP_STATUS32 | \
+ CAP_LEVEL_II_OPLOCKS | \
+ CAP_EXTENDED_SECURITY | \
+ 0)
+#define SMB_CAP_SERVER_MASK ( \
+ CAP_RAW_MODE | \
+ CAP_MPX_MODE | \
+ CAP_LARGE_FILES | \
+ CAP_RPC_REMOTE_APIS | \
+ CAP_LOCK_AND_READ | \
+ CAP_NT_FIND | \
+ CAP_DFS | \
+ CAP_W2K_SMBS | \
+ CAP_LARGE_READX | \
+ CAP_LARGE_WRITEX | \
+ CAP_LWIO | \
+ CAP_UNIX | \
+ 0)
+#define SMB_CAP_CLIENT_MASK ( \
+ CAP_DYNAMIC_REAUTH | \
+ 0)
+/*
+ * Older Samba releases (<= 3.6.x)
+ * expect the client to send CAP_LARGE_READX
+ * in order to let the client use large reads.
+ */
+#define SMB_CAP_LEGACY_CLIENT_MASK ( \
+ SMB_CAP_CLIENT_MASK | \
+ CAP_LARGE_READX | \
+ CAP_LARGE_WRITEX | \
+ 0)
+
+/*
+ * The action flags in the SMB session setup response
+ */
+#define SMB_SETUP_GUEST 0x0001
+#define SMB_SETUP_USE_LANMAN_KEY 0x0002
+
+/* Client-side offline caching policy types */
+enum csc_policy {
+ CSC_POLICY_MANUAL=0,
+ CSC_POLICY_DOCUMENTS=1,
+ CSC_POLICY_PROGRAMS=2,
+ CSC_POLICY_DISABLE=3
+};
+
+/* TCONX Flag (smb_vwv2). [MS-SMB] 2.2.4.7.1 */
+#define TCONX_FLAG_DISCONNECT_TID 0x0001
+#define TCONX_FLAG_EXTENDED_SIGNATURES 0x0004
+#define TCONX_FLAG_EXTENDED_RESPONSE 0x0008
+
+/* this is used on a TConX. [MS-SMB] 2.2.4.7.2 */
+#define SMB_SUPPORT_SEARCH_BITS 0x0001
+#define SMB_SHARE_IN_DFS 0x0002
+#define SMB_CSC_MASK 0x000C
+#define SMB_CSC_POLICY_SHIFT 2
+#define SMB_UNIQUE_FILE_NAME 0x0010
+#define SMB_EXTENDED_SIGNATURES 0x0020
+
+/* NT Flags2 bits - cifs6.txt section 3.1.2 */
+#define FLAGS2_LONG_PATH_COMPONENTS 0x0001
+#define FLAGS2_EXTENDED_ATTRIBUTES 0x0002
+#define FLAGS2_SMB_SECURITY_SIGNATURES 0x0004
+#define FLAGS2_COMPRESSED 0x0008 /* MS-SMB */
+#define FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED 0x0010
+#define FLAGS2_IS_LONG_NAME 0x0040
+#define FLAGS2_REPARSE_PATH 0x0400 /* MS-SMB @GMT- path. */
+#define FLAGS2_EXTENDED_SECURITY 0x0800
+#define FLAGS2_DFS_PATHNAMES 0x1000
+#define FLAGS2_READ_PERMIT_EXECUTE 0x2000
+#define FLAGS2_32_BIT_ERROR_CODES 0x4000
+#define FLAGS2_UNICODE_STRINGS 0x8000
+
+/* FileAttributes (search attributes) field */
+#define FILE_ATTRIBUTE_INVALID 0x0000L
+#define FILE_ATTRIBUTE_READONLY 0x0001L
+#define FILE_ATTRIBUTE_HIDDEN 0x0002L
+#define FILE_ATTRIBUTE_SYSTEM 0x0004L
+#define FILE_ATTRIBUTE_VOLUME 0x0008L
+#define FILE_ATTRIBUTE_DIRECTORY 0x0010L
+#define FILE_ATTRIBUTE_ARCHIVE 0x0020L
+#define FILE_ATTRIBUTE_DEVICE 0x0040L
+#define FILE_ATTRIBUTE_NORMAL 0x0080L
+#define FILE_ATTRIBUTE_TEMPORARY 0x0100L
+#define FILE_ATTRIBUTE_SPARSE 0x0200L
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400L
+#define FILE_ATTRIBUTE_COMPRESSED 0x0800L
+#define FILE_ATTRIBUTE_OFFLINE 0x1000L
+#define FILE_ATTRIBUTE_NONINDEXED 0x2000L
+#define FILE_ATTRIBUTE_ENCRYPTED 0x4000L
+#define FILE_ATTRIBUTE_ALL_MASK 0x7FFFL
+
+#define SAMBA_ATTRIBUTES_MASK (FILE_ATTRIBUTE_READONLY|\
+ FILE_ATTRIBUTE_HIDDEN|\
+ FILE_ATTRIBUTE_SYSTEM|\
+ FILE_ATTRIBUTE_DIRECTORY|\
+ FILE_ATTRIBUTE_ARCHIVE|\
+ FILE_ATTRIBUTE_OFFLINE)
+
+/* File type flags */
+#define FILE_TYPE_DISK 0
+#define FILE_TYPE_BYTE_MODE_PIPE 1
+#define FILE_TYPE_MESSAGE_MODE_PIPE 2
+#define FILE_TYPE_PRINTER 3
+#define FILE_TYPE_COMM_DEVICE 4
+#define FILE_TYPE_UNKNOWN 0xFFFF
+
+/* Lock types. */
+#define LOCKING_ANDX_EXCLUSIVE_LOCK 0x00
+#define LOCKING_ANDX_SHARED_LOCK 0x01
+#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
+#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
+#define LOCKING_ANDX_CANCEL_LOCK 0x08
+#define LOCKING_ANDX_LARGE_FILES 0x10
+
+/*
+ * Bits we test with.
+ */
+
+#define OPLOCK_NONE 0
+#define OPLOCK_EXCLUSIVE 1
+#define OPLOCK_BATCH 2
+#define OPLOCK_LEVEL_II 4
+
+#define CORE_OPLOCK_GRANTED (1<<5)
+#define EXTENDED_OPLOCK_GRANTED (1<<15)
+
+/*
+ * Return values for oplock types.
+ */
+
+#define NO_OPLOCK_RETURN 0
+#define EXCLUSIVE_OPLOCK_RETURN 1
+#define BATCH_OPLOCK_RETURN 2
+#define LEVEL_II_OPLOCK_RETURN 3
+
+/* oplock levels sent in oplock break */
+#define OPLOCK_BREAK_TO_NONE 0
+#define OPLOCK_BREAK_TO_LEVEL_II 1
+
+/* Filesystem Attributes. */
+#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
+#define FILE_CASE_PRESERVED_NAMES 0x00000002
+#define FILE_UNICODE_ON_DISK 0x00000004
+/* According to cifs9f, this is 4, not 8 */
+/* According to testing, this actually sets the security attribute! */
+#define FILE_PERSISTENT_ACLS 0x00000008
+#define FILE_FILE_COMPRESSION 0x00000010
+#define FILE_VOLUME_QUOTAS 0x00000020
+#define FILE_SUPPORTS_SPARSE_FILES 0x00000040
+#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080
+#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100
+#define FS_LFN_APIS 0x00004000
+#define FILE_VOLUME_IS_COMPRESSED 0x00008000
+#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
+#define FILE_SUPPORTS_ENCRYPTION 0x00020000
+#define FILE_NAMED_STREAMS 0x00040000
+#define FILE_READ_ONLY_VOLUME 0x00080000
+#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000
+
+/* ShareAccess field. */
+#define FILE_SHARE_NONE 0 /* Cannot be used in bitmask. */
+#define FILE_SHARE_READ 1
+#define FILE_SHARE_WRITE 2
+#define FILE_SHARE_DELETE 4
+
+/* Flags - combined with attributes. */
+#define FILE_FLAG_WRITE_THROUGH 0x80000000L
+#define FILE_FLAG_NO_BUFFERING 0x20000000L
+#define FILE_FLAG_RANDOM_ACCESS 0x10000000L
+#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000L
+#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000L
+#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000L
+#define FILE_FLAG_POSIX_SEMANTICS 0x01000000L
+
+/* CreateDisposition field. */
+#define FILE_SUPERSEDE 0 /* File exists overwrite/supersede. File not exist create. */
+#define FILE_OPEN 1 /* File exists open. File not exist fail. */
+#define FILE_CREATE 2 /* File exists fail. File not exist create. */
+#define FILE_OPEN_IF 3 /* File exists open. File not exist create. */
+#define FILE_OVERWRITE 4 /* File exists overwrite. File not exist fail. */
+#define FILE_OVERWRITE_IF 5 /* File exists overwrite. File not exist create. */
+
+/* CreateOptions field. */
+#define FILE_DIRECTORY_FILE 0x0001
+#define FILE_WRITE_THROUGH 0x0002
+#define FILE_SEQUENTIAL_ONLY 0x0004
+#define FILE_NO_INTERMEDIATE_BUFFERING 0x0008
+#define FILE_SYNCHRONOUS_IO_ALERT 0x0010 /* may be ignored */
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x0020 /* may be ignored */
+#define FILE_NON_DIRECTORY_FILE 0x0040
+#define FILE_CREATE_TREE_CONNECTION 0x0080 /* ignore, should be zero */
+#define FILE_COMPLETE_IF_OPLOCKED 0x0100 /* ignore, should be zero */
+#define FILE_NO_EA_KNOWLEDGE 0x0200
+#define FILE_EIGHT_DOT_THREE_ONLY 0x0400 /* aka OPEN_FOR_RECOVERY: ignore, should be zero */
+#define FILE_RANDOM_ACCESS 0x0800
+#define FILE_DELETE_ON_CLOSE 0x1000
+#define FILE_OPEN_BY_FILE_ID 0x2000
+#define FILE_OPEN_FOR_BACKUP_INTENT 0x4000
+#define FILE_NO_COMPRESSION 0x8000
+#define FILE_RESERVER_OPFILTER 0x00100000 /* ignore, should be zero */
+#define FILE_OPEN_REPARSE_POINT 0x00200000
+#define FILE_OPEN_NO_RECALL 0x00400000
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 /* ignore should be zero */
+
+/* Responses when opening a file. */
+#define FILE_WAS_SUPERSEDED 0
+#define FILE_WAS_OPENED 1
+#define FILE_WAS_CREATED 2
+#define FILE_WAS_OVERWRITTEN 3
+
+/* These are the trans subcommands */
+#define TRANSACT_SETNAMEDPIPEHANDLESTATE 0x01
+#define TRANSACT_DCERPCCMD 0x26
+#define TRANSACT_WAITNAMEDPIPEHANDLESTATE 0x53
+
+/* These are the TRANS2 sub commands */
+#define TRANSACT2_OPEN 0
+#define TRANSACT2_FINDFIRST 1
+#define TRANSACT2_FINDNEXT 2
+#define TRANSACT2_QFSINFO 3
+#define TRANSACT2_SETFSINFO 4
+#define TRANSACT2_QPATHINFO 5
+#define TRANSACT2_SETPATHINFO 6
+#define TRANSACT2_QFILEINFO 7
+#define TRANSACT2_SETFILEINFO 8
+#define TRANSACT2_FSCTL 9
+#define TRANSACT2_IOCTL 0xA
+#define TRANSACT2_FINDNOTIFYFIRST 0xB
+#define TRANSACT2_FINDNOTIFYNEXT 0xC
+#define TRANSACT2_MKDIR 0xD
+#define TRANSACT2_SESSION_SETUP 0xE
+#define TRANSACT2_GET_DFS_REFERRAL 0x10
+#define TRANSACT2_REPORT_DFS_INCONSISTANCY 0x11
+
+/* These are the NT transact sub commands. */
+#define NT_TRANSACT_CREATE 1
+#define NT_TRANSACT_IOCTL 2
+#define NT_TRANSACT_SET_SECURITY_DESC 3
+#define NT_TRANSACT_NOTIFY_CHANGE 4
+#define NT_TRANSACT_RENAME 5
+#define NT_TRANSACT_QUERY_SECURITY_DESC 6
+#define NT_TRANSACT_GET_USER_QUOTA 7
+#define NT_TRANSACT_SET_USER_QUOTA 8
+
+/* ioctl codes */
+#define IOCTL_QUERY_JOB_INFO 0x530060
+
+/* filesystem control codes */
+#define FSCTL_METHOD_BUFFERED 0x00000000
+#define FSCTL_METHOD_IN_DIRECT 0x00000001
+#define FSCTL_METHOD_OUT_DIRECT 0x00000002
+#define FSCTL_METHOD_NEITHER 0x00000003
+
+#define FSCTL_ACCESS_ANY 0x00000000
+#define FSCTL_ACCESS_READ 0x00004000
+#define FSCTL_ACCESS_WRITE 0x00008000
+
+#define IOCTL_DEV_TYPE_MASK 0xFFFF0000
+
+#define FSCTL_DFS 0x00060000
+#define FSCTL_DFS_GET_REFERRALS (FSCTL_DFS | FSCTL_ACCESS_ANY | 0x0194 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_DFS_GET_REFERRALS_EX (FSCTL_DFS | FSCTL_ACCESS_ANY | 0x01B0 | FSCTL_METHOD_BUFFERED)
+
+#define FSCTL_FILESYSTEM 0x00090000
+#define FSCTL_REQUEST_OPLOCK_LEVEL_1 (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0000 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_REQUEST_OPLOCK_LEVEL_2 (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0004 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_REQUEST_BATCH_OPLOCK (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0008 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x000C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OPBATCH_ACK_CLOSE_PENDING (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0010 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OPLOCK_BREAK_NOTIFY (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0014 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_GET_COMPRESSION (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x003C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_COMPRESSION (FSCTL_FILESYSTEM | FSCTL_ACCESS_READ \
+ | FSCTL_ACCESS_WRITE | 0x0040 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_FILESYS_GET_STATISTICS (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0060 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_GET_NTFS_VOLUME_DATA (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0064 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_IS_VOLUME_DIRTY (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0078 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_FIND_FILES_BY_SID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x008C | FSCTL_METHOD_NEITHER)
+#define FSCTL_SET_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0098 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_GET_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x009C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_DELETE_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00A0 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_REPARSE_POINT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00A4 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_GET_REPARSE_POINT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00A8 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_DELETE_REPARSE_POINT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00AC | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_OBJECT_ID_EXTENDED (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00BC | FSCTL_METHOD_BUFFERED)
+#define FSCTL_CREATE_OR_GET_OBJECT_ID (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00C0 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_SPARSE (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00C4 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_ZERO_DATA (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x00C8 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_ZERO_ON_DEALLOCATION (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0194 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_READ_FILE_USN_DATA (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00EB | FSCTL_METHOD_BUFFERED)
+#define FSCTL_WRITE_USN_CLOSE_RECORD (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00EF | FSCTL_METHOD_BUFFERED)
+#define FSCTL_QUERY_ALLOCATED_RANGES (FSCTL_FILESYSTEM | FSCTL_ACCESS_READ | 0x00CC | FSCTL_METHOD_NEITHER)
+#define FSCTL_QUERY_ON_DISK_VOLUME_INFO (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x013C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_QUERY_SPARING_INFO (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x0138 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_FILE_LEVEL_TRIM (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x0208 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OFFLOAD_READ (FSCTL_FILESYSTEM | FSCTL_ACCESS_READ | 0x0264 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_OFFLOAD_WRITE (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x0268 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SET_INTEGRITY_INFORMATION (FSCTL_FILESYSTEM | FSCTL_ACCESS_READ \
+ | FSCTL_ACCESS_WRITE | 0x0280 | FSCTL_METHOD_BUFFERED)
+/* this one is really FSCTL_DUPLICATE_EXTENTS_TO_FILE in the MS docs: */
+#define FSCTL_DUP_EXTENTS_TO_FILE (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x0344 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_DUPLICATE_EXTENTS_TO_FILE_EX (FSCTL_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x03E8 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_STORAGE_QOS_CONTROL (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0350 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SVHDX_SYNC_TUNNEL_REQUEST (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0304 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_QUERY_SHARED_VIRTUAL_DISK_SUPPORT (FSCTL_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0300 | FSCTL_METHOD_BUFFERED)
+
+#define FSCTL_NAMED_PIPE 0x00110000
+#define FSCTL_PIPE_PEEK (FSCTL_NAMED_PIPE | FSCTL_ACCESS_READ | 0x000C | FSCTL_METHOD_BUFFERED)
+#define FSCTL_NAMED_PIPE_READ_WRITE (FSCTL_NAMED_PIPE | FSCTL_ACCESS_READ \
+ | FSCTL_ACCESS_WRITE | 0x0014 | FSCTL_METHOD_NEITHER)
+#define FSCTL_PIPE_TRANSCEIVE FSCTL_NAMED_PIPE_READ_WRITE /* SMB2 function name */
+#define FSCTL_PIPE_WAIT (FSCTL_NAMED_PIPE | FSCTL_ACCESS_ANY | 0x0018 | FSCTL_METHOD_BUFFERED)
+
+#define FSCTL_NETWORK_FILESYSTEM 0x00140000
+#define FSCTL_GET_SHADOW_COPY_DATA (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_READ | 0x0064 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SRV_ENUM_SNAPS FSCTL_GET_SHADOW_COPY_DATA /* SMB2 function name */
+#define FSCTL_SRV_REQUEST_RESUME_KEY (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0078 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_SRV_COPYCHUNK (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_READ | 0x00F0 | FSCTL_METHOD_OUT_DIRECT)
+#define FSCTL_SRV_COPYCHUNK_WRITE (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_WRITE | 0x00F0 | FSCTL_METHOD_OUT_DIRECT)
+#define FSCTL_SRV_READ_HASH (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_READ| 0x01B8 | FSCTL_METHOD_NEITHER)
+#define FSCTL_LMR_REQ_RESILIENCY (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x01D4 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_LMR_SET_LINK_TRACKING_INFORMATION \
+ (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x00EC | FSCTL_METHOD_BUFFERED)
+#define FSCTL_QUERY_NETWORK_INTERFACE_INFO \
+ (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x01FC | FSCTL_METHOD_BUFFERED)
+
+/*
+ * FSCTL_VALIDATE_NEGOTIATE_INFO_224 was used used in
+ * Windows 8 server beta with SMB 2.24
+ */
+#define FSCTL_VALIDATE_NEGOTIATE_INFO_224 \
+ (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0200 | FSCTL_METHOD_BUFFERED)
+#define FSCTL_VALIDATE_NEGOTIATE_INFO (FSCTL_NETWORK_FILESYSTEM | FSCTL_ACCESS_ANY | 0x0204 | FSCTL_METHOD_BUFFERED)
+
+/*
+ * For testing various details we use special codes via
+ * smbtorture in order to test failures
+ */
+#define FSCTL_SMBTORTURE 0x83840000
+#define FSCTL_SMBTORTURE_FORCE_UNACKED_TIMEOUT \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0000 | FSCTL_METHOD_NEITHER)
+#define FSCTL_SMBTORTURE_IOCTL_RESPONSE_BODY_PADDING8 \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0010 | FSCTL_METHOD_NEITHER)
+#define FSCTL_SMBTORTURE_GLOBAL_READ_RESPONSE_BODY_PADDING8 \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0020 | FSCTL_METHOD_NEITHER)
+#define FSCTL_SMBTORTURE_FSP_ASYNC_SLEEP \
+ (FSCTL_SMBTORTURE | FSCTL_ACCESS_WRITE | 0x0040 | FSCTL_METHOD_NEITHER)
+
+/*
+ * A few values from [MS-FSCC] 2.1.2.1 Reparse Tags
+ */
+
+#define IO_REPARSE_TAG_RESERVED_ZERO 0x00000000
+#define IO_REPARSE_TAG_SYMLINK 0xA000000C
+#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
+#define IO_REPARSE_TAG_HSM 0xC0000004
+#define IO_REPARSE_TAG_SIS 0x80000007
+#define IO_REPARSE_TAG_DFS 0x8000000A
+#define IO_REPARSE_TAG_NFS 0x80000014
+
+/*
+ * Sub-types for IO_REPARSE_TAG_NFS from [MS-FSCC] 2.1.2.6 Network
+ * File System (NFS) Reparse Data Buffer
+ */
+#define NFS_SPECFILE_LNK 0x00000000014B4E4C
+#define NFS_SPECFILE_CHR 0x0000000000524843
+#define NFS_SPECFILE_BLK 0x00000000004B4C42
+#define NFS_SPECFILE_FIFO 0x000000004F464946
+#define NFS_SPECFILE_SOCK 0x000000004B434F53
+
+/*
+ * Flag from [MS-FSCC] 2.1.2.4 Symbolic Link Reparse Data Buffer
+ */
+#define SYMLINK_FLAG_RELATIVE 0x00000001
+
+/*
+ * Symlink error tag from [MS-SMB2] 2.2.2.2.1 Symbolic Link Error Response
+ */
+#define SYMLINK_ERROR_TAG 0x4C4D5953
+
+/*
+ * Flags according to answer from Dochelp:
+ * https://lists.samba.org/archive/cifs-protocol/2022-November/003909.html
+ */
+#define SYMLINK_ADMIN 0x20000000 /* The symlink creator is an admin */
+#define SYMLINK_UNTRUSTED 0x10000000 /* The symlink creator is untrusted */
+#define SYMLINK_TRUST_UNKNOWN 0x00000000 /* The symlink creator is unknown/legacy */
+
+#define SYMLINK_TRUST_MASK 0x30000000 /* Encodes the redirection trust level (maps to REDIRECTION_TRUST_LEVEL) */
+#define SYMLINK_TRUST_SHIFT 28 /* Bits to shift to convert to/from REDIRECTION_TRUST_LEVEL */
+
+#endif /* _SMB_CONSTANTS_H */
diff --git a/libcli/smb/smb_seal.c b/libcli/smb/smb_seal.c
new file mode 100644
index 0000000..079744c
--- /dev/null
+++ b/libcli/smb/smb_seal.c
@@ -0,0 +1,220 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Transport encryption (sealing) code.
+ 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 "smb_common.h"
+#ifdef HAVE_KRB5
+#include "lib/krb5_wrap/krb5_samba.h"
+#endif
+#include "auth/gensec/gensec.h"
+#include "libcli/smb/smb_seal.h"
+
+#undef malloc
+
+/******************************************************************************
+ Pull out the encryption context for this packet. 0 means global context.
+******************************************************************************/
+
+NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16_t *p_enc_ctx_num)
+{
+ if (smb_len_nbt(buf) < 8) {
+ return NT_STATUS_INVALID_BUFFER_SIZE;
+ }
+
+ if (buf[4] == 0xFF) {
+ if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
+ /* Not an encrypted buffer. */
+ return NT_STATUS_NOT_FOUND;
+ }
+ if (buf[5] == 'E') {
+ *p_enc_ctx_num = SVAL(buf,6);
+ return NT_STATUS_OK;
+ }
+ }
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
+/*******************************************************************
+ Set the length and marker of an encrypted smb packet.
+********************************************************************/
+
+static void smb_set_enclen(char *buf,int len,uint16_t enc_ctx_num)
+{
+ _smb_setlen_tcp(buf,len);
+
+ SCVAL(buf,4,0xFF);
+ SCVAL(buf,5,'E');
+ SSVAL(buf,6,enc_ctx_num);
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Is encryption turned on ?
+******************************************************************************/
+
+bool common_encryption_on(struct smb_trans_enc_state *es)
+{
+ return ((es != NULL) && es->enc_on);
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ GENSEC decrypt an incoming buffer.
+******************************************************************************/
+
+static NTSTATUS common_gensec_decrypt_buffer(struct gensec_security *gensec,
+ char *buf)
+{
+ NTSTATUS status;
+ size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
+ DATA_BLOB in_buf, out_buf;
+ TALLOC_CTX *frame;
+
+ if (buf_len < 8) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ frame = talloc_stackframe();
+
+ in_buf = data_blob_const(buf + 8, buf_len - 8);
+
+ status = gensec_unwrap(gensec, frame, &in_buf, &out_buf);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap failed. Error %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ if (out_buf.length > in_buf.length) {
+ DEBUG(0,("common_gensec_decrypt_buffer: gensec_unwrap size (%u) too large (%u) !\n",
+ (unsigned int)out_buf.length,
+ (unsigned int)in_buf.length ));
+ TALLOC_FREE(frame);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ memcpy(buf + 8, out_buf.data, out_buf.length);
+
+ /* Reset the length and overwrite the header. */
+ smb_setlen_nbt(buf, out_buf.length + 4);
+
+ TALLOC_FREE(frame);
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ NTLM encrypt an outgoing buffer. Return the encrypted pointer in ppbuf_out.
+******************************************************************************/
+
+static NTSTATUS common_gensec_encrypt_buffer(struct gensec_security *gensec,
+ uint16_t enc_ctx_num,
+ char *buf,
+ char **ppbuf_out)
+{
+ NTSTATUS status;
+ DATA_BLOB in_buf, out_buf;
+ size_t buf_len = smb_len_nbt(buf) + 4; /* Don't forget the 4 length bytes. */
+ TALLOC_CTX *frame;
+
+ *ppbuf_out = NULL;
+
+ if (buf_len < 8) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+ in_buf = data_blob_const(buf + 8, buf_len - 8);
+
+ frame = talloc_stackframe();
+
+ status = gensec_wrap(gensec, frame, &in_buf, &out_buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("common_gensec_encrypt_buffer: gensec_wrap failed. Error %s\n",
+ nt_errstr(status)));
+ TALLOC_FREE(frame);
+ return status;
+ }
+
+ *ppbuf_out = (char *)malloc(out_buf.length + 8); /* We know this can't wrap. */
+ if (!*ppbuf_out) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ memcpy(*ppbuf_out+8, out_buf.data, out_buf.length);
+ smb_set_enclen(*ppbuf_out, out_buf.length + 4, enc_ctx_num);
+
+ TALLOC_FREE(frame);
+
+ return NT_STATUS_OK;
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Encrypt an outgoing buffer. Return the alloced encrypted pointer in buf_out.
+******************************************************************************/
+
+NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out)
+{
+ if (!common_encryption_on(es)) {
+ /* Not encrypting. */
+ *buf_out = buffer;
+ return NT_STATUS_OK;
+ }
+
+ return common_gensec_encrypt_buffer(es->gensec_security, es->enc_ctx_num, buffer, buf_out);
+}
+
+/******************************************************************************
+ Generic code for client and server.
+ Decrypt an incoming SMB buffer. Replaces the data within it.
+ New data must be less than or equal to the current length.
+******************************************************************************/
+
+NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf)
+{
+ if (!common_encryption_on(es)) {
+ /* Not decrypting. */
+ return NT_STATUS_OK;
+ }
+
+ return common_gensec_decrypt_buffer(es->gensec_security, buf);
+}
+
+/******************************************************************************
+ Free an encryption-allocated buffer.
+******************************************************************************/
+
+void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf)
+{
+ uint16_t enc_ctx_num;
+
+ if (!common_encryption_on(es)) {
+ return;
+ }
+
+ if (!NT_STATUS_IS_OK(get_enc_ctx_num((const uint8_t *)buf,
+ &enc_ctx_num))) {
+ return;
+ }
+
+ SAFE_FREE(buf);
+}
diff --git a/libcli/smb/smb_seal.h b/libcli/smb/smb_seal.h
new file mode 100644
index 0000000..f47f904
--- /dev/null
+++ b/libcli/smb/smb_seal.h
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Transport encryption code.
+ 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/>.
+*/
+
+#ifndef _HEADER_SMB_CRYPT_H
+#define _HEADER_SMB_CRYPT_H
+
+struct smb_trans_enc_state {
+ uint16_t enc_ctx_num;
+ bool enc_on;
+ struct gensec_security *gensec_security;
+};
+
+/* The following definitions come from smb_seal.c */
+
+NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16_t *p_enc_ctx_num);
+bool common_encryption_on(struct smb_trans_enc_state *es);
+NTSTATUS common_encrypt_buffer(struct smb_trans_enc_state *es, char *buffer, char **buf_out);
+NTSTATUS common_decrypt_buffer(struct smb_trans_enc_state *es, char *buf);
+void common_free_enc_buffer(struct smb_trans_enc_state *es, char *buf);
+
+#endif /* _HEADER_SMB_CRYPT_H */
diff --git a/libcli/smb/smb_signing.c b/libcli/smb/smb_signing.c
new file mode 100644
index 0000000..d50c963
--- /dev/null
+++ b/libcli/smb/smb_signing.c
@@ -0,0 +1,552 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Signing Code
+ Copyright (C) Jeremy Allison 2003.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Copyright (C) Stefan Metzmacher 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 "smb_common.h"
+#include "smb_signing.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
+/* Used by the SMB1 signing functions. */
+
+struct smb1_signing_state {
+ /* is signing locally allowed */
+ bool allowed;
+
+ /* is signing locally desired */
+ bool desired;
+
+ /* is signing locally mandatory */
+ bool mandatory;
+
+ /* is signing negotiated by the peer */
+ bool negotiated;
+
+ bool active; /* Have I ever seen a validly signed packet? */
+
+ /* mac_key.length > 0 means signing is started */
+ DATA_BLOB mac_key;
+
+ /* the next expected seqnum */
+ uint32_t seqnum;
+
+ TALLOC_CTX *mem_ctx;
+ void *(*alloc_fn)(TALLOC_CTX *mem_ctx, size_t len);
+ void (*free_fn)(TALLOC_CTX *mem_ctx, void *ptr);
+};
+
+static void smb1_signing_reset_info(struct smb1_signing_state *si)
+{
+ si->active = false;
+ si->seqnum = 0;
+
+ if (si->free_fn) {
+ si->free_fn(si->mem_ctx, si->mac_key.data);
+ } else {
+ talloc_free(si->mac_key.data);
+ }
+ si->mac_key.data = NULL;
+ si->mac_key.length = 0;
+}
+
+struct smb1_signing_state *smb1_signing_init_ex(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool desired,
+ bool mandatory,
+ void *(*alloc_fn)(TALLOC_CTX *, size_t),
+ void (*free_fn)(TALLOC_CTX *, void *))
+{
+ struct smb1_signing_state *si;
+
+ if (alloc_fn) {
+ void *p = alloc_fn(mem_ctx, sizeof(struct smb1_signing_state));
+ if (p == NULL) {
+ return NULL;
+ }
+ memset(p, 0, sizeof(struct smb1_signing_state));
+ si = (struct smb1_signing_state *)p;
+ si->mem_ctx = mem_ctx;
+ si->alloc_fn = alloc_fn;
+ si->free_fn = free_fn;
+ } else {
+ si = talloc_zero(mem_ctx, struct smb1_signing_state);
+ if (si == NULL) {
+ return NULL;
+ }
+ }
+
+ if (mandatory) {
+ desired = true;
+ }
+
+ if (desired) {
+ allowed = true;
+ }
+
+ si->allowed = allowed;
+ si->desired = desired;
+ si->mandatory = mandatory;
+
+ return si;
+}
+
+struct smb1_signing_state *smb1_signing_init(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool desired,
+ bool mandatory)
+{
+ return smb1_signing_init_ex(mem_ctx, allowed, desired, mandatory,
+ NULL, NULL);
+}
+
+static bool smb1_signing_good(struct smb1_signing_state *si,
+ bool good, uint32_t seq)
+{
+ if (good) {
+ if (!si->active) {
+ si->active = true;
+ }
+ return true;
+ }
+
+ if (!si->mandatory && !si->active) {
+ /* Non-mandatory signing - just turn off if this is the first bad packet.. */
+ DBG_INFO("signing negotiated but not required and peer\n"
+ "isn't sending correct signatures. Turning off.\n");
+ smb1_signing_reset_info(si);
+ return true;
+ }
+
+ /* Mandatory signing or bad packet after signing started - fail and disconnect. */
+ DBG_ERR("BAD SIG: seq %u\n", (unsigned int)seq);
+ return false;
+}
+
+static NTSTATUS smb1_signing_md5(const DATA_BLOB *mac_key,
+ const uint8_t *hdr, size_t len,
+ uint32_t seq_number,
+ uint8_t calc_md5_mac[16])
+{
+ const size_t offset_end_of_sig = (HDR_SS_FIELD + 8);
+ uint8_t sequence_buf[8];
+ gnutls_hash_hd_t hash_hnd = NULL;
+ int rc;
+
+ /*
+ * Firstly put the sequence number into the first 4 bytes.
+ * and zero out the next 4 bytes.
+ *
+ * We do this here, to avoid modifying the packet.
+ */
+
+ DBG_DEBUG("sequence number %u\n", seq_number );
+
+ SIVAL(sequence_buf, 0, seq_number);
+ SIVAL(sequence_buf, 4, 0);
+
+ /*
+ * Calculate the 16 byte MAC - but don't alter the data in the
+ * incoming packet.
+ *
+ * This makes for a bit of fussing about, but it's not too bad.
+ */
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ /* Initialise with the key. */
+ rc = gnutls_hash(hash_hnd, mac_key->data, mac_key->length);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ /* Copy in the first bit of the SMB header. */
+ rc = gnutls_hash(hash_hnd, hdr, HDR_SS_FIELD);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ /* Copy in the sequence number, instead of the signature. */
+ rc = gnutls_hash(hash_hnd, sequence_buf, sizeof(sequence_buf));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ /* Copy in the rest of the packet in, skipping the signature. */
+ rc = gnutls_hash(hash_hnd, hdr + offset_end_of_sig, len - offset_end_of_sig);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+
+ gnutls_hash_deinit(hash_hnd, calc_md5_mac);
+
+ return NT_STATUS_OK;
+}
+
+uint32_t smb1_signing_next_seqnum(struct smb1_signing_state *si, bool oneway)
+{
+ uint32_t seqnum;
+
+ if (si->mac_key.length == 0) {
+ return 0;
+ }
+
+ seqnum = si->seqnum;
+ if (oneway) {
+ si->seqnum += 1;
+ } else {
+ si->seqnum += 2;
+ }
+
+ return seqnum;
+}
+
+void smb1_signing_cancel_reply(struct smb1_signing_state *si, bool oneway)
+{
+ if (si->mac_key.length == 0) {
+ return;
+ }
+
+ if (oneway) {
+ si->seqnum -= 1;
+ } else {
+ si->seqnum -= 2;
+ }
+}
+
+NTSTATUS smb1_signing_sign_pdu(struct smb1_signing_state *si,
+ uint8_t *outhdr, size_t len,
+ uint32_t seqnum)
+{
+ uint8_t calc_md5_mac[16];
+ uint8_t com;
+ uint8_t flags;
+
+ if (si->mac_key.length == 0) {
+ if (!si->negotiated) {
+ return NT_STATUS_OK;
+ }
+ }
+
+ /* JRA Paranioa test - we should be able to get rid of this... */
+ if (len < (HDR_SS_FIELD + 8)) {
+ DBG_WARNING("Logic error. "
+ "Can't check signature on short packet! smb_len = %u\n",
+ (unsigned)len);
+ abort();
+ }
+
+ com = SVAL(outhdr, HDR_COM);
+ flags = SVAL(outhdr, HDR_FLG);
+
+ if (!(flags & FLAG_REPLY)) {
+ uint16_t flags2 = SVAL(outhdr, HDR_FLG2);
+ /*
+ * If this is a request, specify what is
+ * supported or required by the client
+ */
+ if (si->negotiated && si->desired) {
+ flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
+ }
+ if (si->negotiated && si->mandatory) {
+ flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED;
+ }
+ SSVAL(outhdr, HDR_FLG2, flags2);
+ }
+
+ if (si->mac_key.length == 0) {
+ /* I wonder what BSRSPYL stands for - but this is what MS
+ actually sends! */
+ if (com == SMBsesssetupX) {
+ memcpy(calc_md5_mac, "BSRSPYL ", 8);
+ } else {
+ memset(calc_md5_mac, 0, 8);
+ }
+ } else {
+ NTSTATUS status;
+
+ status = smb1_signing_md5(&si->mac_key,
+ outhdr,
+ len,
+ seqnum,
+ calc_md5_mac);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ DBG_DEBUG("sent SMB signature of\n");
+ dump_data(10, calc_md5_mac, 8);
+
+ memcpy(&outhdr[HDR_SS_FIELD], calc_md5_mac, 8);
+
+/* outhdr[HDR_SS_FIELD+2]=0;
+ Uncomment this to test if the remote server actually verifies signatures...*/
+
+ return NT_STATUS_OK;
+}
+
+bool smb1_signing_check_pdu(struct smb1_signing_state *si,
+ const uint8_t *inhdr, size_t len,
+ uint32_t seqnum)
+{
+ bool good;
+ uint8_t calc_md5_mac[16];
+ const uint8_t *reply_sent_mac;
+ NTSTATUS status;
+
+ if (si->mac_key.length == 0) {
+ return true;
+ }
+
+ if (len < (HDR_SS_FIELD + 8)) {
+ DBG_WARNING("Can't check signature "
+ "on short packet! smb_len = %u\n",
+ (unsigned)len);
+ return false;
+ }
+
+ status = smb1_signing_md5(&si->mac_key,
+ inhdr,
+ len,
+ seqnum,
+ calc_md5_mac);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Failed to calculate signing mac: %s\n",
+ nt_errstr(status));
+ return false;
+ }
+
+ reply_sent_mac = &inhdr[HDR_SS_FIELD];
+ good = mem_equal_const_time(reply_sent_mac, calc_md5_mac, 8);
+
+ if (!good) {
+ int i;
+ const int sign_range = 5;
+
+ DBG_INFO("BAD SIG: wanted SMB signature of\n");
+ dump_data(5, calc_md5_mac, 8);
+
+ DBG_INFO("BAD SIG: got SMB signature of\n");
+ dump_data(5, reply_sent_mac, 8);
+
+ for (i = -sign_range; i < sign_range; i++) {
+ smb1_signing_md5(&si->mac_key, inhdr, len,
+ seqnum+i, calc_md5_mac);
+ if (mem_equal_const_time(reply_sent_mac, calc_md5_mac, 8)) {
+ DBG_ERR("out of seq. seq num %u matches. "
+ "We were expecting seq %u\n",
+ (unsigned int)seqnum+i,
+ (unsigned int)seqnum);
+ break;
+ }
+ }
+ } else {
+ DBG_DEBUG("seq %u: got good SMB signature of\n",
+ (unsigned int)seqnum);
+ dump_data(10, reply_sent_mac, 8);
+ }
+
+ return smb1_signing_good(si, good, seqnum);
+}
+
+bool smb1_signing_activate(struct smb1_signing_state *si,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response)
+{
+ size_t len;
+ off_t ofs;
+
+ if (!user_session_key.length) {
+ return false;
+ }
+
+ if (!si->negotiated) {
+ return false;
+ }
+
+ if (si->active) {
+ return false;
+ }
+
+ if (si->mac_key.length > 0) {
+ return false;
+ }
+
+ smb1_signing_reset_info(si);
+
+ len = response.length + user_session_key.length;
+ if (si->alloc_fn) {
+ si->mac_key.data = (uint8_t *)si->alloc_fn(si->mem_ctx, len);
+ if (si->mac_key.data == NULL) {
+ return false;
+ }
+ } else {
+ si->mac_key.data = (uint8_t *)talloc_size(si, len);
+ if (si->mac_key.data == NULL) {
+ return false;
+ }
+ }
+ si->mac_key.length = len;
+
+ ofs = 0;
+ memcpy(&si->mac_key.data[ofs], user_session_key.data, user_session_key.length);
+
+ DBG_DEBUG("user_session_key\n");
+ dump_data(10, user_session_key.data, user_session_key.length);
+
+ if (response.length) {
+ ofs = user_session_key.length;
+ memcpy(&si->mac_key.data[ofs], response.data, response.length);
+ DBG_DEBUG("response_data\n");
+ dump_data(10, response.data, response.length);
+ } else {
+ DBG_DEBUG("NULL response_data\n");
+ }
+
+ dump_data_pw("smb1_signing_activate: mac key is:\n",
+ si->mac_key.data, si->mac_key.length);
+
+ /* Initialise the sequence number */
+ si->seqnum = 2;
+
+ return true;
+}
+
+bool smb1_signing_is_active(struct smb1_signing_state *si)
+{
+ return si->active;
+}
+
+bool smb1_signing_is_desired(struct smb1_signing_state *si)
+{
+ return si->desired;
+}
+
+bool smb1_signing_is_mandatory(struct smb1_signing_state *si)
+{
+ return si->mandatory;
+}
+
+bool smb1_signing_set_negotiated(struct smb1_signing_state *si,
+ bool allowed, bool mandatory)
+{
+ if (si->active) {
+ return true;
+ }
+
+ if (mandatory) {
+ allowed = true;
+ }
+
+ if (!si->allowed && mandatory) {
+ return false;
+ }
+
+ if (si->mandatory && !allowed) {
+ return false;
+ }
+
+ if (si->mandatory) {
+ si->negotiated = true;
+ return true;
+ }
+
+ if (mandatory) {
+ si->negotiated = true;
+ return true;
+ }
+
+ if (!si->desired) {
+ si->negotiated = false;
+ return true;
+ }
+
+ if (si->desired && allowed) {
+ si->negotiated = true;
+ return true;
+ }
+
+ si->negotiated = false;
+ return true;
+}
+
+bool smb1_signing_is_negotiated(struct smb1_signing_state *si)
+{
+ return si->negotiated;
+}
+
+NTSTATUS smb1_key_derivation(const uint8_t *KI,
+ size_t KI_len,
+ uint8_t KO[16])
+{
+ int rc;
+ static const uint8_t SSKeyHash[256] = {
+ 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79,
+ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
+ 0x72, 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x55,
+ 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x79, 0x07,
+ 0x6e, 0x28, 0x2e, 0x69, 0x88, 0x10, 0xb3, 0xdb,
+ 0x01, 0x55, 0x72, 0xfb, 0x74, 0x14, 0xfb, 0xc4,
+ 0xc5, 0xaf, 0x3b, 0x41, 0x65, 0x32, 0x17, 0xba,
+ 0xa3, 0x29, 0x08, 0xc1, 0xde, 0x16, 0x61, 0x7e,
+ 0x66, 0x98, 0xa4, 0x0b, 0xfe, 0x06, 0x83, 0x53,
+ 0x4d, 0x05, 0xdf, 0x6d, 0xa7, 0x51, 0x10, 0x73,
+ 0xc5, 0x50, 0xdc, 0x5e, 0xf8, 0x21, 0x46, 0xaa,
+ 0x96, 0x14, 0x33, 0xd7, 0x52, 0xeb, 0xaf, 0x1f,
+ 0xbf, 0x36, 0x6c, 0xfc, 0xb7, 0x1d, 0x21, 0x19,
+ 0x81, 0xd0, 0x6b, 0xfa, 0x77, 0xad, 0xbe, 0x18,
+ 0x78, 0xcf, 0x10, 0xbd, 0xd8, 0x78, 0xf7, 0xd3,
+ 0xc6, 0xdf, 0x43, 0x32, 0x19, 0xd3, 0x9b, 0xa8,
+ 0x4d, 0x9e, 0xaa, 0x41, 0xaf, 0xcb, 0xc6, 0xb9,
+ 0x34, 0xe7, 0x48, 0x25, 0xd4, 0x88, 0xc4, 0x51,
+ 0x60, 0x38, 0xd9, 0x62, 0xe8, 0x8d, 0x5b, 0x83,
+ 0x92, 0x7f, 0xb5, 0x0e, 0x1c, 0x2d, 0x06, 0x91,
+ 0xc3, 0x75, 0xb3, 0xcc, 0xf8, 0xf7, 0x92, 0x91,
+ 0x0b, 0x3d, 0xa1, 0x10, 0x5b, 0xd5, 0x0f, 0xa8,
+ 0x3f, 0x5d, 0x13, 0x83, 0x0a, 0x6b, 0x72, 0x93,
+ 0x14, 0x59, 0xd5, 0xab, 0xde, 0x26, 0x15, 0x6d,
+ 0x60, 0x67, 0x71, 0x06, 0x6e, 0x3d, 0x0d, 0xa7,
+ 0xcb, 0x70, 0xe9, 0x08, 0x5c, 0x99, 0xfa, 0x0a,
+ 0x5f, 0x3d, 0x44, 0xa3, 0x8b, 0xc0, 0x8d, 0xda,
+ 0xe2, 0x68, 0xd0, 0x0d, 0xcd, 0x7f, 0x3d, 0xf8,
+ 0x73, 0x7e, 0x35, 0x7f, 0x07, 0x02, 0x0a, 0xb5,
+ 0xe9, 0xb7, 0x87, 0xfb, 0xa1, 0xbf, 0xcb, 0x32,
+ 0x31, 0x66, 0x09, 0x48, 0x88, 0xcc, 0x18, 0xa3,
+ 0xb2, 0x1f, 0x1f, 0x1b, 0x90, 0x4e, 0xd7, 0xe1
+ };
+
+ /* The callers passing down KI_len of 16 so no need to limit to 64 */
+ rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
+ KI,
+ KI_len,
+ SSKeyHash,
+ sizeof(SSKeyHash),
+ KO);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/smb/smb_signing.h b/libcli/smb/smb_signing.h
new file mode 100644
index 0000000..9f2f3c1
--- /dev/null
+++ b/libcli/smb/smb_signing.h
@@ -0,0 +1,58 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB Signing Code
+ Copyright (C) Jeremy Allison 2003.
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
+ Copyright (C) Stefan Metzmacher 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_SIGNING_H_
+#define _SMB_SIGNING_H_
+
+struct smb1_signing_state;
+
+struct smb1_signing_state *smb1_signing_init(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool desired,
+ bool mandatory);
+struct smb1_signing_state *smb1_signing_init_ex(TALLOC_CTX *mem_ctx,
+ bool allowed,
+ bool desired,
+ bool mandatory,
+ void *(*alloc_fn)(TALLOC_CTX *, size_t),
+ void (*free_fn)(TALLOC_CTX *, void *));
+uint32_t smb1_signing_next_seqnum(struct smb1_signing_state *si, bool oneway);
+void smb1_signing_cancel_reply(struct smb1_signing_state *si, bool oneway);
+NTSTATUS smb1_signing_sign_pdu(struct smb1_signing_state *si,
+ uint8_t *outhdr, size_t len,
+ uint32_t seqnum);
+bool smb1_signing_check_pdu(struct smb1_signing_state *si,
+ const uint8_t *inhdr, size_t len,
+ uint32_t seqnum);
+bool smb1_signing_activate(struct smb1_signing_state *si,
+ const DATA_BLOB user_session_key,
+ const DATA_BLOB response);
+bool smb1_signing_is_active(struct smb1_signing_state *si);
+bool smb1_signing_is_desired(struct smb1_signing_state *si);
+bool smb1_signing_is_mandatory(struct smb1_signing_state *si);
+bool smb1_signing_set_negotiated(struct smb1_signing_state *si,
+ bool allowed, bool mandatory);
+bool smb1_signing_is_negotiated(struct smb1_signing_state *si);
+NTSTATUS smb1_key_derivation(const uint8_t *KI,
+ size_t KI_len,
+ uint8_t KO[16]);
+
+#endif /* _SMB_SIGNING_H_ */
diff --git a/libcli/smb/smb_unix_ext.h b/libcli/smb/smb_unix_ext.h
new file mode 100644
index 0000000..2f2357d
--- /dev/null
+++ b/libcli/smb/smb_unix_ext.h
@@ -0,0 +1,458 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB transaction2 handling
+
+ Copyright (C) James Peach 2007
+ Copyright (C) Jeremy Allison 1994-2002.
+
+ Extensively modified by Andrew Tridgell, 1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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_UNIX_EXT_H__
+#define __SMB_UNIX_EXT_H__
+
+/* UNIX CIFS Extensions - created by HP */
+/*
+ * UNIX CIFS Extensions have the range 0x200 - 0x2FF reserved.
+ * Supposedly Microsoft have agreed to this.
+ */
+
+#define MIN_UNIX_INFO_LEVEL 0x200
+#define MAX_UNIX_INFO_LEVEL 0x2FF
+
+#define SMB_QUERY_FILE_UNIX_BASIC 0x200 /* UNIX File Info*/
+#define SMB_SET_FILE_UNIX_BASIC 0x200
+#define SMB_SET_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
+
+#define SMB_MODE_NO_CHANGE 0xFFFFFFFF /* file mode value which */
+ /* means "don't change it" */
+#define SMB_UID_NO_CHANGE 0xFFFFFFFF
+#define SMB_GID_NO_CHANGE 0xFFFFFFFF
+
+#define SMB_SIZE_NO_CHANGE_LO 0xFFFFFFFF
+#define SMB_SIZE_NO_CHANGE_HI 0xFFFFFFFF
+
+#define SMB_TIME_NO_CHANGE_LO 0xFFFFFFFF
+#define SMB_TIME_NO_CHANGE_HI 0xFFFFFFFF
+
+/*
+Offset Size Name
+0 LARGE_INTEGER EndOfFile File size
+8 LARGE_INTEGER Blocks Number of bytes used on disk (st_blocks).
+16 LARGE_INTEGER CreationTime Creation time
+24 LARGE_INTEGER LastAccessTime Last access time
+32 LARGE_INTEGER LastModificationTime Last modification time
+40 LARGE_INTEGER Uid Numeric user id for the owner
+48 LARGE_INTEGER Gid Numeric group id of owner
+56 ULONG Type Enumeration specifying the pathname type:
+ 0 -- File
+ 1 -- Directory
+ 2 -- Symbolic link
+ 3 -- Character device
+ 4 -- Block device
+ 5 -- FIFO (named pipe)
+ 6 -- Unix domain socket
+
+60 LARGE_INTEGER devmajor Major device number if type is device
+68 LARGE_INTEGER devminor Minor device number if type is device
+76 LARGE_INTEGER uniqueid This is a server-assigned unique id for the file. The client
+ will typically map this onto an inode number. The scope of
+ uniqueness is the share.
+84 LARGE_INTEGER permissions Standard UNIX file permissions - see below.
+92 LARGE_INTEGER nlinks The number of directory entries that map to this entry
+ (number of hard links)
+
+100 - end.
+*/
+
+#define SMB_FILE_UNIX_BASIC_SIZE 100
+
+/* UNIX filetype mappings. */
+
+#define UNIX_TYPE_FILE 0
+#define UNIX_TYPE_DIR 1
+#define UNIX_TYPE_SYMLINK 2
+#define UNIX_TYPE_CHARDEV 3
+#define UNIX_TYPE_BLKDEV 4
+#define UNIX_TYPE_FIFO 5
+#define UNIX_TYPE_SOCKET 6
+#define UNIX_TYPE_UNKNOWN 0xFFFFFFFF
+
+/*
+ * Oh this is fun. "Standard UNIX permissions" has no
+ * meaning in POSIX. We need to define the mapping onto
+ * and off the wire as this was not done in the original HP
+ * spec. JRA.
+ */
+
+#define UNIX_X_OTH 0000001
+#define UNIX_W_OTH 0000002
+#define UNIX_R_OTH 0000004
+#define UNIX_X_GRP 0000010
+#define UNIX_W_GRP 0000020
+#define UNIX_R_GRP 0000040
+#define UNIX_X_USR 0000100
+#define UNIX_W_USR 0000200
+#define UNIX_R_USR 0000400
+#define UNIX_STICKY 0001000
+#define UNIX_SET_GID 0002000
+#define UNIX_SET_UID 0004000
+
+/* Masks for the above */
+#define UNIX_OTH_MASK 0000007
+#define UNIX_GRP_MASK 0000070
+#define UNIX_USR_MASK 0000700
+#define UNIX_PERM_MASK 0000777
+#define UNIX_EXTRA_MASK 0007000
+#define UNIX_ALL_MASK 0007777
+
+/* Flags for chflags (CIFS_UNIX_EXTATTR_CAP capability) and
+ * SMB_QUERY_FILE_UNIX_INFO2.
+ */
+#define EXT_SECURE_DELETE 0x00000001
+#define EXT_ENABLE_UNDELETE 0x00000002
+#define EXT_SYNCHRONOUS 0x00000004
+#define EXT_IMMUTABLE 0x00000008
+#define EXT_OPEN_APPEND_ONLY 0x00000010
+#define EXT_DO_NOT_BACKUP 0x00000020
+#define EXT_NO_UPDATE_ATIME 0x00000040
+#define EXT_HIDDEN 0x00000080
+
+#define SMB_QUERY_FILE_UNIX_LINK 0x201
+#define SMB_SET_FILE_UNIX_LINK 0x201
+#define SMB_SET_FILE_UNIX_HLINK 0x203
+/* SMB_QUERY_POSIX_ACL 0x204 see below */
+#define SMB_QUERY_XATTR 0x205 /* need for non-user XATTRs */
+#define SMB_QUERY_ATTR_FLAGS 0x206 /* chflags, chattr */
+#define SMB_SET_ATTR_FLAGS 0x206
+#define SMB_QUERY_POSIX_PERMISSION 0x207
+/* Only valid for qfileinfo */
+#define SMB_QUERY_POSIX_LOCK 0x208
+/* Only valid for setfileinfo */
+#define SMB_SET_POSIX_LOCK 0x208
+
+/* The set info levels for POSIX path operations. */
+#define SMB_POSIX_PATH_OPEN 0x209
+#define SMB_POSIX_PATH_UNLINK 0x20A
+
+#define SMB_QUERY_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
+#define SMB_SET_FILE_UNIX_INFO2 0x20B
+
+/*
+SMB_QUERY_FILE_UNIX_INFO2 is SMB_QUERY_FILE_UNIX_BASIC with create
+time and file flags appended. The corresponding info level for
+findfirst/findnext is SMB_FIND_FILE_UNIX_INFO2.
+ Size Offset Value
+ ---------------------
+ 0 LARGE_INTEGER EndOfFile File size
+ 8 LARGE_INTEGER Blocks Number of blocks used on disk
+ 16 LARGE_INTEGER ChangeTime Attribute change time
+ 24 LARGE_INTEGER LastAccessTime Last access time
+ 32 LARGE_INTEGER LastModificationTime Last modification time
+ 40 LARGE_INTEGER Uid Numeric user id for the owner
+ 48 LARGE_INTEGER Gid Numeric group id of owner
+ 56 ULONG Type Enumeration specifying the file type
+ 60 LARGE_INTEGER devmajor Major device number if type is device
+ 68 LARGE_INTEGER devminor Minor device number if type is device
+ 76 LARGE_INTEGER uniqueid This is a server-assigned unique id
+ 84 LARGE_INTEGER permissions Standard UNIX permissions
+ 92 LARGE_INTEGER nlinks Number of hard links
+ 100 LARGE_INTEGER CreationTime Create/birth time
+ 108 ULONG FileFlags File flags enumeration
+ 112 ULONG FileFlagsMask Mask of valid flags
+*/
+
+/* Transact 2 Find First levels */
+#define SMB_FIND_FILE_UNIX 0x202
+#define SMB_FIND_FILE_UNIX_INFO2 0x20B /* UNIX File Info2 */
+
+#define SMB_FILE_UNIX_INFO2_SIZE 116
+
+/*
+ Info level for TRANS2_QFSINFO - returns version of CIFS UNIX extensions, plus
+ 64-bits worth of capability fun :-).
+ Use the same info level for TRANS2_SETFSINFO
+*/
+
+#define SMB_QUERY_CIFS_UNIX_INFO 0x200
+#define SMB_SET_CIFS_UNIX_INFO 0x200
+
+/* Returns or sets the following.
+
+ UINT16 major version number
+ UINT16 minor version number
+ LARGE_INTEGER capability bitfield
+
+*/
+
+#define CIFS_UNIX_MAJOR_VERSION 1
+#define CIFS_UNIX_MINOR_VERSION 0
+
+#define CIFS_UNIX_FCNTL_LOCKS_CAP 0x1
+#define CIFS_UNIX_POSIX_ACLS_CAP 0x2
+#define CIFS_UNIX_XATTTR_CAP 0x4 /* for support of other xattr
+ namespaces such as system,
+ security and trusted */
+#define CIFS_UNIX_EXTATTR_CAP 0x8 /* for support of chattr
+ (chflags) and lsattr */
+#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x10 /* Use POSIX pathnames on the wire. */
+#define CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP 0x20 /* We can cope with POSIX open/mkdir/unlink etc. */
+#define CIFS_UNIX_LARGE_READ_CAP 0x40 /* We can cope with 24 bit reads in readX. */
+#define CIFS_UNIX_LARGE_WRITE_CAP 0x80 /* We can cope with 24 bit writes in writeX. */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x100 /* We can do SPNEGO negotiations for encryption. */
+#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x200 /* We *must* SPNEGO negotiations for encryption. */
+
+#define SMB_QUERY_POSIX_FS_INFO 0x201
+
+/* Returns FILE_SYSTEM_POSIX_INFO struct as follows
+ (NB For undefined values return -1 in that field)
+ le32 OptimalTransferSize; bsize on some os, iosize on other os, This
+ is a hint to the client about best size. Server
+ can return -1 if no preference, ie if SMB
+ negotiated size is adequate for optimal
+ read/write performance
+ le32 BlockSize; (often 512 bytes) NB: BlockSize * TotalBlocks = disk space
+ le64 TotalBlocks; redundant with other infolevels but easy to ret here
+ le64 BlocksAvail; although redundant, easy to return
+ le64 UserBlocksAvail; bavail
+ le64 TotalFileNodes;
+ le64 FreeFileNodes;
+ le64 FileSysIdentifier; fsid
+ (NB statfs field Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call)
+ (NB statfs field flags can come from FILE_SYSTEM_DEVICE_INFO call)
+*/
+
+#define SMB_QUERY_POSIX_WHO_AM_I 0x202 /* QFS Info */
+/* returns:
+ __u32 flags; 0 = Authenticated user 1 = GUEST
+ __u32 mask; which flags bits server understands ie 0x0001
+ __u64 unix_user_id;
+ __u64 unix_user_gid;
+ __u32 number_of_supplementary_gids; may be zero
+ __u32 number_of_sids; may be zero
+ __u32 length_of_sid_array; in bytes - may be zero
+ __u32 pad; reserved - MBZ
+ __u64 gid_array[0]; may be empty
+ __u8 * psid_list may be empty
+*/
+
+/* ... more as we think of them :-). */
+
+/* SMB POSIX ACL definitions. */
+/* Wire format is (all little endian) :
+
+[2 bytes] - Version number.
+[2 bytes] - Number of ACE entries to follow.
+[2 bytes] - Number of default ACE entries to follow.
+-------------------------------------
+^
+|
+ACE entries
+|
+v
+-------------------------------------
+^
+|
+Default ACE entries
+|
+v
+-------------------------------------
+
+Where an ACE entry looks like :
+
+[1 byte] - Entry type.
+
+Entry types are :
+
+ACL_USER_OBJ 0x01
+ACL_USER 0x02
+ACL_GROUP_OBJ 0x04
+ACL_GROUP 0x08
+ACL_MASK 0x10
+ACL_OTHER 0x20
+
+[1 byte] - permissions (perm_t)
+
+perm_t types are :
+
+ACL_READ 0x04
+ACL_WRITE 0x02
+ACL_EXECUTE 0x01
+
+[8 bytes] - uid/gid to apply this permission to.
+
+In the same format as the uid/gid fields in the other
+UNIX extensions definitions. Use 0xFFFFFFFFFFFFFFFF for
+the MASK and OTHER entry types.
+
+If the Number of ACE entries for either file or default ACE's
+is set to 0xFFFF this means ignore this kind of ACE (and the
+number of entries sent will be zero.
+
+*/
+
+#define SMB_QUERY_POSIX_WHOAMI 0x202
+
+enum smb_whoami_flags {
+ SMB_WHOAMI_GUEST = 0x1 /* Logged in as (or squashed to) guest */
+};
+
+/* Mask of which WHOAMI bits are valid. This should make it easier for clients
+ * to cope with servers that have different sets of WHOAMI flags (as more get
+ * added).
+ */
+#define SMB_WHOAMI_MASK 0x00000001
+
+/*
+ SMBWhoami - Query the user mapping performed by the server for the
+ connected tree. This is a subcommand of the TRANS2_QFSINFO.
+
+ Returns:
+ 4 bytes unsigned - mapping flags (smb_whoami_flags)
+ 4 bytes unsigned - flags mask
+
+ 8 bytes unsigned - primary UID
+ 8 bytes unsigned - primary GID
+ 4 bytes unsigned - number of supplementary GIDs
+ 4 bytes unsigned - number of SIDs
+ 4 bytes unsigned - SID list byte count
+ 4 bytes - pad / reserved (must be zero)
+
+ 8 bytes unsigned[] - list of GIDs (may be empty)
+ struct dom_sid[] - list of SIDs (may be empty)
+*/
+
+/*
+ * The following trans2 is done between client and server
+ * as a FSINFO call to set up the encryption state for transport
+ * encryption.
+ * This is a subcommand of the TRANS2_QFSINFO.
+ *
+ * The request looks like :
+ *
+ * [data block] -> SPNEGO framed GSSAPI request.
+ *
+ * The reply looks like :
+ *
+ * [data block] -> SPNEGO framed GSSAPI reply - if error
+ * is NT_STATUS_OK then we're done, if it's
+ * NT_STATUS_MORE_PROCESSING_REQUIRED then the
+ * client needs to keep going. If it's an
+ * error it can be any NT_STATUS error.
+ *
+ */
+
+#define SMB_REQUEST_TRANSPORT_ENCRYPTION 0x203 /* QFSINFO */
+#define SMB_ENCRYPTION_GSSAPI 0x8000
+
+/* The query/set info levels for POSIX ACLs. */
+#define SMB_QUERY_POSIX_ACL 0x204
+#define SMB_SET_POSIX_ACL 0x204
+
+/* Current on the wire ACL version. */
+#define SMB_POSIX_ACL_VERSION 1
+
+/* ACE entry type. */
+#define SMB_POSIX_ACL_USER_OBJ 0x01
+#define SMB_POSIX_ACL_USER 0x02
+#define SMB_POSIX_ACL_GROUP_OBJ 0x04
+#define SMB_POSIX_ACL_GROUP 0x08
+#define SMB_POSIX_ACL_MASK 0x10
+#define SMB_POSIX_ACL_OTHER 0x20
+
+/* perm_t types. */
+#define SMB_POSIX_ACL_READ 0x04
+#define SMB_POSIX_ACL_WRITE 0x02
+#define SMB_POSIX_ACL_EXECUTE 0x01
+
+#define SMB_POSIX_ACL_HEADER_SIZE 6
+#define SMB_POSIX_ACL_ENTRY_SIZE 10
+
+#define SMB_POSIX_IGNORE_ACE_ENTRIES 0xFFFF
+
+/* Definition of data block of SMB_SET_POSIX_LOCK */
+/*
+ [2 bytes] lock_type - 0 = Read, 1 = Write, 2 = Unlock
+ [2 bytes] lock_flags - 1 = Wait (only valid for setlock)
+ [4 bytes] pid = locking context.
+ [8 bytes] start = unsigned 64 bits.
+ [8 bytes] length = unsigned 64 bits.
+*/
+
+#define POSIX_LOCK_TYPE_OFFSET 0
+#define POSIX_LOCK_FLAGS_OFFSET 2
+#define POSIX_LOCK_PID_OFFSET 4
+#define POSIX_LOCK_START_OFFSET 8
+#define POSIX_LOCK_LEN_OFFSET 16
+#define POSIX_LOCK_DATA_SIZE 24
+
+#define POSIX_LOCK_FLAG_NOWAIT 0
+#define POSIX_LOCK_FLAG_WAIT 1
+
+#define POSIX_LOCK_TYPE_READ 0
+#define POSIX_LOCK_TYPE_WRITE 1
+#define POSIX_LOCK_TYPE_UNLOCK 2
+
+/* SMB_POSIX_PATH_OPEN "open_mode" definitions. */
+#define SMB_O_RDONLY 0x1
+#define SMB_O_WRONLY 0x2
+#define SMB_O_RDWR 0x4
+
+#define SMB_ACCMODE 0x7
+
+#define SMB_O_CREAT 0x10
+#define SMB_O_EXCL 0x20
+#define SMB_O_TRUNC 0x40
+#define SMB_O_APPEND 0x80
+#define SMB_O_SYNC 0x100
+#define SMB_O_DIRECTORY 0x200
+#define SMB_O_NOFOLLOW 0x400
+#define SMB_O_DIRECT 0x800
+
+/* Definition of request data block for SMB_POSIX_PATH_OPEN */
+/*
+ [4 bytes] flags (as smb_ntcreate_Flags).
+ [4 bytes] open_mode - SMB_O_xxx flags above.
+ [8 bytes] mode_t (permissions) - same encoding as "Standard UNIX permissions" above in SMB_SET_FILE_UNIX_BASIC.
+ [2 bytes] ret_info_level - optimization. Info level to be returned.
+*/
+
+/* Definition of reply data block for SMB_POSIX_PATH_OPEN */
+
+#define SMB_NO_INFO_LEVEL_RETURNED 0xFFFF
+
+/*
+ [2 bytes] - flags field. Identical to flags reply for oplock response field in SMBNTCreateX)
+ [2 bytes] - FID returned.
+ [4 bytes] - CreateAction (same as in NTCreateX response).
+ [2 bytes] - reply info level - as requested or 0xFFFF if not available.
+ [2 bytes] - padding (must be zero)
+ [n bytes] - info level reply - if available.
+*/
+
+/* Definition of request data block for SMB_POSIX_UNLINK */
+/*
+ [2 bytes] flags (defined below).
+*/
+
+#define SMB_POSIX_UNLINK_FILE_TARGET 0
+#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1
+
+#define INFO_LEVEL_IS_UNIX(level) ((((level) >= MIN_UNIX_INFO_LEVEL) && \
+ ((level) <= MAX_UNIX_INFO_LEVEL)) || \
+ ((level) == SMB2_FILE_POSIX_INFORMATION_INTERNAL))
+
+#endif /* __SMB_UNIX_EXT_H__ */
diff --git a/libcli/smb/smb_util.h b/libcli/smb/smb_util.h
new file mode 100644
index 0000000..f2cc0fb
--- /dev/null
+++ b/libcli/smb/smb_util.h
@@ -0,0 +1,57 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file operations
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) James 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 "smb_constants.h"
+#include <talloc.h>
+#include "libcli/util/ntstatus.h"
+
+#ifndef _SMB_UTIL_H
+#define _SMB_UTIL_H
+
+const char *smb_protocol_types_string(enum protocol_types protocol);
+char *attrib_string(TALLOC_CTX *mem_ctx, uint32_t attrib);
+uint32_t unix_perms_to_wire(mode_t perms);
+mode_t wire_perms_to_unix(uint32_t perms);
+mode_t unix_filetype_from_wire(uint32_t wire_type);
+
+bool smb_buffer_oob(uint32_t bufsize, uint32_t offset, uint32_t length);
+
+uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size);
+uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
+ const uint8_t *bytes, size_t num_bytes);
+uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size);
+uint8_t *trans2_bytes_push_bytes(uint8_t *buf,
+ const uint8_t *bytes, size_t num_bytes);
+NTSTATUS smb_bytes_pull_str(TALLOC_CTX *mem_ctx, char **_str, bool ucs2,
+ const uint8_t *buf, size_t buf_len,
+ const uint8_t *position,
+ size_t *_consumed);
+
+enum smb_signing_setting smb_signing_setting_translate(const char *str);
+enum smb_encryption_setting smb_encryption_setting_translate(const char *str);
+
+#endif /* _SMB_UTIL_H */
diff --git a/libcli/smb/test_smb1cli_session.c b/libcli/smb/test_smb1cli_session.c
new file mode 100644
index 0000000..6a526c9
--- /dev/null
+++ b/libcli/smb/test_smb1cli_session.c
@@ -0,0 +1,216 @@
+#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 "smb_constants.h"
+#include "smb_util.h"
+
+static const uint8_t smb1_session_setup_bytes[] = {
+ 0xA1, 0x82, 0x01, 0x02, 0x30, 0x81, 0xFF, 0xA0,
+ 0x03, 0x0A, 0x01, 0x01, 0xA1, 0x0C, 0x06, 0x0A,
+ 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
+ 0x02, 0x0A, 0xA2, 0x81, 0xE9, 0x04, 0x81, 0xE6,
+ 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x16, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x15, 0x82, 0x89, 0x62,
+ 0xF6, 0x65, 0xAB, 0x23, 0x47, 0xBC, 0x4D, 0x21,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x98, 0x00, 0x98, 0x00, 0x4E, 0x00, 0x00, 0x00,
+ 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
+ 0x53, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x42, 0x00,
+ 0x41, 0x00, 0x44, 0x00, 0x4F, 0x00, 0x4D, 0x00,
+ 0x41, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x02, 0x00,
+ 0x16, 0x00, 0x53, 0x00, 0x41, 0x00, 0x4D, 0x00,
+ 0x42, 0x00, 0x41, 0x00, 0x44, 0x00, 0x4F, 0x00,
+ 0x4D, 0x00, 0x41, 0x00, 0x49, 0x00, 0x4E, 0x00,
+ 0x01, 0x00, 0x0E, 0x00, 0x4C, 0x00, 0x4F, 0x00,
+ 0x43, 0x00, 0x41, 0x00, 0x4C, 0x00, 0x44, 0x00,
+ 0x43, 0x00, 0x04, 0x00, 0x22, 0x00, 0x73, 0x00,
+ 0x61, 0x00, 0x6D, 0x00, 0x62, 0x00, 0x61, 0x00,
+ 0x2E, 0x00, 0x65, 0x00, 0x78, 0x00, 0x61, 0x00,
+ 0x6D, 0x00, 0x70, 0x00, 0x6C, 0x00, 0x65, 0x00,
+ 0x2E, 0x00, 0x63, 0x00, 0x6F, 0x00, 0x6D, 0x00,
+ 0x03, 0x00, 0x32, 0x00, 0x6C, 0x00, 0x6F, 0x00,
+ 0x63, 0x00, 0x61, 0x00, 0x6C, 0x00, 0x64, 0x00,
+ 0x63, 0x00, 0x2E, 0x00, 0x73, 0x00, 0x61, 0x00,
+ 0x6D, 0x00, 0x62, 0x00, 0x61, 0x00, 0x2E, 0x00,
+ 0x65, 0x00, 0x78, 0x00, 0x61, 0x00, 0x6D, 0x00,
+ 0x70, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x2E, 0x00,
+ 0x63, 0x00, 0x6F, 0x00, 0x6D, 0x00, 0x07, 0x00,
+ 0x08, 0x00, 0x0C, 0x40, 0xA3, 0xC3, 0x5B, 0xE0,
+ 0xD2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
+ 0x00, 0x6E, 0x00, 0x69, 0x00, 0x78, 0x00, 0x00,
+ 0x00, 0x53, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x62,
+ 0x00, 0x61, 0x00, 0x20, 0x00, 0x34, 0x00, 0x2E,
+ 0x00, 0x37, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x70,
+ 0x00, 0x72, 0x00, 0x65, 0x00, 0x31, 0x00, 0x2D,
+ 0x00, 0x44, 0x00, 0x45, 0x00, 0x56, 0x00, 0x45,
+ 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x50, 0x00, 0x45,
+ 0x00, 0x52, 0x00, 0x42, 0x00, 0x55, 0x00, 0x49,
+ 0x00, 0x4C, 0x00, 0x44, 0x00, 0x00, 0x00, 0x53,
+ 0x00, 0x41, 0x00, 0x4D, 0x00, 0x42, 0x00, 0x41,
+ 0x00, 0x44, 0x00, 0x4F, 0x00, 0x4D, 0x00, 0x41,
+ 0x00, 0x49, 0x00, 0x4E, 0x00, 0x00, 0x00
+};
+
+static void test_smb_bytes_pull_str(void **state)
+{
+ NTSTATUS status;
+ const uint8_t *bytes = smb1_session_setup_bytes;
+ const size_t num_bytes = sizeof(smb1_session_setup_bytes);
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ size_t out_security_blob_length = 262;
+ bool use_unicode = true;
+ char *str = NULL;
+
+ p = bytes;
+ p += out_security_blob_length;
+
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "Unix");
+ assert_int_equal(ret, 0x0b);
+ TALLOC_FREE(str);
+
+ p += ret;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "Samba 4.7.0pre1-DEVELOPERBUILD");
+ assert_int_equal(ret, 0x3e);
+ TALLOC_FREE(str);
+
+ p += ret;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "SAMBADOMAIN");
+ assert_int_equal(ret, 0x18);
+ TALLOC_FREE(str);
+
+ p += ret;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "");
+ assert_int_equal(ret, 0x00);
+ TALLOC_FREE(str);
+}
+
+static void test_smb_bytes_pull_str_no_unicode(void **state)
+{
+ NTSTATUS status;
+ const uint8_t *bytes = smb1_session_setup_bytes;
+ const size_t num_bytes = sizeof(smb1_session_setup_bytes);
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ size_t out_security_blob_length = 262;
+ bool use_unicode = false;
+ char *str = NULL;
+
+ p = bytes;
+ p += out_security_blob_length;
+
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "");
+ assert_int_equal(ret, 0x01);
+ TALLOC_FREE(str);
+}
+
+static void test_smb_bytes_pull_str_wrong_offset(void **state)
+{
+ NTSTATUS status;
+ const uint8_t *bytes = smb1_session_setup_bytes;
+ const size_t num_bytes = sizeof(smb1_session_setup_bytes);
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ size_t out_security_blob_length = 261;
+ bool use_unicode = true;
+ char *str = NULL;
+
+ bytes += 1;
+ p = bytes;
+ p += out_security_blob_length;
+
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+
+ assert_string_equal(str, "\xE5\x94\x80\xE6\xB8\x80\xE6\xA4\x80\xE7\xA0\x80");
+ assert_int_equal(ret, 0x0a);
+ TALLOC_FREE(str);
+}
+
+static void test_smb_bytes_pull_str_invalid_offset(void **state)
+{
+ NTSTATUS status;
+ const uint8_t *bytes = smb1_session_setup_bytes;
+ const size_t num_bytes = sizeof(smb1_session_setup_bytes);
+ const uint8_t *p = NULL;
+ size_t ret = 0;
+ bool use_unicode = true;
+ char *str = NULL;
+ intptr_t bytes_address = (intptr_t)bytes;
+
+ /* Warning: array subscript is below array bounds */
+ p = (const uint8_t *)(bytes_address - 1);
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
+
+ p = bytes + num_bytes;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "");
+ assert_int_equal(ret, 0x00);
+ TALLOC_FREE(str);
+
+ p = bytes + num_bytes - 1;
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_true(NT_STATUS_IS_OK(status));
+ assert_string_equal(str, "");
+ assert_int_equal(ret, 0x01);
+ TALLOC_FREE(str);
+
+ /* Warning: array subscript is above array bounds */
+ p = (const uint8_t *)(bytes_address + num_bytes + 1);
+ status = smb_bytes_pull_str(NULL, &str, use_unicode,
+ bytes, num_bytes,
+ p, &ret);
+ assert_int_equal(NT_STATUS_V(status),
+ NT_STATUS_V(NT_STATUS_BUFFER_TOO_SMALL));
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_smb_bytes_pull_str),
+ cmocka_unit_test(test_smb_bytes_pull_str_no_unicode),
+ cmocka_unit_test(test_smb_bytes_pull_str_wrong_offset),
+ cmocka_unit_test(test_smb_bytes_pull_str_invalid_offset),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/smb/test_util_translate.c b/libcli/smb/test_util_translate.c
new file mode 100644
index 0000000..b300af5
--- /dev/null
+++ b/libcli/smb/test_util_translate.c
@@ -0,0 +1,83 @@
+/*
+ * 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 "libcli/smb/util.c"
+
+static void test_smb_signing_setting_translate(void **state)
+{
+ enum smb_signing_setting signing_state;
+
+ signing_state = smb_signing_setting_translate("wurst");
+ assert_int_equal(signing_state, SMB_SIGNING_REQUIRED);
+
+ signing_state = smb_signing_setting_translate("off");
+ assert_int_equal(signing_state, SMB_SIGNING_OFF);
+
+ signing_state = smb_signing_setting_translate("if_required");
+ assert_int_equal(signing_state, SMB_SIGNING_IF_REQUIRED);
+
+ signing_state = smb_signing_setting_translate("mandatory");
+ assert_int_equal(signing_state, SMB_SIGNING_REQUIRED);
+
+}
+
+static void test_smb_encryption_setting_translate(void **state)
+{
+ enum smb_encryption_setting encryption_state;
+
+ encryption_state = smb_encryption_setting_translate("wurst");
+ assert_int_equal(encryption_state, SMB_ENCRYPTION_REQUIRED);
+
+ encryption_state = smb_encryption_setting_translate("off");
+ assert_int_equal(encryption_state, SMB_ENCRYPTION_OFF);
+
+ encryption_state = smb_encryption_setting_translate("if_required");
+ assert_int_equal(encryption_state, SMB_ENCRYPTION_IF_REQUIRED);
+
+ encryption_state = smb_encryption_setting_translate("mandatory");
+ assert_int_equal(encryption_state, SMB_ENCRYPTION_REQUIRED);
+
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_smb_signing_setting_translate),
+ cmocka_unit_test(test_smb_encryption_setting_translate),
+ };
+
+ 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/libcli/smb/tstream_smbXcli_np.c b/libcli/smb/tstream_smbXcli_np.c
new file mode 100644
index 0000000..0248300
--- /dev/null
+++ b/libcli/smb/tstream_smbXcli_np.c
@@ -0,0 +1,1399 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 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 "system/network.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../lib/tsocket/tsocket_internal.h"
+#include "smb_common.h"
+#include "smbXcli_base.h"
+#include "tstream_smbXcli_np.h"
+#include "libcli/security/security.h"
+
+static const struct tstream_context_ops tstream_smbXcli_np_ops;
+
+#define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \
+ SEC_STD_READ_CONTROL | \
+ SEC_FILE_READ_DATA | \
+ SEC_FILE_WRITE_DATA | \
+ SEC_FILE_APPEND_DATA | \
+ SEC_FILE_READ_EA | \
+ SEC_FILE_WRITE_EA | \
+ SEC_FILE_READ_ATTRIBUTE | \
+ SEC_FILE_WRITE_ATTRIBUTE | \
+0)
+
+struct tstream_smbXcli_np_ref;
+
+struct tstream_smbXcli_np {
+ struct smbXcli_conn *conn;
+ struct tstream_smbXcli_np_ref *conn_ref;
+ struct smbXcli_session *session;
+ struct tstream_smbXcli_np_ref *session_ref;
+ struct smbXcli_tcon *tcon;
+ struct tstream_smbXcli_np_ref *tcon_ref;
+ uint16_t pid;
+ unsigned int timeout;
+
+ const char *npipe;
+ bool is_smb1;
+ uint16_t fnum;
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+ uint32_t max_data;
+
+ struct {
+ bool active;
+ struct tevent_req *read_req;
+ struct tevent_req *write_req;
+ uint16_t setup[2];
+ } trans;
+
+ struct {
+ off_t ofs;
+ size_t left;
+ uint8_t *buf;
+ } read, write;
+};
+
+struct tstream_smbXcli_np_ref {
+ struct tstream_smbXcli_np *cli_nps;
+};
+
+static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
+{
+ NTSTATUS status;
+
+ if (cli_nps->conn_ref != NULL) {
+ cli_nps->conn_ref->cli_nps = NULL;
+ TALLOC_FREE(cli_nps->conn_ref);
+ }
+
+ if (cli_nps->session_ref != NULL) {
+ cli_nps->session_ref->cli_nps = NULL;
+ TALLOC_FREE(cli_nps->session_ref);
+ }
+
+ if (cli_nps->tcon_ref != NULL) {
+ cli_nps->tcon_ref->cli_nps = NULL;
+ TALLOC_FREE(cli_nps->tcon_ref);
+ }
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ return 0;
+ }
+
+ /*
+ * TODO: do not use a sync call with a destructor!!!
+ *
+ * This only happens, if a caller does talloc_free(),
+ * while the everything was still ok.
+ *
+ * If we get an unexpected failure within a normal
+ * operation, we already do an async cli_close_send()/_recv().
+ *
+ * Once we've fixed all callers to call
+ * tstream_disconnect_send()/_recv(), this will
+ * never be called.
+ *
+ * We use a maximum timeout of 1 second == 1000 msec.
+ */
+ cli_nps->timeout = MIN(cli_nps->timeout, 1000);
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_close(cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ cli_nps->fnum, UINT32_MAX);
+ } else {
+ status = smb2cli_close(cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ 0, /* flags */
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close "
+ "failed on pipe %s. Error was %s\n",
+ cli_nps->npipe, nt_errstr(status)));
+ }
+ /*
+ * We can't do much on failure
+ */
+ return 0;
+}
+
+static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
+{
+ if (ref->cli_nps == NULL) {
+ return 0;
+ }
+
+ if (ref->cli_nps->conn == NULL) {
+ return 0;
+ }
+
+ ref->cli_nps->conn = NULL;
+ ref->cli_nps->session = NULL;
+ ref->cli_nps->tcon = NULL;
+
+ TALLOC_FREE(ref->cli_nps->conn_ref);
+ TALLOC_FREE(ref->cli_nps->session_ref);
+ TALLOC_FREE(ref->cli_nps->tcon_ref);
+
+ return 0;
+};
+
+static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
+struct tstream_smbXcli_np_open_state {
+ struct smbXcli_conn *conn;
+ struct smbXcli_session *session;
+ struct smbXcli_tcon *tcon;
+ uint16_t pid;
+ unsigned int timeout;
+
+ bool is_smb1;
+ uint16_t fnum;
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+ const char *npipe;
+};
+
+static void tstream_smbXcli_np_open_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_smbXcli_np_open_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t pid,
+ unsigned int timeout,
+ const char *npipe)
+{
+ struct tevent_req *req;
+ struct tstream_smbXcli_np_open_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_smbXcli_np_open_state);
+ if (!req) {
+ return NULL;
+ }
+ state->conn = conn;
+ state->tcon = tcon;
+ state->session = session;
+ state->pid = pid;
+ state->timeout = timeout;
+
+ state->npipe = talloc_strdup(state, npipe);
+ if (tevent_req_nomem(state->npipe, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
+ state->is_smb1 = true;
+ }
+
+ if (state->is_smb1) {
+ const char *smb1_npipe;
+
+ /*
+ * Windows and newer Samba versions allow
+ * the pipe name without leading backslash,
+ * but we should better behave like windows clients
+ */
+ smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
+ if (tevent_req_nomem(smb1_npipe, req)) {
+ return tevent_req_post(req, ev);
+ }
+ subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
+ state->timeout,
+ state->pid,
+ state->tcon,
+ state->session,
+ smb1_npipe,
+ 0, /* CreatFlags */
+ 0, /* RootDirectoryFid */
+ TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
+ 0, /* AllocationSize */
+ 0, /* FileAttributes */
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, /* CreateDisposition */
+ 0, /* CreateOptions */
+ 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */
+ 0); /* SecurityFlags */
+ } else {
+ subreq = smb2cli_create_send(state, ev, state->conn,
+ state->timeout, state->session,
+ state->tcon,
+ npipe,
+ SMB2_OPLOCK_LEVEL_NONE,
+ SMB2_IMPERSONATION_IMPERSONATION,
+ TSTREAM_SMBXCLI_NP_DESIRED_ACCESS,
+ 0, /* file_attributes */
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN,
+ 0, /* create_options */
+ NULL); /* blobs */
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
+
+ return req;
+}
+
+static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_open_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_open_state);
+ NTSTATUS status;
+
+ if (state->is_smb1) {
+ status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
+ } else {
+ status = smb2cli_create_recv(
+ subreq,
+ &state->fid_persistent,
+ &state->fid_volatile,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ }
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **_stream,
+ const char *location)
+{
+ struct tstream_smbXcli_np_open_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_open_state);
+ struct tstream_context *stream;
+ struct tstream_smbXcli_np *cli_nps;
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ stream = tstream_context_create(mem_ctx,
+ &tstream_smbXcli_np_ops,
+ &cli_nps,
+ struct tstream_smbXcli_np,
+ location);
+ if (!stream) {
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCTP(cli_nps);
+
+ cli_nps->conn_ref = talloc_zero(state->conn,
+ struct tstream_smbXcli_np_ref);
+ if (cli_nps->conn_ref == NULL) {
+ TALLOC_FREE(cli_nps);
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_nps->conn_ref->cli_nps = cli_nps;
+
+ cli_nps->session_ref = talloc_zero(state->session,
+ struct tstream_smbXcli_np_ref);
+ if (cli_nps->session_ref == NULL) {
+ TALLOC_FREE(cli_nps);
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_nps->session_ref->cli_nps = cli_nps;
+
+ cli_nps->tcon_ref = talloc_zero(state->tcon,
+ struct tstream_smbXcli_np_ref);
+ if (cli_nps->tcon_ref == NULL) {
+ TALLOC_FREE(cli_nps);
+ tevent_req_received(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_nps->tcon_ref->cli_nps = cli_nps;
+
+ cli_nps->conn = state->conn;
+ cli_nps->session = state->session;
+ cli_nps->tcon = state->tcon;
+ cli_nps->pid = state->pid;
+ cli_nps->timeout = state->timeout;
+ cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
+ cli_nps->is_smb1 = state->is_smb1;
+ cli_nps->fnum = state->fnum;
+ cli_nps->fid_persistent = state->fid_persistent;
+ cli_nps->fid_volatile = state->fid_volatile;
+ cli_nps->max_data = TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE;
+
+ talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
+ talloc_set_destructor(cli_nps->conn_ref,
+ tstream_smbXcli_np_ref_destructor);
+ talloc_set_destructor(cli_nps->session_ref,
+ tstream_smbXcli_np_ref_destructor);
+ talloc_set_destructor(cli_nps->tcon_ref,
+ tstream_smbXcli_np_ref_destructor);
+
+ cli_nps->trans.active = false;
+ cli_nps->trans.read_req = NULL;
+ cli_nps->trans.write_req = NULL;
+ SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
+ SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
+
+ *_stream = stream;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ return cli_nps->read.left;
+}
+
+bool tstream_is_smbXcli_np(struct tstream_context *stream)
+{
+ struct tstream_smbXcli_np *cli_nps =
+ talloc_get_type(_tstream_context_data(stream),
+ struct tstream_smbXcli_np);
+
+ if (!cli_nps) {
+ return false;
+ }
+
+ return true;
+}
+
+NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+
+ if (cli_nps->trans.read_req) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cli_nps->trans.write_req) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cli_nps->trans.active) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ cli_nps->trans.active = true;
+
+ return NT_STATUS_OK;
+}
+
+void tstream_smbXcli_np_set_max_data(struct tstream_context *stream,
+ uint32_t max_data)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(
+ stream, struct tstream_smbXcli_np);
+
+ cli_nps->max_data = max_data;
+}
+
+unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
+ unsigned int timeout)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+ unsigned int old_timeout = cli_nps->timeout;
+
+ cli_nps->timeout = timeout;
+ return old_timeout;
+}
+
+struct tstream_smbXcli_np_writev_state {
+ struct tstream_context *stream;
+ struct tevent_context *ev;
+
+ struct iovec *vector;
+ size_t count;
+
+ int ret;
+
+ struct {
+ int val;
+ const char *location;
+ } error;
+};
+
+static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
+{
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+
+ cli_nps->trans.write_req = NULL;
+
+ return 0;
+}
+
+static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
+
+static struct tevent_req *tstream_smbXcli_np_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_smbXcli_np_writev_state *state;
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_smbXcli_np_writev_state);
+ if (!req) {
+ return NULL;
+ }
+ state->stream = stream;
+ state->ev = ev;
+ state->ret = 0;
+
+ talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ tevent_req_error(req, ENOTCONN);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * we make a copy of the vector so we can change the structure
+ */
+ state->vector = talloc_array(state, struct iovec, count);
+ if (tevent_req_nomem(state->vector, req)) {
+ return tevent_req_post(req, ev);
+ }
+ memcpy(state->vector, vector, sizeof(struct iovec) * count);
+ state->count = count;
+
+ tstream_smbXcli_np_writev_write_next(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req);
+static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
+{
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_writev_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+ size_t i;
+ size_t left = 0;
+
+ for (i=0; i < state->count; i++) {
+ left += state->vector[i].iov_len;
+ }
+
+ if (left == 0) {
+ TALLOC_FREE(cli_nps->write.buf);
+ tevent_req_done(req);
+ return;
+ }
+
+ cli_nps->write.ofs = 0;
+ cli_nps->write.left = MIN(left, cli_nps->max_data);
+ cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
+ uint8_t, cli_nps->write.left);
+ if (tevent_req_nomem(cli_nps->write.buf, req)) {
+ return;
+ }
+
+ /*
+ * copy the pending buffer first
+ */
+ while (cli_nps->write.left > 0 && state->count > 0) {
+ uint8_t *base = (uint8_t *)state->vector[0].iov_base;
+ size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
+
+ memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
+
+ base += len;
+ state->vector[0].iov_base = base;
+ state->vector[0].iov_len -= len;
+
+ cli_nps->write.ofs += len;
+ cli_nps->write.left -= len;
+
+ if (state->vector[0].iov_len == 0) {
+ state->vector += 1;
+ state->count -= 1;
+ }
+
+ state->ret += len;
+ }
+
+ if (cli_nps->trans.active && state->count == 0) {
+ cli_nps->trans.active = false;
+ cli_nps->trans.write_req = req;
+ return;
+ }
+
+ if (cli_nps->trans.read_req && state->count == 0) {
+ cli_nps->trans.write_req = req;
+ tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
+ return;
+ }
+
+ if (cli_nps->is_smb1) {
+ subreq = smb1cli_writex_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ cli_nps->fnum,
+ 8, /* 8 means message mode. */
+ cli_nps->write.buf,
+ 0, /* offset */
+ cli_nps->write.ofs); /* size */
+ } else {
+ subreq = smb2cli_write_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ cli_nps->write.ofs, /* length */
+ 0, /* offset */
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile,
+ 0, /* remaining_bytes */
+ 0, /* flags */
+ cli_nps->write.buf);
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_writev_write_done,
+ req);
+}
+
+static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
+ int error,
+ const char *location);
+
+static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ uint32_t written;
+ NTSTATUS status;
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_writex_recv(subreq, &written, NULL);
+ } else {
+ status = smb2cli_write_recv(subreq, &written);
+ }
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ if (written != cli_nps->write.ofs) {
+ tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
+ return;
+ }
+
+ tstream_smbXcli_np_writev_write_next(req);
+}
+
+static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
+ int error,
+ const char *location)
+{
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_writev_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+
+ state->error.val = error;
+ state->error.location = location;
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+
+ subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
+ state->stream);
+ if (subreq == NULL) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_writev_disconnect_done,
+ req);
+}
+
+static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
+ int error;
+
+ tstream_smbXcli_np_disconnect_recv(subreq, &error);
+ TALLOC_FREE(subreq);
+
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+}
+
+static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_smbXcli_np_writev_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_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_smbXcli_np_readv_state {
+ struct tstream_context *stream;
+ struct tevent_context *ev;
+
+ struct iovec *vector;
+ size_t count;
+
+ int ret;
+
+ struct {
+ struct tevent_immediate *im;
+ } trans;
+
+ struct {
+ int val;
+ const char *location;
+ } error;
+};
+
+static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
+{
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+
+ cli_nps->trans.read_req = NULL;
+
+ return 0;
+}
+
+static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
+
+static struct tevent_req *tstream_smbXcli_np_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_smbXcli_np_readv_state *state;
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(stream, struct tstream_smbXcli_np);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_smbXcli_np_readv_state);
+ if (!req) {
+ return NULL;
+ }
+ state->stream = stream;
+ state->ev = ev;
+ state->ret = 0;
+
+ talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ tevent_req_error(req, ENOTCONN);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * we make a copy of the vector so we can change the structure
+ */
+ state->vector = talloc_array(state, struct iovec, count);
+ if (tevent_req_nomem(state->vector, req)) {
+ return tevent_req_post(req, ev);
+ }
+ memcpy(state->vector, vector, sizeof(struct iovec) * count);
+ state->count = count;
+
+ tstream_smbXcli_np_readv_read_next(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ return req;
+}
+
+static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+
+ /*
+ * copy the pending buffer first
+ */
+ while (cli_nps->read.left > 0 && state->count > 0) {
+ uint8_t *base = (uint8_t *)state->vector[0].iov_base;
+ size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
+
+ memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
+
+ base += len;
+ state->vector[0].iov_base = base;
+ state->vector[0].iov_len -= len;
+
+ cli_nps->read.ofs += len;
+ cli_nps->read.left -= len;
+
+ if (state->vector[0].iov_len == 0) {
+ state->vector += 1;
+ state->count -= 1;
+ }
+
+ state->ret += len;
+ }
+
+ if (cli_nps->read.left == 0) {
+ TALLOC_FREE(cli_nps->read.buf);
+ }
+
+ if (state->count == 0) {
+ tevent_req_done(req);
+ return;
+ }
+
+ if (cli_nps->trans.active) {
+ cli_nps->trans.active = false;
+ cli_nps->trans.read_req = req;
+ return;
+ }
+
+ if (cli_nps->trans.write_req) {
+ cli_nps->trans.read_req = req;
+ tstream_smbXcli_np_readv_trans_start(req);
+ return;
+ }
+
+ if (cli_nps->is_smb1) {
+ subreq = smb1cli_readx_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ cli_nps->fnum,
+ 0, /* offset */
+ cli_nps->max_data);
+ } else {
+ subreq = smb2cli_read_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ cli_nps->max_data, /* length */
+ 0, /* offset */
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile,
+ 0, /* minimum_count */
+ 0); /* remaining_bytes */
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_readv_read_done,
+ req);
+}
+
+static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+
+ state->trans.im = tevent_create_immediate(state);
+ if (tevent_req_nomem(state->trans.im, req)) {
+ return;
+ }
+
+ if (cli_nps->is_smb1) {
+ subreq = smb1cli_trans_send(state, state->ev,
+ cli_nps->conn, SMBtrans,
+ 0, 0, /* *_flags */
+ 0, 0, /* *_flags2 */
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ "\\PIPE\\",
+ 0, 0, 0,
+ cli_nps->trans.setup, 2,
+ 0,
+ NULL, 0, 0,
+ cli_nps->write.buf,
+ cli_nps->write.ofs,
+ cli_nps->max_data);
+ } else {
+ DATA_BLOB in_input_buffer = data_blob_null;
+ DATA_BLOB in_output_buffer = data_blob_null;
+
+ in_input_buffer = data_blob_const(cli_nps->write.buf,
+ cli_nps->write.ofs);
+
+ subreq = smb2cli_ioctl_send(state, state->ev,
+ cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile,
+ FSCTL_NAMED_PIPE_READ_WRITE,
+ 0, /* in_max_input_length */
+ &in_input_buffer,
+ /* in_max_output_length */
+ cli_nps->max_data,
+ &in_output_buffer,
+ SMB2_IOCTL_FLAG_IS_FSCTL);
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_readv_trans_done,
+ req);
+}
+
+static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
+ int error,
+ const char *location);
+static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream, struct tstream_smbXcli_np);
+ uint8_t *rcvbuf;
+ uint32_t received;
+ NTSTATUS status;
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
+ NULL, 0, NULL,
+ &rcvbuf, 0, &received);
+ } else {
+ DATA_BLOB out_input_buffer = data_blob_null;
+ DATA_BLOB out_output_buffer = data_blob_null;
+
+ status = smb2cli_ioctl_recv(subreq, state,
+ &out_input_buffer,
+ &out_output_buffer);
+
+ /* Note that rcvbuf is not a talloc pointer here */
+ rcvbuf = out_output_buffer.data;
+ received = out_output_buffer.length;
+ }
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /*
+ * STATUS_BUFFER_OVERFLOW means that there's
+ * more data to read when the named pipe is used
+ * in message mode (which is the case here).
+ *
+ * But we hide this from the caller.
+ */
+ status = NT_STATUS_OK;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ if (received > cli_nps->max_data) {
+ tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
+ return;
+ }
+
+ if (received == 0) {
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ cli_nps->read.ofs = 0;
+ cli_nps->read.left = received;
+ cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
+ if (cli_nps->read.buf == NULL) {
+ TALLOC_FREE(subreq);
+ tevent_req_oom(req);
+ return;
+ }
+ memcpy(cli_nps->read.buf, rcvbuf, received);
+
+ if (cli_nps->trans.write_req == NULL) {
+ tstream_smbXcli_np_readv_read_next(req);
+ return;
+ }
+
+ tevent_schedule_immediate(state->trans.im, state->ev,
+ tstream_smbXcli_np_readv_trans_next, req);
+
+ tevent_req_done(cli_nps->trans.write_req);
+}
+
+static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+
+ tstream_smbXcli_np_readv_read_next(req);
+}
+
+static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream, struct tstream_smbXcli_np);
+ uint8_t *rcvbuf;
+ uint32_t received;
+ NTSTATUS status;
+
+ /*
+ * We must free subreq in this function as there is
+ * a timer event attached to it.
+ */
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
+ } else {
+ status = smb2cli_read_recv(subreq, state, &rcvbuf, &received);
+ }
+ /*
+ * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
+ * child of that.
+ */
+ if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
+ /*
+ * STATUS_BUFFER_OVERFLOW means that there's
+ * more data to read when the named pipe is used
+ * in message mode (which is the case here).
+ *
+ * But we hide this from the caller.
+ */
+ status = NT_STATUS_OK;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ if (received > cli_nps->max_data) {
+ TALLOC_FREE(subreq);
+ tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
+ return;
+ }
+
+ if (received == 0) {
+ TALLOC_FREE(subreq);
+ tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
+ return;
+ }
+
+ cli_nps->read.ofs = 0;
+ cli_nps->read.left = received;
+ cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
+ if (cli_nps->read.buf == NULL) {
+ TALLOC_FREE(subreq);
+ tevent_req_oom(req);
+ return;
+ }
+ memcpy(cli_nps->read.buf, rcvbuf, received);
+ TALLOC_FREE(subreq);
+
+ tstream_smbXcli_np_readv_read_next(req);
+}
+
+static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_readv_error(struct tevent_req *req);
+
+static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
+ int error,
+ const char *location)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *subreq;
+
+ state->error.val = error;
+ state->error.location = location;
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ /* return the original error */
+ tstream_smbXcli_np_readv_error(req);
+ return;
+ }
+
+ subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
+ state->stream);
+ if (subreq == NULL) {
+ /* return the original error */
+ tstream_smbXcli_np_readv_error(req);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ tstream_smbXcli_np_readv_disconnect_done,
+ req);
+}
+
+static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ int error;
+
+ tstream_smbXcli_np_disconnect_recv(subreq, &error);
+ TALLOC_FREE(subreq);
+
+ tstream_smbXcli_np_readv_error(req);
+}
+
+static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
+
+static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream,
+ struct tstream_smbXcli_np);
+
+ if (cli_nps->trans.write_req == NULL) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+
+ if (state->trans.im == NULL) {
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+ return;
+ }
+
+ tevent_schedule_immediate(state->trans.im, state->ev,
+ tstream_smbXcli_np_readv_error_trigger, req);
+
+ /* return the original error for writev */
+ _tevent_req_error(cli_nps->trans.write_req,
+ state->error.val, state->error.location);
+}
+
+static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_req *req =
+ talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req,
+ struct tstream_smbXcli_np_readv_state);
+
+ /* return the original error */
+ _tevent_req_error(req, state->error.val, state->error.location);
+}
+
+static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tstream_smbXcli_np_readv_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_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_smbXcli_np_disconnect_state {
+ struct tstream_context *stream;
+ struct tevent_req *subreq;
+};
+
+static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq);
+static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
+
+static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream)
+{
+ struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
+ struct tstream_smbXcli_np);
+ struct tevent_req *req;
+ struct tstream_smbXcli_np_disconnect_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_smbXcli_np_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->stream = stream;
+
+ if (!smbXcli_conn_is_connected(cli_nps->conn)) {
+ tevent_req_error(req, ENOTCONN);
+ return tevent_req_post(req, ev);
+ }
+
+ if (cli_nps->is_smb1) {
+ subreq = smb1cli_close_send(state, ev, cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->pid,
+ cli_nps->tcon,
+ cli_nps->session,
+ cli_nps->fnum, UINT32_MAX);
+ } else {
+ subreq = smb2cli_close_send(state, ev, cli_nps->conn,
+ cli_nps->timeout,
+ cli_nps->session,
+ cli_nps->tcon,
+ 0, /* flags */
+ cli_nps->fid_persistent,
+ cli_nps->fid_volatile);
+ }
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
+ state->subreq = subreq;
+
+ tevent_req_set_cleanup_fn(req, tstream_smbXcli_np_disconnect_cleanup);
+
+ /*
+ * Make sure we don't send any requests anymore.
+ */
+ cli_nps->conn = NULL;
+
+ return req;
+}
+
+static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_smbXcli_np_disconnect_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
+ struct tstream_smbXcli_np *cli_nps =
+ tstream_context_data(state->stream, struct tstream_smbXcli_np);
+ NTSTATUS status;
+
+ state->subreq = NULL;
+
+ if (cli_nps->is_smb1) {
+ status = smb1cli_close_recv(subreq);
+ } else {
+ status = smb2cli_close_recv(subreq);
+ }
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_error(req, EPIPE);
+ return;
+ }
+
+ cli_nps->conn = NULL;
+ cli_nps->session = NULL;
+ cli_nps->tcon = NULL;
+
+ tevent_req_done(req);
+}
+
+static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
+
+static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct tstream_smbXcli_np_disconnect_state *state =
+ tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
+ struct tstream_smbXcli_np *cli_nps = NULL;
+
+ if (state->subreq == NULL) {
+ return;
+ }
+
+ cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
+
+ if (cli_nps->tcon == NULL) {
+ return;
+ }
+
+ /*
+ * We're no longer interested in the result
+ * any more, but need to make sure that the close
+ * request arrives at the server if the smb connection,
+ * session and tcon are still alive.
+ *
+ * We move the low level request to the tcon,
+ * which means that it stays as long as the tcon
+ * is available.
+ */
+ talloc_steal(cli_nps->tcon, state->subreq);
+ tevent_req_set_callback(state->subreq,
+ tstream_smbXcli_np_disconnect_free,
+ NULL);
+ state->subreq = NULL;
+
+ cli_nps->conn = NULL;
+ cli_nps->session = NULL;
+ cli_nps->tcon = NULL;
+}
+
+static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
+{
+ TALLOC_FREE(subreq);
+}
+
+static int tstream_smbXcli_np_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_smbXcli_np_ops = {
+ .name = "smbXcli_np",
+
+ .pending_bytes = tstream_smbXcli_np_pending_bytes,
+
+ .readv_send = tstream_smbXcli_np_readv_send,
+ .readv_recv = tstream_smbXcli_np_readv_recv,
+
+ .writev_send = tstream_smbXcli_np_writev_send,
+ .writev_recv = tstream_smbXcli_np_writev_recv,
+
+ .disconnect_send = tstream_smbXcli_np_disconnect_send,
+ .disconnect_recv = tstream_smbXcli_np_disconnect_recv,
+};
diff --git a/libcli/smb/tstream_smbXcli_np.h b/libcli/smb/tstream_smbXcli_np.h
new file mode 100644
index 0000000..d7a4e3c
--- /dev/null
+++ b/libcli/smb/tstream_smbXcli_np.h
@@ -0,0 +1,75 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 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 _CLI_NP_TSTREAM_H_
+#define _CLI_NP_TSTREAM_H_
+
+struct tevent_context;
+struct tevent_req;
+struct tstream_context;
+struct smbXcli_conn;
+struct smbXcli_session;
+struct smbXcli_tcon;
+
+struct tevent_req *tstream_smbXcli_np_open_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint16_t pid,
+ unsigned int timeout,
+ const char *npipe);
+NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **_stream,
+ const char *location);
+#define tstream_smbXcli_np_open_recv(req, mem_ctx, stream) \
+ _tstream_smbXcli_np_open_recv(req, mem_ctx, stream, __location__)
+
+bool tstream_is_smbXcli_np(struct tstream_context *stream);
+
+NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream);
+
+unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
+ unsigned int timeout);
+
+/*
+ * Windows uses 4280 (the max xmit/recv size negotiated on DCERPC).
+ * This is fits into the max_xmit negotiated at the SMB layer.
+ *
+ * On the sending side they may use SMBtranss if the request does not
+ * fit into a single SMBtrans call.
+ *
+ * Windows uses 1024 as max data size of a SMBtrans request and then
+ * possibly reads the rest of the DCERPC fragment (up to 3256 bytes)
+ * via a SMBreadX.
+ *
+ * For now we just ask for the full 4280 bytes (max data size) in the SMBtrans
+ * request to get the whole fragment at once (like samba 3.5.x and below did.
+ *
+ * It is important that we use do SMBwriteX with the size of a full fragment,
+ * otherwise we may get NT_STATUS_PIPE_BUSY on the SMBtrans request
+ * from NT4 servers. (See bug #8195)
+ */
+#define TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE 4280
+
+void tstream_smbXcli_np_set_max_data(struct tstream_context *stream,
+ uint32_t max_data);
+
+#endif /* _CLI_NP_TSTREAM_H_ */
diff --git a/libcli/smb/util.c b/libcli/smb/util.c
new file mode 100644
index 0000000..baae532
--- /dev/null
+++ b/libcli/smb/util.c
@@ -0,0 +1,716 @@
+/*
+ Unix SMB/CIFS implementation.
+ client file operations
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Jeremy Allison 2001-2002
+ Copyright (C) James 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 "includes.h"
+#include "libcli/smb/smb_common.h"
+#include "system/filesys.h"
+#include "lib/param/loadparm.h"
+#include "lib/param/param.h"
+#include "libcli/smb/smb2_negotiate_context.h"
+
+const char *smb_protocol_types_string(enum protocol_types protocol)
+{
+ switch (protocol) {
+ case PROTOCOL_DEFAULT:
+ return "DEFAULT";
+ case PROTOCOL_NONE:
+ return "NONE";
+ case PROTOCOL_CORE:
+ return "CORE";
+ case PROTOCOL_COREPLUS:
+ return "COREPLUS";
+ case PROTOCOL_LANMAN1:
+ return "LANMAN1";
+ case PROTOCOL_LANMAN2:
+ return "LANMAN2";
+ case PROTOCOL_NT1:
+ return "NT1";
+ case PROTOCOL_SMB2_02:
+ return "SMB2_02";
+ case PROTOCOL_SMB2_10:
+ return "SMB2_10";
+ case PROTOCOL_SMB3_00:
+ return "SMB3_00";
+ case PROTOCOL_SMB3_02:
+ return "SMB3_02";
+ case PROTOCOL_SMB3_11:
+ return "SMB3_11";
+ }
+
+ return "Invalid protocol_types value";
+}
+
+/**
+ Return a string representing a CIFS attribute for a file.
+**/
+char *attrib_string(TALLOC_CTX *mem_ctx, uint32_t attrib)
+{
+ size_t i, len;
+ static const struct {
+ char c;
+ uint16_t attr;
+ } attr_strs[] = {
+ {'V', FILE_ATTRIBUTE_VOLUME},
+ {'D', FILE_ATTRIBUTE_DIRECTORY},
+ {'A', FILE_ATTRIBUTE_ARCHIVE},
+ {'H', FILE_ATTRIBUTE_HIDDEN},
+ {'S', FILE_ATTRIBUTE_SYSTEM},
+ {'N', FILE_ATTRIBUTE_NORMAL},
+ {'R', FILE_ATTRIBUTE_READONLY},
+ {'d', FILE_ATTRIBUTE_DEVICE},
+ {'t', FILE_ATTRIBUTE_TEMPORARY},
+ {'s', FILE_ATTRIBUTE_SPARSE},
+ {'r', FILE_ATTRIBUTE_REPARSE_POINT},
+ {'c', FILE_ATTRIBUTE_COMPRESSED},
+ {'o', FILE_ATTRIBUTE_OFFLINE},
+ {'n', FILE_ATTRIBUTE_NONINDEXED},
+ {'e', FILE_ATTRIBUTE_ENCRYPTED}
+ };
+ char *ret;
+
+ ret = talloc_array(mem_ctx, char, ARRAY_SIZE(attr_strs)+1);
+ if (!ret) {
+ return NULL;
+ }
+
+ for (len=i=0; i<ARRAY_SIZE(attr_strs); i++) {
+ if (attrib & attr_strs[i].attr) {
+ ret[len++] = attr_strs[i].c;
+ }
+ }
+
+ ret[len] = 0;
+
+ talloc_set_name_const(ret, ret);
+
+ return ret;
+}
+
+/****************************************************************************
+ Map standard UNIX permissions onto wire representations.
+****************************************************************************/
+
+uint32_t unix_perms_to_wire(mode_t perms)
+{
+ unsigned int ret = 0;
+
+ ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0);
+ ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0);
+ ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0);
+ ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0);
+ ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0);
+ ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0);
+ ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0);
+ ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0);
+ ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & S_ISUID) ? UNIX_SET_UID : 0);
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Map wire permissions to standard UNIX.
+****************************************************************************/
+
+mode_t wire_perms_to_unix(uint32_t perms)
+{
+ mode_t ret = (mode_t)0;
+
+ ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
+ ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
+ ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
+ ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
+ ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
+ ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
+ ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
+ ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
+ ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Return the file type from the wire filetype for UNIX extensions.
+****************************************************************************/
+
+mode_t unix_filetype_from_wire(uint32_t wire_type)
+{
+ switch (wire_type) {
+ case UNIX_TYPE_FILE:
+ return S_IFREG;
+ case UNIX_TYPE_DIR:
+ return S_IFDIR;
+#ifdef S_IFLNK
+ case UNIX_TYPE_SYMLINK:
+ return S_IFLNK;
+#endif
+#ifdef S_IFCHR
+ case UNIX_TYPE_CHARDEV:
+ return S_IFCHR;
+#endif
+#ifdef S_IFBLK
+ case UNIX_TYPE_BLKDEV:
+ return S_IFBLK;
+#endif
+#ifdef S_IFIFO
+ case UNIX_TYPE_FIFO:
+ return S_IFIFO;
+#endif
+#ifdef S_IFSOCK
+ case UNIX_TYPE_SOCKET:
+ return S_IFSOCK;
+#endif
+ default:
+ return (mode_t)0;
+ }
+}
+
+bool smb_buffer_oob(uint32_t bufsize, uint32_t offset, uint32_t length)
+{
+ if ((offset + length < offset) || (offset + length < length)) {
+ /* wrap */
+ return true;
+ }
+ if ((offset > bufsize) || (offset + length > bufsize)) {
+ /* overflow */
+ return true;
+ }
+ return false;
+}
+
+/***********************************************************
+ Common function for pushing strings, used by smb_bytes_push_str()
+ and trans_bytes_push_str(). Only difference is the align_odd
+ parameter setting.
+***********************************************************/
+
+static uint8_t *internal_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ bool align_odd,
+ size_t *pconverted_size)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ size_t buflen;
+ char *converted;
+ size_t converted_size;
+
+ /*
+ * This check prevents us from
+ * (re)alloc buf on a NULL TALLOC_CTX.
+ */
+ if (buf == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ buflen = talloc_get_size(buf);
+
+ if (ucs2 &&
+ ((align_odd && (buflen % 2 == 0)) ||
+ (!align_odd && (buflen % 2 == 1)))) {
+ /*
+ * We're pushing into an SMB buffer, align odd
+ */
+ buf = talloc_realloc(NULL, buf, uint8_t, buflen + 1);
+ if (buf == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+ buf[buflen] = '\0';
+ buflen += 1;
+ }
+
+ if (!convert_string_talloc(frame, CH_UNIX,
+ ucs2 ? CH_UTF16LE : CH_DOS,
+ str, str_len, &converted,
+ &converted_size)) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ buf = talloc_realloc(NULL, buf, uint8_t,
+ buflen + converted_size);
+ if (buf == NULL) {
+ TALLOC_FREE(frame);
+ return NULL;
+ }
+
+ memcpy(buf + buflen, converted, converted_size);
+
+ TALLOC_FREE(converted);
+
+ if (pconverted_size) {
+ *pconverted_size = converted_size;
+ }
+
+ TALLOC_FREE(frame);
+ return buf;
+}
+
+/***********************************************************
+ Push a string into an SMB buffer, with odd byte alignment
+ if it's a UCS2 string.
+***********************************************************/
+
+uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size)
+{
+ return internal_bytes_push_str(buf, ucs2, str, str_len,
+ true, pconverted_size);
+}
+
+uint8_t *smb_bytes_push_bytes(uint8_t *buf, uint8_t prefix,
+ const uint8_t *bytes, size_t num_bytes)
+{
+ size_t buflen;
+
+ /*
+ * This check prevents us from
+ * (re)alloc buf on a NULL TALLOC_CTX.
+ */
+ if (buf == NULL) {
+ return NULL;
+ }
+ buflen = talloc_get_size(buf);
+
+ buf = talloc_realloc(NULL, buf, uint8_t,
+ buflen + 1 + num_bytes);
+ if (buf == NULL) {
+ return NULL;
+ }
+ buf[buflen] = prefix;
+ memcpy(&buf[buflen+1], bytes, num_bytes);
+ return buf;
+}
+
+/***********************************************************
+ Same as smb_bytes_push_str(), but without the odd byte
+ align for ucs2 (we're pushing into a param or data block).
+ static for now, although this will probably change when
+ other modules use async trans calls.
+***********************************************************/
+
+uint8_t *trans2_bytes_push_str(uint8_t *buf, bool ucs2,
+ const char *str, size_t str_len,
+ size_t *pconverted_size)
+{
+ return internal_bytes_push_str(buf, ucs2, str, str_len,
+ false, pconverted_size);
+}
+
+uint8_t *trans2_bytes_push_bytes(uint8_t *buf,
+ const uint8_t *bytes, size_t num_bytes)
+{
+ size_t buflen;
+
+ if (buf == NULL) {
+ return NULL;
+ }
+ buflen = talloc_get_size(buf);
+
+ buf = talloc_realloc(NULL, buf, uint8_t,
+ buflen + num_bytes);
+ if (buf == NULL) {
+ return NULL;
+ }
+ memcpy(&buf[buflen], bytes, num_bytes);
+ return buf;
+}
+
+static NTSTATUS internal_bytes_pull_str(TALLOC_CTX *mem_ctx, char **_str,
+ bool ucs2, bool align_odd,
+ const uint8_t *buf, size_t buf_len,
+ const uint8_t *position,
+ size_t *p_consumed)
+{
+ size_t pad = 0;
+ size_t offset;
+ char *str = NULL;
+ size_t str_len = 0;
+ bool ok;
+
+ *_str = NULL;
+ if (p_consumed != NULL) {
+ *p_consumed = 0;
+ }
+
+ if (position < buf) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ offset = PTR_DIFF(position, buf);
+ if (offset > buf_len) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (ucs2 &&
+ ((align_odd && (offset % 2 == 0)) ||
+ (!align_odd && (offset % 2 == 1)))) {
+ pad += 1;
+ offset += 1;
+ }
+
+ if (offset > buf_len) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ buf_len -= offset;
+ buf += offset;
+
+ if (ucs2) {
+ buf_len = utf16_null_terminated_len_n(buf, buf_len);
+ } else {
+ size_t tmp = strnlen((const char *)buf, buf_len);
+ if (tmp < buf_len) {
+ tmp += 1;
+ }
+ buf_len = tmp;
+ }
+
+ ok = convert_string_talloc(mem_ctx,
+ ucs2 ? CH_UTF16LE : CH_DOS,
+ CH_UNIX,
+ buf, buf_len,
+ &str, &str_len);
+ if (!ok) {
+ return map_nt_error_from_unix_common(errno);
+ }
+
+ if (p_consumed != NULL) {
+ *p_consumed = buf_len + pad;
+ }
+ *_str = str;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS smb_bytes_pull_str(TALLOC_CTX *mem_ctx, char **_str, bool ucs2,
+ const uint8_t *buf, size_t buf_len,
+ const uint8_t *position,
+ size_t *_consumed)
+{
+ return internal_bytes_pull_str(mem_ctx, _str, ucs2, true,
+ buf, buf_len, position, _consumed);
+}
+
+/**
+ * @brief Translate SMB signing settings as string to an enum.
+ *
+ * @param[in] str The string to translate.
+ *
+ * @return A corresponding enum @smb_signing_setting translated from the string.
+ */
+enum smb_signing_setting smb_signing_setting_translate(const char *str)
+{
+ enum smb_signing_setting signing_state = SMB_SIGNING_REQUIRED;
+ int32_t val = lpcfg_parse_enum_vals("client signing", str);
+
+ if (val != INT32_MIN) {
+ signing_state = val;
+ }
+
+ return signing_state;
+}
+
+/**
+ * @brief Translate SMB encryption settings as string to an enum.
+ *
+ * @param[in] str The string to translate.
+ *
+ * @return A corresponding enum @smb_encryption_setting translated from the
+ * string.
+ */
+enum smb_encryption_setting smb_encryption_setting_translate(const char *str)
+{
+ enum smb_encryption_setting encryption_state = SMB_ENCRYPTION_REQUIRED;
+ int32_t val = lpcfg_parse_enum_vals("client smb encrypt", str);
+
+ if (val != INT32_MIN) {
+ encryption_state = val;
+ }
+
+ return encryption_state;
+}
+
+static const struct enum_list enum_smb3_signing_algorithms[] = {
+ {SMB2_SIGNING_AES128_GMAC, "AES-128-GMAC"},
+ {SMB2_SIGNING_AES128_CMAC, "AES-128-CMAC"},
+ {SMB2_SIGNING_HMAC_SHA256, "HMAC-SHA256"},
+ {-1, NULL}
+};
+
+const char *smb3_signing_algorithm_name(uint16_t algo)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(enum_smb3_signing_algorithms); i++) {
+ if (enum_smb3_signing_algorithms[i].value != algo) {
+ continue;
+ }
+
+ return enum_smb3_signing_algorithms[i].name;
+ }
+
+ return NULL;
+}
+
+static const struct enum_list enum_smb3_encryption_algorithms[] = {
+ {SMB2_ENCRYPTION_AES128_GCM, "AES-128-GCM"},
+ {SMB2_ENCRYPTION_AES128_CCM, "AES-128-CCM"},
+ {SMB2_ENCRYPTION_AES256_GCM, "AES-256-GCM"},
+ {SMB2_ENCRYPTION_AES256_CCM, "AES-256-CCM"},
+ {-1, NULL}
+};
+
+const char *smb3_encryption_algorithm_name(uint16_t algo)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(enum_smb3_encryption_algorithms); i++) {
+ if (enum_smb3_encryption_algorithms[i].value != algo) {
+ continue;
+ }
+
+ return enum_smb3_encryption_algorithms[i].name;
+ }
+
+ return NULL;
+}
+
+static int32_t parse_enum_val(const struct enum_list *e,
+ const char *param_name,
+ const char *param_value)
+{
+ struct parm_struct parm = {
+ .label = param_name,
+ .type = P_LIST,
+ .p_class = P_GLOBAL,
+ .enum_list = e,
+ };
+ int32_t ret = INT32_MIN;
+ bool ok;
+
+ ok = lp_set_enum_parm(&parm, param_value, &ret);
+ if (!ok) {
+ return INT32_MIN;
+ }
+
+ return ret;
+}
+
+struct smb311_capabilities smb311_capabilities_parse(const char *role,
+ const char * const *signing_algos,
+ const char * const *encryption_algos)
+{
+ struct smb311_capabilities c = {
+ .signing = {
+ .num_algos = 0,
+ },
+ .encryption = {
+ .num_algos = 0,
+ },
+ };
+ char sign_param[64] = { 0, };
+ char enc_param[64] = { 0, };
+ size_t ai;
+
+ snprintf(sign_param, sizeof(sign_param),
+ "%s smb3 signing algorithms", role);
+ snprintf(enc_param, sizeof(enc_param),
+ "%s smb3 encryption algorithms", role);
+
+ for (ai = 0; signing_algos != NULL && signing_algos[ai] != NULL; ai++) {
+ const char *algoname = signing_algos[ai];
+ int32_t v32;
+ uint16_t algo;
+ size_t di;
+ bool ignore = false;
+
+ if (c.signing.num_algos >= SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS) {
+ DBG_ERR("WARNING: Ignoring trailing value '%s' for parameter '%s'\n",
+ algoname, sign_param);
+ continue;
+ }
+
+ v32 = parse_enum_val(enum_smb3_signing_algorithms,
+ sign_param, algoname);
+ if (v32 == INT32_MAX) {
+ continue;
+ }
+ algo = v32;
+
+ for (di = 0; di < c.signing.num_algos; di++) {
+ if (algo != c.signing.algos[di]) {
+ continue;
+ }
+
+ ignore = true;
+ break;
+ }
+
+ if (ignore) {
+ DBG_ERR("WARNING: Ignoring duplicate value '%s' for parameter '%s'\n",
+ algoname, sign_param);
+ continue;
+ }
+
+ c.signing.algos[c.signing.num_algos] = algo;
+ c.signing.num_algos += 1;
+ }
+
+ for (ai = 0; encryption_algos != NULL && encryption_algos[ai] != NULL; ai++) {
+ const char *algoname = encryption_algos[ai];
+ int32_t v32;
+ uint16_t algo;
+ size_t di;
+ bool ignore = false;
+
+ if (c.encryption.num_algos >= SMB3_ENCRYTION_CAPABILITIES_MAX_ALGOS) {
+ DBG_ERR("WARNING: Ignoring trailing value '%s' for parameter '%s'\n",
+ algoname, enc_param);
+ continue;
+ }
+
+ v32 = parse_enum_val(enum_smb3_encryption_algorithms,
+ enc_param, algoname);
+ if (v32 == INT32_MAX) {
+ continue;
+ }
+ algo = v32;
+
+ for (di = 0; di < c.encryption.num_algos; di++) {
+ if (algo != c.encryption.algos[di]) {
+ continue;
+ }
+
+ ignore = true;
+ break;
+ }
+
+ if (ignore) {
+ DBG_ERR("WARNING: Ignoring duplicate value '%s' for parameter '%s'\n",
+ algoname, enc_param);
+ continue;
+ }
+
+ c.encryption.algos[c.encryption.num_algos] = algo;
+ c.encryption.num_algos += 1;
+ }
+
+ return c;
+}
+
+NTSTATUS smb311_capabilities_check(const struct smb311_capabilities *c,
+ const char *debug_prefix,
+ int debug_lvl,
+ NTSTATUS error_status,
+ const char *role,
+ enum protocol_types protocol,
+ uint16_t sign_algo,
+ uint16_t cipher_algo)
+{
+ const struct smb3_signing_capabilities *sign_algos =
+ &c->signing;
+ const struct smb3_encryption_capabilities *ciphers =
+ &c->encryption;
+ bool found_signing = false;
+ bool found_encryption = false;
+ size_t i;
+
+ for (i = 0; i < sign_algos->num_algos; i++) {
+ if (sign_algo == sign_algos->algos[i]) {
+ /*
+ * We found a match
+ */
+ found_signing = true;
+ break;
+ }
+ }
+
+ for (i = 0; i < ciphers->num_algos; i++) {
+ if (cipher_algo == SMB2_ENCRYPTION_NONE) {
+ /*
+ * encryption not supported, we'll error out later
+ */
+ found_encryption = true;
+ break;
+ }
+
+ if (cipher_algo == ciphers->algos[i]) {
+ /*
+ * We found a match
+ */
+ found_encryption = true;
+ break;
+ }
+ }
+
+ if (!found_signing) {
+ /*
+ * We negotiated a signing algo we don't allow,
+ * most likely for SMB < 3.1.1
+ */
+ DEBUG(debug_lvl,("%s: "
+ "SMB3 signing algorithm[%u][%s] on dialect[%s] "
+ "not allowed by '%s smb3 signing algorithms' - %s.\n",
+ debug_prefix,
+ sign_algo,
+ smb3_signing_algorithm_name(sign_algo),
+ smb_protocol_types_string(protocol),
+ role,
+ nt_errstr(error_status)));
+ return error_status;
+ }
+
+ if (!found_encryption) {
+ /*
+ * We negotiated a cipher we don't allow,
+ * most likely for SMB 3.0 and 3.0.2
+ */
+ DEBUG(debug_lvl,("%s: "
+ "SMB3 encryption algorithm[%u][%s] on dialect[%s] "
+ "not allowed by '%s smb3 encryption algorithms' - %s.\n",
+ debug_prefix,
+ cipher_algo,
+ smb3_encryption_algorithm_name(cipher_algo),
+ smb_protocol_types_string(protocol),
+ role,
+ nt_errstr(error_status)));
+ return error_status;
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/libcli/smb/wscript b/libcli/smb/wscript
new file mode 100644
index 0000000..9849284
--- /dev/null
+++ b/libcli/smb/wscript
@@ -0,0 +1,86 @@
+#!/usr/bin/env python
+
+
+def build(bld):
+ bld.SAMBA_LIBRARY('smb_transport',
+ source='''
+ read_smb.c
+ ''',
+ deps='LIBASYNC_REQ',
+ public_deps='talloc tevent',
+ private_library=True,
+ private_headers='''
+ read_smb.h
+ ''',
+ )
+
+ bld.SAMBA_LIBRARY('cli_smb_common',
+ source='''
+ smb_signing.c
+ smb_seal.c
+ smb2_negotiate_context.c
+ smb2_create_blob.c smb2_signing.c
+ smb2_lease.c
+ util.c
+ smbXcli_base.c
+ smb1cli_trans.c
+ smb1cli_echo.c
+ smb1cli_create.c
+ smb1cli_session.c
+ smb1cli_close.c
+ smb1cli_write.c
+ smb1cli_read.c
+ smb2cli_session.c
+ smb2cli_tcon.c
+ smb2cli_create.c
+ smb2cli_close.c
+ smb2cli_read.c
+ smb2cli_write.c
+ smb2cli_flush.c
+ smb2cli_set_info.c
+ smb2cli_query_info.c
+ smb2cli_notify.c
+ smb2cli_query_directory.c
+ smb2cli_ioctl.c
+ smb2cli_echo.c
+ smb2_posix.c
+ tstream_smbXcli_np.c
+ reparse.c
+ ''',
+ deps='''
+ LIBCRYPTO gnutls NDR_SMB2_LEASE_STRUCT samba-errors gensec krb5samba
+ smb_transport GNUTLS_HELPERS NDR_IOCTL
+ ''',
+ public_deps='talloc samba-util iov_buf',
+ private_library=True,
+ private_headers='''
+ smb_common.h
+ smb2_constants.h
+ smb_constants.h
+ smb_signing.h
+ smb_seal.h
+ smb2_create_blob.h
+ smb2_signing.h
+ smb2_lease.h
+ smb_util.h
+ smb_unix_ext.h
+ smb_posix.h
+ tstream_smbXcli_np.h
+ ''',
+ )
+
+ bld.SAMBA_BINARY('test_smb1cli_session',
+ source='test_smb1cli_session.c',
+ deps='cmocka cli_smb_common',
+ for_selftest=True)
+
+ bld.SAMBA_BINARY('test_util_translate',
+ source='test_util_translate.c',
+ deps='cmocka cli_smb_common',
+ for_selftest=True)
+
+ bld.SAMBA_PYTHON('py_reparse_symlink',
+ source='py_reparse_symlink.c',
+ deps='cli_smb_common',
+ realname='samba/reparse_symlink.so'
+ )
diff --git a/libcli/smbreadline/smbreadline.c b/libcli/smbreadline/smbreadline.c
new file mode 100644
index 0000000..0a95c63
--- /dev/null
+++ b/libcli/smbreadline/smbreadline.c
@@ -0,0 +1,184 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba readline wrapper implementation
+ Copyright (C) Simo Sorce 2001
+ 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 "includes.h"
+#include "../lib/util/select.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "system/readline.h"
+#include "libcli/smbreadline/smbreadline.h"
+
+#undef malloc
+
+#ifdef HAVE_LIBREADLINE
+# ifdef HAVE_READLINE_READLINE_H
+# 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
+
+static bool smb_rl_done;
+
+#ifdef HAVE_LIBREADLINE
+/*
+ * MacOS/X does not have rl_done in readline.h, but
+ * readline.so has it
+ */
+extern int rl_done;
+#endif
+
+void smb_readline_done(void)
+{
+ smb_rl_done = true;
+#ifdef HAVE_LIBREADLINE
+ rl_done = 1;
+#endif
+}
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly
+****************************************************************************/
+
+static char *smb_readline_replacement(const char *prompt, void (*callback)(void),
+ char **(completion_fn)(const char *text, int start, int end))
+{
+ char *line = NULL;
+ int fd = fileno(stdin);
+ char *ret;
+
+ /* Prompt might be NULL in non-interactive mode. */
+ if (prompt) {
+ printf("%s", prompt);
+ fflush(stdout);
+ }
+
+ line = (char *)malloc(BUFSIZ);
+ if (!line) {
+ return NULL;
+ }
+
+ while (!smb_rl_done) {
+ struct pollfd pfd;
+
+ ZERO_STRUCT(pfd);
+ pfd.fd = fd;
+ pfd.events = POLLIN|POLLHUP;
+
+ if (sys_poll_intr(&pfd, 1, 5000) == 1) {
+ ret = fgets(line, BUFSIZ, stdin);
+ if (ret == 0) {
+ SAFE_FREE(line);
+ }
+ return ret;
+ }
+ if (callback) {
+ callback();
+ }
+ }
+ SAFE_FREE(line);
+ return NULL;
+}
+
+/****************************************************************************
+ Display the prompt and wait for input. Call callback() regularly.
+****************************************************************************/
+
+char *smb_readline(const char *prompt, void (*callback)(void),
+ char **(completion_fn)(const char *text, int start, int end))
+{
+ char *ret;
+ bool interactive;
+
+ interactive = isatty(fileno(stdin)) || getenv("CLI_FORCE_INTERACTIVE");
+ if (!interactive) {
+ return smb_readline_replacement(NULL, callback, completion_fn);
+ }
+
+#ifdef HAVE_LIBREADLINE
+
+ /* Aargh! Readline does bizarre things with the terminal width
+ that mucks up expect(1). Set CLI_NO_READLINE in the environment
+ to force readline not to be used. */
+
+ if (getenv("CLI_NO_READLINE"))
+ return smb_readline_replacement(prompt, callback, completion_fn);
+
+ if (completion_fn) {
+ /* The callback prototype has changed slightly between
+ different versions of Readline, so the same function
+ works in all of them to date, but we get compiler
+ warnings in some. */
+ rl_attempted_completion_function = RL_COMPLETION_CAST completion_fn;
+
+ /*
+ * We only want sensible characters as the word-break chars
+ * for the most part. This allows us to tab through a path.
+ */
+ rl_basic_word_break_characters = " \t\n";
+ }
+
+#ifdef HAVE_DECL_RL_EVENT_HOOK
+ if (callback)
+ rl_event_hook = (rl_hook_func_t *)callback;
+#endif
+ ret = readline(prompt);
+ if (ret && *ret)
+ add_history(ret);
+
+#else
+ ret = smb_readline_replacement(prompt, callback, completion_fn);
+#endif
+
+ return ret;
+}
+
+/****************************************************************************
+ * return line buffer text
+ ****************************************************************************/
+const char *smb_readline_get_line_buffer(void)
+{
+#if defined(HAVE_LIBREADLINE)
+ return rl_line_buffer;
+#else
+ return NULL;
+#endif
+}
+
+
+/****************************************************************************
+ * set completion append character
+ ***************************************************************************/
+void smb_readline_ca_char(char c)
+{
+#if defined(HAVE_LIBREADLINE)
+ rl_completion_append_character = c;
+#endif
+}
diff --git a/libcli/smbreadline/smbreadline.h b/libcli/smbreadline/smbreadline.h
new file mode 100644
index 0000000..9adc4b3
--- /dev/null
+++ b/libcli/smbreadline/smbreadline.h
@@ -0,0 +1,30 @@
+/*
+ Unix SMB/CIFS implementation.
+ Samba readline wrapper implementation
+ Copyright (C) Simo Sorce 2001
+ 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 __SMBREADLINE_H__
+#define __SMBREADLINE_H__
+
+char *smb_readline(const char *prompt, void (*callback)(void),
+ char **(completion_fn)(const char *text, int start, int end));
+const char *smb_readline_get_line_buffer(void);
+void smb_readline_ca_char(char c);
+void smb_readline_done(void);
+
+#endif /* __SMBREADLINE_H__ */
diff --git a/libcli/smbreadline/wscript_build b/libcli/smbreadline/wscript_build
new file mode 100644
index 0000000..17699ea
--- /dev/null
+++ b/libcli/smbreadline/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+
+termlib=bld.env.READLINE_TERMLIB or ''
+
+bld.SAMBA_SUBSYSTEM('SMBREADLINE',
+ source='smbreadline.c',
+ deps=termlib + ' readline talloc')
diff --git a/libcli/smbreadline/wscript_configure b/libcli/smbreadline/wscript_configure
new file mode 100644
index 0000000..912ff53
--- /dev/null
+++ b/libcli/smbreadline/wscript_configure
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+
+conf.CHECK_HEADERS('readline.h history.h readline/readline.h readline/history.h')
+for termlib in ['ncurses', 'curses', 'termcap', 'terminfo', 'termlib', 'tinfo']:
+ if conf.CHECK_FUNCS_IN('tgetent', termlib):
+ conf.env['READLINE_TERMLIB'] = termlib
+ break
+
+#
+# Check if we need to work around readline/readline.h
+# deprecated declarations
+#
+if conf.CONFIG_SET('HAVE_READLINE_READLINE_H'):
+ if not conf.CHECK_CODE('''
+ #include <readline/readline.h>
+ int main() {return 0;}
+ ''',
+ define='HAVE_WORKING_READLINE_READLINE_WITH_STRICT_PROTO',
+ cflags=conf.env['WERROR_CFLAGS'] +
+ ['-Wstrict-prototypes',
+ '-Werror=strict-prototypes'],
+ msg='for compiling <readline/readline.h> with strict prototypes',
+ addmain=False):
+ conf.CHECK_CODE('''
+ #define _FUNCTION_DEF
+ #include <readline/readline.h>
+ int main() {return 0;}
+ ''',
+ cflags=conf.env['WERROR_CFLAGS'] +
+ ['-Wstrict-prototypes',
+ '-Werror=strict-prototypes'],
+ msg='for workaround to <readline/readline.h> strict prototypes issue',
+ define='HAVE_READLINE_READLINE_WORKAROUND',
+ addmain=False)
+
+conf.CHECK_CODE('''
+#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
+# endif
+#endif
+int main(void) {rl_completion_t f; return 0;}
+''',
+'HAVE_RL_COMPLETION_FUNC_T', execute=False, addmain=False,
+msg='Checking for rl_completion_t')
+
+conf.CHECK_CODE('''
+#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
+# endif
+#endif
+int main(void) {CPPFunction f; return 0;}
+''',
+'HAVE_CPPFUNCTION', execute=False, addmain=False,
+msg='Checking for CPPFunction')
+
+if conf.CHECK_FUNCS_IN('rl_completion_matches', 'readline'):
+ conf.DEFINE('HAVE_NEW_LIBREADLINE', 1)
+
+if conf.CHECK_FUNCS_IN('history_list', 'readline'):
+ conf.DEFINE('HAVE_HISTORY_LIST', 1)
diff --git a/libcli/tstream_binding_handle/tstream_binding_handle.c b/libcli/tstream_binding_handle/tstream_binding_handle.c
new file mode 100644
index 0000000..76f54a7
--- /dev/null
+++ b/libcli/tstream_binding_handle/tstream_binding_handle.c
@@ -0,0 +1,341 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Ralph Boehme 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 <tevent.h>
+#include "libcli/tstream_binding_handle/tstream_binding_handle.h"
+#include "system/filesys.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/debug.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "libcli/smb/tstream_smbXcli_np.h"
+
+struct tstream_bh_state {
+ struct tstream_context *stream;
+ struct tevent_queue *write_queue;
+ const struct ndr_interface_table *table;
+ uint32_t request_timeout;
+ size_t call_initial_read_size;
+ tstream_read_pdu_blob_full_fn_t *complete_pdu_fn;
+ void *complete_pdu_fn_private;
+};
+
+static bool tstream_bh_is_connected(struct dcerpc_binding_handle *h)
+{
+ struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+ h, struct tstream_bh_state);
+ ssize_t ret;
+
+ if (hs->stream == NULL) {
+ return false;
+ }
+
+ ret = tstream_pending_bytes(hs->stream);
+ if (ret == -1) {
+ return false;
+ }
+
+ return true;
+}
+
+static uint32_t tstream_bh_set_timeout(struct dcerpc_binding_handle *h,
+ uint32_t timeout)
+{
+ struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+ h, struct tstream_bh_state);
+ uint32_t old;
+
+ old = hs->request_timeout;
+ hs->request_timeout = timeout;
+
+ return old;
+}
+
+struct tstream_bh_disconnect_state {
+ struct tstream_bh_state *hs;
+};
+
+static void tstream_bh_disconnect_done(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_bh_disconnect_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h)
+{
+ struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+ h, struct tstream_bh_state);
+ struct tevent_req *req = NULL;
+ struct tstream_bh_disconnect_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_bh_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->hs = hs;
+
+ ok = tstream_bh_is_connected(h);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = tstream_disconnect_send(state, ev, hs->stream);
+ if (tevent_req_nomem(subreq, req)) {
+ tevent_req_post(req, ev);
+ return req;
+ }
+ tevent_req_set_callback(subreq, tstream_bh_disconnect_done, req);
+
+ return req;
+}
+
+static void tstream_bh_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct tstream_bh_disconnect_state *state = tevent_req_data(
+ req, struct tstream_bh_disconnect_state);
+ int ret, err;
+
+ ret = tstream_disconnect_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ DBG_ERR("tstream_bh_disconnect failed [%s]\n", strerror(err));
+ tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+ return;
+ }
+
+ state->hs->stream = NULL;
+}
+
+static NTSTATUS tstream_bh_disconnect_recv(struct tevent_req *req)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+struct tstream_bh_call_state {
+ struct tevent_context *ev;
+ struct tstream_context *stream;
+ struct tstream_bh_state *hs;
+ struct iovec out_data;
+ DATA_BLOB in_data;
+};
+
+static void tstream_bh_call_writev_done(struct tevent_req *subreq);
+static void tstream_bh_call_read_pdu_done(struct tevent_req *subreq);
+
+static struct tevent_req *tstream_bh_call_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ uint32_t opnum,
+ uint32_t in_flags,
+ const uint8_t *out_data,
+ size_t out_length)
+{
+ struct tstream_bh_state *hs = dcerpc_binding_handle_data(
+ h, struct tstream_bh_state);
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct tstream_bh_call_state* state = NULL;
+ struct timeval timeout;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_bh_call_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ *state = (struct tstream_bh_call_state) {
+ .ev = ev,
+ .stream = hs->stream,
+ .hs = hs,
+ .out_data = {
+ .iov_base = discard_const_p(uint8_t, out_data),
+ .iov_len = out_length,
+ },
+ };
+
+ ok = tstream_bh_is_connected(h);
+ if (!ok) {
+ tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
+ return tevent_req_post(req, ev);
+ }
+
+ if (tstream_is_smbXcli_np(hs->stream)) {
+ tstream_smbXcli_np_use_trans(hs->stream);
+ }
+ if (tevent_queue_length(hs->write_queue) > 0) {
+ tevent_req_nterror(req, NT_STATUS_PIPE_BUSY);
+ }
+
+ timeout = timeval_current_ofs(hs->request_timeout, 0);
+
+ subreq = tstream_writev_queue_send(state, ev,
+ state->stream,
+ hs->write_queue,
+ &state->out_data, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_set_endtime(subreq, ev, timeout)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_bh_call_writev_done, req);
+
+ subreq = tstream_read_pdu_blob_send(state,
+ ev,
+ hs->stream,
+ hs->call_initial_read_size,
+ hs->complete_pdu_fn,
+ hs->complete_pdu_fn_private);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ if (!tevent_req_set_endtime(subreq, ev, timeout)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_bh_call_read_pdu_done, req);
+
+ return req;
+}
+
+static void tstream_bh_call_writev_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct tstream_bh_call_state *state = tevent_req_data(
+ req, struct tstream_bh_call_state);
+ int ret, err;
+
+ ret = tstream_writev_queue_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ state->hs->stream = NULL;
+ tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+ return;
+ }
+}
+
+static void tstream_bh_call_read_pdu_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct tstream_bh_call_state *state = tevent_req_data(
+ req, struct tstream_bh_call_state);
+ NTSTATUS status;
+
+ status = tstream_read_pdu_blob_recv(subreq, state, &state->in_data);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ state->hs->stream = NULL;
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS tstream_bh_call_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **in_data,
+ size_t *in_length,
+ uint32_t *in_flags)
+{
+ NTSTATUS status;
+ struct tstream_bh_call_state *state = tevent_req_data(
+ req, struct tstream_bh_call_state);
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *in_data = talloc_move(mem_ctx, &state->in_data.data);
+ *in_length = state->in_data.length;
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+static const struct dcerpc_binding_handle_ops tstream_bh_ops = {
+ .name = "tstream_binding_handle",
+ .is_connected = tstream_bh_is_connected,
+ .set_timeout = tstream_bh_set_timeout,
+ .raw_call_send = tstream_bh_call_send,
+ .raw_call_recv = tstream_bh_call_recv,
+ .disconnect_send = tstream_bh_disconnect_send,
+ .disconnect_recv = tstream_bh_disconnect_recv,
+};
+
+struct dcerpc_binding_handle *tstream_binding_handle_create(
+ TALLOC_CTX *mem_ctx,
+ const struct ndr_interface_table *table,
+ struct tstream_context **stream,
+ size_t call_initial_read_size,
+ tstream_read_pdu_blob_full_fn_t *complete_pdu_fn,
+ void *complete_pdu_fn_private,
+ uint32_t max_data)
+{
+ struct dcerpc_binding_handle *h = NULL;
+ struct tstream_bh_state *hs = NULL;
+
+ h = dcerpc_binding_handle_create(mem_ctx,
+ &tstream_bh_ops,
+ NULL,
+ table,
+ &hs,
+ struct tstream_bh_state,
+ __location__);
+ if (h == NULL) {
+ return NULL;
+ }
+
+ hs->table = table;
+ hs->stream = talloc_move(hs, stream);
+ hs->call_initial_read_size = call_initial_read_size;
+ hs->complete_pdu_fn = complete_pdu_fn;
+ hs->complete_pdu_fn_private = complete_pdu_fn_private;
+
+ hs->write_queue = tevent_queue_create(hs, "write_queue");
+ if (hs->write_queue == NULL) {
+ TALLOC_FREE(h);
+ return NULL;
+ }
+
+ if (max_data > 0) {
+ tstream_smbXcli_np_set_max_data(hs->stream, max_data);
+ }
+
+ return h;
+}
diff --git a/libcli/tstream_binding_handle/tstream_binding_handle.h b/libcli/tstream_binding_handle/tstream_binding_handle.h
new file mode 100644
index 0000000..e540737
--- /dev/null
+++ b/libcli/tstream_binding_handle/tstream_binding_handle.h
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Ralph Boehme 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 _TSTREAM_BINDING_HANDLE_H_
+#define _TSTREAM_BINDING_HANDLE_H_
+
+#include <talloc.h>
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/rpc_common.h"
+#include "libcli/util/tstream.h"
+
+struct dcerpc_binding_handle *tstream_binding_handle_create(
+ TALLOC_CTX *mem_ctx,
+ const struct ndr_interface_table *table,
+ struct tstream_context **stream,
+ size_t call_initial_read_size,
+ tstream_read_pdu_blob_full_fn_t *complete_pdu_fn,
+ void *complete_pdu_fn_private,
+ uint32_t max_data);
+
+#endif /* _TSTREAM_BINDING_HANDLE_H_ */
diff --git a/libcli/tstream_binding_handle/wscript_build b/libcli/tstream_binding_handle/wscript_build
new file mode 100644
index 0000000..622ed70
--- /dev/null
+++ b/libcli/tstream_binding_handle/wscript_build
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+bld.SAMBA_SUBSYSTEM('tstream_binding_handle',
+ source='tstream_binding_handle.c',
+ deps='tevent LIBTSOCKET')
diff --git a/libcli/util/doserr.c b/libcli/util/doserr.c
new file mode 100644
index 0000000..c30abc8
--- /dev/null
+++ b/libcli/util/doserr.c
@@ -0,0 +1,147 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * DOS error routines
+ * Copyright (C) Tim Potter 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/>.
+ */
+
+/* DOS error codes. please read doserr.h */
+
+#include "replace.h"
+#include "libcli/util/werror.h"
+#include "libcli/util/hresult.h"
+
+struct werror_code_struct {
+ const char *dos_errstr;
+ WERROR werror;
+};
+
+struct werror_str_struct {
+ WERROR werror;
+ const char *friendly_errstr;
+};
+
+static const struct werror_code_struct special_errs[] =
+{
+ { "WERR_DNS_ERROR_NOT_ALLOWED_ON_ACTIVE_SKD", WERR_DNS_ERROR_NOT_ALLOWED_ON_ACTIVE_SKD },
+ { "WERR_DNS_ERROR_INVALID_NSEC3_PARAMETERS", WERR_DNS_ERROR_INVALID_NSEC3_PARAMETERS },
+ { "WERR_DNS_ERROR_DNSSEC_IS_DISABLED", WERR_DNS_ERROR_DNSSEC_IS_DISABLED },
+ { "WERR_DNS_ERROR_NOT_ALLOWED_ON_UNSIGNED_ZONE", WERR_DNS_ERROR_NOT_ALLOWED_ON_UNSIGNED_ZONE },
+ { "WERR_DNS_ERROR_KSP_DOES_NOT_SUPPORT_PROTECTION", WERR_DNS_ERROR_KSP_DOES_NOT_SUPPORT_PROTECTION },
+ { "WERR_DNS_ERROR_BAD_KEYMASTER", WERR_DNS_ERROR_BAD_KEYMASTER },
+ { "WERR_USER_APC", WERR_USER_APC },
+ { "WERR_DNS_ERROR_UNEXPECTED_DATA_PROTECTION_ERROR", WERR_DNS_ERROR_UNEXPECTED_DATA_PROTECTION_ERROR },
+ { "WERR_WAIT_2", WERR_WAIT_2 },
+ { "WERR_WAIT_3", WERR_WAIT_3 },
+ { "WERR_WAIT_1", WERR_WAIT_1 },
+ { "WERR_DNS_ERROR_NSEC3_NAME_COLLISION", WERR_DNS_ERROR_NSEC3_NAME_COLLISION },
+ { "WERR_DNS_ERROR_KSP_NOT_ACCESSIBLE", WERR_DNS_ERROR_KSP_NOT_ACCESSIBLE },
+ { "WERR_DNS_ERROR_ROLLOVER_NOT_POKEABLE", WERR_DNS_ERROR_ROLLOVER_NOT_POKEABLE },
+ { "WERR_DNS_ERROR_INVALID_KEY_SIZE", WERR_DNS_ERROR_INVALID_KEY_SIZE },
+ { "WERR_DNS_ERROR_ROLLOVER_ALREADY_QUEUED", WERR_DNS_ERROR_ROLLOVER_ALREADY_QUEUED },
+ { "WERR_DNS_ERROR_UNKNOWN_SIGNING_PARAMETER_VERSION", WERR_DNS_ERROR_UNKNOWN_SIGNING_PARAMETER_VERSION },
+ { "WERR_DNS_ERROR_INVALID_INITIAL_ROLLOVER_OFFSET", WERR_DNS_ERROR_INVALID_INITIAL_ROLLOVER_OFFSET },
+ { "WERR_DNS_ERROR_SIGNING_KEY_NOT_ACCESSIBLE", WERR_DNS_ERROR_SIGNING_KEY_NOT_ACCESSIBLE },
+ { "WERR_DNS_REQUEST_PENDING", WERR_DNS_REQUEST_PENDING },
+ { "WERR_LOG_HARD_ERROR", WERR_LOG_HARD_ERROR },
+ { "WERR_DNS_ERROR_NOT_ALLOWED_ON_ZSK", WERR_DNS_ERROR_NOT_ALLOWED_ON_ZSK },
+ { "WERR_OK", WERR_OK },
+ { "WERR_DNS_ERROR_KEYMASTER_REQUIRED", WERR_DNS_ERROR_KEYMASTER_REQUIRED },
+ { "WERR_STATUS_MORE_ENTRIES", WERR_STATUS_MORE_ENTRIES },
+ { "WERR_DS_INVALID_ATTRIBUTE_SYNTAX", WERR_DS_INVALID_ATTRIBUTE_SYNTAX },
+ { "WERR_ALERTED", WERR_ALERTED },
+ { "WERR_DNS_ERROR_UNSUPPORTED_ALGORITHM", WERR_DNS_ERROR_UNSUPPORTED_ALGORITHM },
+ { "WERR_DNS_ERROR_INVALID_NSEC3_ITERATION_COUNT", WERR_DNS_ERROR_INVALID_NSEC3_ITERATION_COUNT },
+ { "WERR_DNS_ERROR_INVALID_XML", WERR_DNS_ERROR_INVALID_XML },
+ { "WERR_DNS_ERROR_DELEGATION_REQUIRED", WERR_DNS_ERROR_DELEGATION_REQUIRED },
+ { "WERR_ABANDONED_WAIT_63", WERR_ABANDONED_WAIT_63 },
+ { "WERR_DNS_ERROR_UNEXPECTED_CNG_ERROR", WERR_DNS_ERROR_UNEXPECTED_CNG_ERROR },
+ { "WERR_DNS_ERROR_DNAME_COLLISION", WERR_DNS_ERROR_DNAME_COLLISION },
+ { "WERR_DNS_ERROR_INVALID_POLICY_TABLE", WERR_DNS_ERROR_INVALID_POLICY_TABLE },
+ { "WERR_DNS_ERROR_NO_VALID_TRUST_ANCHORS", WERR_DNS_ERROR_NO_VALID_TRUST_ANCHORS },
+ { "WERR_MULTIPLE_FAULT_VIOLATION", WERR_MULTIPLE_FAULT_VIOLATION },
+ { "WERR_DNS_ERROR_INVALID_ROLLOVER_PERIOD", WERR_DNS_ERROR_INVALID_ROLLOVER_PERIOD },
+ { "WERR_DNS_ERROR_INVALID_SIGNATURE_VALIDITY_PERIOD", WERR_DNS_ERROR_INVALID_SIGNATURE_VALIDITY_PERIOD },
+ { "WERR_DNS_ERROR_NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS", WERR_DNS_ERROR_NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS },
+ { "WERR_INVALID_PRIMARY_GROUP", WERR_INVALID_PRIMARY_GROUP },
+ { "WERR_KERNEL_APC", WERR_KERNEL_APC },
+ { "WERR_DNS_ERROR_NOT_ALLOWED_UNDER_DNAME", WERR_DNS_ERROR_NOT_ALLOWED_UNDER_DNAME },
+ { "WERR_DNS_ERROR_TOO_MANY_SKDS", WERR_DNS_ERROR_TOO_MANY_SKDS },
+ { "WERR_DNS_ERROR_NODE_IS_DNMAE", WERR_DNS_ERROR_NODE_IS_DNAME },
+ { "WERR_DNS_ERROR_NODE_IS_DNAME", WERR_DNS_ERROR_NODE_IS_DNAME },
+ { "WERR_SERVICE_NOTIFICATION", WERR_SERVICE_NOTIFICATION },
+ { "WERR_WAIT_63", WERR_WAIT_63 },
+ { "WERR_DNS_ERROR_STANDBY_KEY_NOT_PRESENT", WERR_DNS_ERROR_STANDBY_KEY_NOT_PRESENT },
+ { "WERR_DNS_ERROR_ALIAS_LOOP", WERR_DNS_ERROR_ALIAS_LOOP },
+ { "WERR_DNS_ERROR_ROLLOVER_IN_PROGRESS", WERR_DNS_ERROR_ROLLOVER_IN_PROGRESS },
+ { "WERR_DNS_ERROR_NOT_ALLOWED_ON_SIGNED_ZONE", WERR_DNS_ERROR_NOT_ALLOWED_ON_SIGNED_ZONE },
+ { 0, W_ERROR(0) }
+};
+
+/*****************************************************************************
+ returns a windows error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+const char *win_errstr(WERROR werror)
+{
+ static char msg[40];
+ int idx = 0;
+
+ while (special_errs[idx].dos_errstr != NULL) {
+ if (W_ERROR_V(special_errs[idx].werror) ==
+ W_ERROR_V(werror))
+ return special_errs[idx].dos_errstr;
+ idx++;
+ }
+
+ idx = 0;
+
+ switch W_ERROR_V(werror) {
+#include "werror_gen.c"
+ default:
+ break;
+ }
+
+ /*
+ * WERROR codes are 16-bit only, if the
+ * upper 16-bit are not 0, it's likely
+ * an HRESULT.
+ *
+ * E.g. we should display HRES_SEC_E_WRONG_PRINCIPAL instead of
+ * 'DOS code 0x80090322'
+ */
+ if ((W_ERROR_V(werror) & 0xFFFF0000) != 0) {
+ HRESULT hres = HRES_ERROR(W_ERROR_V(werror));
+ return hresult_errstr(hres);
+ }
+
+ slprintf(msg, sizeof(msg), "DOS code 0x%08x", W_ERROR_V(werror));
+
+ return msg;
+}
+
+/*****************************************************************************
+ Get friendly error string for WERRORs
+ *****************************************************************************/
+
+const char *get_friendly_werror_msg(WERROR werror)
+{
+ switch W_ERROR_V(werror) {
+#include "werror_friendly_gen.c"
+ default:
+ break;
+ }
+
+ return win_errstr(werror);
+}
diff --git a/libcli/util/doserr.h b/libcli/util/doserr.h
new file mode 100644
index 0000000..b57ac5d
--- /dev/null
+++ b/libcli/util/doserr.h
@@ -0,0 +1,176 @@
+/*
+ Unix SMB/CIFS implementation.
+ DOS error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 1998-2000
+ Copyright (C) Gerald (Jerry) Carter 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 _DOSERR_H
+#define _DOSERR_H
+
+/* Error classes */
+
+#define ERRDOS 0x01 /* Error is from the core DOS operating system set. */
+#define ERRSRV 0x02 /* Error is generated by the server network file manager.*/
+#define ERRHRD 0x03 /* Error is an hardware error. */
+#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
+
+/* SMB X/Open error codes for the ERRDOS error class */
+#define ERRsuccess 0 /* No error */
+#define ERRbadfunc 1 /* Invalid function (or system call) */
+#define ERRbadfile 2 /* File not found (pathname error) */
+#define ERRbadpath 3 /* Directory not found */
+#define ERRnofids 4 /* Too many open files */
+#define ERRnoaccess 5 /* Access denied */
+#define ERRbadfid 6 /* Invalid fid */
+#define ERRbadmcb 7 /* Memory control blocks destroyed. */
+#define ERRnomem 8 /* Out of memory */
+#define ERRbadmem 9 /* Invalid memory block address */
+#define ERRbadenv 10 /* Invalid environment */
+#define ERRbadformat 11 /* Bad Format */
+#define ERRbadaccess 12 /* Invalid open mode */
+#define ERRbaddata 13 /* Invalid data (only from ioctl call) */
+#define ERRres 14 /* reserved */
+#define ERRbaddrive 15 /* Invalid drive */
+#define ERRremcd 16 /* Attempt to delete current directory */
+#define ERRdiffdevice 17 /* rename/move across different filesystems */
+#define ERRnofiles 18 /* no more files found in file search */
+#define ERRgeneral 31 /* General failure */
+#define ERRbadshare 32 /* Share mode on file conflict with open mode */
+#define ERRlock 33 /* Lock request conflicts with existing lock */
+#define ERRunsup 50 /* Request unsupported, returned by Win 95, RJS 20Jun98 */
+#define ERRnetnamedel 64 /* Network name deleted or not available */
+#define ERRnosuchshare 67 /* You specified an invalid share name */
+#define ERRfilexists 80 /* File in operation already exists */
+#define ERRinvalidparam 87
+#define ERRcannotopen 110 /* Cannot open the file specified */
+#define ERRbufferoverflow 111
+#define ERRinsufficientbuffer 122
+#define ERRinvalidname 123 /* Invalid name */
+#define ERRunknownlevel 124
+#define ERRnotlocked 158 /* This region is not locked by this locking context. */
+#define ERRinvalidpath 161
+#define ERRcancelviolation 173
+#define ERRnoatomiclocks 174
+#define ERRrename 183
+#define ERRbadpipe 230 /* Named pipe invalid */
+#define ERRpipebusy 231 /* All instances of pipe are busy */
+#define ERRpipeclosing 232 /* named pipe close in progress */
+#define ERRnotconnected 233 /* No process on other end of named pipe */
+#define ERRmoredata 234 /* More data to be returned */
+#define ERReainconsistent 255 /* from EMC */
+#define ERRnomoreitems 259
+#define ERRbaddirectory 267 /* Invalid directory name in a path. */
+#define ERReasnotsupported 282 /* Extended attributes */
+#define ERRlogonfailure 1326 /* Unknown username or bad password */
+#define ERRbuftoosmall 2123
+#define ERRunknownipc 2142
+#define ERRnosuchprintjob 2151
+#define ERRinvgroup 2455
+
+/* here's a special one from observing NT */
+#define ERRnoipc 66 /* don't support ipc */
+
+/* These errors seem to be only returned by the NT printer driver system */
+#define ERRdriveralreadyinstalled 1795 /* ERROR_PRINTER_DRIVER_ALREADY_INSTALLED */
+#define ERRunknownprinterport 1796 /* ERROR_UNKNOWN_PORT */
+#define ERRunknownprinterdriver 1797 /* ERROR_UNKNOWN_PRINTER_DRIVER */
+#define ERRunknownprintprocessor 1798 /* ERROR_UNKNOWN_PRINTPROCESSOR */
+#define ERRinvalidseparatorfile 1799 /* ERROR_INVALID_SEPARATOR_FILE */
+#define ERRinvalidjobpriority 1800 /* ERROR_INVALID_PRIORITY */
+#define ERRinvalidprintername 1801 /* ERROR_INVALID_PRINTER_NAME */
+#define ERRprinteralreadyexists 1802 /* ERROR_PRINTER_ALREADY_EXISTS */
+#define ERRinvalidprintercommand 1803 /* ERROR_INVALID_PRINTER_COMMAND */
+#define ERRinvaliddatatype 1804 /* ERROR_INVALID_DATATYPE */
+#define ERRinvalidenvironment 1805 /* ERROR_INVALID_ENVIRONMENT */
+
+#define ERRunknownprintmonitor 3000 /* ERROR_UNKNOWN_PRINT_MONITOR */
+#define ERRprinterdriverinuse 3001 /* ERROR_PRINTER_DRIVER_IN_USE */
+#define ERRspoolfilenotfound 3002 /* ERROR_SPOOL_FILE_NOT_FOUND */
+#define ERRnostartdoc 3003 /* ERROR_SPL_NO_STARTDOC */
+#define ERRnoaddjob 3004 /* ERROR_SPL_NO_ADDJOB */
+#define ERRprintprocessoralreadyinstalled 3005 /* ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED */
+#define ERRprintmonitoralreadyinstalled 3006 /* ERROR_PRINT_MONITOR_ALREADY_INSTALLED */
+#define ERRinvalidprintmonitor 3007 /* ERROR_INVALID_PRINT_MONITOR */
+#define ERRprintmonitorinuse 3008 /* ERROR_PRINT_MONITOR_IN_USE */
+#define ERRprinterhasjobsqueued 3009 /* ERROR_PRINTER_HAS_JOBS_QUEUED */
+
+/* Error codes for the ERRSRV class */
+
+#define ERRerror 1 /* Non specific error code */
+#define ERRbadpw 2 /* Bad password */
+#define ERRbadtype 3 /* reserved */
+#define ERRaccess 4 /* No permissions to do the requested operation */
+#define ERRinvnid 5 /* tid invalid */
+#define ERRinvnetname 6 /* Invalid servername */
+#define ERRinvdevice 7 /* Invalid device */
+#define ERRqfull 49 /* Print queue full */
+#define ERRqtoobig 50 /* Queued item too big */
+#define ERRinvpfid 52 /* Invalid print file in smb_fid */
+#define ERRsmbcmd 64 /* Unrecognised command */
+#define ERRsrverror 65 /* smb server internal error */
+#define ERRfilespecs 67 /* fid and pathname invalid combination */
+#define ERRbadlink 68 /* reserved */
+#define ERRbadpermits 69 /* Access specified for a file is not valid */
+#define ERRbadpid 70 /* reserved */
+#define ERRsetattrmode 71 /* attribute mode invalid */
+#define ERRpaused 81 /* Message server paused */
+#define ERRmsgoff 82 /* Not receiving messages */
+#define ERRnoroom 83 /* No room for message */
+#define ERRrmuns 87 /* too many remote usernames */
+#define ERRtimeout 88 /* operation timed out */
+#define ERRnoresource 89 /* No resources currently available for request. */
+#define ERRtoomanyuids 90 /* too many userids */
+#define ERRbaduid 91 /* bad userid */
+#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */
+#define ERRuseSTD 251 /* temporarily unable to use raw mode, use standard mode */
+#define ERRcontMPX 252 /* resume MPX mode */
+#define ERRbadPW /* reserved */
+#define ERRnosupport 0xFFFF
+#define ERRunknownsmb 22 /* from NT 3.5 response */
+
+/* Error codes for the ERRHRD class */
+
+#define ERRnowrite 19 /* read only media */
+#define ERRbadunit 20 /* Unknown device */
+#define ERRnotready 21 /* Drive not ready */
+#define ERRbadcmd 22 /* Unknown command */
+#define ERRdata 23 /* Data (CRC) error */
+#define ERRbadreq 24 /* Bad request structure length */
+#define ERRseek 25
+#define ERRbadmedia 26
+#define ERRbadsector 27
+#define ERRnopaper 28
+#define ERRwrite 29 /* write fault */
+#define ERRread 30 /* read fault */
+#define ERRgeneral 31 /* General hardware failure */
+#define ERRwrongdisk 34
+#define ERRFCBunavail 35
+#define ERRsharebufexc 36 /* share buffer exceeded */
+#define ERRdiskfull 39
+
+#ifndef NERR_BASE
+#define NERR_BASE (2100)
+#endif
+
+#ifndef FRS_ERR_BASE
+#define FRS_ERR_BASE (8000)
+#endif
+
+#endif /* _DOSERR_H */
diff --git a/libcli/util/errmap_unix.c b/libcli/util/errmap_unix.c
new file mode 100644
index 0000000..16c7b49
--- /dev/null
+++ b/libcli/util/errmap_unix.c
@@ -0,0 +1,297 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * error mapping functions
+ * Copyright (C) Andrew Tridgell 2001
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Tim Potter 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 "includes.h"
+
+/* Mapping between Unix, and NT error numbers */
+
+static const struct {
+ int unix_error;
+ NTSTATUS nt_error;
+} unix_nt_errmap[] = {
+ { EAGAIN, STATUS_MORE_ENTRIES },
+ { EINTR, STATUS_MORE_ENTRIES },
+ { ENOBUFS, STATUS_MORE_ENTRIES },
+#ifdef EWOULDBLOCK
+ { EWOULDBLOCK, STATUS_MORE_ENTRIES },
+#endif
+ { EINPROGRESS, NT_STATUS_MORE_PROCESSING_REQUIRED },
+ { EPERM, NT_STATUS_ACCESS_DENIED },
+ { EACCES, NT_STATUS_ACCESS_DENIED },
+ { ENOENT, NT_STATUS_OBJECT_NAME_NOT_FOUND },
+ { ENOTDIR, NT_STATUS_NOT_A_DIRECTORY },
+ { EIO, NT_STATUS_IO_DEVICE_ERROR },
+ { EBADF, NT_STATUS_INVALID_HANDLE },
+ { EINVAL, NT_STATUS_INVALID_PARAMETER },
+ { EEXIST, NT_STATUS_OBJECT_NAME_COLLISION},
+ { ENFILE, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { EMFILE, NT_STATUS_TOO_MANY_OPENED_FILES },
+ { ENOSPC, NT_STATUS_DISK_FULL },
+ { ENOTSOCK, NT_STATUS_INVALID_HANDLE },
+ { EFAULT, NT_STATUS_INVALID_PARAMETER },
+ { EMSGSIZE, NT_STATUS_INVALID_BUFFER_SIZE },
+ { ENOMEM, NT_STATUS_NO_MEMORY },
+ { EISDIR, NT_STATUS_FILE_IS_A_DIRECTORY},
+#ifdef EPIPE
+ { EPIPE, NT_STATUS_CONNECTION_DISCONNECTED },
+#endif
+ { EBUSY, NT_STATUS_SHARING_VIOLATION },
+ { ENOSYS, NT_STATUS_INVALID_SYSTEM_SERVICE },
+#ifdef EOPNOTSUPP
+ { EOPNOTSUPP, NT_STATUS_NOT_SUPPORTED},
+#endif
+ { EMLINK, NT_STATUS_TOO_MANY_LINKS },
+ { ENOSYS, NT_STATUS_NOT_SUPPORTED },
+#ifdef ELOOP
+ { ELOOP, NT_STATUS_OBJECT_PATH_NOT_FOUND },
+#endif
+#ifdef ENODATA
+ { ENODATA, NT_STATUS_NOT_FOUND },
+#endif
+#ifdef EFTYPE
+ { EFTYPE, NT_STATUS_OBJECT_PATH_NOT_FOUND },
+#endif
+#ifdef EDQUOT
+ { EDQUOT, NT_STATUS_DISK_FULL }, /* Windows apps need this, not NT_STATUS_QUOTA_EXCEEDED */
+#endif
+#ifdef ENOTEMPTY
+ { ENOTEMPTY, NT_STATUS_DIRECTORY_NOT_EMPTY },
+#endif
+#ifdef EXDEV
+ { EXDEV, NT_STATUS_NOT_SAME_DEVICE },
+#endif
+#ifdef EROFS
+ { EROFS, NT_STATUS_MEDIA_WRITE_PROTECTED },
+#endif
+#ifdef ENAMETOOLONG
+ { ENAMETOOLONG, NT_STATUS_NAME_TOO_LONG },
+#endif
+#ifdef EFBIG
+ { EFBIG, NT_STATUS_DISK_FULL },
+#endif
+#ifdef EADDRINUSE
+ { EADDRINUSE, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+#endif
+#ifdef ENETUNREACH
+ { ENETUNREACH, NT_STATUS_NETWORK_UNREACHABLE},
+#endif
+#ifdef EHOSTUNREACH
+ { EHOSTUNREACH, NT_STATUS_HOST_UNREACHABLE},
+#endif
+#ifdef ECONNREFUSED
+ { ECONNREFUSED, NT_STATUS_CONNECTION_REFUSED},
+#endif
+#ifdef EADDRNOTAVAIL
+ { EADDRNOTAVAIL,NT_STATUS_ADDRESS_NOT_ASSOCIATED },
+#endif
+#ifdef ETIMEDOUT
+ { ETIMEDOUT, NT_STATUS_IO_TIMEOUT},
+#endif
+#ifdef ESOCKTNOSUPPORT
+ { ESOCKTNOSUPPORT,NT_STATUS_INVALID_PARAMETER_MIX },
+#endif
+#ifdef EAFNOSUPPORT
+ { EAFNOSUPPORT, NT_STATUS_INVALID_PARAMETER_MIX },
+#endif
+#ifdef ECONNABORTED
+ { ECONNABORTED, NT_STATUS_CONNECTION_ABORTED},
+#endif
+#ifdef ECONNRESET
+ { ECONNRESET, NT_STATUS_CONNECTION_RESET},
+#endif
+#ifdef ENOPROTOOPT
+ { ENOPROTOOPT, NT_STATUS_INVALID_PARAMETER_MIX },
+#endif
+#ifdef ENODEV
+ { ENODEV, NT_STATUS_NO_SUCH_DEVICE },
+#endif
+#ifdef ENOATTR
+ { ENOATTR, NT_STATUS_NOT_FOUND },
+#endif
+#ifdef ECANCELED
+ { ECANCELED, NT_STATUS_CANCELLED},
+#endif
+#ifdef ENOTSUP
+ { ENOTSUP, NT_STATUS_NOT_SUPPORTED},
+#endif
+
+ { 0, NT_STATUS_UNSUCCESSFUL }
+};
+
+
+/*********************************************************************
+ Map an NT error code from a Unix error code.
+*********************************************************************/
+NTSTATUS map_nt_error_from_unix_common(int unix_error)
+{
+ size_t i;
+
+ /* Look through list */
+ for (i=0;i<ARRAY_SIZE(unix_nt_errmap);i++) {
+ if (unix_nt_errmap[i].unix_error == unix_error) {
+ return unix_nt_errmap[i].nt_error;
+ }
+ }
+
+ /* Default return */
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/* Return a UNIX errno from a NT status code */
+static const struct {
+ NTSTATUS status;
+ int error;
+} nt_errno_map[] = {
+ {NT_STATUS_ACCESS_VIOLATION, EACCES},
+ {NT_STATUS_INVALID_HANDLE, EBADF},
+ {NT_STATUS_ACCESS_DENIED, EACCES},
+ {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT},
+ {NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT},
+ {NT_STATUS_SHARING_VIOLATION, EBUSY},
+ {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR},
+ {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST},
+ {NT_STATUS_PATH_NOT_COVERED, ENOENT},
+ {NT_STATUS_UNSUCCESSFUL, EINVAL},
+ {NT_STATUS_NOT_IMPLEMENTED, ENOSYS},
+ {NT_STATUS_IN_PAGE_ERROR, EFAULT},
+ {NT_STATUS_BAD_NETWORK_NAME, ENOENT},
+#ifdef EDQUOT
+ {NT_STATUS_PAGEFILE_QUOTA, EDQUOT},
+ {NT_STATUS_QUOTA_EXCEEDED, EDQUOT},
+ {NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT},
+ {NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT},
+#endif
+#ifdef ETIME
+ {NT_STATUS_TIMER_NOT_CANCELED, ETIME},
+#endif
+ {NT_STATUS_INVALID_PARAMETER, EINVAL},
+ {NT_STATUS_NO_SUCH_DEVICE, ENODEV},
+ {NT_STATUS_NO_SUCH_FILE, ENOENT},
+#ifdef ENODATA
+ {NT_STATUS_END_OF_FILE, ENODATA},
+#endif
+#ifdef ENOMEDIUM
+ {NT_STATUS_NO_MEDIA_IN_DEVICE, ENOMEDIUM},
+ {NT_STATUS_NO_MEDIA, ENOMEDIUM},
+#endif
+ {NT_STATUS_NONEXISTENT_SECTOR, ESPIPE},
+ {NT_STATUS_NO_MEMORY, ENOMEM},
+ {NT_STATUS_CONFLICTING_ADDRESSES, EADDRINUSE},
+ {NT_STATUS_NOT_MAPPED_VIEW, EINVAL},
+ {NT_STATUS_UNABLE_TO_FREE_VM, EADDRINUSE},
+ {NT_STATUS_ACCESS_DENIED, EACCES},
+ {NT_STATUS_BUFFER_TOO_SMALL, ENOBUFS},
+ {NT_STATUS_WRONG_PASSWORD, EACCES},
+ {NT_STATUS_LOGON_FAILURE, EACCES},
+ {NT_STATUS_INVALID_WORKSTATION, EACCES},
+ {NT_STATUS_INVALID_LOGON_HOURS, EACCES},
+ {NT_STATUS_PASSWORD_EXPIRED, EACCES},
+ {NT_STATUS_ACCOUNT_DISABLED, EACCES},
+ {NT_STATUS_DISK_FULL, ENOSPC},
+ {NT_STATUS_INVALID_PIPE_STATE, EPIPE},
+ {NT_STATUS_PIPE_BUSY, EPIPE},
+ {NT_STATUS_PIPE_DISCONNECTED, EPIPE},
+ {NT_STATUS_PIPE_NOT_AVAILABLE, ENOSYS},
+ {NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR},
+ {NT_STATUS_NOT_SUPPORTED, ENOSYS},
+ {NT_STATUS_NOT_A_DIRECTORY, ENOTDIR},
+ {NT_STATUS_DIRECTORY_NOT_EMPTY, ENOTEMPTY},
+ {NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH},
+ {NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH},
+ {NT_STATUS_CONNECTION_ABORTED, ECONNABORTED},
+ {NT_STATUS_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_TOO_MANY_LINKS, EMLINK},
+ {NT_STATUS_NETWORK_BUSY, EBUSY},
+ {NT_STATUS_DEVICE_DOES_NOT_EXIST, ENODEV},
+#ifdef ELIBACC
+ {NT_STATUS_DLL_NOT_FOUND, ELIBACC},
+#endif
+ {NT_STATUS_PIPE_BROKEN, EPIPE},
+ {NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED},
+ {NT_STATUS_NETWORK_ACCESS_DENIED, EACCES},
+ {NT_STATUS_TOO_MANY_OPENED_FILES, EMFILE},
+#ifdef EPROTO
+ {NT_STATUS_DEVICE_PROTOCOL_ERROR, EPROTO},
+#endif
+ {NT_STATUS_FLOAT_OVERFLOW, ERANGE},
+ {NT_STATUS_FLOAT_UNDERFLOW, ERANGE},
+ {NT_STATUS_INTEGER_OVERFLOW, ERANGE},
+ {NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS},
+ {NT_STATUS_PIPE_CONNECTED, EISCONN},
+ {NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT},
+ {NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE},
+ {NT_STATUS_ILL_FORMED_PASSWORD, EACCES},
+ {NT_STATUS_PASSWORD_RESTRICTION, EACCES},
+ {NT_STATUS_ACCOUNT_RESTRICTION, EACCES},
+ {NT_STATUS_PORT_CONNECTION_REFUSED, ECONNREFUSED},
+ {NT_STATUS_NAME_TOO_LONG, ENAMETOOLONG},
+ {NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN},
+ {NT_STATUS_CONNECTION_DISCONNECTED, ECONNABORTED},
+ {NT_STATUS_CONNECTION_RESET, ENETRESET},
+#ifdef ENOTUNIQ
+ {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ},
+ {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ},
+#endif
+ {NT_STATUS_PORT_MESSAGE_TOO_LONG, EMSGSIZE},
+ {NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT},
+ {NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE},
+ {NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH},
+ {NT_STATUS_IO_TIMEOUT, ETIMEDOUT},
+ {NT_STATUS_RETRY, EAGAIN},
+#ifdef ENOTUNIQ
+ {NT_STATUS_DUPLICATE_NAME, ENOTUNIQ},
+#endif
+#ifdef ECOMM
+ {NT_STATUS_NET_WRITE_FAULT, ECOMM},
+#endif
+#ifdef EXDEV
+ {NT_STATUS_NOT_SAME_DEVICE, EXDEV},
+#endif
+#ifdef ECANCELED
+ {NT_STATUS_CANCELLED, ECANCELED},
+#endif
+};
+
+/*********************************************************************
+ Map a Unix error code from a NT error code.
+*********************************************************************/
+int map_errno_from_nt_status(NTSTATUS status)
+{
+ size_t i;
+
+ DBG_DEBUG("32 bit codes: code=%08x\n", NT_STATUS_V(status));
+
+ /* Status codes without this bit set are not errors */
+
+ if (!(NT_STATUS_V(status) & 0xc0000000)) {
+ return 0;
+ }
+
+ for (i=0;i<ARRAY_SIZE(nt_errno_map);i++) {
+ if (NT_STATUS_V(nt_errno_map[i].status) ==
+ NT_STATUS_V(status)) {
+ return nt_errno_map[i].error;
+ }
+ }
+
+ /* for all other cases - a default code */
+ return EINVAL;
+}
diff --git a/libcli/util/error.h b/libcli/util/error.h
new file mode 100644
index 0000000..c908292
--- /dev/null
+++ b/libcli/util/error.h
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/CIFS implementation.
+ Error handling 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/>.
+*/
+
+#ifndef _SAMBA_ERROR_H_
+#define _SAMBA_ERROR_H_
+
+#include "libcli/util/werror.h"
+#include "libcli/util/doserr.h"
+#include "libcli/util/ntstatus.h"
+#include "libcli/util/hresult.h"
+
+/*****************************************************************************
+convert a NT status code to a dos class/code
+ *****************************************************************************/
+void ntstatus_to_dos(NTSTATUS ntstatus, uint8_t *eclass, uint32_t *ecode);
+
+/*****************************************************************************
+convert a WERROR to a NT status32 code
+ *****************************************************************************/
+NTSTATUS werror_to_ntstatus(WERROR error);
+
+/*****************************************************************************
+convert a NTSTATUS to a WERROR
+ *****************************************************************************/
+WERROR ntstatus_to_werror(NTSTATUS error);
+
+/*********************************************************************
+ Map an NT error code from a Unix error code.
+*********************************************************************/
+NTSTATUS map_nt_error_from_unix_common(int unix_error);
+
+/*********************************************************************
+ Map a Unix error code from a NT error code.
+*********************************************************************/
+int map_errno_from_nt_status(NTSTATUS status);
+
+NTSTATUS nt_status_squash(NTSTATUS nt_status);
+
+/*****************************************************************************
+convert a Unix error to a WERROR
+ *****************************************************************************/
+WERROR unix_to_werror(int unix_error);
+
+#endif /* _SAMBA_ERROR_H */
diff --git a/libcli/util/errormap.c b/libcli/util/errormap.c
new file mode 100644
index 0000000..4907cec
--- /dev/null
+++ b/libcli/util/errormap.c
@@ -0,0 +1,1246 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * error mapping functions
+ * Copyright (C) Andrew Tridgell 2001
+ * Copyright (C) Andrew Bartlett 2001
+ * Copyright (C) Tim Potter 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 "includes.h"
+
+/* This map was extracted by the ERRMAPEXTRACT smbtorture command.
+ The setup was a Samba HEAD (2002-01-03) PDC and an Win2k member
+ workstation. The PDC was modified (by using the 'name_to_nt_status'
+ authentication module) to convert the username (in hex) into the
+ corresponding NTSTATUS error return.
+
+ By opening two nbt sessions to the Win2k workstation, one negotiating
+ DOS and one negotiating NT errors it was possible to extract the
+ error mapping. (Because the server only supplies NT errors, the
+ NT4 workstation had to use its own error tables to convert these
+ to dos errors).
+
+ Some errors show up as 'squashed' because the NT error connection
+ got back a different error to the one it sent, so a mapping could
+ not be determined (a guess has been made in this case, to map the
+ error as squashed). This is done mainly to prevent users from getting
+ NT_STATUS_WRONG_PASSWORD and NT_STATUS_NO_SUCH_USER errors (they get
+ NT_STATUS_LOGON_FAILURE instead.
+
+ -- abartlet (2002-01-03)
+*/
+
+/* NT status -> dos error map */
+static const struct {
+ uint8_t dos_class;
+ uint32_t dos_code;
+ NTSTATUS ntstatus;
+} ntstatus_to_dos_map[] = {
+/*
+ * Not an official error, as only bit 0x80000000, not bits 0xC0000000 are set.
+ */
+ {ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW},
+ {ERRDOS, ERRnofiles, STATUS_NO_MORE_FILES},
+ {ERRDOS, ERRbadfile, STATUS_INVALID_EA_NAME},
+ {ERRDOS, ERRnofiles, NT_STATUS_NO_MORE_ENTRIES},
+ {ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL},
+ {ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED},
+ {ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS},
+ {ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK},
+ {ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC},
+ {ERRDOS, 87, NT_STATUS_INVALID_CID},
+ {ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED},
+ {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE},
+ {ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE},
+ {ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST},
+ {ERRDOS, 38, NT_STATUS_END_OF_FILE},
+ {ERRDOS, 34, NT_STATUS_WRONG_VOLUME},
+ {ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA},
+ {ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
+/** Session setup succeeded. This shouldn't happen...*/
+/** Session setup succeeded. This shouldn't happen...*/
+/** NT error on DOS connection! (NT_STATUS_OK) */
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
+ during the session setup }
+*/
+#if 0
+ {SUCCESS, 0, NT_STATUS_OK},
+#endif
+ {ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY},
+ {ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES},
+ {ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW},
+ {ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM},
+ {ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION},
+ {ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION},
+ {ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE},
+ {ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED},
+ {ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL},
+ {ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNWIND},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET},
+ {ERRDOS, 158, NT_STATUS_NOT_LOCKED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR},
+ {ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM},
+ {ERRDOS, 487, NT_STATUS_NOT_COMMITTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES},
+ {ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR},
+ {ERRDOS, ERRinvalidname, NT_STATUS_OBJECT_NAME_INVALID},
+ {ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND},
+ {ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION},
+ {ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE},
+ {ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED},
+ {ERRDOS, ERRinvalidpath, NT_STATUS_OBJECT_PATH_INVALID},
+ {ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND},
+ {ERRDOS, ERRinvalidpath, NT_STATUS_OBJECT_PATH_SYNTAX_BAD},
+ {ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN},
+ {ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR},
+ {ERRDOS, 23, NT_STATUS_DATA_ERROR},
+ {ERRDOS, 23, NT_STATUS_CRC_ERROR},
+ {ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG},
+ {ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED},
+ {ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE},
+ {ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED},
+ {ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION},
+ {ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED},
+ {ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+ {ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET},
+ {ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE},
+ {ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING},
+ {ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT},
+ {ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP},
+ {ERRDOS, 87, NT_STATUS_SECTION_PROTECTION},
+ {ERRDOS, ERReasnotsupported, NT_STATUS_EAS_NOT_SUPPORTED},
+ {ERRDOS, 255, NT_STATUS_EA_TOO_LARGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR},
+ {ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT},
+ {ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_DELETE_PENDING},
+ {ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION},
+ {ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY},
+ {ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME},
+ {ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER},
+ {ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
+ during the session setup }
+*/
+ {ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD},
+ {ERRSRV, ERRbaduid, NT_STATUS_USER_SESSION_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD},
+ {ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION},
+ {ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION},
+ {ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS},
+ {ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION},
+ {ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED},
+ {ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR},
+ {ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL},
+ {ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED},
+ {ERRDOS, 112, NT_STATUS_DISK_FULL},
+ {ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+ {ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY},
+ {ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED},
+ {ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL},
+ {ERRDOS, ERRres, NT_STATUS_SECTION_NOT_EXTENDED},
+ {ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO},
+ {ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION},
+ {ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES},
+ {ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID},
+ {ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES
+ during the session setup }
+*/
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES},
+ {ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND},
+ {ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED},
+ {ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE},
+ {ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE},
+ {ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA},
+ {ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED},
+ {ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE},
+ {ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD},
+ {ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT},
+ {ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE},
+ {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE},
+ {ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY},
+ {ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION},
+ {ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING},
+ {ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING},
+ {ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE},
+ {ERRDOS, 121, NT_STATUS_IO_TIMEOUT},
+ {ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED},
+ {ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET},
+ {ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED},
+ {ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING},
+ {ERRDOS, 52, NT_STATUS_DUPLICATE_NAME},
+ {ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH},
+ {ERRDOS, 54, NT_STATUS_NETWORK_BUSY},
+ {ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST},
+ {ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS},
+ {ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR},
+ {ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE},
+ {ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+ {ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER},
+ {ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL},
+ {ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE},
+ {ERRDOS, 63, NT_STATUS_PRINT_CANCELLED},
+ {ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED},
+ {ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED},
+ {ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE},
+ {ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES},
+ {ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS},
+ {ERRDOS, 70, NT_STATUS_SHARING_PAUSED},
+ {ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED},
+ {ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED},
+ {ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT},
+ {ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED},
+ {ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT},
+ {ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED},
+ {ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED},
+ {ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11},
+ {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12},
+ {ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE},
+ {ERRDOS, 203, NT_STATUS(0xc0000100)},
+ {ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
+ {ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR},
+ {ERRDOS, ERRbaddirectory, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION},
+ {ERRDOS, 206, NT_STATUS_NAME_TOO_LONG},
+ {ERRDOS, 2401, NT_STATUS_FILES_OPEN},
+ {ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE},
+ {ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND},
+ {ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_LDT},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT},
+ {ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO},
+ {ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANCELLED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME},
+ {ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT},
+ {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP},
+ {ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP},
+ {ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS},
+ {ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED},
+ {ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT},
+ {ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT},
+ {ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC},
+ {ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED},
+ {ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED},
+ {ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT},
+ {ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT},
+ {ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT},
+ {ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES},
+ {ERRDOS, 59, NT_STATUS_LINK_FAILED},
+ {ERRDOS, 59, NT_STATUS_LINK_TIMEOUT},
+ {ERRDOS, 59, NT_STATUS_INVALID_CONNECTION},
+ {ERRDOS, 59, NT_STATUS_INVALID_ADDRESS},
+ {ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE},
+ {ERRDOS, ERRunknownlevel, NT_STATUS_INVALID_LEVEL},
+ {ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT},
+ {ERRDOS, 109, NT_STATUS_PIPE_BROKEN},
+ {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT},
+ {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME},
+ {ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS},
+ {ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS},
+ {ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS},
+ {ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG},
+ {ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS},
+ {ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY},
+ {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY},
+ {ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000016e)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000016f)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc0000170)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc0000171)},
+ {ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA},
+ {ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc0000179)},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER},
+ {ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS},
+ {ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN},
+ {ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE},
+ {ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR},
+ {ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE},
+ {ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL},
+ {ERRDOS, 19, NT_STATUS_TOO_LATE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT},
+ {ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE},
+ {ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT},
+ {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START},
+ {ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED},
+ {ERRDOS, ERRinvgroup, NT_STATUS_NETLOGON_NOT_STARTED},
+ {ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK},
+ {ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT},
+ {ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT},
+ {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT},
+ {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
+/* { This NT error code was 'sqashed'
+ from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
+ during the session setup }
+*/
+ {ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY},
+ {ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED},
+ {ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND},
+ {ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES},
+ {ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS},
+ {ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED},
+ {ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED},
+ {ERRDOS, 64, NT_STATUS_CONNECTION_RESET},
+ {ERRDOS, 68, NT_STATUS_TOO_MANY_NODES},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID},
+ {ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION},
+ {ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION},
+ {ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR},
+ {ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT},
+ {ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT},
+ {ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA},
+ {ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID},
+ {ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM},
+ {ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE},
+ {ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ},
+ {ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK},
+ {ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID},
+ {ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE},
+ {ERRHRD, ERRgeneral, NT_STATUS_RETRY},
+ {ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE},
+ {ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND},
+ {ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT},
+ {ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
+ {ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT},
+ {ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED},
+ {ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT},
+ {ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE},
+ {ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE},
+ {ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER},
+ {ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET},
+ {ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION},
+ {ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION},
+ {ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024a)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024b)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024c)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024d)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024e)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000024f)},
+ {ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT},
+ {ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT},
+ {ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST},
+ {ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1},
+ {ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2},
+ {ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT},
+ {ERRSRV, ERRbadtype, NT_STATUS_PATH_NOT_COVERED},
+ {ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE},
+ {ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED},
+ {ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT},
+ {ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000025d)},
+ {ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE},
+ {ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE},
+ {ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH},
+ {ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND},
+ {ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND},
+ {ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED},
+ {ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS},
+ {ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT},
+ {ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE},
+ {ERRDOS, 21, NT_STATUS(0xc000026e)},
+ {ERRDOS, 161, NT_STATUS(0xc0000281)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028a)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028b)},
+ {ERRHRD, ERRgeneral, NT_STATUS(0xc000028c)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028d)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028e)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc000028f)},
+ {ERRDOS, ERRnoaccess, NT_STATUS(0xc0000290)},
+ {ERRDOS, ERRbadfunc, NT_STATUS(0xc000029c)},
+};
+
+/* errmap NTSTATUS->Win32 */
+static const struct {
+ NTSTATUS ntstatus;
+ WERROR werror;
+} ntstatus_to_werror_map[] = {
+ {NT_STATUS(0x103), W_ERROR(0x3e5)},
+ {NT_STATUS(0x105), W_ERROR(0xea)},
+ {NT_STATUS(0x106), W_ERROR(0x514)},
+ {NT_STATUS(0x107), W_ERROR(0x515)},
+ {NT_STATUS(0x10c), W_ERROR(0x3fe)},
+ {NT_STATUS(0x10d), W_ERROR(0x516)},
+ {NT_STATUS(0x121), W_ERROR(0x2009)},
+ {NT_STATUS(0xc0000001), W_ERROR(0x1f)},
+ {NT_STATUS(0xc0000002), W_ERROR(0x1)},
+ {NT_STATUS(0xc0000003), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000004), W_ERROR(0x18)},
+ {NT_STATUS(0xc0000005), W_ERROR(0x3e6)},
+ {NT_STATUS(0xc0000006), W_ERROR(0x3e7)},
+ {NT_STATUS(0xc0000007), W_ERROR(0x5ae)},
+ {NT_STATUS(0xc0000008), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000009), W_ERROR(0x3e9)},
+ {NT_STATUS(0xc000000a), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000000b), W_ERROR(0x57)},
+ {NT_STATUS(0xc000000d), W_ERROR(0x57)},
+ {NT_STATUS(0xc000000e), W_ERROR(0x2)},
+ {NT_STATUS(0xc000000f), W_ERROR(0x2)},
+ {NT_STATUS(0xc0000010), W_ERROR(0x1)},
+ {NT_STATUS(0xc0000011), W_ERROR(0x26)},
+ {NT_STATUS(0xc0000012), W_ERROR(0x22)},
+ {NT_STATUS(0xc0000013), W_ERROR(0x15)},
+ {NT_STATUS(0xc0000014), W_ERROR(0x6f9)},
+ {NT_STATUS(0xc0000015), W_ERROR(0x1b)},
+ {NT_STATUS(0xc0000016), W_ERROR(0xea)},
+ {NT_STATUS(0xc0000017), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000018), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000019), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc000001a), W_ERROR(0x57)},
+ {NT_STATUS(0xc000001b), W_ERROR(0x57)},
+ {NT_STATUS(0xc000001c), W_ERROR(0x1)},
+ {NT_STATUS(0xc000001d), W_ERROR(0xc000001d)},
+ {NT_STATUS(0xc000001e), W_ERROR(0x5)},
+ {NT_STATUS(0xc000001f), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000020), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000021), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000022), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000023), W_ERROR(0x7a)},
+ {NT_STATUS(0xc0000024), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000025), W_ERROR(0xc0000025)},
+ {NT_STATUS(0xc0000026), W_ERROR(0xc0000026)},
+ {NT_STATUS(0xc000002a), W_ERROR(0x9e)},
+ {NT_STATUS(0xc000002b), W_ERROR(0xc000002b)},
+ {NT_STATUS(0xc000002c), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc000002d), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000030), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000032), W_ERROR(0x571)},
+ {NT_STATUS(0xc0000033), W_ERROR(0x7b)},
+ {NT_STATUS(0xc0000034), W_ERROR(0x2)},
+ {NT_STATUS(0xc0000035), W_ERROR(0xb7)},
+ {NT_STATUS(0xc0000037), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000039), W_ERROR(0xa1)},
+ {NT_STATUS(0xc000003a), W_ERROR(0x3)},
+ {NT_STATUS(0xc000003b), W_ERROR(0xa1)},
+ {NT_STATUS(0xc000003c), W_ERROR(0x45d)},
+ {NT_STATUS(0xc000003d), W_ERROR(0x45d)},
+ {NT_STATUS(0xc000003e), W_ERROR(0x17)},
+ {NT_STATUS(0xc000003f), W_ERROR(0x17)},
+ {NT_STATUS(0xc0000040), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000041), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000042), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000043), W_ERROR(0x20)},
+ {NT_STATUS(0xc0000044), W_ERROR(0x718)},
+ {NT_STATUS(0xc0000045), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000046), W_ERROR(0x120)},
+ {NT_STATUS(0xc0000047), W_ERROR(0x12a)},
+ {NT_STATUS(0xc0000048), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000049), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004a), W_ERROR(0x9c)},
+ {NT_STATUS(0xc000004b), W_ERROR(0x5)},
+ {NT_STATUS(0xc000004c), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004d), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004e), W_ERROR(0x57)},
+ {NT_STATUS(0xc000004f), W_ERROR(0x11a)},
+ {NT_STATUS(0xc0000050), W_ERROR(0xff)},
+ {NT_STATUS(0xc0000051), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000052), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000053), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000054), W_ERROR(0x21)},
+ {NT_STATUS(0xc0000055), W_ERROR(0x21)},
+ {NT_STATUS(0xc0000056), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000057), W_ERROR(0x32)},
+ {NT_STATUS(0xc0000058), W_ERROR(0x519)},
+ {NT_STATUS(0xc0000059), W_ERROR(0x51a)},
+ {NT_STATUS(0xc000005a), W_ERROR(0x51b)},
+ {NT_STATUS(0xc000005b), W_ERROR(0x51c)},
+ {NT_STATUS(0xc000005c), W_ERROR(0x51d)},
+ {NT_STATUS(0xc000005d), W_ERROR(0x51e)},
+ {NT_STATUS(0xc000005e), W_ERROR(0x51f)},
+ {NT_STATUS(0xc000005f), W_ERROR(0x520)},
+ {NT_STATUS(0xc0000060), W_ERROR(0x521)},
+ {NT_STATUS(0xc0000061), W_ERROR(0x522)},
+ {NT_STATUS(0xc0000062), W_ERROR(0x523)},
+ {NT_STATUS(0xc0000063), W_ERROR(0x524)},
+ {NT_STATUS(0xc0000064), W_ERROR(0x525)},
+ {NT_STATUS(0xc0000065), W_ERROR(0x526)},
+ {NT_STATUS(0xc0000066), W_ERROR(0x527)},
+ {NT_STATUS(0xc0000067), W_ERROR(0x528)},
+ {NT_STATUS(0xc0000068), W_ERROR(0x529)},
+ {NT_STATUS(0xc0000069), W_ERROR(0x52a)},
+ {NT_STATUS(0xc000006a), W_ERROR(0x56)},
+ {NT_STATUS(0xc000006b), W_ERROR(0x52c)},
+ {NT_STATUS(0xc000006c), W_ERROR(0x52d)},
+ {NT_STATUS(0xc000006d), W_ERROR(0x52e)},
+ {NT_STATUS(0xc000006e), W_ERROR(0x52f)},
+ {NT_STATUS(0xc000006f), W_ERROR(0x530)},
+ {NT_STATUS(0xc0000070), W_ERROR(0x531)},
+ {NT_STATUS(0xc0000071), W_ERROR(0x532)},
+ {NT_STATUS(0xc0000072), W_ERROR(0x533)},
+ {NT_STATUS(0xc0000073), W_ERROR(0x534)},
+ {NT_STATUS(0xc0000074), W_ERROR(0x535)},
+ {NT_STATUS(0xc0000075), W_ERROR(0x536)},
+ {NT_STATUS(0xc0000076), W_ERROR(0x537)},
+ {NT_STATUS(0xc0000077), W_ERROR(0x538)},
+ {NT_STATUS(0xc0000078), W_ERROR(0x539)},
+ {NT_STATUS(0xc0000079), W_ERROR(0x53a)},
+ {NT_STATUS(0xc000007a), W_ERROR(0x7f)},
+ {NT_STATUS(0xc000007b), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000007c), W_ERROR(0x3f0)},
+ {NT_STATUS(0xc000007d), W_ERROR(0x53c)},
+ {NT_STATUS(0xc000007e), W_ERROR(0x9e)},
+ {NT_STATUS(0xc000007f), W_ERROR(0x70)},
+ {NT_STATUS(0xc0000080), W_ERROR(0x53d)},
+ {NT_STATUS(0xc0000081), W_ERROR(0x53e)},
+ {NT_STATUS(0xc0000082), W_ERROR(0x44)},
+ {NT_STATUS(0xc0000083), W_ERROR(0x103)},
+ {NT_STATUS(0xc0000084), W_ERROR(0x53f)},
+ {NT_STATUS(0xc0000085), W_ERROR(0x103)},
+ {NT_STATUS(0xc0000086), W_ERROR(0x9a)},
+ {NT_STATUS(0xc0000087), W_ERROR(0xe)},
+ {NT_STATUS(0xc0000088), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc0000089), W_ERROR(0x714)},
+ {NT_STATUS(0xc000008a), W_ERROR(0x715)},
+ {NT_STATUS(0xc000008b), W_ERROR(0x716)},
+ {NT_STATUS(0xc000008c), W_ERROR(0xc000008c)},
+ {NT_STATUS(0xc000008d), W_ERROR(0xc000008d)},
+ {NT_STATUS(0xc000008e), W_ERROR(0xc000008e)},
+ {NT_STATUS(0xc000008f), W_ERROR(0xc000008f)},
+ {NT_STATUS(0xc0000090), W_ERROR(0xc0000090)},
+ {NT_STATUS(0xc0000091), W_ERROR(0xc0000091)},
+ {NT_STATUS(0xc0000092), W_ERROR(0xc0000092)},
+ {NT_STATUS(0xc0000093), W_ERROR(0xc0000093)},
+ {NT_STATUS(0xc0000094), W_ERROR(0xc0000094)},
+ {NT_STATUS(0xc0000095), W_ERROR(0x216)},
+ {NT_STATUS(0xc0000096), W_ERROR(0xc0000096)},
+ {NT_STATUS(0xc0000097), W_ERROR(0x8)},
+ {NT_STATUS(0xc0000098), W_ERROR(0x3ee)},
+ {NT_STATUS(0xc0000099), W_ERROR(0x540)},
+ {NT_STATUS(0xc000009a), W_ERROR(0x5aa)},
+ {NT_STATUS(0xc000009b), W_ERROR(0x3)},
+ {NT_STATUS(0xc000009c), W_ERROR(0x17)},
+ {NT_STATUS(0xc000009d), W_ERROR(0x48f)},
+ {NT_STATUS(0xc000009e), W_ERROR(0x15)},
+ {NT_STATUS(0xc000009f), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc00000a0), W_ERROR(0x1e7)},
+ {NT_STATUS(0xc00000a1), W_ERROR(0x5ad)},
+ {NT_STATUS(0xc00000a2), W_ERROR(0x13)},
+ {NT_STATUS(0xc00000a3), W_ERROR(0x15)},
+ {NT_STATUS(0xc00000a4), W_ERROR(0x541)},
+ {NT_STATUS(0xc00000a5), W_ERROR(0x542)},
+ {NT_STATUS(0xc00000a6), W_ERROR(0x543)},
+ {NT_STATUS(0xc00000a7), W_ERROR(0x544)},
+ {NT_STATUS(0xc00000a8), W_ERROR(0x545)},
+ {NT_STATUS(0xc00000a9), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000ab), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000ac), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000ad), W_ERROR(0xe6)},
+ {NT_STATUS(0xc00000ae), W_ERROR(0xe7)},
+ {NT_STATUS(0xc00000af), W_ERROR(0x1)},
+ {NT_STATUS(0xc00000b0), W_ERROR(0xe9)},
+ {NT_STATUS(0xc00000b1), W_ERROR(0xe8)},
+ {NT_STATUS(0xc00000b2), W_ERROR(0x217)},
+ {NT_STATUS(0xc00000b3), W_ERROR(0x218)},
+ {NT_STATUS(0xc00000b4), W_ERROR(0xe6)},
+ {NT_STATUS(0xc00000b5), W_ERROR(0x79)},
+ {NT_STATUS(0xc00000b6), W_ERROR(0x26)},
+ {NT_STATUS(0xc00000ba), W_ERROR(0x5)},
+ {NT_STATUS(0xc00000bb), W_ERROR(0x32)},
+ {NT_STATUS(0xc00000bc), W_ERROR(0x33)},
+ {NT_STATUS(0xc00000bd), W_ERROR(0x34)},
+ {NT_STATUS(0xc00000be), W_ERROR(0x35)},
+ {NT_STATUS(0xc00000bf), W_ERROR(0x36)},
+ {NT_STATUS(0xc00000c0), W_ERROR(0x37)},
+ {NT_STATUS(0xc00000c1), W_ERROR(0x38)},
+ {NT_STATUS(0xc00000c2), W_ERROR(0x39)},
+ {NT_STATUS(0xc00000c3), W_ERROR(0x3a)},
+ {NT_STATUS(0xc00000c4), W_ERROR(0x3b)},
+ {NT_STATUS(0xc00000c5), W_ERROR(0x3c)},
+ {NT_STATUS(0xc00000c6), W_ERROR(0x3d)},
+ {NT_STATUS(0xc00000c7), W_ERROR(0x3e)},
+ {NT_STATUS(0xc00000c8), W_ERROR(0x3f)},
+ {NT_STATUS(0xc00000c9), W_ERROR(0x40)},
+ {NT_STATUS(0xc00000ca), W_ERROR(0x41)},
+ {NT_STATUS(0xc00000cb), W_ERROR(0x42)},
+ {NT_STATUS(0xc00000cc), W_ERROR(0x43)},
+ {NT_STATUS(0xc00000cd), W_ERROR(0x44)},
+ {NT_STATUS(0xc00000ce), W_ERROR(0x45)},
+ {NT_STATUS(0xc00000cf), W_ERROR(0x46)},
+ {NT_STATUS(0xc00000d0), W_ERROR(0x47)},
+ {NT_STATUS(0xc00000d1), W_ERROR(0x48)},
+ {NT_STATUS(0xc00000d2), W_ERROR(0x58)},
+ {NT_STATUS(0xc00000d4), W_ERROR(0x11)},
+ {NT_STATUS(0xc00000d5), W_ERROR(0x5)},
+ {NT_STATUS(0xc00000d6), W_ERROR(0xf0)},
+ {NT_STATUS(0xc00000d7), W_ERROR(0x546)},
+ {NT_STATUS(0xc00000d9), W_ERROR(0xe8)},
+ {NT_STATUS(0xc00000da), W_ERROR(0x547)},
+ {NT_STATUS(0xc00000dc), W_ERROR(0x548)},
+ {NT_STATUS(0xc00000dd), W_ERROR(0x549)},
+ {NT_STATUS(0xc00000de), W_ERROR(0x54a)},
+ {NT_STATUS(0xc00000df), W_ERROR(0x54b)},
+ {NT_STATUS(0xc00000e0), W_ERROR(0x54c)},
+ {NT_STATUS(0xc00000e1), W_ERROR(0x54d)},
+ {NT_STATUS(0xc00000e2), W_ERROR(0x12c)},
+ {NT_STATUS(0xc00000e3), W_ERROR(0x12d)},
+ {NT_STATUS(0xc00000e4), W_ERROR(0x54e)},
+ {NT_STATUS(0xc00000e5), W_ERROR(0x54f)},
+ {NT_STATUS(0xc00000e6), W_ERROR(0x550)},
+ {NT_STATUS(0xc00000e7), W_ERROR(0x551)},
+ {NT_STATUS(0xc00000e8), W_ERROR(0x6f8)},
+ {NT_STATUS(0xc00000ed), W_ERROR(0x552)},
+ {NT_STATUS(0xc00000ee), W_ERROR(0x553)},
+ {NT_STATUS(0xc00000ef), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f0), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f1), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f2), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f3), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f4), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f5), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f6), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f7), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f8), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000f9), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000fa), W_ERROR(0x57)},
+ {NT_STATUS(0xc00000fb), W_ERROR(0x3)},
+ {NT_STATUS(0xc00000fd), W_ERROR(0x3e9)},
+ {NT_STATUS(0xc00000fe), W_ERROR(0x554)},
+ {NT_STATUS(0xc0000100), W_ERROR(0xcb)},
+ {NT_STATUS(0xc0000101), W_ERROR(0x91)},
+ {NT_STATUS(0xc0000102), W_ERROR(0x570)},
+ {NT_STATUS(0xc0000103), W_ERROR(0x10b)},
+ {NT_STATUS(0xc0000104), W_ERROR(0x555)},
+ {NT_STATUS(0xc0000105), W_ERROR(0x556)},
+ {NT_STATUS(0xc0000106), W_ERROR(0xce)},
+ {NT_STATUS(0xc0000107), W_ERROR(0x961)},
+ {NT_STATUS(0xc0000108), W_ERROR(0x964)},
+ {NT_STATUS(0xc000010a), W_ERROR(0x5)},
+ {NT_STATUS(0xc000010b), W_ERROR(0x557)},
+ {NT_STATUS(0xc000010d), W_ERROR(0x558)},
+ {NT_STATUS(0xc000010e), W_ERROR(0x420)},
+ {NT_STATUS(0xc0000117), W_ERROR(0x5a4)},
+ {NT_STATUS(0xc000011b), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000011c), W_ERROR(0x559)},
+ {NT_STATUS(0xc000011d), W_ERROR(0x55a)},
+ {NT_STATUS(0xc000011e), W_ERROR(0x3ee)},
+ {NT_STATUS(0xc000011f), W_ERROR(0x4)},
+ {NT_STATUS(0xc0000120), W_ERROR(0x3e3)},
+ {NT_STATUS(0xc0000121), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000122), W_ERROR(0x4ba)},
+ {NT_STATUS(0xc0000123), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000124), W_ERROR(0x55b)},
+ {NT_STATUS(0xc0000125), W_ERROR(0x55c)},
+ {NT_STATUS(0xc0000126), W_ERROR(0x55d)},
+ {NT_STATUS(0xc0000127), W_ERROR(0x55e)},
+ {NT_STATUS(0xc0000128), W_ERROR(0x6)},
+ {NT_STATUS(0xc000012b), W_ERROR(0x55f)},
+ {NT_STATUS(0xc000012d), W_ERROR(0x5af)},
+ {NT_STATUS(0xc000012e), W_ERROR(0xc1)},
+ {NT_STATUS(0xc000012f), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000130), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000131), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000133), W_ERROR(0x576)},
+ {NT_STATUS(0xc0000135), W_ERROR(0x7e)},
+ {NT_STATUS(0xc0000138), W_ERROR(0xb6)},
+ {NT_STATUS(0xc0000139), W_ERROR(0x7f)},
+ {NT_STATUS(0xc000013b), W_ERROR(0x40)},
+ {NT_STATUS(0xc000013c), W_ERROR(0x40)},
+ {NT_STATUS(0xc000013d), W_ERROR(0x33)},
+ {NT_STATUS(0xc000013e), W_ERROR(0x3b)},
+ {NT_STATUS(0xc000013f), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000140), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000141), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000142), W_ERROR(0x45a)},
+ {NT_STATUS(0xc0000148), W_ERROR(0x7c)},
+ {NT_STATUS(0xc0000149), W_ERROR(0x56)},
+ {NT_STATUS(0xc000014b), W_ERROR(0x6d)},
+ {NT_STATUS(0xc000014c), W_ERROR(0x3f1)},
+ {NT_STATUS(0xc000014d), W_ERROR(0x3f8)},
+ {NT_STATUS(0xc000014f), W_ERROR(0x3ed)},
+ {NT_STATUS(0xc0000150), W_ERROR(0x45e)},
+ {NT_STATUS(0xc0000151), W_ERROR(0x560)},
+ {NT_STATUS(0xc0000152), W_ERROR(0x561)},
+ {NT_STATUS(0xc0000153), W_ERROR(0x562)},
+ {NT_STATUS(0xc0000154), W_ERROR(0x563)},
+ {NT_STATUS(0xc0000155), W_ERROR(0x564)},
+ {NT_STATUS(0xc0000156), W_ERROR(0x565)},
+ {NT_STATUS(0xc0000157), W_ERROR(0x566)},
+ {NT_STATUS(0xc0000158), W_ERROR(0x567)},
+ {NT_STATUS(0xc0000159), W_ERROR(0x3ef)},
+ {NT_STATUS(0xc000015a), W_ERROR(0x568)},
+ {NT_STATUS(0xc000015b), W_ERROR(0x569)},
+ {NT_STATUS(0xc000015c), W_ERROR(0x3f9)},
+ {NT_STATUS(0xc000015d), W_ERROR(0x56a)},
+ {NT_STATUS(0xc000015f), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000162), W_ERROR(0x459)},
+ {NT_STATUS(0xc0000165), W_ERROR(0x462)},
+ {NT_STATUS(0xc0000166), W_ERROR(0x463)},
+ {NT_STATUS(0xc0000167), W_ERROR(0x464)},
+ {NT_STATUS(0xc0000168), W_ERROR(0x465)},
+ {NT_STATUS(0xc0000169), W_ERROR(0x466)},
+ {NT_STATUS(0xc000016a), W_ERROR(0x467)},
+ {NT_STATUS(0xc000016b), W_ERROR(0x468)},
+ {NT_STATUS(0xc000016c), W_ERROR(0x45f)},
+ {NT_STATUS(0xc000016d), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000172), W_ERROR(0x451)},
+ {NT_STATUS(0xc0000173), W_ERROR(0x452)},
+ {NT_STATUS(0xc0000174), W_ERROR(0x453)},
+ {NT_STATUS(0xc0000175), W_ERROR(0x454)},
+ {NT_STATUS(0xc0000176), W_ERROR(0x455)},
+ {NT_STATUS(0xc0000177), W_ERROR(0x469)},
+ {NT_STATUS(0xc0000178), W_ERROR(0x458)},
+ {NT_STATUS(0xc000017a), W_ERROR(0x56b)},
+ {NT_STATUS(0xc000017b), W_ERROR(0x56c)},
+ {NT_STATUS(0xc000017c), W_ERROR(0x3fa)},
+ {NT_STATUS(0xc000017d), W_ERROR(0x3fb)},
+ {NT_STATUS(0xc000017e), W_ERROR(0x56d)},
+ {NT_STATUS(0xc000017f), W_ERROR(0x56e)},
+ {NT_STATUS(0xc0000180), W_ERROR(0x3fc)},
+ {NT_STATUS(0xc0000181), W_ERROR(0x3fd)},
+ {NT_STATUS(0xc0000182), W_ERROR(0x57)},
+ {NT_STATUS(0xc0000183), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000184), W_ERROR(0x16)},
+ {NT_STATUS(0xc0000185), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000186), W_ERROR(0x45d)},
+ {NT_STATUS(0xc0000188), W_ERROR(0x5de)},
+ {NT_STATUS(0xc0000189), W_ERROR(0x13)},
+ {NT_STATUS(0xc000018a), W_ERROR(0x6fa)},
+ {NT_STATUS(0xc000018b), W_ERROR(0x6fb)},
+ {NT_STATUS(0xc000018c), W_ERROR(0x6fc)},
+ {NT_STATUS(0xc000018d), W_ERROR(0x6fd)},
+ {NT_STATUS(0xc000018e), W_ERROR(0x5dc)},
+ {NT_STATUS(0xc000018f), W_ERROR(0x5dd)},
+ {NT_STATUS(0xc0000190), W_ERROR(0x6fe)},
+ {NT_STATUS(0xc0000192), W_ERROR(0x700)},
+ {NT_STATUS(0xc0000193), W_ERROR(0x701)},
+ {NT_STATUS(0xc0000194), W_ERROR(0x46b)},
+ {NT_STATUS(0xc0000195), W_ERROR(0x4c3)},
+ {NT_STATUS(0xc0000196), W_ERROR(0x4c4)},
+ {NT_STATUS(0xc0000197), W_ERROR(0x5df)},
+ {NT_STATUS(0xc0000198), W_ERROR(0x70f)},
+ {NT_STATUS(0xc0000199), W_ERROR(0x710)},
+ {NT_STATUS(0xc000019a), W_ERROR(0x711)},
+ {NT_STATUS(0xc000019b), W_ERROR(0x712)},
+ {NT_STATUS(0xc0000202), W_ERROR(0x572)},
+ {NT_STATUS(0xc0000203), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000204), W_ERROR(0x717)},
+ {NT_STATUS(0xc0000205), W_ERROR(0x46a)},
+ {NT_STATUS(0xc0000206), W_ERROR(0x6f8)},
+ {NT_STATUS(0xc0000207), W_ERROR(0x4be)},
+ {NT_STATUS(0xc0000208), W_ERROR(0x4be)},
+ {NT_STATUS(0xc0000209), W_ERROR(0x44)},
+ {NT_STATUS(0xc000020a), W_ERROR(0x34)},
+ {NT_STATUS(0xc000020b), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020c), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020d), W_ERROR(0x40)},
+ {NT_STATUS(0xc000020e), W_ERROR(0x44)},
+ {NT_STATUS(0xc000020f), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000210), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000211), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000212), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000213), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000214), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000215), W_ERROR(0x3b)},
+ {NT_STATUS(0xc0000216), W_ERROR(0x32)},
+ {NT_STATUS(0xc0000217), W_ERROR(0x32)},
+ {NT_STATUS(0xc000021c), W_ERROR(0x17e6)},
+ {NT_STATUS(0xc0000220), W_ERROR(0x46c)},
+ {NT_STATUS(0xc0000221), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000224), W_ERROR(0x773)},
+ {NT_STATUS(0xc0000225), W_ERROR(0x490)},
+ {NT_STATUS(0xc000022a), W_ERROR(0xc000022a)},
+ {NT_STATUS(0xc000022b), W_ERROR(0xc000022b)},
+ {NT_STATUS(0xc000022d), W_ERROR(0x4d5)},
+ {NT_STATUS(0xc0000230), W_ERROR(0x492)},
+ {NT_STATUS(0xc0000233), W_ERROR(0x774)},
+ {NT_STATUS(0xc0000234), W_ERROR(0x775)},
+ {NT_STATUS(0xc0000235), W_ERROR(0x6)},
+ {NT_STATUS(0xc0000236), W_ERROR(0x4c9)},
+ {NT_STATUS(0xc0000237), W_ERROR(0x4ca)},
+ {NT_STATUS(0xc0000238), W_ERROR(0x4cb)},
+ {NT_STATUS(0xc0000239), W_ERROR(0x4cc)},
+ {NT_STATUS(0xc000023a), W_ERROR(0x4cd)},
+ {NT_STATUS(0xc000023b), W_ERROR(0x4ce)},
+ {NT_STATUS(0xc000023c), W_ERROR(0x4cf)},
+ {NT_STATUS(0xc000023d), W_ERROR(0x4d0)},
+ {NT_STATUS(0xc000023e), W_ERROR(0x4d1)},
+ {NT_STATUS(0xc000023f), W_ERROR(0x4d2)},
+ {NT_STATUS(0xc0000240), W_ERROR(0x4d3)},
+ {NT_STATUS(0xc0000241), W_ERROR(0x4d4)},
+ {NT_STATUS(0xc0000243), W_ERROR(0x4c8)},
+ {NT_STATUS(0xc0000246), W_ERROR(0x4d6)},
+ {NT_STATUS(0xc0000247), W_ERROR(0x4d7)},
+ {NT_STATUS(0xc0000248), W_ERROR(0x4d8)},
+ {NT_STATUS(0xc0000249), W_ERROR(0xc1)},
+ {NT_STATUS(0xc0000253), W_ERROR(0x54f)},
+ {NT_STATUS(0xc0000257), W_ERROR(0x4d0)},
+ {NT_STATUS(0xc0000259), W_ERROR(0x573)},
+ {NT_STATUS(0xc000025e), W_ERROR(0x422)},
+ {NT_STATUS(0xc0000262), W_ERROR(0xb6)},
+ {NT_STATUS(0xc0000263), W_ERROR(0x7f)},
+ {NT_STATUS(0xc0000264), W_ERROR(0x120)},
+ {NT_STATUS(0xc0000265), W_ERROR(0x476)},
+ {NT_STATUS(0xc0000267), W_ERROR(0x10fe)},
+ {NT_STATUS(0xc000026c), W_ERROR(0x7d1)},
+ {NT_STATUS(0xc000026d), W_ERROR(0x4b1)},
+ {NT_STATUS(0xc000026e), W_ERROR(0x15)},
+ {NT_STATUS(0xc0000272), W_ERROR(0x491)},
+ {NT_STATUS(0xc0000275), W_ERROR(0x1126)},
+ {NT_STATUS(0xc0000276), W_ERROR(0x1129)},
+ {NT_STATUS(0xc0000277), W_ERROR(0x112a)},
+ {NT_STATUS(0xc0000278), W_ERROR(0x1128)},
+ {NT_STATUS(0xc0000279), W_ERROR(0x780)},
+ {NT_STATUS(0xc0000280), W_ERROR(0x781)},
+ {NT_STATUS(0xc0000281), W_ERROR(0xa1)},
+ {NT_STATUS(0xc0000283), W_ERROR(0x488)},
+ {NT_STATUS(0xc0000284), W_ERROR(0x489)},
+ {NT_STATUS(0xc0000285), W_ERROR(0x48a)},
+ {NT_STATUS(0xc0000286), W_ERROR(0x48b)},
+ {NT_STATUS(0xc0000287), W_ERROR(0x48c)},
+ {NT_STATUS(0xc000028a), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028b), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028d), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028e), W_ERROR(0x5)},
+ {NT_STATUS(0xc000028f), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000290), W_ERROR(0x5)},
+ {NT_STATUS(0xc0000291), W_ERROR(0x1777)},
+ {NT_STATUS(0xc0000292), W_ERROR(0x1778)},
+ {NT_STATUS(0xc0000293), W_ERROR(0x1772)},
+ {NT_STATUS(0xc0000295), W_ERROR(0x1068)},
+ {NT_STATUS(0xc0000296), W_ERROR(0x1069)},
+ {NT_STATUS(0xc0000297), W_ERROR(0x106a)},
+ {NT_STATUS(0xc0000298), W_ERROR(0x106b)},
+ {NT_STATUS(0xc0000299), W_ERROR(0x201a)},
+ {NT_STATUS(0xc000029a), W_ERROR(0x201b)},
+ {NT_STATUS(0xc000029b), W_ERROR(0x201c)},
+ {NT_STATUS(0xc000029c), W_ERROR(0x1)},
+ {NT_STATUS(0xc000029d), W_ERROR(0x10ff)},
+ {NT_STATUS(0xc000029e), W_ERROR(0x1100)},
+ {NT_STATUS(0xc000029f), W_ERROR(0x494)},
+ {NT_STATUS(0xc00002a1), W_ERROR(0x200a)},
+ {NT_STATUS(0xc00002a2), W_ERROR(0x200b)},
+ {NT_STATUS(0xc00002a3), W_ERROR(0x200c)},
+ {NT_STATUS(0xc00002a4), W_ERROR(0x200d)},
+ {NT_STATUS(0xc00002a5), W_ERROR(0x200e)},
+ {NT_STATUS(0xc00002a6), W_ERROR(0x200f)},
+ {NT_STATUS(0xc00002a7), W_ERROR(0x2010)},
+ {NT_STATUS(0xc00002a8), W_ERROR(0x2011)},
+ {NT_STATUS(0xc00002a9), W_ERROR(0x2012)},
+ {NT_STATUS(0xc00002aa), W_ERROR(0x2013)},
+ {NT_STATUS(0xc00002ab), W_ERROR(0x2014)},
+ {NT_STATUS(0xc00002ac), W_ERROR(0x2015)},
+ {NT_STATUS(0xc00002ad), W_ERROR(0x2016)},
+ {NT_STATUS(0xc00002ae), W_ERROR(0x2017)},
+ {NT_STATUS(0xc00002af), W_ERROR(0x2018)},
+ {NT_STATUS(0xc00002b0), W_ERROR(0x2019)},
+ {NT_STATUS(0xc00002b1), W_ERROR(0x211e)},
+ {NT_STATUS(0xc00002b2), W_ERROR(0x1127)},
+ {NT_STATUS(0xc00002b6), W_ERROR(0x651)},
+ {NT_STATUS(0xc00002b7), W_ERROR(0x49a)},
+ {NT_STATUS(0xc00002b8), W_ERROR(0x49b)},
+ {NT_STATUS(0xc00002c1), W_ERROR(0x2024)},
+ {NT_STATUS(0xc00002c3), W_ERROR(0x575)},
+ {NT_STATUS(0xc00002c5), W_ERROR(0x3e6)},
+ {NT_STATUS(0xc00002c6), W_ERROR(0x1075)},
+ {NT_STATUS(0xc00002c7), W_ERROR(0x1076)},
+ {NT_STATUS(0xc00002ca), W_ERROR(0x10e8)},
+ {NT_STATUS(0xc00002cb), W_ERROR(0x2138)},
+ {NT_STATUS(0xc00002cc), W_ERROR(0x4e3)},
+ {NT_STATUS(0xc00002cd), W_ERROR(0x2139)},
+ {NT_STATUS(0xc00002cf), W_ERROR(0x49d)},
+ {NT_STATUS(0xc00002d0), W_ERROR(0x213a)},
+ {NT_STATUS(0xc00002d4), W_ERROR(0x2141)},
+ {NT_STATUS(0xc00002d5), W_ERROR(0x2142)},
+ {NT_STATUS(0xc00002d6), W_ERROR(0x2143)},
+ {NT_STATUS(0xc00002d7), W_ERROR(0x2144)},
+ {NT_STATUS(0xc00002d8), W_ERROR(0x2145)},
+ {NT_STATUS(0xc00002d9), W_ERROR(0x2146)},
+ {NT_STATUS(0xc00002da), W_ERROR(0x2147)},
+ {NT_STATUS(0xc00002db), W_ERROR(0x2148)},
+ {NT_STATUS(0xc00002dc), W_ERROR(0x2149)},
+ {NT_STATUS(0xc00002dd), W_ERROR(0x32)},
+ {NT_STATUS(0xc00002df), W_ERROR(0x2151)},
+ {NT_STATUS(0xc00002e0), W_ERROR(0x2152)},
+ {NT_STATUS(0xc00002e1), W_ERROR(0x2153)},
+ {NT_STATUS(0xc00002e2), W_ERROR(0x2154)},
+ {NT_STATUS(0xc00002e3), W_ERROR(0x215d)},
+ {NT_STATUS(0xc00002e4), W_ERROR(0x2163)},
+ {NT_STATUS(0xc00002e5), W_ERROR(0x2164)},
+ {NT_STATUS(0xc00002e6), W_ERROR(0x2165)},
+ {NT_STATUS(0xc00002e7), W_ERROR(0x216d)},
+ {NT_STATUS(0xc00002fe), W_ERROR(0x45b)},
+ {NT_STATUS(0xc00002ff), W_ERROR(0x4e7)},
+ {NT_STATUS(0xc0000300), W_ERROR(0x4e6)},
+ {NT_STATUS(0x80000001), W_ERROR(0x80000001)},
+ {NT_STATUS(0x80000002), W_ERROR(0x3e6)},
+ {NT_STATUS(0x80000003), W_ERROR(0x80000003)},
+ {NT_STATUS(0x80000004), W_ERROR(0x80000004)},
+ {NT_STATUS(0x80000005), W_ERROR(0xea)},
+ {NT_STATUS(0x80000006), W_ERROR(0x12)},
+ {NT_STATUS(0x8000000b), W_ERROR(0x56f)},
+ {NT_STATUS(0x8000000d), W_ERROR(0x12b)},
+ {NT_STATUS(0x8000000e), W_ERROR(0x1c)},
+ {NT_STATUS(0x8000000f), W_ERROR(0x15)},
+ {NT_STATUS(0x80000010), W_ERROR(0x15)},
+ {NT_STATUS(0x80000011), W_ERROR(0xaa)},
+ {NT_STATUS(0x80000012), W_ERROR(0x103)},
+ {NT_STATUS(0x80000013), W_ERROR(0xfe)},
+ {NT_STATUS(0x80000014), W_ERROR(0xff)},
+ {NT_STATUS(0x80000015), W_ERROR(0xff)},
+ {NT_STATUS(0x80000016), W_ERROR(0x456)},
+ {NT_STATUS(0x8000001a), W_ERROR(0x103)},
+ {NT_STATUS(0x8000001b), W_ERROR(0x44d)},
+ {NT_STATUS(0x8000001c), W_ERROR(0x456)},
+ {NT_STATUS(0x8000001d), W_ERROR(0x457)},
+ {NT_STATUS(0x8000001e), W_ERROR(0x44c)},
+ {NT_STATUS(0x8000001f), W_ERROR(0x44e)},
+ {NT_STATUS(0x80000021), W_ERROR(0x44f)},
+ {NT_STATUS(0x80000022), W_ERROR(0x450)},
+ {NT_STATUS(0x80000025), W_ERROR(0x962)},
+ {NT_STATUS(0x80000288), W_ERROR(0x48d)},
+ {NT_STATUS(0x80000289), W_ERROR(0x48e)},
+ {NT_STATUS_OK, WERR_OK}};
+
+static const struct {
+ WERROR werror;
+ NTSTATUS ntstatus;
+} werror_to_ntstatus_map[] = {
+ { W_ERROR(0x5), NT_STATUS_ACCESS_DENIED },
+ { WERR_OK, NT_STATUS_OK }
+};
+
+
+/*****************************************************************************
+convert a NT status code to a dos class/code
+ *****************************************************************************/
+void ntstatus_to_dos(NTSTATUS ntstatus, uint8_t *eclass, uint32_t *ecode)
+{
+ int i;
+ if (NT_STATUS_IS_OK(ntstatus)) {
+ *eclass = 0;
+ *ecode = 0;
+ return;
+ }
+ if (NT_STATUS_IS_DOS(ntstatus)) {
+ *eclass = NT_STATUS_DOS_CLASS(ntstatus);
+ *ecode = NT_STATUS_DOS_CODE(ntstatus);
+ return;
+ }
+ for (i=0; NT_STATUS_V(ntstatus_to_dos_map[i].ntstatus); i++) {
+ if (NT_STATUS_V(ntstatus) ==
+ NT_STATUS_V(ntstatus_to_dos_map[i].ntstatus)) {
+ *eclass = ntstatus_to_dos_map[i].dos_class;
+ *ecode = ntstatus_to_dos_map[i].dos_code;
+ return;
+ }
+ }
+ *eclass = ERRHRD;
+ *ecode = ERRgeneral;
+}
+
+
+/*****************************************************************************
+convert a WERROR to a NT status32 code
+ *****************************************************************************/
+NTSTATUS werror_to_ntstatus(WERROR error)
+{
+ int i;
+ if (W_ERROR_IS_OK(error)) return NT_STATUS_OK;
+
+ for (i=0; !W_ERROR_IS_OK(werror_to_ntstatus_map[i].werror); i++) {
+ if (W_ERROR_V(error) ==
+ W_ERROR_V(werror_to_ntstatus_map[i].werror)) {
+ return werror_to_ntstatus_map[i].ntstatus;
+ }
+ }
+
+ for (i=0; NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus); i++) {
+ if (W_ERROR_V(error) ==
+ W_ERROR_V(ntstatus_to_werror_map[i].werror)) {
+ return ntstatus_to_werror_map[i].ntstatus;
+ }
+ }
+
+ /* just guess ... */
+ return NT_STATUS(W_ERROR_V(error) | 0xc0000000);
+}
+
+/*****************************************************************************
+convert a NTSTATUS to a WERROR
+ *****************************************************************************/
+WERROR ntstatus_to_werror(NTSTATUS error)
+{
+ int i;
+ if (NT_STATUS_IS_OK(error)) return WERR_OK;
+ for (i=0; NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus); i++) {
+ if (NT_STATUS_V(error) ==
+ NT_STATUS_V(ntstatus_to_werror_map[i].ntstatus)) {
+ return ntstatus_to_werror_map[i].werror;
+ }
+ }
+
+ /* a lame guess */
+ return W_ERROR(NT_STATUS_V(error) & 0xffff);
+}
+
+/* Convert a Unix error code to a WERROR. */
+WERROR unix_to_werror(int unix_error)
+{
+ return ntstatus_to_werror(map_nt_error_from_unix_common(unix_error));
+}
diff --git a/libcli/util/hresult_err_table.txt b/libcli/util/hresult_err_table.txt
new file mode 100644
index 0000000..d04dff9
--- /dev/null
+++ b/libcli/util/hresult_err_table.txt
@@ -0,0 +1,20520 @@
+Errors retrieved from https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/705fb797-2175-4a90-b5a3-3918024b10b8.
+Licence retrieved from https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/1bc92ddf-b79e-413c-bbaa-99a5281a6c90:
+
+Intellectual Property Rights Notice for Open Specifications Documentation
+
+ - Technical Documentation. Microsoft publishes Open Specifications documentation (“this documentation”) for protocols, file formats, data portability, computer languages, and standards support. Additionally, overview documents cover inter-protocol relationships and interactions.
+
+ - Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other terms that are contained in the terms of use for the Microsoft website that hosts this documentation, you can make copies of it in order to develop implementations of the technologies that are described in this documentation and can distribute portions of it in your implementations that use these technologies or in your documentation as necessary to properly document the implementation. You can also distribute in your implementation, with or without modification, any schemas, IDLs, or code samples that are included in the documentation. This permission also applies to any documents that are referenced in the Open Specifications documentation.
+
+ - No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation.
+
+ - Patents. Microsoft has patents that might cover your implementations of the technologies described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of this documentation grants any licenses under those patents or any other Microsoft patents. However, a given Open Specifications document might be covered by the Microsoft Open Specifications Promise or the Microsoft Community Promise. If you would prefer a written license, or if the technologies described in this documentation are not covered by the Open Specifications Promise or Community Promise, as applicable, patent licenses are available by contacting iplg@microsoft.com.
+
+ - License Programs. To see all of the protocols in scope under a specific license program and the associated patents, visit the Patent Map.
+
+ - Trademarks. The names of companies and products contained in this documentation might be covered by trademarks or similar intellectual property rights. This notice does not grant any licenses under those rights. For a list of Microsoft trademarks, visit www.microsoft.com/trademarks.
+
+ - Fictitious Names. The example companies, organizations, products, domain names, email addresses, logos, people, places, and events that are depicted in this documentation are fictitious. No association with any real company, organization, product, domain name, email address, logo, person, place, or event is intended or should be inferred.
+
+Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other than as specifically described above, whether by implication, estoppel, or otherwise.
+
+Tools. The Open Specifications documentation does not require the use of Microsoft programming tools or programming environments in order for you to develop an implementation. If you have access to Microsoft programming tools and environments, you are free to take advantage of them. Certain Open Specifications documents are intended for use in conjunction with publicly available standards specifications and network programming art and, as such, assume that the reader either is familiar with the aforementioned material or has immediate access to it.
+
+===========
+
+0x00030200
+
+STG_S_CONVERTED
+
+
+The underlying file was converted to compound file format.
+
+0x00030201
+
+STG_S_BLOCK
+
+
+The storage operation should block until more data is available.
+
+0x00030202
+
+STG_S_RETRYNOW
+
+
+The storage operation should retry immediately.
+
+0x00030203
+
+STG_S_MONITORING
+
+
+The notified event sink will not influence the storage operation.
+
+0x00030204
+
+STG_S_MULTIPLEOPENS
+
+
+Multiple opens prevent consolidated (commit succeeded).
+
+0x00030205
+
+STG_S_CONSOLIDATIONFAILED
+
+
+Consolidation of the storage file failed (commit succeeded).
+
+0x00030206
+
+STG_S_CANNOTCONSOLIDATE
+
+
+Consolidation of the storage file is inappropriate (commit succeeded).
+
+0x00040000
+
+OLE_S_USEREG
+
+
+Use the registry database to provide the requested information.
+
+0x00040001
+
+OLE_S_STATIC
+
+
+Success, but static.
+
+0x00040002
+
+OLE_S_MAC_CLIPFORMAT
+
+
+Macintosh clipboard format.
+
+0x00040100
+
+DRAGDROP_S_DROP
+
+
+Successful drop took place.
+
+0x00040101
+
+DRAGDROP_S_CANCEL
+
+
+Drag-drop operation canceled.
+
+0x00040102
+
+DRAGDROP_S_USEDEFAULTCURSORS
+
+
+Use the default cursor.
+
+0x00040130
+
+DATA_S_SAMEFORMATETC
+
+
+Data has same FORMATETC.
+
+0x00040140
+
+VIEW_S_ALREADY_FROZEN
+
+
+View is already frozen.
+
+0x00040170
+
+CACHE_S_FORMATETC_NOTSUPPORTED
+
+
+FORMATETC not supported.
+
+0x00040171
+
+CACHE_S_SAMECACHE
+
+
+Same cache.
+
+0x00040172
+
+CACHE_S_SOMECACHES_NOTUPDATED
+
+
+Some caches are not updated.
+
+0x00040180
+
+OLEOBJ_S_INVALIDVERB
+
+
+Invalid verb for OLE object.
+
+0x00040181
+
+OLEOBJ_S_CANNOT_DOVERB_NOW
+
+
+Verb number is valid but verb cannot be done now.
+
+0x00040182
+
+OLEOBJ_S_INVALIDHWND
+
+
+Invalid window handle passed.
+
+0x000401A0
+
+INPLACE_S_TRUNCATED
+
+
+Message is too long; some of it had to be truncated before displaying.
+
+0x000401C0
+
+CONVERT10_S_NO_PRESENTATION
+
+
+Unable to convert OLESTREAM to IStorage.
+
+0x000401E2
+
+MK_S_REDUCED_TO_SELF
+
+
+Moniker reduced to itself.
+
+0x000401E4
+
+MK_S_ME
+
+
+Common prefix is this moniker.
+
+0x000401E5
+
+MK_S_HIM
+
+
+Common prefix is input moniker.
+
+0x000401E6
+
+MK_S_US
+
+
+Common prefix is both monikers.
+
+0x000401E7
+
+MK_S_MONIKERALREADYREGISTERED
+
+
+Moniker is already registered in running object table.
+
+0x00040200
+
+EVENT_S_SOME_SUBSCRIBERS_FAILED
+
+
+An event was able to invoke some, but not all, of the subscribers.
+
+0x00040202
+
+EVENT_S_NOSUBSCRIBERS
+
+
+An event was delivered, but there were no subscribers.
+
+0x00041300
+
+SCHED_S_TASK_READY
+
+
+The task is ready to run at its next scheduled time.
+
+0x00041301
+
+SCHED_S_TASK_RUNNING
+
+
+The task is currently running.
+
+0x00041302
+
+SCHED_S_TASK_DISABLED
+
+
+The task will not run at the scheduled times because it has been disabled.
+
+0x00041303
+
+SCHED_S_TASK_HAS_NOT_RUN
+
+
+The task has not yet run.
+
+0x00041304
+
+SCHED_S_TASK_NO_MORE_RUNS
+
+
+There are no more runs scheduled for this task.
+
+0x00041305
+
+SCHED_S_TASK_NOT_SCHEDULED
+
+
+One or more of the properties that are needed to run this task on a schedule have not been set.
+
+0x00041306
+
+SCHED_S_TASK_TERMINATED
+
+
+The last run of the task was terminated by the user.
+
+0x00041307
+
+SCHED_S_TASK_NO_VALID_TRIGGERS
+
+
+Either the task has no triggers, or the existing triggers are disabled or not set.
+
+0x00041308
+
+SCHED_S_EVENT_TRIGGER
+
+
+Event triggers do not have set run times.
+
+0x0004131B
+
+SCHED_S_SOME_TRIGGERS_FAILED
+
+
+The task is registered, but not all specified triggers will start the task.
+
+0x0004131C
+
+SCHED_S_BATCH_LOGON_PROBLEM
+
+
+The task is registered, but it might fail to start. Batch logon privilege needs to be enabled for the task principal.
+
+0x0004D000
+
+XACT_S_ASYNC
+
+
+An asynchronous operation was specified. The operation has begun, but its outcome is not known yet.
+
+0x0004D002
+
+XACT_S_READONLY
+
+
+The method call succeeded because the transaction was read-only.
+
+0x0004D003
+
+XACT_S_SOMENORETAIN
+
+
+The transaction was successfully aborted. However, this is a coordinated transaction, and a number of enlisted resources were aborted outright because they could not support abort-retaining semantics.
+
+0x0004D004
+
+XACT_S_OKINFORM
+
+
+No changes were made during this call, but the sink wants another chance to look if any other sinks make further changes.
+
+0x0004D005
+
+XACT_S_MADECHANGESCONTENT
+
+
+The sink is content and wants the transaction to proceed. Changes were made to one or more resources during this call.
+
+0x0004D006
+
+XACT_S_MADECHANGESINFORM
+
+
+The sink is for the moment and wants the transaction to proceed, but if other changes are made following this return by other event sinks, this sink wants another chance to look.
+
+0x0004D007
+
+XACT_S_ALLNORETAIN
+
+
+The transaction was successfully aborted. However, the abort was nonretaining.
+
+0x0004D008
+
+XACT_S_ABORTING
+
+
+An abort operation was already in progress.
+
+0x0004D009
+
+XACT_S_SINGLEPHASE
+
+
+The resource manager has performed a single-phase commit of the transaction.
+
+0x0004D00A
+
+XACT_S_LOCALLY_OK
+
+
+The local transaction has not aborted.
+
+0x0004D010
+
+XACT_S_LASTRESOURCEMANAGER
+
+
+The resource manager has requested to be the coordinator (last resource manager) for the transaction.
+
+0x00080012
+
+CO_S_NOTALLINTERFACES
+
+
+Not all the requested interfaces were available.
+
+0x00080013
+
+CO_S_MACHINENAMENOTFOUND
+
+
+The specified machine name was not found in the cache.
+
+0x00090312
+
+SEC_I_CONTINUE_NEEDED
+
+
+The function completed successfully, but it must be called again to complete the context.
+
+0x00090313
+
+SEC_I_COMPLETE_NEEDED
+
+
+The function completed successfully, but CompleteToken must be called.
+
+0x00090314
+
+SEC_I_COMPLETE_AND_CONTINUE
+
+
+The function completed successfully, but both CompleteToken and this function must be called to complete the context.
+
+0x00090315
+
+SEC_I_LOCAL_LOGON
+
+
+The logon was completed, but no network authority was available. The logon was made using locally known information.
+
+0x00090317
+
+SEC_I_CONTEXT_EXPIRED
+
+
+The context has expired and can no longer be used.
+
+0x00090320
+
+SEC_I_INCOMPLETE_CREDENTIALS
+
+
+The credentials supplied were not complete and could not be verified. Additional information can be returned from the context.
+
+0x00090321
+
+SEC_I_RENEGOTIATE
+
+
+The context data must be renegotiated with the peer.
+
+0x00090323
+
+SEC_I_NO_LSA_CONTEXT
+
+
+There is no LSA mode context associated with this context.
+
+0x0009035C
+
+SEC_I_SIGNATURE_NEEDED
+
+
+A signature operation must be performed before the user can authenticate.
+
+0x00091012
+
+CRYPT_I_NEW_PROTECTION_REQUIRED
+
+
+The protected data needs to be reprotected.
+
+0x000D0000
+
+NS_S_CALLPENDING
+
+
+The requested operation is pending completion.
+
+0x000D0001
+
+NS_S_CALLABORTED
+
+
+The requested operation was aborted by the client.
+
+0x000D0002
+
+NS_S_STREAM_TRUNCATED
+
+
+The stream was purposefully stopped before completion.
+
+0x000D0BC8
+
+NS_S_REBUFFERING
+
+
+The requested operation has caused the source to rebuffer.
+
+0x000D0BC9
+
+NS_S_DEGRADING_QUALITY
+
+
+The requested operation has caused the source to degrade codec quality.
+
+0x000D0BDB
+
+NS_S_TRANSCRYPTOR_EOF
+
+
+The transcryptor object has reached end of file.
+
+0x000D0FE8
+
+NS_S_WMP_UI_VERSIONMISMATCH
+
+
+An upgrade is needed for the theme manager to correctly show this skin. Skin reports version: %.1f.
+
+0x000D0FE9
+
+NS_S_WMP_EXCEPTION
+
+
+An error occurred in one of the UI components.
+
+0x000D1040
+
+NS_S_WMP_LOADED_GIF_IMAGE
+
+
+Successfully loaded a GIF file.
+
+0x000D1041
+
+NS_S_WMP_LOADED_PNG_IMAGE
+
+
+Successfully loaded a PNG file.
+
+0x000D1042
+
+NS_S_WMP_LOADED_BMP_IMAGE
+
+
+Successfully loaded a BMP file.
+
+0x000D1043
+
+NS_S_WMP_LOADED_JPG_IMAGE
+
+
+Successfully loaded a JPG file.
+
+0x000D104F
+
+NS_S_WMG_FORCE_DROP_FRAME
+
+
+Drop this frame.
+
+0x000D105F
+
+NS_S_WMR_ALREADYRENDERED
+
+
+The specified stream has already been rendered.
+
+0x000D1060
+
+NS_S_WMR_PINTYPEPARTIALMATCH
+
+
+The specified type partially matches this pin type.
+
+0x000D1061
+
+NS_S_WMR_PINTYPEFULLMATCH
+
+
+The specified type fully matches this pin type.
+
+0x000D1066
+
+NS_S_WMG_ADVISE_DROP_FRAME
+
+
+The timestamp is late compared to the current render position. Advise dropping this frame.
+
+0x000D1067
+
+NS_S_WMG_ADVISE_DROP_TO_KEYFRAME
+
+
+The timestamp is severely late compared to the current render position. Advise dropping everything up to the next key frame.
+
+0x000D10DB
+
+NS_S_NEED_TO_BUY_BURN_RIGHTS
+
+
+No burn rights. You will be prompted to buy burn rights when you try to burn this file to an audio CD.
+
+0x000D10FE
+
+NS_S_WMPCORE_PLAYLISTCLEARABORT
+
+
+Failed to clear playlist because it was aborted by user.
+
+0x000D10FF
+
+NS_S_WMPCORE_PLAYLISTREMOVEITEMABORT
+
+
+Failed to remove item in the playlist since it was aborted by user.
+
+0x000D1102
+
+NS_S_WMPCORE_PLAYLIST_CREATION_PENDING
+
+
+Playlist is being generated asynchronously.
+
+0x000D1103
+
+NS_S_WMPCORE_MEDIA_VALIDATION_PENDING
+
+
+Validation of the media is pending.
+
+0x000D1104
+
+NS_S_WMPCORE_PLAYLIST_REPEAT_SECONDARY_SEGMENTS_IGNORED
+
+
+Encountered more than one Repeat block during ASX processing.
+
+0x000D1105
+
+NS_S_WMPCORE_COMMAND_NOT_AVAILABLE
+
+
+Current state of WMP disallows calling this method or property.
+
+0x000D1106
+
+NS_S_WMPCORE_PLAYLIST_NAME_AUTO_GENERATED
+
+
+Name for the playlist has been auto generated.
+
+0x000D1107
+
+NS_S_WMPCORE_PLAYLIST_IMPORT_MISSING_ITEMS
+
+
+The imported playlist does not contain all items from the original.
+
+0x000D1108
+
+NS_S_WMPCORE_PLAYLIST_COLLAPSED_TO_SINGLE_MEDIA
+
+
+The M3U playlist has been ignored because it only contains one item.
+
+0x000D1109
+
+NS_S_WMPCORE_MEDIA_CHILD_PLAYLIST_OPEN_PENDING
+
+
+The open for the child playlist associated with this media is pending.
+
+0x000D110A
+
+NS_S_WMPCORE_MORE_NODES_AVAIABLE
+
+
+More nodes support the interface requested, but the array for returning them is full.
+
+0x000D1135
+
+NS_S_WMPBR_SUCCESS
+
+
+Backup or Restore successful!.
+
+0x000D1136
+
+NS_S_WMPBR_PARTIALSUCCESS
+
+
+Transfer complete with limitations.
+
+0x000D1144
+
+NS_S_WMPEFFECT_TRANSPARENT
+
+
+Request to the effects control to change transparency status to transparent.
+
+0x000D1145
+
+NS_S_WMPEFFECT_OPAQUE
+
+
+Request to the effects control to change transparency status to opaque.
+
+0x000D114E
+
+NS_S_OPERATION_PENDING
+
+
+The requested application pane is performing an operation and will not be released.
+
+0x000D1359
+
+NS_S_TRACK_BUY_REQUIRES_ALBUM_PURCHASE
+
+
+The file is only available for purchase when you buy the entire album.
+
+0x000D135E
+
+NS_S_NAVIGATION_COMPLETE_WITH_ERRORS
+
+
+There were problems completing the requested navigation. There are identifiers missing in the catalog.
+
+0x000D1361
+
+NS_S_TRACK_ALREADY_DOWNLOADED
+
+
+Track already downloaded.
+
+0x000D1519
+
+NS_S_PUBLISHING_POINT_STARTED_WITH_FAILED_SINKS
+
+
+The publishing point successfully started, but one or more of the requested data writer plug-ins failed.
+
+0x000D2726
+
+NS_S_DRM_LICENSE_ACQUIRED
+
+
+Status message: The license was acquired.
+
+0x000D2727
+
+NS_S_DRM_INDIVIDUALIZED
+
+
+Status message: The security upgrade has been completed.
+
+0x000D2746
+
+NS_S_DRM_MONITOR_CANCELLED
+
+
+Status message: License monitoring has been canceled.
+
+0x000D2747
+
+NS_S_DRM_ACQUIRE_CANCELLED
+
+
+Status message: License acquisition has been canceled.
+
+0x000D276E
+
+NS_S_DRM_BURNABLE_TRACK
+
+
+The track is burnable and had no playlist burn limit.
+
+0x000D276F
+
+NS_S_DRM_BURNABLE_TRACK_WITH_PLAYLIST_RESTRICTION
+
+
+The track is burnable but has a playlist burn limit.
+
+0x000D27DE
+
+NS_S_DRM_NEEDS_INDIVIDUALIZATION
+
+
+A security upgrade is required to perform the operation on this media file.
+
+0x000D2AF8
+
+NS_S_REBOOT_RECOMMENDED
+
+
+Installation was successful; however, some file cleanup is not complete. For best results, restart your computer.
+
+0x000D2AF9
+
+NS_S_REBOOT_REQUIRED
+
+
+Installation was successful; however, some file cleanup is not complete. To continue, you must restart your computer.
+
+0x000D2F09
+
+NS_S_EOSRECEDING
+
+
+EOS hit during rewinding.
+
+0x000D2F0D
+
+NS_S_CHANGENOTICE
+
+
+Internal.
+
+0x001F0001
+
+ERROR_FLT_IO_COMPLETE
+
+
+The IO was completed by a filter.
+
+0x00262307
+
+ERROR_GRAPHICS_MODE_NOT_PINNED
+
+
+No mode is pinned on the specified VidPN source or target.
+
+0x0026231E
+
+ERROR_GRAPHICS_NO_PREFERRED_MODE
+
+
+Specified mode set does not specify preference for one of its modes.
+
+0x0026234B
+
+ERROR_GRAPHICS_DATASET_IS_EMPTY
+
+
+Specified data set (for example, mode set, frequency range set, descriptor set, and topology) is empty.
+
+0x0026234C
+
+ERROR_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET
+
+
+Specified data set (for example, mode set, frequency range set, descriptor set, and topology) does not contain any more elements.
+
+0x00262351
+
+ERROR_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED
+
+
+Specified content transformation is not pinned on the specified VidPN present path.
+
+0x00300100
+
+PLA_S_PROPERTY_IGNORED
+
+
+Property value will be ignored.
+
+0x00340001
+
+ERROR_NDIS_INDICATION_REQUIRED
+
+
+The request will be completed later by a Network Driver Interface Specification (NDIS) status indication.
+
+0x0DEAD100
+
+TRK_S_OUT_OF_SYNC
+
+
+The VolumeSequenceNumber of a MOVE_NOTIFICATION request is incorrect.
+
+0x0DEAD102
+
+TRK_VOLUME_NOT_FOUND
+
+
+The VolumeID in a request was not found in the server's ServerVolumeTable.
+
+0x0DEAD103
+
+TRK_VOLUME_NOT_OWNED
+
+
+A notification was sent to the LnkSvrMessage method, but the RequestMachine for the request was not the VolumeOwner for a VolumeID in the request.
+
+0x0DEAD107
+
+TRK_S_NOTIFICATION_QUOTA_EXCEEDED
+
+
+The server received a MOVE_NOTIFICATION request, but the FileTable size limit has already been reached.
+
+0x400D004F
+
+NS_I_TIGER_START
+
+
+The Title Server %1 is running.
+
+0x400D0051
+
+NS_I_CUB_START
+
+
+Content Server %1 (%2) is starting.
+
+0x400D0052
+
+NS_I_CUB_RUNNING
+
+
+Content Server %1 (%2) is running.
+
+0x400D0054
+
+NS_I_DISK_START
+
+
+Disk %1 ( %2 ) on Content Server %3, is running.
+
+0x400D0056
+
+NS_I_DISK_REBUILD_STARTED
+
+
+Started rebuilding disk %1 ( %2 ) on Content Server %3.
+
+0x400D0057
+
+NS_I_DISK_REBUILD_FINISHED
+
+
+Finished rebuilding disk %1 ( %2 ) on Content Server %3.
+
+0x400D0058
+
+NS_I_DISK_REBUILD_ABORTED
+
+
+Aborted rebuilding disk %1 ( %2 ) on Content Server %3.
+
+0x400D0059
+
+NS_I_LIMIT_FUNNELS
+
+
+A NetShow administrator at network location %1 set the data stream limit to %2 streams.
+
+0x400D005A
+
+NS_I_START_DISK
+
+
+A NetShow administrator at network location %1 started disk %2.
+
+0x400D005B
+
+NS_I_STOP_DISK
+
+
+A NetShow administrator at network location %1 stopped disk %2.
+
+0x400D005C
+
+NS_I_STOP_CUB
+
+
+A NetShow administrator at network location %1 stopped Content Server %2.
+
+0x400D005D
+
+NS_I_KILL_USERSESSION
+
+
+A NetShow administrator at network location %1 aborted user session %2 from the system.
+
+0x400D005E
+
+NS_I_KILL_CONNECTION
+
+
+A NetShow administrator at network location %1 aborted obsolete connection %2 from the system.
+
+0x400D005F
+
+NS_I_REBUILD_DISK
+
+
+A NetShow administrator at network location %1 started rebuilding disk %2.
+
+0x400D0069
+
+MCMADM_I_NO_EVENTS
+
+
+Event initialization failed, there will be no MCM events.
+
+0x400D006E
+
+NS_I_LOGGING_FAILED
+
+
+The logging operation failed.
+
+0x400D0070
+
+NS_I_LIMIT_BANDWIDTH
+
+
+A NetShow administrator at network location %1 set the maximum bandwidth limit to %2 bps.
+
+0x400D0191
+
+NS_I_CUB_UNFAIL_LINK
+
+
+Content Server %1 (%2) has established its link to Content Server %3.
+
+0x400D0193
+
+NS_I_RESTRIPE_START
+
+
+Restripe operation has started.
+
+0x400D0194
+
+NS_I_RESTRIPE_DONE
+
+
+Restripe operation has completed.
+
+0x400D0196
+
+NS_I_RESTRIPE_DISK_OUT
+
+
+Content disk %1 (%2) on Content Server %3 has been restriped out.
+
+0x400D0197
+
+NS_I_RESTRIPE_CUB_OUT
+
+
+Content server %1 (%2) has been restriped out.
+
+0x400D0198
+
+NS_I_DISK_STOP
+
+
+Disk %1 ( %2 ) on Content Server %3, has been offlined.
+
+0x400D14BE
+
+NS_I_PLAYLIST_CHANGE_RECEDING
+
+
+The playlist change occurred while receding.
+
+0x400D2EFF
+
+NS_I_RECONNECTED
+
+
+The client is reconnected.
+
+0x400D2F01
+
+NS_I_NOLOG_STOP
+
+
+Forcing a switch to a pending header on start.
+
+0x400D2F03
+
+NS_I_EXISTING_PACKETIZER
+
+
+There is already an existing packetizer plugin for the stream.
+
+0x400D2F04
+
+NS_I_MANUAL_PROXY
+
+
+The proxy setting is manual.
+
+0x40262009
+
+ERROR_GRAPHICS_DRIVER_MISMATCH
+
+
+The kernel driver detected a version mismatch between it and the user mode driver.
+
+0x4026242F
+
+ERROR_GRAPHICS_UNKNOWN_CHILD_STATUS
+
+
+Child device presence was not reliably detected.
+
+0x40262437
+
+ERROR_GRAPHICS_LEADLINK_START_DEFERRED
+
+
+Starting the lead-link adapter has been deferred temporarily.
+
+0x40262439
+
+ERROR_GRAPHICS_POLLING_TOO_FREQUENTLY
+
+
+The display adapter is being polled for children too frequently at the same polling level.
+
+0x4026243A
+
+ERROR_GRAPHICS_START_DEFERRED
+
+
+Starting the adapter has been deferred temporarily.
+
+0x8000000A
+
+E_PENDING
+
+
+The data necessary to complete this operation is not yet available.
+
+0x80004001
+
+E_NOTIMPL
+
+
+Not implemented.
+
+0x80004002
+
+E_NOINTERFACE
+
+
+No such interface supported.
+
+0x80004003
+
+E_POINTER
+
+
+Invalid pointer.
+
+0x80004004
+
+E_ABORT
+
+
+Operation aborted.
+
+0x80004005
+
+E_FAIL
+
+
+Unspecified error.
+
+0x80004006
+
+CO_E_INIT_TLS
+
+
+Thread local storage failure.
+
+0x80004007
+
+CO_E_INIT_SHARED_ALLOCATOR
+
+
+Get shared memory allocator failure.
+
+0x80004008
+
+CO_E_INIT_MEMORY_ALLOCATOR
+
+
+Get memory allocator failure.
+
+0x80004009
+
+CO_E_INIT_CLASS_CACHE
+
+
+Unable to initialize class cache.
+
+0x8000400A
+
+CO_E_INIT_RPC_CHANNEL
+
+
+Unable to initialize remote procedure call (RPC) services.
+
+0x8000400B
+
+CO_E_INIT_TLS_SET_CHANNEL_CONTROL
+
+
+Cannot set thread local storage channel control.
+
+0x8000400C
+
+CO_E_INIT_TLS_CHANNEL_CONTROL
+
+
+Could not allocate thread local storage channel control.
+
+0x8000400D
+
+CO_E_INIT_UNACCEPTED_USER_ALLOCATOR
+
+
+The user-supplied memory allocator is unacceptable.
+
+0x8000400E
+
+CO_E_INIT_SCM_MUTEX_EXISTS
+
+
+The OLE service mutex already exists.
+
+0x8000400F
+
+CO_E_INIT_SCM_FILE_MAPPING_EXISTS
+
+
+The OLE service file mapping already exists.
+
+0x80004010
+
+CO_E_INIT_SCM_MAP_VIEW_OF_FILE
+
+
+Unable to map view of file for OLE service.
+
+0x80004011
+
+CO_E_INIT_SCM_EXEC_FAILURE
+
+
+Failure attempting to launch OLE service.
+
+0x80004012
+
+CO_E_INIT_ONLY_SINGLE_THREADED
+
+
+There was an attempt to call CoInitialize a second time while single-threaded.
+
+0x80004013
+
+CO_E_CANT_REMOTE
+
+
+A Remote activation was necessary but was not allowed.
+
+0x80004014
+
+CO_E_BAD_SERVER_NAME
+
+
+A Remote activation was necessary, but the server name provided was invalid.
+
+0x80004015
+
+CO_E_WRONG_SERVER_IDENTITY
+
+
+The class is configured to run as a security ID different from the caller.
+
+0x80004016
+
+CO_E_OLE1DDE_DISABLED
+
+
+Use of OLE1 services requiring Dynamic Data Exchange (DDE) Windows is disabled.
+
+0x80004017
+
+CO_E_RUNAS_SYNTAX
+
+
+A RunAs specification must be <domain name>\<user name> or simply <user name>.
+
+0x80004018
+
+CO_E_CREATEPROCESS_FAILURE
+
+
+The server process could not be started. The path name might be incorrect.
+
+0x80004019
+
+CO_E_RUNAS_CREATEPROCESS_FAILURE
+
+
+The server process could not be started as the configured identity. The path name might be incorrect or unavailable.
+
+0x8000401A
+
+CO_E_RUNAS_LOGON_FAILURE
+
+
+The server process could not be started because the configured identity is incorrect. Check the user name and password.
+
+0x8000401B
+
+CO_E_LAUNCH_PERMSSION_DENIED
+
+
+The client is not allowed to launch this server.
+
+0x8000401C
+
+CO_E_START_SERVICE_FAILURE
+
+
+The service providing this server could not be started.
+
+0x8000401D
+
+CO_E_REMOTE_COMMUNICATION_FAILURE
+
+
+This computer was unable to communicate with the computer providing the server.
+
+0x8000401E
+
+CO_E_SERVER_START_TIMEOUT
+
+
+The server did not respond after being launched.
+
+0x8000401F
+
+CO_E_CLSREG_INCONSISTENT
+
+
+The registration information for this server is inconsistent or incomplete.
+
+0x80004020
+
+CO_E_IIDREG_INCONSISTENT
+
+
+The registration information for this interface is inconsistent or incomplete.
+
+0x80004021
+
+CO_E_NOT_SUPPORTED
+
+
+The operation attempted is not supported.
+
+0x80004022
+
+CO_E_RELOAD_DLL
+
+
+A DLL must be loaded.
+
+0x80004023
+
+CO_E_MSI_ERROR
+
+
+A Microsoft Software Installer error was encountered.
+
+0x80004024
+
+CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT
+
+
+The specified activation could not occur in the client context as specified.
+
+0x80004025
+
+CO_E_SERVER_PAUSED
+
+
+Activations on the server are paused.
+
+0x80004026
+
+CO_E_SERVER_NOT_PAUSED
+
+
+Activations on the server are not paused.
+
+0x80004027
+
+CO_E_CLASS_DISABLED
+
+
+The component or application containing the component has been disabled.
+
+0x80004028
+
+CO_E_CLRNOTAVAILABLE
+
+
+The common language runtime is not available.
+
+0x80004029
+
+CO_E_ASYNC_WORK_REJECTED
+
+
+The thread-pool rejected the submitted asynchronous work.
+
+0x8000402A
+
+CO_E_SERVER_INIT_TIMEOUT
+
+
+The server started, but it did not finish initializing in a timely fashion.
+
+0x8000402B
+
+CO_E_NO_SECCTX_IN_ACTIVATE
+
+
+Unable to complete the call because there is no COM+ security context inside IObjectControl.Activate.
+
+0x80004030
+
+CO_E_TRACKER_CONFIG
+
+
+The provided tracker configuration is invalid.
+
+0x80004031
+
+CO_E_THREADPOOL_CONFIG
+
+
+The provided thread pool configuration is invalid.
+
+0x80004032
+
+CO_E_SXS_CONFIG
+
+
+The provided side-by-side configuration is invalid.
+
+0x80004033
+
+CO_E_MALFORMED_SPN
+
+
+The server principal name (SPN) obtained during security negotiation is malformed.
+
+0x8000FFFF
+
+E_UNEXPECTED
+
+
+Catastrophic failure.
+
+0x80010001
+
+RPC_E_CALL_REJECTED
+
+
+Call was rejected by callee.
+
+0x80010002
+
+RPC_E_CALL_CANCELED
+
+
+Call was canceled by the message filter.
+
+0x80010003
+
+RPC_E_CANTPOST_INSENDCALL
+
+
+The caller is dispatching an intertask SendMessage call and cannot call out via PostMessage.
+
+0x80010004
+
+RPC_E_CANTCALLOUT_INASYNCCALL
+
+
+The caller is dispatching an asynchronous call and cannot make an outgoing call on behalf of this call.
+
+0x80010005
+
+RPC_E_CANTCALLOUT_INEXTERNALCALL
+
+
+It is illegal to call out while inside message filter.
+
+0x80010006
+
+RPC_E_CONNECTION_TERMINATED
+
+
+The connection terminated or is in a bogus state and can no longer be used. Other connections are still valid.
+
+0x80010007
+
+RPC_E_SERVER_DIED
+
+
+The callee (the server, not the server application) is not available and disappeared; all connections are invalid. The call might have executed.
+
+0x80010008
+
+RPC_E_CLIENT_DIED
+
+
+The caller (client) disappeared while the callee (server) was processing a call.
+
+0x80010009
+
+RPC_E_INVALID_DATAPACKET
+
+
+The data packet with the marshaled parameter data is incorrect.
+
+0x8001000A
+
+RPC_E_CANTTRANSMIT_CALL
+
+
+The call was not transmitted properly; the message queue was full and was not emptied after yielding.
+
+0x8001000B
+
+RPC_E_CLIENT_CANTMARSHAL_DATA
+
+
+The client RPC caller cannot marshal the parameter data due to errors (such as low memory).
+
+0x8001000C
+
+RPC_E_CLIENT_CANTUNMARSHAL_DATA
+
+
+The client RPC caller cannot unmarshal the return data due to errors (such as low memory).
+
+0x8001000D
+
+RPC_E_SERVER_CANTMARSHAL_DATA
+
+
+The server RPC callee cannot marshal the return data due to errors (such as low memory).
+
+0x8001000E
+
+RPC_E_SERVER_CANTUNMARSHAL_DATA
+
+
+The server RPC callee cannot unmarshal the parameter data due to errors (such as low memory).
+
+0x8001000F
+
+RPC_E_INVALID_DATA
+
+
+Received data is invalid. The data might be server or client data.
+
+0x80010010
+
+RPC_E_INVALID_PARAMETER
+
+
+A particular parameter is invalid and cannot be (un)marshaled.
+
+0x80010011
+
+RPC_E_CANTCALLOUT_AGAIN
+
+
+There is no second outgoing call on same channel in DDE conversation.
+
+0x80010012
+
+RPC_E_SERVER_DIED_DNE
+
+
+The callee (the server, not the server application) is not available and disappeared; all connections are invalid. The call did not execute.
+
+0x80010100
+
+RPC_E_SYS_CALL_FAILED
+
+
+System call failed.
+
+0x80010101
+
+RPC_E_OUT_OF_RESOURCES
+
+
+Could not allocate some required resource (such as memory or events)
+
+0x80010102
+
+RPC_E_ATTEMPTED_MULTITHREAD
+
+
+Attempted to make calls on more than one thread in single-threaded mode.
+
+0x80010103
+
+RPC_E_NOT_REGISTERED
+
+
+The requested interface is not registered on the server object.
+
+0x80010104
+
+RPC_E_FAULT
+
+
+RPC could not call the server or could not return the results of calling the server.
+
+0x80010105
+
+RPC_E_SERVERFAULT
+
+
+The server threw an exception.
+
+0x80010106
+
+RPC_E_CHANGED_MODE
+
+
+Cannot change thread mode after it is set.
+
+0x80010107
+
+RPC_E_INVALIDMETHOD
+
+
+The method called does not exist on the server.
+
+0x80010108
+
+RPC_E_DISCONNECTED
+
+
+The object invoked has disconnected from its clients.
+
+0x80010109
+
+RPC_E_RETRY
+
+
+The object invoked chose not to process the call now. Try again later.
+
+0x8001010A
+
+RPC_E_SERVERCALL_RETRYLATER
+
+
+The message filter indicated that the application is busy.
+
+0x8001010B
+
+RPC_E_SERVERCALL_REJECTED
+
+
+The message filter rejected the call.
+
+0x8001010C
+
+RPC_E_INVALID_CALLDATA
+
+
+A call control interface was called with invalid data.
+
+0x8001010D
+
+RPC_E_CANTCALLOUT_ININPUTSYNCCALL
+
+
+An outgoing call cannot be made because the application is dispatching an input-synchronous call.
+
+0x8001010E
+
+RPC_E_WRONG_THREAD
+
+
+The application called an interface that was marshaled for a different thread.
+
+0x8001010F
+
+RPC_E_THREAD_NOT_INIT
+
+
+CoInitialize has not been called on the current thread.
+
+0x80010110
+
+RPC_E_VERSION_MISMATCH
+
+
+The version of OLE on the client and server machines does not match.
+
+0x80010111
+
+RPC_E_INVALID_HEADER
+
+
+OLE received a packet with an invalid header.
+
+0x80010112
+
+RPC_E_INVALID_EXTENSION
+
+
+OLE received a packet with an invalid extension.
+
+0x80010113
+
+RPC_E_INVALID_IPID
+
+
+The requested object or interface does not exist.
+
+0x80010114
+
+RPC_E_INVALID_OBJECT
+
+
+The requested object does not exist.
+
+0x80010115
+
+RPC_S_CALLPENDING
+
+
+OLE has sent a request and is waiting for a reply.
+
+0x80010116
+
+RPC_S_WAITONTIMER
+
+
+OLE is waiting before retrying a request.
+
+0x80010117
+
+RPC_E_CALL_COMPLETE
+
+
+Call context cannot be accessed after call completed.
+
+0x80010118
+
+RPC_E_UNSECURE_CALL
+
+
+Impersonate on unsecure calls is not supported.
+
+0x80010119
+
+RPC_E_TOO_LATE
+
+
+Security must be initialized before any interfaces are marshaled or unmarshaled. It cannot be changed after initialized.
+
+0x8001011A
+
+RPC_E_NO_GOOD_SECURITY_PACKAGES
+
+
+No security packages are installed on this machine, the user is not logged on, or there are no compatible security packages between the client and server.
+
+0x8001011B
+
+RPC_E_ACCESS_DENIED
+
+
+Access is denied.
+
+0x8001011C
+
+RPC_E_REMOTE_DISABLED
+
+
+Remote calls are not allowed for this process.
+
+0x8001011D
+
+RPC_E_INVALID_OBJREF
+
+
+The marshaled interface data packet (OBJREF) has an invalid or unknown format.
+
+0x8001011E
+
+RPC_E_NO_CONTEXT
+
+
+No context is associated with this call. This happens for some custom marshaled calls and on the client side of the call.
+
+0x8001011F
+
+RPC_E_TIMEOUT
+
+
+This operation returned because the time-out period expired.
+
+0x80010120
+
+RPC_E_NO_SYNC
+
+
+There are no synchronize objects to wait on.
+
+0x80010121
+
+RPC_E_FULLSIC_REQUIRED
+
+
+Full subject issuer chain Secure Sockets Layer (SSL) principal name expected from the server.
+
+0x80010122
+
+RPC_E_INVALID_STD_NAME
+
+
+Principal name is not a valid Microsoft standard (msstd) name.
+
+0x80010123
+
+CO_E_FAILEDTOIMPERSONATE
+
+
+Unable to impersonate DCOM client.
+
+0x80010124
+
+CO_E_FAILEDTOGETSECCTX
+
+
+Unable to obtain server's security context.
+
+0x80010125
+
+CO_E_FAILEDTOOPENTHREADTOKEN
+
+
+Unable to open the access token of the current thread.
+
+0x80010126
+
+CO_E_FAILEDTOGETTOKENINFO
+
+
+Unable to obtain user information from an access token.
+
+0x80010127
+
+CO_E_TRUSTEEDOESNTMATCHCLIENT
+
+
+The client who called IAccessControl::IsAccessPermitted was not the trustee provided to the method.
+
+0x80010128
+
+CO_E_FAILEDTOQUERYCLIENTBLANKET
+
+
+Unable to obtain the client's security blanket.
+
+0x80010129
+
+CO_E_FAILEDTOSETDACL
+
+
+Unable to set a discretionary access control list (ACL) into a security descriptor.
+
+0x8001012A
+
+CO_E_ACCESSCHECKFAILED
+
+
+The system function AccessCheck returned false.
+
+0x8001012B
+
+CO_E_NETACCESSAPIFAILED
+
+
+Either NetAccessDel or NetAccessAdd returned an error code.
+
+0x8001012C
+
+CO_E_WRONGTRUSTEENAMESYNTAX
+
+
+One of the trustee strings provided by the user did not conform to the <Domain>\<Name> syntax and it was not the *" string".
+
+0x8001012D
+
+CO_E_INVALIDSID
+
+
+One of the security identifiers provided by the user was invalid.
+
+0x8001012E
+
+CO_E_CONVERSIONFAILED
+
+
+Unable to convert a wide character trustee string to a multiple-byte trustee string.
+
+0x8001012F
+
+CO_E_NOMATCHINGSIDFOUND
+
+
+Unable to find a security identifier that corresponds to a trustee string provided by the user.
+
+0x80010130
+
+CO_E_LOOKUPACCSIDFAILED
+
+
+The system function LookupAccountSID failed.
+
+0x80010131
+
+CO_E_NOMATCHINGNAMEFOUND
+
+
+Unable to find a trustee name that corresponds to a security identifier provided by the user.
+
+0x80010132
+
+CO_E_LOOKUPACCNAMEFAILED
+
+
+The system function LookupAccountName failed.
+
+0x80010133
+
+CO_E_SETSERLHNDLFAILED
+
+
+Unable to set or reset a serialization handle.
+
+0x80010134
+
+CO_E_FAILEDTOGETWINDIR
+
+
+Unable to obtain the Windows directory.
+
+0x80010135
+
+CO_E_PATHTOOLONG
+
+
+Path too long.
+
+0x80010136
+
+CO_E_FAILEDTOGENUUID
+
+
+Unable to generate a UUID.
+
+0x80010137
+
+CO_E_FAILEDTOCREATEFILE
+
+
+Unable to create file.
+
+0x80010138
+
+CO_E_FAILEDTOCLOSEHANDLE
+
+
+Unable to close a serialization handle or a file handle.
+
+0x80010139
+
+CO_E_EXCEEDSYSACLLIMIT
+
+
+The number of access control entries (ACEs) in an ACL exceeds the system limit.
+
+0x8001013A
+
+CO_E_ACESINWRONGORDER
+
+
+Not all the DENY_ACCESS ACEs are arranged in front of the GRANT_ACCESS ACEs in the stream.
+
+0x8001013B
+
+CO_E_INCOMPATIBLESTREAMVERSION
+
+
+The version of ACL format in the stream is not supported by this implementation of IAccessControl.
+
+0x8001013C
+
+CO_E_FAILEDTOOPENPROCESSTOKEN
+
+
+Unable to open the access token of the server process.
+
+0x8001013D
+
+CO_E_DECODEFAILED
+
+
+Unable to decode the ACL in the stream provided by the user.
+
+0x8001013F
+
+CO_E_ACNOTINITIALIZED
+
+
+The COM IAccessControl object is not initialized.
+
+0x80010140
+
+CO_E_CANCEL_DISABLED
+
+
+Call Cancellation is disabled.
+
+0x8001FFFF
+
+RPC_E_UNEXPECTED
+
+
+An internal error occurred.
+
+0x80020001
+
+DISP_E_UNKNOWNINTERFACE
+
+
+Unknown interface.
+
+0x80020003
+
+DISP_E_MEMBERNOTFOUND
+
+
+Member not found.
+
+0x80020004
+
+DISP_E_PARAMNOTFOUND
+
+
+Parameter not found.
+
+0x80020005
+
+DISP_E_TYPEMISMATCH
+
+
+Type mismatch.
+
+0x80020006
+
+DISP_E_UNKNOWNNAME
+
+
+Unknown name.
+
+0x80020007
+
+DISP_E_NONAMEDARGS
+
+
+No named arguments.
+
+0x80020008
+
+DISP_E_BADVARTYPE
+
+
+Bad variable type.
+
+0x80020009
+
+DISP_E_EXCEPTION
+
+
+Exception occurred.
+
+0x8002000A
+
+DISP_E_OVERFLOW
+
+
+Out of present range.
+
+0x8002000B
+
+DISP_E_BADINDEX
+
+
+Invalid index.
+
+0x8002000C
+
+DISP_E_UNKNOWNLCID
+
+
+Unknown language.
+
+0x8002000D
+
+DISP_E_ARRAYISLOCKED
+
+
+Memory is locked.
+
+0x8002000E
+
+DISP_E_BADPARAMCOUNT
+
+
+Invalid number of parameters.
+
+0x8002000F
+
+DISP_E_PARAMNOTOPTIONAL
+
+
+Parameter not optional.
+
+0x80020010
+
+DISP_E_BADCALLEE
+
+
+Invalid callee.
+
+0x80020011
+
+DISP_E_NOTACOLLECTION
+
+
+Does not support a collection.
+
+0x80020012
+
+DISP_E_DIVBYZERO
+
+
+Division by zero.
+
+0x80020013
+
+DISP_E_BUFFERTOOSMALL
+
+
+Buffer too small.
+
+0x80028016
+
+TYPE_E_BUFFERTOOSMALL
+
+
+Buffer too small.
+
+0x80028017
+
+TYPE_E_FIELDNOTFOUND
+
+
+Field name not defined in the record.
+
+0x80028018
+
+TYPE_E_INVDATAREAD
+
+
+Old format or invalid type library.
+
+0x80028019
+
+TYPE_E_UNSUPFORMAT
+
+
+Old format or invalid type library.
+
+0x8002801C
+
+TYPE_E_REGISTRYACCESS
+
+
+Error accessing the OLE registry.
+
+0x8002801D
+
+TYPE_E_LIBNOTREGISTERED
+
+
+Library not registered.
+
+0x80028027
+
+TYPE_E_UNDEFINEDTYPE
+
+
+Bound to unknown type.
+
+0x80028028
+
+TYPE_E_QUALIFIEDNAMEDISALLOWED
+
+
+Qualified name disallowed.
+
+0x80028029
+
+TYPE_E_INVALIDSTATE
+
+
+Invalid forward reference, or reference to uncompiled type.
+
+0x8002802A
+
+TYPE_E_WRONGTYPEKIND
+
+
+Type mismatch.
+
+0x8002802B
+
+TYPE_E_ELEMENTNOTFOUND
+
+
+Element not found.
+
+0x8002802C
+
+TYPE_E_AMBIGUOUSNAME
+
+
+Ambiguous name.
+
+0x8002802D
+
+TYPE_E_NAMECONFLICT
+
+
+Name already exists in the library.
+
+0x8002802E
+
+TYPE_E_UNKNOWNLCID
+
+
+Unknown language code identifier (LCID).
+
+0x8002802F
+
+TYPE_E_DLLFUNCTIONNOTFOUND
+
+
+Function not defined in specified DLL.
+
+0x800288BD
+
+TYPE_E_BADMODULEKIND
+
+
+Wrong module kind for the operation.
+
+0x800288C5
+
+TYPE_E_SIZETOOBIG
+
+
+Size cannot exceed 64 KB.
+
+0x800288C6
+
+TYPE_E_DUPLICATEID
+
+
+Duplicate ID in inheritance hierarchy.
+
+0x800288CF
+
+TYPE_E_INVALIDID
+
+
+Incorrect inheritance depth in standard OLE hmember.
+
+0x80028CA0
+
+TYPE_E_TYPEMISMATCH
+
+
+Type mismatch.
+
+0x80028CA1
+
+TYPE_E_OUTOFBOUNDS
+
+
+Invalid number of arguments.
+
+0x80028CA2
+
+TYPE_E_IOERROR
+
+
+I/O error.
+
+0x80028CA3
+
+TYPE_E_CANTCREATETMPFILE
+
+
+Error creating unique .tmp file.
+
+0x80029C4A
+
+TYPE_E_CANTLOADLIBRARY
+
+
+Error loading type library or DLL.
+
+0x80029C83
+
+TYPE_E_INCONSISTENTPROPFUNCS
+
+
+Inconsistent property functions.
+
+0x80029C84
+
+TYPE_E_CIRCULARTYPE
+
+
+Circular dependency between types and modules.
+
+0x80030001
+
+STG_E_INVALIDFUNCTION
+
+
+Unable to perform requested operation.
+
+0x80030002
+
+STG_E_FILENOTFOUND
+
+
+%1 could not be found.
+
+0x80030003
+
+STG_E_PATHNOTFOUND
+
+
+The path %1 could not be found.
+
+0x80030004
+
+STG_E_TOOMANYOPENFILES
+
+
+There are insufficient resources to open another file.
+
+0x80030005
+
+STG_E_ACCESSDENIED
+
+
+Access denied.
+
+0x80030006
+
+STG_E_INVALIDHANDLE
+
+
+Attempted an operation on an invalid object.
+
+0x80030008
+
+STG_E_INSUFFICIENTMEMORY
+
+
+There is insufficient memory available to complete operation.
+
+0x80030009
+
+STG_E_INVALIDPOINTER
+
+
+Invalid pointer error.
+
+0x80030012
+
+STG_E_NOMOREFILES
+
+
+There are no more entries to return.
+
+0x80030013
+
+STG_E_DISKISWRITEPROTECTED
+
+
+Disk is write-protected.
+
+0x80030019
+
+STG_E_SEEKERROR
+
+
+An error occurred during a seek operation.
+
+0x8003001D
+
+STG_E_WRITEFAULT
+
+
+A disk error occurred during a write operation.
+
+0x8003001E
+
+STG_E_READFAULT
+
+
+A disk error occurred during a read operation.
+
+0x80030020
+
+STG_E_SHAREVIOLATION
+
+
+A share violation has occurred.
+
+0x80030021
+
+STG_E_LOCKVIOLATION
+
+
+A lock violation has occurred.
+
+0x80030050
+
+STG_E_FILEALREADYEXISTS
+
+
+%1 already exists.
+
+0x80030057
+
+STG_E_INVALIDPARAMETER
+
+
+Invalid parameter error.
+
+0x80030070
+
+STG_E_MEDIUMFULL
+
+
+There is insufficient disk space to complete operation.
+
+0x800300F0
+
+STG_E_PROPSETMISMATCHED
+
+
+Illegal write of non-simple property to simple property set.
+
+0x800300FA
+
+STG_E_ABNORMALAPIEXIT
+
+
+An application programming interface (API) call exited abnormally.
+
+0x800300FB
+
+STG_E_INVALIDHEADER
+
+
+The file %1 is not a valid compound file.
+
+0x800300FC
+
+STG_E_INVALIDNAME
+
+
+The name %1 is not valid.
+
+0x800300FD
+
+STG_E_UNKNOWN
+
+
+An unexpected error occurred.
+
+0x800300FE
+
+STG_E_UNIMPLEMENTEDFUNCTION
+
+
+That function is not implemented.
+
+0x800300FF
+
+STG_E_INVALIDFLAG
+
+
+Invalid flag error.
+
+0x80030100
+
+STG_E_INUSE
+
+
+Attempted to use an object that is busy.
+
+0x80030101
+
+STG_E_NOTCURRENT
+
+
+The storage has been changed since the last commit.
+
+0x80030102
+
+STG_E_REVERTED
+
+
+Attempted to use an object that has ceased to exist.
+
+0x80030103
+
+STG_E_CANTSAVE
+
+
+Cannot save.
+
+0x80030104
+
+STG_E_OLDFORMAT
+
+
+The compound file %1 was produced with an incompatible version of storage.
+
+0x80030105
+
+STG_E_OLDDLL
+
+
+The compound file %1 was produced with a newer version of storage.
+
+0x80030106
+
+STG_E_SHAREREQUIRED
+
+
+Share.exe or equivalent is required for operation.
+
+0x80030107
+
+STG_E_NOTFILEBASEDSTORAGE
+
+
+Illegal operation called on non-file based storage.
+
+0x80030108
+
+STG_E_EXTANTMARSHALLINGS
+
+
+Illegal operation called on object with extant marshalings.
+
+0x80030109
+
+STG_E_DOCFILECORRUPT
+
+
+The docfile has been corrupted.
+
+0x80030110
+
+STG_E_BADBASEADDRESS
+
+
+OLE32.DLL has been loaded at the wrong address.
+
+0x80030111
+
+STG_E_DOCFILETOOLARGE
+
+
+The compound file is too large for the current implementation.
+
+0x80030112
+
+STG_E_NOTSIMPLEFORMAT
+
+
+The compound file was not created with the STGM_SIMPLE flag.
+
+0x80030201
+
+STG_E_INCOMPLETE
+
+
+The file download was aborted abnormally. The file is incomplete.
+
+0x80030202
+
+STG_E_TERMINATED
+
+
+The file download has been terminated.
+
+0x80030305
+
+STG_E_STATUS_COPY_PROTECTION_FAILURE
+
+
+Generic Copy Protection Error.
+
+0x80030306
+
+STG_E_CSS_AUTHENTICATION_FAILURE
+
+
+Copy Protection Error—DVD CSS Authentication failed.
+
+0x80030307
+
+STG_E_CSS_KEY_NOT_PRESENT
+
+
+Copy Protection Error—The given sector does not have a valid CSS key.
+
+0x80030308
+
+STG_E_CSS_KEY_NOT_ESTABLISHED
+
+
+Copy Protection Error—DVD session key not established.
+
+0x80030309
+
+STG_E_CSS_SCRAMBLED_SECTOR
+
+
+Copy Protection Error—The read failed because the sector is encrypted.
+
+0x8003030A
+
+STG_E_CSS_REGION_MISMATCH
+
+
+Copy Protection Error—The current DVD's region does not correspond to the region setting of the drive.
+
+0x8003030B
+
+STG_E_RESETS_EXHAUSTED
+
+
+Copy Protection Error—The drive's region setting might be permanent or the number of user resets has been exhausted.
+
+0x80040000
+
+OLE_E_OLEVERB
+
+
+Invalid OLEVERB structure.
+
+0x80040001
+
+OLE_E_ADVF
+
+
+Invalid advise flags.
+
+0x80040002
+
+OLE_E_ENUM_NOMORE
+
+
+Cannot enumerate any more because the associated data is missing.
+
+0x80040003
+
+OLE_E_ADVISENOTSUPPORTED
+
+
+This implementation does not take advises.
+
+0x80040004
+
+OLE_E_NOCONNECTION
+
+
+There is no connection for this connection ID.
+
+0x80040005
+
+OLE_E_NOTRUNNING
+
+
+Need to run the object to perform this operation.
+
+0x80040006
+
+OLE_E_NOCACHE
+
+
+There is no cache to operate on.
+
+0x80040007
+
+OLE_E_BLANK
+
+
+Uninitialized object.
+
+0x80040008
+
+OLE_E_CLASSDIFF
+
+
+Linked object's source class has changed.
+
+0x80040009
+
+OLE_E_CANT_GETMONIKER
+
+
+Not able to get the moniker of the object.
+
+0x8004000A
+
+OLE_E_CANT_BINDTOSOURCE
+
+
+Not able to bind to the source.
+
+0x8004000B
+
+OLE_E_STATIC
+
+
+Object is static; operation not allowed.
+
+0x8004000C
+
+OLE_E_PROMPTSAVECANCELLED
+
+
+User canceled out of the Save dialog box.
+
+0x8004000D
+
+OLE_E_INVALIDRECT
+
+
+Invalid rectangle.
+
+0x8004000E
+
+OLE_E_WRONGCOMPOBJ
+
+
+compobj.dll is too old for the ole2.dll initialized.
+
+0x8004000F
+
+OLE_E_INVALIDHWND
+
+
+Invalid window handle.
+
+0x80040010
+
+OLE_E_NOT_INPLACEACTIVE
+
+
+Object is not in any of the inplace active states.
+
+0x80040011
+
+OLE_E_CANTCONVERT
+
+
+Not able to convert object.
+
+0x80040012
+
+OLE_E_NOSTORAGE
+
+
+Not able to perform the operation because object is not given storage yet.
+
+0x80040064
+
+DV_E_FORMATETC
+
+
+Invalid FORMATETC structure.
+
+0x80040065
+
+DV_E_DVTARGETDEVICE
+
+
+Invalid DVTARGETDEVICE structure.
+
+0x80040066
+
+DV_E_STGMEDIUM
+
+
+Invalid STDGMEDIUM structure.
+
+0x80040067
+
+DV_E_STATDATA
+
+
+Invalid STATDATA structure.
+
+0x80040068
+
+DV_E_LINDEX
+
+
+Invalid lindex.
+
+0x80040069
+
+DV_E_TYMED
+
+
+Invalid TYMED structure.
+
+0x8004006A
+
+DV_E_CLIPFORMAT
+
+
+Invalid clipboard format.
+
+0x8004006B
+
+DV_E_DVASPECT
+
+
+Invalid aspects.
+
+0x8004006C
+
+DV_E_DVTARGETDEVICE_SIZE
+
+
+The tdSize parameter of the DVTARGETDEVICE structure is invalid.
+
+0x8004006D
+
+DV_E_NOIVIEWOBJECT
+
+
+Object does not support IViewObject interface.
+
+0x80040100
+
+DRAGDROP_E_NOTREGISTERED
+
+
+Trying to revoke a drop target that has not been registered.
+
+0x80040101
+
+DRAGDROP_E_ALREADYREGISTERED
+
+
+This window has already been registered as a drop target.
+
+0x80040102
+
+DRAGDROP_E_INVALIDHWND
+
+
+Invalid window handle.
+
+0x80040110
+
+CLASS_E_NOAGGREGATION
+
+
+Class does not support aggregation (or class object is remote).
+
+0x80040111
+
+CLASS_E_CLASSNOTAVAILABLE
+
+
+ClassFactory cannot supply requested class.
+
+0x80040112
+
+CLASS_E_NOTLICENSED
+
+
+Class is not licensed for use.
+
+0x80040140
+
+VIEW_E_DRAW
+
+
+Error drawing view.
+
+0x80040150
+
+REGDB_E_READREGDB
+
+
+Could not read key from registry.
+
+0x80040151
+
+REGDB_E_WRITEREGDB
+
+
+Could not write key to registry.
+
+0x80040152
+
+REGDB_E_KEYMISSING
+
+
+Could not find the key in the registry.
+
+0x80040153
+
+REGDB_E_INVALIDVALUE
+
+
+Invalid value for registry.
+
+0x80040154
+
+REGDB_E_CLASSNOTREG
+
+
+Class not registered.
+
+0x80040155
+
+REGDB_E_IIDNOTREG
+
+
+Interface not registered.
+
+0x80040156
+
+REGDB_E_BADTHREADINGMODEL
+
+
+Threading model entry is not valid.
+
+0x80040160
+
+CAT_E_CATIDNOEXIST
+
+
+CATID does not exist.
+
+0x80040161
+
+CAT_E_NODESCRIPTION
+
+
+Description not found.
+
+0x80040164
+
+CS_E_PACKAGE_NOTFOUND
+
+
+No package in the software installation data in Active Directory meets this criteria.
+
+0x80040165
+
+CS_E_NOT_DELETABLE
+
+
+Deleting this will break the referential integrity of the software installation data in Active Directory.
+
+0x80040166
+
+CS_E_CLASS_NOTFOUND
+
+
+The CLSID was not found in the software installation data in Active Directory.
+
+0x80040167
+
+CS_E_INVALID_VERSION
+
+
+The software installation data in Active Directory is corrupt.
+
+0x80040168
+
+CS_E_NO_CLASSSTORE
+
+
+There is no software installation data in Active Directory.
+
+0x80040169
+
+CS_E_OBJECT_NOTFOUND
+
+
+There is no software installation data object in Active Directory.
+
+0x8004016A
+
+CS_E_OBJECT_ALREADY_EXISTS
+
+
+The software installation data object in Active Directory already exists.
+
+0x8004016B
+
+CS_E_INVALID_PATH
+
+
+The path to the software installation data in Active Directory is not correct.
+
+0x8004016C
+
+CS_E_NETWORK_ERROR
+
+
+A network error interrupted the operation.
+
+0x8004016D
+
+CS_E_ADMIN_LIMIT_EXCEEDED
+
+
+The size of this object exceeds the maximum size set by the administrator.
+
+0x8004016E
+
+CS_E_SCHEMA_MISMATCH
+
+
+The schema for the software installation data in Active Directory does not match the required schema.
+
+0x8004016F
+
+CS_E_INTERNAL_ERROR
+
+
+An error occurred in the software installation data in Active Directory.
+
+0x80040170
+
+CACHE_E_NOCACHE_UPDATED
+
+
+Cache not updated.
+
+0x80040180
+
+OLEOBJ_E_NOVERBS
+
+
+No verbs for OLE object.
+
+0x80040181
+
+OLEOBJ_E_INVALIDVERB
+
+
+Invalid verb for OLE object.
+
+0x800401A0
+
+INPLACE_E_NOTUNDOABLE
+
+
+Undo is not available.
+
+0x800401A1
+
+INPLACE_E_NOTOOLSPACE
+
+
+Space for tools is not available.
+
+0x800401C0
+
+CONVERT10_E_OLESTREAM_GET
+
+
+OLESTREAM Get method failed.
+
+0x800401C1
+
+CONVERT10_E_OLESTREAM_PUT
+
+
+OLESTREAM Put method failed.
+
+0x800401C2
+
+CONVERT10_E_OLESTREAM_FMT
+
+
+Contents of the OLESTREAM not in correct format.
+
+0x800401C3
+
+CONVERT10_E_OLESTREAM_BITMAP_TO_DIB
+
+
+There was an error in a Windows GDI call while converting the bitmap to a device-independent bitmap (DIB).
+
+0x800401C4
+
+CONVERT10_E_STG_FMT
+
+
+Contents of the IStorage not in correct format.
+
+0x800401C5
+
+CONVERT10_E_STG_NO_STD_STREAM
+
+
+Contents of IStorage is missing one of the standard streams.
+
+0x800401C6
+
+CONVERT10_E_STG_DIB_TO_BITMAP
+
+
+There was an error in a Windows Graphics Device Interface (GDI) call while converting the DIB to a bitmap.
+
+0x800401D0
+
+CLIPBRD_E_CANT_OPEN
+
+
+OpenClipboard failed.
+
+0x800401D1
+
+CLIPBRD_E_CANT_EMPTY
+
+
+EmptyClipboard failed.
+
+0x800401D2
+
+CLIPBRD_E_CANT_SET
+
+
+SetClipboard failed.
+
+0x800401D3
+
+CLIPBRD_E_BAD_DATA
+
+
+Data on clipboard is invalid.
+
+0x800401D4
+
+CLIPBRD_E_CANT_CLOSE
+
+
+CloseClipboard failed.
+
+0x800401E0
+
+MK_E_CONNECTMANUALLY
+
+
+Moniker needs to be connected manually.
+
+0x800401E1
+
+MK_E_EXCEEDEDDEADLINE
+
+
+Operation exceeded deadline.
+
+0x800401E2
+
+MK_E_NEEDGENERIC
+
+
+Moniker needs to be generic.
+
+0x800401E3
+
+MK_E_UNAVAILABLE
+
+
+Operation unavailable.
+
+0x800401E4
+
+MK_E_SYNTAX
+
+
+Invalid syntax.
+
+0x800401E5
+
+MK_E_NOOBJECT
+
+
+No object for moniker.
+
+0x800401E6
+
+MK_E_INVALIDEXTENSION
+
+
+Bad extension for file.
+
+0x800401E7
+
+MK_E_INTERMEDIATEINTERFACENOTSUPPORTED
+
+
+Intermediate operation failed.
+
+0x800401E8
+
+MK_E_NOTBINDABLE
+
+
+Moniker is not bindable.
+
+0x800401E9
+
+MK_E_NOTBOUND
+
+
+Moniker is not bound.
+
+0x800401EA
+
+MK_E_CANTOPENFILE
+
+
+Moniker cannot open file.
+
+0x800401EB
+
+MK_E_MUSTBOTHERUSER
+
+
+User input required for operation to succeed.
+
+0x800401EC
+
+MK_E_NOINVERSE
+
+
+Moniker class has no inverse.
+
+0x800401ED
+
+MK_E_NOSTORAGE
+
+
+Moniker does not refer to storage.
+
+0x800401EE
+
+MK_E_NOPREFIX
+
+
+No common prefix.
+
+0x800401EF
+
+MK_E_ENUMERATION_FAILED
+
+
+Moniker could not be enumerated.
+
+0x800401F0
+
+CO_E_NOTINITIALIZED
+
+
+CoInitialize has not been called.
+
+0x800401F1
+
+CO_E_ALREADYINITIALIZED
+
+
+CoInitialize has already been called.
+
+0x800401F2
+
+CO_E_CANTDETERMINECLASS
+
+
+Class of object cannot be determined.
+
+0x800401F3
+
+CO_E_CLASSSTRING
+
+
+Invalid class string.
+
+0x800401F4
+
+CO_E_IIDSTRING
+
+
+Invalid interface string.
+
+0x800401F5
+
+CO_E_APPNOTFOUND
+
+
+Application not found.
+
+0x800401F6
+
+CO_E_APPSINGLEUSE
+
+
+Application cannot be run more than once.
+
+0x800401F7
+
+CO_E_ERRORINAPP
+
+
+Some error in application.
+
+0x800401F8
+
+CO_E_DLLNOTFOUND
+
+
+DLL for class not found.
+
+0x800401F9
+
+CO_E_ERRORINDLL
+
+
+Error in the DLL.
+
+0x800401FA
+
+CO_E_WRONGOSFORAPP
+
+
+Wrong operating system or operating system version for application.
+
+0x800401FB
+
+CO_E_OBJNOTREG
+
+
+Object is not registered.
+
+0x800401FC
+
+CO_E_OBJISREG
+
+
+Object is already registered.
+
+0x800401FD
+
+CO_E_OBJNOTCONNECTED
+
+
+Object is not connected to server.
+
+0x800401FE
+
+CO_E_APPDIDNTREG
+
+
+Application was launched, but it did not register a class factory.
+
+0x800401FF
+
+CO_E_RELEASED
+
+
+Object has been released.
+
+0x80040201
+
+EVENT_E_ALL_SUBSCRIBERS_FAILED
+
+
+An event was unable to invoke any of the subscribers.
+
+0x80040203
+
+EVENT_E_QUERYSYNTAX
+
+
+A syntax error occurred trying to evaluate a query string.
+
+0x80040204
+
+EVENT_E_QUERYFIELD
+
+
+An invalid field name was used in a query string.
+
+0x80040205
+
+EVENT_E_INTERNALEXCEPTION
+
+
+An unexpected exception was raised.
+
+0x80040206
+
+EVENT_E_INTERNALERROR
+
+
+An unexpected internal error was detected.
+
+0x80040207
+
+EVENT_E_INVALID_PER_USER_SID
+
+
+The owner security identifier (SID) on a per-user subscription does not exist.
+
+0x80040208
+
+EVENT_E_USER_EXCEPTION
+
+
+A user-supplied component or subscriber raised an exception.
+
+0x80040209
+
+EVENT_E_TOO_MANY_METHODS
+
+
+An interface has too many methods to fire events from.
+
+0x8004020A
+
+EVENT_E_MISSING_EVENTCLASS
+
+
+A subscription cannot be stored unless its event class already exists.
+
+0x8004020B
+
+EVENT_E_NOT_ALL_REMOVED
+
+
+Not all the objects requested could be removed.
+
+0x8004020C
+
+EVENT_E_COMPLUS_NOT_INSTALLED
+
+
+COM+ is required for this operation, but it is not installed.
+
+0x8004020D
+
+EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT
+
+
+Cannot modify or delete an object that was not added using the COM+ Administrative SDK.
+
+0x8004020E
+
+EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT
+
+
+Cannot modify or delete an object that was added using the COM+ Administrative SDK.
+
+0x8004020F
+
+EVENT_E_INVALID_EVENT_CLASS_PARTITION
+
+
+The event class for this subscription is in an invalid partition.
+
+0x80040210
+
+EVENT_E_PER_USER_SID_NOT_LOGGED_ON
+
+
+The owner of the PerUser subscription is not logged on to the system specified.
+
+0x80041309
+
+SCHED_E_TRIGGER_NOT_FOUND
+
+
+Trigger not found.
+
+0x8004130A
+
+SCHED_E_TASK_NOT_READY
+
+
+One or more of the properties that are needed to run this task have not been set.
+
+0x8004130B
+
+SCHED_E_TASK_NOT_RUNNING
+
+
+There is no running instance of the task.
+
+0x8004130C
+
+SCHED_E_SERVICE_NOT_INSTALLED
+
+
+The Task Scheduler service is not installed on this computer.
+
+0x8004130D
+
+SCHED_E_CANNOT_OPEN_TASK
+
+
+The task object could not be opened.
+
+0x8004130E
+
+SCHED_E_INVALID_TASK
+
+
+The object is either an invalid task object or is not a task object.
+
+0x8004130F
+
+SCHED_E_ACCOUNT_INFORMATION_NOT_SET
+
+
+No account information could be found in the Task Scheduler security database for the task indicated.
+
+0x80041310
+
+SCHED_E_ACCOUNT_NAME_NOT_FOUND
+
+
+Unable to establish existence of the account specified.
+
+0x80041311
+
+SCHED_E_ACCOUNT_DBASE_CORRUPT
+
+
+Corruption was detected in the Task Scheduler security database; the database has been reset.
+
+0x80041312
+
+SCHED_E_NO_SECURITY_SERVICES
+
+
+Task Scheduler security services are available only on Windows NT operating system.
+
+0x80041313
+
+SCHED_E_UNKNOWN_OBJECT_VERSION
+
+
+The task object version is either unsupported or invalid.
+
+0x80041314
+
+SCHED_E_UNSUPPORTED_ACCOUNT_OPTION
+
+
+The task has been configured with an unsupported combination of account settings and run-time options.
+
+0x80041315
+
+SCHED_E_SERVICE_NOT_RUNNING
+
+
+The Task Scheduler service is not running.
+
+0x80041316
+
+SCHED_E_UNEXPECTEDNODE
+
+
+The task XML contains an unexpected node.
+
+0x80041317
+
+SCHED_E_NAMESPACE
+
+
+The task XML contains an element or attribute from an unexpected namespace.
+
+0x80041318
+
+SCHED_E_INVALIDVALUE
+
+
+The task XML contains a value that is incorrectly formatted or out of range.
+
+0x80041319
+
+SCHED_E_MISSINGNODE
+
+
+The task XML is missing a required element or attribute.
+
+0x8004131A
+
+SCHED_E_MALFORMEDXML
+
+
+The task XML is malformed.
+
+0x8004131D
+
+SCHED_E_TOO_MANY_NODES
+
+
+The task XML contains too many nodes of the same type.
+
+0x8004131E
+
+SCHED_E_PAST_END_BOUNDARY
+
+
+The task cannot be started after the trigger's end boundary.
+
+0x8004131F
+
+SCHED_E_ALREADY_RUNNING
+
+
+An instance of this task is already running.
+
+0x80041320
+
+SCHED_E_USER_NOT_LOGGED_ON
+
+
+The task will not run because the user is not logged on.
+
+0x80041321
+
+SCHED_E_INVALID_TASK_HASH
+
+
+The task image is corrupt or has been tampered with.
+
+0x80041322
+
+SCHED_E_SERVICE_NOT_AVAILABLE
+
+
+The Task Scheduler service is not available.
+
+0x80041323
+
+SCHED_E_SERVICE_TOO_BUSY
+
+
+The Task Scheduler service is too busy to handle your request. Try again later.
+
+0x80041324
+
+SCHED_E_TASK_ATTEMPTED
+
+
+The Task Scheduler service attempted to run the task, but the task did not run due to one of the constraints in the task definition.
+
+0x8004D000
+
+XACT_E_ALREADYOTHERSINGLEPHASE
+
+
+Another single phase resource manager has already been enlisted in this transaction.
+
+0x8004D001
+
+XACT_E_CANTRETAIN
+
+
+A retaining commit or abort is not supported.
+
+0x8004D002
+
+XACT_E_COMMITFAILED
+
+
+The transaction failed to commit for an unknown reason. The transaction was aborted.
+
+0x8004D003
+
+XACT_E_COMMITPREVENTED
+
+
+Cannot call commit on this transaction object because the calling application did not initiate the transaction.
+
+0x8004D004
+
+XACT_E_HEURISTICABORT
+
+
+Instead of committing, the resource heuristically aborted.
+
+0x8004D005
+
+XACT_E_HEURISTICCOMMIT
+
+
+Instead of aborting, the resource heuristically committed.
+
+0x8004D006
+
+XACT_E_HEURISTICDAMAGE
+
+
+Some of the states of the resource were committed while others were aborted, likely because of heuristic decisions.
+
+0x8004D007
+
+XACT_E_HEURISTICDANGER
+
+
+Some of the states of the resource might have been committed while others were aborted, likely because of heuristic decisions.
+
+0x8004D008
+
+XACT_E_ISOLATIONLEVEL
+
+
+The requested isolation level is not valid or supported.
+
+0x8004D009
+
+XACT_E_NOASYNC
+
+
+The transaction manager does not support an asynchronous operation for this method.
+
+0x8004D00A
+
+XACT_E_NOENLIST
+
+
+Unable to enlist in the transaction.
+
+0x8004D00B
+
+XACT_E_NOISORETAIN
+
+
+The requested semantics of retention of isolation across retaining commit and abort boundaries cannot be supported by this transaction implementation, or isoFlags was not equal to 0.
+
+0x8004D00C
+
+XACT_E_NORESOURCE
+
+
+There is no resource presently associated with this enlistment.
+
+0x8004D00D
+
+XACT_E_NOTCURRENT
+
+
+The transaction failed to commit due to the failure of optimistic concurrency control in at least one of the resource managers.
+
+0x8004D00E
+
+XACT_E_NOTRANSACTION
+
+
+The transaction has already been implicitly or explicitly committed or aborted.
+
+0x8004D00F
+
+XACT_E_NOTSUPPORTED
+
+
+An invalid combination of flags was specified.
+
+0x8004D010
+
+XACT_E_UNKNOWNRMGRID
+
+
+The resource manager ID is not associated with this transaction or the transaction manager.
+
+0x8004D011
+
+XACT_E_WRONGSTATE
+
+
+This method was called in the wrong state.
+
+0x8004D012
+
+XACT_E_WRONGUOW
+
+
+The indicated unit of work does not match the unit of work expected by the resource manager.
+
+0x8004D013
+
+XACT_E_XTIONEXISTS
+
+
+An enlistment in a transaction already exists.
+
+0x8004D014
+
+XACT_E_NOIMPORTOBJECT
+
+
+An import object for the transaction could not be found.
+
+0x8004D015
+
+XACT_E_INVALIDCOOKIE
+
+
+The transaction cookie is invalid.
+
+0x8004D016
+
+XACT_E_INDOUBT
+
+
+The transaction status is in doubt. A communication failure occurred, or a transaction manager or resource manager has failed.
+
+0x8004D017
+
+XACT_E_NOTIMEOUT
+
+
+A time-out was specified, but time-outs are not supported.
+
+0x8004D018
+
+XACT_E_ALREADYINPROGRESS
+
+
+The requested operation is already in progress for the transaction.
+
+0x8004D019
+
+XACT_E_ABORTED
+
+
+The transaction has already been aborted.
+
+0x8004D01A
+
+XACT_E_LOGFULL
+
+
+The Transaction Manager returned a log full error.
+
+0x8004D01B
+
+XACT_E_TMNOTAVAILABLE
+
+
+The transaction manager is not available.
+
+0x8004D01C
+
+XACT_E_CONNECTION_DOWN
+
+
+A connection with the transaction manager was lost.
+
+0x8004D01D
+
+XACT_E_CONNECTION_DENIED
+
+
+A request to establish a connection with the transaction manager was denied.
+
+0x8004D01E
+
+XACT_E_REENLISTTIMEOUT
+
+
+Resource manager reenlistment to determine transaction status timed out.
+
+0x8004D01F
+
+XACT_E_TIP_CONNECT_FAILED
+
+
+The transaction manager failed to establish a connection with another Transaction Internet Protocol (TIP) transaction manager.
+
+0x8004D020
+
+XACT_E_TIP_PROTOCOL_ERROR
+
+
+The transaction manager encountered a protocol error with another TIP transaction manager.
+
+0x8004D021
+
+XACT_E_TIP_PULL_FAILED
+
+
+The transaction manager could not propagate a transaction from another TIP transaction manager.
+
+0x8004D022
+
+XACT_E_DEST_TMNOTAVAILABLE
+
+
+The transaction manager on the destination machine is not available.
+
+0x8004D023
+
+XACT_E_TIP_DISABLED
+
+
+The transaction manager has disabled its support for TIP.
+
+0x8004D024
+
+XACT_E_NETWORK_TX_DISABLED
+
+
+The transaction manager has disabled its support for remote or network transactions.
+
+0x8004D025
+
+XACT_E_PARTNER_NETWORK_TX_DISABLED
+
+
+The partner transaction manager has disabled its support for remote or network transactions.
+
+0x8004D026
+
+XACT_E_XA_TX_DISABLED
+
+
+The transaction manager has disabled its support for XA transactions.
+
+0x8004D027
+
+XACT_E_UNABLE_TO_READ_DTC_CONFIG
+
+
+Microsoft Distributed Transaction Coordinator (MSDTC) was unable to read its configuration information.
+
+0x8004D028
+
+XACT_E_UNABLE_TO_LOAD_DTC_PROXY
+
+
+MSDTC was unable to load the DTC proxy DLL.
+
+0x8004D029
+
+XACT_E_ABORTING
+
+
+The local transaction has aborted.
+
+0x8004D080
+
+XACT_E_CLERKNOTFOUND
+
+
+The specified CRM clerk was not found. It might have completed before it could be held.
+
+0x8004D081
+
+XACT_E_CLERKEXISTS
+
+
+The specified CRM clerk does not exist.
+
+0x8004D082
+
+XACT_E_RECOVERYINPROGRESS
+
+
+Recovery of the CRM log file is still in progress.
+
+0x8004D083
+
+XACT_E_TRANSACTIONCLOSED
+
+
+The transaction has completed, and the log records have been discarded from the log file. They are no longer available.
+
+0x8004D084
+
+XACT_E_INVALIDLSN
+
+
+lsnToRead is outside of the current limits of the log
+
+0x8004D085
+
+XACT_E_REPLAYREQUEST
+
+
+The COM+ Compensating Resource Manager has records it wishes to replay.
+
+0x8004D100
+
+XACT_E_CONNECTION_REQUEST_DENIED
+
+
+The request to connect to the specified transaction coordinator was denied.
+
+0x8004D101
+
+XACT_E_TOOMANY_ENLISTMENTS
+
+
+The maximum number of enlistments for the specified transaction has been reached.
+
+0x8004D102
+
+XACT_E_DUPLICATE_GUID
+
+
+A resource manager with the same identifier is already registered with the specified transaction coordinator.
+
+0x8004D103
+
+XACT_E_NOTSINGLEPHASE
+
+
+The prepare request given was not eligible for single-phase optimizations.
+
+0x8004D104
+
+XACT_E_RECOVERYALREADYDONE
+
+
+RecoveryComplete has already been called for the given resource manager.
+
+0x8004D105
+
+XACT_E_PROTOCOL
+
+
+The interface call made was incorrect for the current state of the protocol.
+
+0x8004D106
+
+XACT_E_RM_FAILURE
+
+
+The xa_open call failed for the XA resource.
+
+0x8004D107
+
+XACT_E_RECOVERY_FAILED
+
+
+The xa_recover call failed for the XA resource.
+
+0x8004D108
+
+XACT_E_LU_NOT_FOUND
+
+
+The logical unit of work specified cannot be found.
+
+0x8004D109
+
+XACT_E_DUPLICATE_LU
+
+
+The specified logical unit of work already exists.
+
+0x8004D10A
+
+XACT_E_LU_NOT_CONNECTED
+
+
+Subordinate creation failed. The specified logical unit of work was not connected.
+
+0x8004D10B
+
+XACT_E_DUPLICATE_TRANSID
+
+
+A transaction with the given identifier already exists.
+
+0x8004D10C
+
+XACT_E_LU_BUSY
+
+
+The resource is in use.
+
+0x8004D10D
+
+XACT_E_LU_NO_RECOVERY_PROCESS
+
+
+The LU Recovery process is down.
+
+0x8004D10E
+
+XACT_E_LU_DOWN
+
+
+The remote session was lost.
+
+0x8004D10F
+
+XACT_E_LU_RECOVERING
+
+
+The resource is currently recovering.
+
+0x8004D110
+
+XACT_E_LU_RECOVERY_MISMATCH
+
+
+There was a mismatch in driving recovery.
+
+0x8004D111
+
+XACT_E_RM_UNAVAILABLE
+
+
+An error occurred with the XA resource.
+
+0x8004E002
+
+CONTEXT_E_ABORTED
+
+
+The root transaction wanted to commit, but the transaction aborted.
+
+0x8004E003
+
+CONTEXT_E_ABORTING
+
+
+The COM+ component on which the method call was made has a transaction that has already aborted or is in the process of aborting.
+
+0x8004E004
+
+CONTEXT_E_NOCONTEXT
+
+
+There is no Microsoft Transaction Server (MTS) object context.
+
+0x8004E005
+
+CONTEXT_E_WOULD_DEADLOCK
+
+
+The component is configured to use synchronization, and this method call would cause a deadlock to occur.
+
+0x8004E006
+
+CONTEXT_E_SYNCH_TIMEOUT
+
+
+The component is configured to use synchronization, and a thread has timed out waiting to enter the context.
+
+0x8004E007
+
+CONTEXT_E_OLDREF
+
+
+You made a method call on a COM+ component that has a transaction that has already committed or aborted.
+
+0x8004E00C
+
+CONTEXT_E_ROLENOTFOUND
+
+
+The specified role was not configured for the application.
+
+0x8004E00F
+
+CONTEXT_E_TMNOTAVAILABLE
+
+
+COM+ was unable to talk to the MSDTC.
+
+0x8004E021
+
+CO_E_ACTIVATIONFAILED
+
+
+An unexpected error occurred during COM+ activation.
+
+0x8004E022
+
+CO_E_ACTIVATIONFAILED_EVENTLOGGED
+
+
+COM+ activation failed. Check the event log for more information.
+
+0x8004E023
+
+CO_E_ACTIVATIONFAILED_CATALOGERROR
+
+
+COM+ activation failed due to a catalog or configuration error.
+
+0x8004E024
+
+CO_E_ACTIVATIONFAILED_TIMEOUT
+
+
+COM+ activation failed because the activation could not be completed in the specified amount of time.
+
+0x8004E025
+
+CO_E_INITIALIZATIONFAILED
+
+
+COM+ activation failed because an initialization function failed. Check the event log for more information.
+
+0x8004E026
+
+CONTEXT_E_NOJIT
+
+
+The requested operation requires that just-in-time (JIT) be in the current context, and it is not.
+
+0x8004E027
+
+CONTEXT_E_NOTRANSACTION
+
+
+The requested operation requires that the current context have a transaction, and it does not.
+
+0x8004E028
+
+CO_E_THREADINGMODEL_CHANGED
+
+
+The components threading model has changed after install into a COM+ application. Re-install component.
+
+0x8004E029
+
+CO_E_NOIISINTRINSICS
+
+
+Internet Information Services (IIS) intrinsics not available. Start your work with IIS.
+
+0x8004E02A
+
+CO_E_NOCOOKIES
+
+
+An attempt to write a cookie failed.
+
+0x8004E02B
+
+CO_E_DBERROR
+
+
+An attempt to use a database generated a database-specific error.
+
+0x8004E02C
+
+CO_E_NOTPOOLED
+
+
+The COM+ component you created must use object pooling to work.
+
+0x8004E02D
+
+CO_E_NOTCONSTRUCTED
+
+
+The COM+ component you created must use object construction to work correctly.
+
+0x8004E02E
+
+CO_E_NOSYNCHRONIZATION
+
+
+The COM+ component requires synchronization, and it is not configured for it.
+
+0x8004E02F
+
+CO_E_ISOLEVELMISMATCH
+
+
+The TxIsolation Level property for the COM+ component being created is stronger than the TxIsolationLevel for the root.
+
+0x8004E030
+
+CO_E_CALL_OUT_OF_TX_SCOPE_NOT_ALLOWED
+
+
+The component attempted to make a cross-context call between invocations of EnterTransactionScope and ExitTransactionScope. This is not allowed. Cross-context calls cannot be made while inside a transaction scope.
+
+0x8004E031
+
+CO_E_EXIT_TRANSACTION_SCOPE_NOT_CALLED
+
+
+The component made a call to EnterTransactionScope, but did not make a corresponding call to ExitTransactionScope before returning.
+
+0x80070005
+
+E_ACCESSDENIED
+
+
+General access denied error.
+
+0x8007000E
+
+E_OUTOFMEMORY
+
+
+The server does not have enough memory for the new channel.
+
+0x80070032
+
+ERROR_NOT_SUPPORTED
+
+
+The server cannot support a client request for a dynamic virtual channel.
+
+0x80070057
+
+E_INVALIDARG
+
+
+One or more arguments are invalid.
+
+0x80070070
+
+ERROR_DISK_FULL
+
+
+There is not enough space on the disk.
+
+0x80080001
+
+CO_E_CLASS_CREATE_FAILED
+
+
+Attempt to create a class object failed.
+
+0x80080002
+
+CO_E_SCM_ERROR
+
+
+OLE service could not bind object.
+
+0x80080003
+
+CO_E_SCM_RPC_FAILURE
+
+
+RPC communication failed with OLE service.
+
+0x80080004
+
+CO_E_BAD_PATH
+
+
+Bad path to object.
+
+0x80080005
+
+CO_E_SERVER_EXEC_FAILURE
+
+
+Server execution failed.
+
+0x80080006
+
+CO_E_OBJSRV_RPC_FAILURE
+
+
+OLE service could not communicate with the object server.
+
+0x80080007
+
+MK_E_NO_NORMALIZED
+
+
+Moniker path could not be normalized.
+
+0x80080008
+
+CO_E_SERVER_STOPPING
+
+
+Object server is stopping when OLE service contacts it.
+
+0x80080009
+
+MEM_E_INVALID_ROOT
+
+
+An invalid root block pointer was specified.
+
+0x80080010
+
+MEM_E_INVALID_LINK
+
+
+An allocation chain contained an invalid link pointer.
+
+0x80080011
+
+MEM_E_INVALID_SIZE
+
+
+The requested allocation size was too large.
+
+0x80080015
+
+CO_E_MISSING_DISPLAYNAME
+
+
+The activation requires a display name to be present under the class identifier (CLSID) key.
+
+0x80080016
+
+CO_E_RUNAS_VALUE_MUST_BE_AAA
+
+
+The activation requires that the RunAs value for the application is Activate As Activator.
+
+0x80080017
+
+CO_E_ELEVATION_DISABLED
+
+
+The class is not configured to support elevated activation.
+
+0x80090001
+
+NTE_BAD_UID
+
+
+Bad UID.
+
+0x80090002
+
+NTE_BAD_HASH
+
+
+Bad hash.
+
+0x80090003
+
+NTE_BAD_KEY
+
+
+Bad key.
+
+0x80090004
+
+NTE_BAD_LEN
+
+
+Bad length.
+
+0x80090005
+
+NTE_BAD_DATA
+
+
+Bad data.
+
+0x80090006
+
+NTE_BAD_SIGNATURE
+
+
+Invalid signature.
+
+0x80090007
+
+NTE_BAD_VER
+
+
+Bad version of provider.
+
+0x80090008
+
+NTE_BAD_ALGID
+
+
+Invalid algorithm specified.
+
+0x80090009
+
+NTE_BAD_FLAGS
+
+
+Invalid flags specified.
+
+0x8009000A
+
+NTE_BAD_TYPE
+
+
+Invalid type specified.
+
+0x8009000B
+
+NTE_BAD_KEY_STATE
+
+
+Key not valid for use in specified state.
+
+0x8009000C
+
+NTE_BAD_HASH_STATE
+
+
+Hash not valid for use in specified state.
+
+0x8009000D
+
+NTE_NO_KEY
+
+
+Key does not exist.
+
+0x8009000E
+
+NTE_NO_MEMORY
+
+
+Insufficient memory available for the operation.
+
+0x8009000F
+
+NTE_EXISTS
+
+
+Object already exists.
+
+0x80090010
+
+NTE_PERM
+
+
+Access denied.
+
+0x80090011
+
+NTE_NOT_FOUND
+
+
+Object was not found.
+
+0x80090012
+
+NTE_DOUBLE_ENCRYPT
+
+
+Data already encrypted.
+
+0x80090013
+
+NTE_BAD_PROVIDER
+
+
+Invalid provider specified.
+
+0x80090014
+
+NTE_BAD_PROV_TYPE
+
+
+Invalid provider type specified.
+
+0x80090015
+
+NTE_BAD_PUBLIC_KEY
+
+
+Provider's public key is invalid.
+
+0x80090016
+
+NTE_BAD_KEYSET
+
+
+Key set does not exist.
+
+0x80090017
+
+NTE_PROV_TYPE_NOT_DEF
+
+
+Provider type not defined.
+
+0x80090018
+
+NTE_PROV_TYPE_ENTRY_BAD
+
+
+The provider type, as registered, is invalid.
+
+0x80090019
+
+NTE_KEYSET_NOT_DEF
+
+
+The key set is not defined.
+
+0x8009001A
+
+NTE_KEYSET_ENTRY_BAD
+
+
+The key set, as registered, is invalid.
+
+0x8009001B
+
+NTE_PROV_TYPE_NO_MATCH
+
+
+Provider type does not match registered value.
+
+0x8009001C
+
+NTE_SIGNATURE_FILE_BAD
+
+
+The digital signature file is corrupt.
+
+0x8009001D
+
+NTE_PROVIDER_DLL_FAIL
+
+
+Provider DLL failed to initialize correctly.
+
+0x8009001E
+
+NTE_PROV_DLL_NOT_FOUND
+
+
+Provider DLL could not be found.
+
+0x8009001F
+
+NTE_BAD_KEYSET_PARAM
+
+
+The keyset parameter is invalid.
+
+0x80090020
+
+NTE_FAIL
+
+
+An internal error occurred.
+
+0x80090021
+
+NTE_SYS_ERR
+
+
+A base error occurred.
+
+0x80090022
+
+NTE_SILENT_CONTEXT
+
+
+Provider could not perform the action because the context was acquired as silent.
+
+0x80090023
+
+NTE_TOKEN_KEYSET_STORAGE_FULL
+
+
+The security token does not have storage space available for an additional container.
+
+0x80090024
+
+NTE_TEMPORARY_PROFILE
+
+
+The profile for the user is a temporary profile.
+
+0x80090025
+
+NTE_FIXEDPARAMETER
+
+
+The key parameters could not be set because the configuration service provider (CSP) uses fixed parameters.
+
+0x80090026
+
+NTE_INVALID_HANDLE
+
+
+The supplied handle is invalid.
+
+0x80090027
+
+NTE_INVALID_PARAMETER
+
+
+The parameter is incorrect.
+
+0x80090028
+
+NTE_BUFFER_TOO_SMALL
+
+
+The buffer supplied to a function was too small.
+
+0x80090029
+
+NTE_NOT_SUPPORTED
+
+
+The requested operation is not supported.
+
+0x8009002A
+
+NTE_NO_MORE_ITEMS
+
+
+No more data is available.
+
+0x8009002B
+
+NTE_BUFFERS_OVERLAP
+
+
+The supplied buffers overlap incorrectly.
+
+0x8009002C
+
+NTE_DECRYPTION_FAILURE
+
+
+The specified data could not be decrypted.
+
+0x8009002D
+
+NTE_INTERNAL_ERROR
+
+
+An internal consistency check failed.
+
+0x8009002E
+
+NTE_UI_REQUIRED
+
+
+This operation requires input from the user.
+
+0x8009002F
+
+NTE_HMAC_NOT_SUPPORTED
+
+
+The cryptographic provider does not support Hash Message Authentication Code (HMAC).
+
+0x80090300
+
+SEC_E_INSUFFICIENT_MEMORY
+
+
+Not enough memory is available to complete this request.
+
+0x80090301
+
+SEC_E_INVALID_HANDLE
+
+
+The handle specified is invalid.
+
+0x80090302
+
+SEC_E_UNSUPPORTED_FUNCTION
+
+
+The function requested is not supported.
+
+0x80090303
+
+SEC_E_TARGET_UNKNOWN
+
+
+The specified target is unknown or unreachable.
+
+0x80090304
+
+SEC_E_INTERNAL_ERROR
+
+
+The Local Security Authority (LSA) cannot be contacted.
+
+0x80090305
+
+SEC_E_SECPKG_NOT_FOUND
+
+
+The requested security package does not exist.
+
+0x80090306
+
+SEC_E_NOT_OWNER
+
+
+The caller is not the owner of the desired credentials.
+
+0x80090307
+
+SEC_E_CANNOT_INSTALL
+
+
+The security package failed to initialize and cannot be installed.
+
+0x80090308
+
+SEC_E_INVALID_TOKEN
+
+
+The token supplied to the function is invalid.
+
+0x80090309
+
+SEC_E_CANNOT_PACK
+
+
+The security package is not able to marshal the logon buffer, so the logon attempt has failed.
+
+0x8009030A
+
+SEC_E_QOP_NOT_SUPPORTED
+
+
+The per-message quality of protection is not supported by the security package.
+
+0x8009030B
+
+SEC_E_NO_IMPERSONATION
+
+
+The security context does not allow impersonation of the client.
+
+0x8009030C
+
+SEC_E_LOGON_DENIED
+
+
+The logon attempt failed.
+
+0x8009030D
+
+SEC_E_UNKNOWN_CREDENTIALS
+
+
+The credentials supplied to the package were not recognized.
+
+0x8009030E
+
+SEC_E_NO_CREDENTIALS
+
+
+No credentials are available in the security package.
+
+0x8009030F
+
+SEC_E_MESSAGE_ALTERED
+
+
+The message or signature supplied for verification has been altered.
+
+0x80090310
+
+SEC_E_OUT_OF_SEQUENCE
+
+
+The message supplied for verification is out of sequence.
+
+0x80090311
+
+SEC_E_NO_AUTHENTICATING_AUTHORITY
+
+
+No authority could be contacted for authentication.
+
+0x80090316
+
+SEC_E_BAD_PKGID
+
+
+The requested security package does not exist.
+
+0x80090317
+
+SEC_E_CONTEXT_EXPIRED
+
+
+The context has expired and can no longer be used.
+
+0x80090318
+
+SEC_E_INCOMPLETE_MESSAGE
+
+
+The supplied message is incomplete. The signature was not verified.
+
+0x80090320
+
+SEC_E_INCOMPLETE_CREDENTIALS
+
+
+The credentials supplied were not complete and could not be verified. The context could not be initialized.
+
+0x80090321
+
+SEC_E_BUFFER_TOO_SMALL
+
+
+The buffers supplied to a function was too small.
+
+0x80090322
+
+SEC_E_WRONG_PRINCIPAL
+
+
+The target principal name is incorrect.
+
+0x80090324
+
+SEC_E_TIME_SKEW
+
+
+The clocks on the client and server machines are skewed.
+
+0x80090325
+
+SEC_E_UNTRUSTED_ROOT
+
+
+The certificate chain was issued by an authority that is not trusted.
+
+0x80090326
+
+SEC_E_ILLEGAL_MESSAGE
+
+
+The message received was unexpected or badly formatted.
+
+0x80090327
+
+SEC_E_CERT_UNKNOWN
+
+
+An unknown error occurred while processing the certificate.
+
+0x80090328
+
+SEC_E_CERT_EXPIRED
+
+
+The received certificate has expired.
+
+0x80090329
+
+SEC_E_ENCRYPT_FAILURE
+
+
+The specified data could not be encrypted.
+
+0x80090330
+
+SEC_E_DECRYPT_FAILURE
+
+
+The specified data could not be decrypted.
+
+0x80090331
+
+SEC_E_ALGORITHM_MISMATCH
+
+
+The client and server cannot communicate because they do not possess a common algorithm.
+
+0x80090332
+
+SEC_E_SECURITY_QOS_FAILED
+
+
+The security context could not be established due to a failure in the requested quality of service (for example, mutual authentication or delegation).
+
+0x80090333
+
+SEC_E_UNFINISHED_CONTEXT_DELETED
+
+
+A security context was deleted before the context was completed. This is considered a logon failure.
+
+0x80090334
+
+SEC_E_NO_TGT_REPLY
+
+
+The client is trying to negotiate a context and the server requires user-to-user but did not send a ticket granting ticket (TGT) reply.
+
+0x80090335
+
+SEC_E_NO_IP_ADDRESSES
+
+
+Unable to accomplish the requested task because the local machine does not have an IP addresses.
+
+0x80090336
+
+SEC_E_WRONG_CREDENTIAL_HANDLE
+
+
+The supplied credential handle does not match the credential associated with the security context.
+
+0x80090337
+
+SEC_E_CRYPTO_SYSTEM_INVALID
+
+
+The cryptographic system or checksum function is invalid because a required function is unavailable.
+
+0x80090338
+
+SEC_E_MAX_REFERRALS_EXCEEDED
+
+
+The number of maximum ticket referrals has been exceeded.
+
+0x80090339
+
+SEC_E_MUST_BE_KDC
+
+
+The local machine must be a Kerberos domain controller (KDC), and it is not.
+
+0x8009033A
+
+SEC_E_STRONG_CRYPTO_NOT_SUPPORTED
+
+
+The other end of the security negotiation requires strong cryptographics, but it is not supported on the local machine.
+
+0x8009033B
+
+SEC_E_TOO_MANY_PRINCIPALS
+
+
+The KDC reply contained more than one principal name.
+
+0x8009033C
+
+SEC_E_NO_PA_DATA
+
+
+Expected to find PA data for a hint of what etype to use, but it was not found.
+
+0x8009033D
+
+SEC_E_PKINIT_NAME_MISMATCH
+
+
+The client certificate does not contain a valid user principal name (UPN), or does not match the client name in the logon request. Contact your administrator.
+
+0x8009033E
+
+SEC_E_SMARTCARD_LOGON_REQUIRED
+
+
+Smart card logon is required and was not used.
+
+0x8009033F
+
+SEC_E_SHUTDOWN_IN_PROGRESS
+
+
+A system shutdown is in progress.
+
+0x80090340
+
+SEC_E_KDC_INVALID_REQUEST
+
+
+An invalid request was sent to the KDC.
+
+0x80090341
+
+SEC_E_KDC_UNABLE_TO_REFER
+
+
+The KDC was unable to generate a referral for the service requested.
+
+0x80090342
+
+SEC_E_KDC_UNKNOWN_ETYPE
+
+
+The encryption type requested is not supported by the KDC.
+
+0x80090343
+
+SEC_E_UNSUPPORTED_PREAUTH
+
+
+An unsupported pre-authentication mechanism was presented to the Kerberos package.
+
+0x80090345
+
+SEC_E_DELEGATION_REQUIRED
+
+
+The requested operation cannot be completed. The computer must be trusted for delegation, and the current user account must be configured to allow delegation.
+
+0x80090346
+
+SEC_E_BAD_BINDINGS
+
+
+Client's supplied Security Support Provider Interface (SSPI) channel bindings were incorrect.
+
+0x80090347
+
+SEC_E_MULTIPLE_ACCOUNTS
+
+
+The received certificate was mapped to multiple accounts.
+
+0x80090348
+
+SEC_E_NO_KERB_KEY
+
+
+No Kerberos key was found.
+
+0x80090349
+
+SEC_E_CERT_WRONG_USAGE
+
+
+The certificate is not valid for the requested usage.
+
+0x80090350
+
+SEC_E_DOWNGRADE_DETECTED
+
+
+The system detected a possible attempt to compromise security. Ensure that you can contact the server that authenticated you.
+
+0x80090351
+
+SEC_E_SMARTCARD_CERT_REVOKED
+
+
+The smart card certificate used for authentication has been revoked. Contact your system administrator. The event log might contain additional information.
+
+0x80090352
+
+SEC_E_ISSUING_CA_UNTRUSTED
+
+
+An untrusted certification authority (CA) was detected while processing the smart card certificate used for authentication. Contact your system administrator.
+
+0x80090353
+
+SEC_E_REVOCATION_OFFLINE_C
+
+
+The revocation status of the smart card certificate used for authentication could not be determined. Contact your system administrator.
+
+0x80090354
+
+SEC_E_PKINIT_CLIENT_FAILURE
+
+
+The smart card certificate used for authentication was not trusted. Contact your system administrator.
+
+0x80090355
+
+SEC_E_SMARTCARD_CERT_EXPIRED
+
+
+The smart card certificate used for authentication has expired. Contact your system administrator.
+
+0x80090356
+
+SEC_E_NO_S4U_PROT_SUPPORT
+
+
+The Kerberos subsystem encountered an error. A service for user protocol requests was made against a domain controller that does not support services for users.
+
+0x80090357
+
+SEC_E_CROSSREALM_DELEGATION_FAILURE
+
+
+An attempt was made by this server to make a Kerberos-constrained delegation request for a target outside the server's realm. This is not supported and indicates a misconfiguration on this server's allowed-to-delegate-to list. Contact your administrator.
+
+0x80090358
+
+SEC_E_REVOCATION_OFFLINE_KDC
+
+
+The revocation status of the domain controller certificate used for smart card authentication could not be determined. The system event log contains additional information. Contact your system administrator.
+
+0x80090359
+
+SEC_E_ISSUING_CA_UNTRUSTED_KDC
+
+
+An untrusted CA was detected while processing the domain controller certificate used for authentication. The system event log contains additional information. Contact your system administrator.
+
+0x8009035A
+
+SEC_E_KDC_CERT_EXPIRED
+
+
+The domain controller certificate used for smart card logon has expired. Contact your system administrator with the contents of your system event log.
+
+0x8009035B
+
+SEC_E_KDC_CERT_REVOKED
+
+
+The domain controller certificate used for smart card logon has been revoked. Contact your system administrator with the contents of your system event log.
+
+0x8009035D
+
+SEC_E_INVALID_PARAMETER
+
+
+One or more of the parameters passed to the function were invalid.
+
+0x8009035E
+
+SEC_E_DELEGATION_POLICY
+
+
+The client policy does not allow credential delegation to the target server.
+
+0x8009035F
+
+SEC_E_POLICY_NLTM_ONLY
+
+
+The client policy does not allow credential delegation to the target server with NLTM only authentication.
+
+0x80091001
+
+CRYPT_E_MSG_ERROR
+
+
+An error occurred while performing an operation on a cryptographic message.
+
+0x80091002
+
+CRYPT_E_UNKNOWN_ALGO
+
+
+Unknown cryptographic algorithm.
+
+0x80091003
+
+CRYPT_E_OID_FORMAT
+
+
+The object identifier is poorly formatted.
+
+0x80091004
+
+CRYPT_E_INVALID_MSG_TYPE
+
+
+Invalid cryptographic message type.
+
+0x80091005
+
+CRYPT_E_UNEXPECTED_ENCODING
+
+
+Unexpected cryptographic message encoding.
+
+0x80091006
+
+CRYPT_E_AUTH_ATTR_MISSING
+
+
+The cryptographic message does not contain an expected authenticated attribute.
+
+0x80091007
+
+CRYPT_E_HASH_VALUE
+
+
+The hash value is not correct.
+
+0x80091008
+
+CRYPT_E_INVALID_INDEX
+
+
+The index value is not valid.
+
+0x80091009
+
+CRYPT_E_ALREADY_DECRYPTED
+
+
+The content of the cryptographic message has already been decrypted.
+
+0x8009100A
+
+CRYPT_E_NOT_DECRYPTED
+
+
+The content of the cryptographic message has not been decrypted yet.
+
+0x8009100B
+
+CRYPT_E_RECIPIENT_NOT_FOUND
+
+
+The enveloped-data message does not contain the specified recipient.
+
+0x8009100C
+
+CRYPT_E_CONTROL_TYPE
+
+
+Invalid control type.
+
+0x8009100D
+
+CRYPT_E_ISSUER_SERIALNUMBER
+
+
+Invalid issuer or serial number.
+
+0x8009100E
+
+CRYPT_E_SIGNER_NOT_FOUND
+
+
+Cannot find the original signer.
+
+0x8009100F
+
+CRYPT_E_ATTRIBUTES_MISSING
+
+
+The cryptographic message does not contain all of the requested attributes.
+
+0x80091010
+
+CRYPT_E_STREAM_MSG_NOT_READY
+
+
+The streamed cryptographic message is not ready to return data.
+
+0x80091011
+
+CRYPT_E_STREAM_INSUFFICIENT_DATA
+
+
+The streamed cryptographic message requires more data to complete the decode operation.
+
+0x80092001
+
+CRYPT_E_BAD_LEN
+
+
+The length specified for the output data was insufficient.
+
+0x80092002
+
+CRYPT_E_BAD_ENCODE
+
+
+An error occurred during the encode or decode operation.
+
+0x80092003
+
+CRYPT_E_FILE_ERROR
+
+
+An error occurred while reading or writing to a file.
+
+0x80092004
+
+CRYPT_E_NOT_FOUND
+
+
+Cannot find object or property.
+
+0x80092005
+
+CRYPT_E_EXISTS
+
+
+The object or property already exists.
+
+0x80092006
+
+CRYPT_E_NO_PROVIDER
+
+
+No provider was specified for the store or object.
+
+0x80092007
+
+CRYPT_E_SELF_SIGNED
+
+
+The specified certificate is self-signed.
+
+0x80092008
+
+CRYPT_E_DELETED_PREV
+
+
+The previous certificate or certificate revocation list (CRL) context was deleted.
+
+0x80092009
+
+CRYPT_E_NO_MATCH
+
+
+Cannot find the requested object.
+
+0x8009200A
+
+CRYPT_E_UNEXPECTED_MSG_TYPE
+
+
+The certificate does not have a property that references a private key.
+
+0x8009200B
+
+CRYPT_E_NO_KEY_PROPERTY
+
+
+Cannot find the certificate and private key for decryption.
+
+0x8009200C
+
+CRYPT_E_NO_DECRYPT_CERT
+
+
+Cannot find the certificate and private key to use for decryption.
+
+0x8009200D
+
+CRYPT_E_BAD_MSG
+
+
+Not a cryptographic message or the cryptographic message is not formatted correctly.
+
+0x8009200E
+
+CRYPT_E_NO_SIGNER
+
+
+The signed cryptographic message does not have a signer for the specified signer index.
+
+0x8009200F
+
+CRYPT_E_PENDING_CLOSE
+
+
+Final closure is pending until additional frees or closes.
+
+0x80092010
+
+CRYPT_E_REVOKED
+
+
+The certificate is revoked.
+
+0x80092011
+
+CRYPT_E_NO_REVOCATION_DLL
+
+
+No DLL or exported function was found to verify revocation.
+
+0x80092012
+
+CRYPT_E_NO_REVOCATION_CHECK
+
+
+The revocation function was unable to check revocation for the certificate.
+
+0x80092013
+
+CRYPT_E_REVOCATION_OFFLINE
+
+
+The revocation function was unable to check revocation because the revocation server was offline.
+
+0x80092014
+
+CRYPT_E_NOT_IN_REVOCATION_DATABASE
+
+
+The certificate is not in the revocation server's database.
+
+0x80092020
+
+CRYPT_E_INVALID_NUMERIC_STRING
+
+
+The string contains a non-numeric character.
+
+0x80092021
+
+CRYPT_E_INVALID_PRINTABLE_STRING
+
+
+The string contains a nonprintable character.
+
+0x80092022
+
+CRYPT_E_INVALID_IA5_STRING
+
+
+The string contains a character not in the 7-bit ASCII character set.
+
+0x80092023
+
+CRYPT_E_INVALID_X500_STRING
+
+
+The string contains an invalid X500 name attribute key, object identifier (OID), value, or delimiter.
+
+0x80092024
+
+CRYPT_E_NOT_CHAR_STRING
+
+
+The dwValueType for the CERT_NAME_VALUE is not one of the character strings. Most likely it is either a CERT_RDN_ENCODED_BLOB or CERT_TDN_OCTED_STRING.
+
+0x80092025
+
+CRYPT_E_FILERESIZED
+
+
+The Put operation cannot continue. The file needs to be resized. However, there is already a signature present. A complete signing operation must be done.
+
+0x80092026
+
+CRYPT_E_SECURITY_SETTINGS
+
+
+The cryptographic operation failed due to a local security option setting.
+
+0x80092027
+
+CRYPT_E_NO_VERIFY_USAGE_DLL
+
+
+No DLL or exported function was found to verify subject usage.
+
+0x80092028
+
+CRYPT_E_NO_VERIFY_USAGE_CHECK
+
+
+The called function was unable to perform a usage check on the subject.
+
+0x80092029
+
+CRYPT_E_VERIFY_USAGE_OFFLINE
+
+
+The called function was unable to complete the usage check because the server was offline.
+
+0x8009202A
+
+CRYPT_E_NOT_IN_CTL
+
+
+The subject was not found in a certificate trust list (CTL).
+
+0x8009202B
+
+CRYPT_E_NO_TRUSTED_SIGNER
+
+
+None of the signers of the cryptographic message or certificate trust list is trusted.
+
+0x8009202C
+
+CRYPT_E_MISSING_PUBKEY_PARA
+
+
+The public key's algorithm parameters are missing.
+
+0x80093000
+
+CRYPT_E_OSS_ERROR
+
+
+OSS Certificate encode/decode error code base.
+
+0x80093001
+
+OSS_MORE_BUF
+
+
+OSS ASN.1 Error: Output Buffer is too small.
+
+0x80093002
+
+OSS_NEGATIVE_UINTEGER
+
+
+OSS ASN.1 Error: Signed integer is encoded as a unsigned integer.
+
+0x80093003
+
+OSS_PDU_RANGE
+
+
+OSS ASN.1 Error: Unknown ASN.1 data type.
+
+0x80093004
+
+OSS_MORE_INPUT
+
+
+OSS ASN.1 Error: Output buffer is too small; the decoded data has been truncated.
+
+0x80093005
+
+OSS_DATA_ERROR
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093006
+
+OSS_BAD_ARG
+
+
+OSS ASN.1 Error: Invalid argument.
+
+0x80093007
+
+OSS_BAD_VERSION
+
+
+OSS ASN.1 Error: Encode/Decode version mismatch.
+
+0x80093008
+
+OSS_OUT_MEMORY
+
+
+OSS ASN.1 Error: Out of memory.
+
+0x80093009
+
+OSS_PDU_MISMATCH
+
+
+OSS ASN.1 Error: Encode/Decode error.
+
+0x8009300A
+
+OSS_LIMITED
+
+
+OSS ASN.1 Error: Internal error.
+
+0x8009300B
+
+OSS_BAD_PTR
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x8009300C
+
+OSS_BAD_TIME
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x8009300D
+
+OSS_INDEFINITE_NOT_SUPPORTED
+
+
+OSS ASN.1 Error: Unsupported BER indefinite-length encoding.
+
+0x8009300E
+
+OSS_MEM_ERROR
+
+
+OSS ASN.1 Error: Access violation.
+
+0x8009300F
+
+OSS_BAD_TABLE
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093010
+
+OSS_TOO_LONG
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093011
+
+OSS_CONSTRAINT_VIOLATED
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093012
+
+OSS_FATAL_ERROR
+
+
+OSS ASN.1 Error: Internal error.
+
+0x80093013
+
+OSS_ACCESS_SERIALIZATION_ERROR
+
+
+OSS ASN.1 Error: Multithreading conflict.
+
+0x80093014
+
+OSS_NULL_TBL
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093015
+
+OSS_NULL_FCN
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093016
+
+OSS_BAD_ENCRULES
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x80093017
+
+OSS_UNAVAIL_ENCRULES
+
+
+OSS ASN.1 Error: Encode/Decode function not implemented.
+
+0x80093018
+
+OSS_CANT_OPEN_TRACE_WINDOW
+
+
+OSS ASN.1 Error: Trace file error.
+
+0x80093019
+
+OSS_UNIMPLEMENTED
+
+
+OSS ASN.1 Error: Function not implemented.
+
+0x8009301A
+
+OSS_OID_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009301B
+
+OSS_CANT_OPEN_TRACE_FILE
+
+
+OSS ASN.1 Error: Trace file error.
+
+0x8009301C
+
+OSS_TRACE_FILE_ALREADY_OPEN
+
+
+OSS ASN.1 Error: Trace file error.
+
+0x8009301D
+
+OSS_TABLE_MISMATCH
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x8009301E
+
+OSS_TYPE_NOT_SUPPORTED
+
+
+OSS ASN.1 Error: Invalid data.
+
+0x8009301F
+
+OSS_REAL_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093020
+
+OSS_REAL_CODE_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093021
+
+OSS_OUT_OF_RANGE
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093022
+
+OSS_COPIER_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093023
+
+OSS_CONSTRAINT_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093024
+
+OSS_COMPARATOR_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093025
+
+OSS_COMPARATOR_CODE_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093026
+
+OSS_MEM_MGR_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093027
+
+OSS_PDV_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093028
+
+OSS_PDV_CODE_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x80093029
+
+OSS_API_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009302A
+
+OSS_BERDER_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009302B
+
+OSS_PER_DLL_NOT_LINKED
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009302C
+
+OSS_OPEN_TYPE_ERROR
+
+
+OSS ASN.1 Error: Program link error.
+
+0x8009302D
+
+OSS_MUTEX_NOT_CREATED
+
+
+OSS ASN.1 Error: System resource error.
+
+0x8009302E
+
+OSS_CANT_CLOSE_TRACE_FILE
+
+
+OSS ASN.1 Error: Trace file error.
+
+0x80093100
+
+CRYPT_E_ASN1_ERROR
+
+
+ASN1 Certificate encode/decode error code base.
+
+0x80093101
+
+CRYPT_E_ASN1_INTERNAL
+
+
+ASN1 internal encode or decode error.
+
+0x80093102
+
+CRYPT_E_ASN1_EOD
+
+
+ASN1 unexpected end of data.
+
+0x80093103
+
+CRYPT_E_ASN1_CORRUPT
+
+
+ASN1 corrupted data.
+
+0x80093104
+
+CRYPT_E_ASN1_LARGE
+
+
+ASN1 value too large.
+
+0x80093105
+
+CRYPT_E_ASN1_CONSTRAINT
+
+
+ASN1 constraint violated.
+
+0x80093106
+
+CRYPT_E_ASN1_MEMORY
+
+
+ASN1 out of memory.
+
+0x80093107
+
+CRYPT_E_ASN1_OVERFLOW
+
+
+ASN1 buffer overflow.
+
+0x80093108
+
+CRYPT_E_ASN1_BADPDU
+
+
+ASN1 function not supported for this protocol data unit (PDU).
+
+0x80093109
+
+CRYPT_E_ASN1_BADARGS
+
+
+ASN1 bad arguments to function call.
+
+0x8009310A
+
+CRYPT_E_ASN1_BADREAL
+
+
+ASN1 bad real value.
+
+0x8009310B
+
+CRYPT_E_ASN1_BADTAG
+
+
+ASN1 bad tag value met.
+
+0x8009310C
+
+CRYPT_E_ASN1_CHOICE
+
+
+ASN1 bad choice value.
+
+0x8009310D
+
+CRYPT_E_ASN1_RULE
+
+
+ASN1 bad encoding rule.
+
+0x8009310E
+
+CRYPT_E_ASN1_UTF8
+
+
+ASN1 bad Unicode (UTF8).
+
+0x80093133
+
+CRYPT_E_ASN1_PDU_TYPE
+
+
+ASN1 bad PDU type.
+
+0x80093134
+
+CRYPT_E_ASN1_NYI
+
+
+ASN1 not yet implemented.
+
+0x80093201
+
+CRYPT_E_ASN1_EXTENDED
+
+
+ASN1 skipped unknown extensions.
+
+0x80093202
+
+CRYPT_E_ASN1_NOEOD
+
+
+ASN1 end of data expected.
+
+0x80094001
+
+CERTSRV_E_BAD_REQUESTSUBJECT
+
+
+The request subject name is invalid or too long.
+
+0x80094002
+
+CERTSRV_E_NO_REQUEST
+
+
+The request does not exist.
+
+0x80094003
+
+CERTSRV_E_BAD_REQUESTSTATUS
+
+
+The request's current status does not allow this operation.
+
+0x80094004
+
+CERTSRV_E_PROPERTY_EMPTY
+
+
+The requested property value is empty.
+
+0x80094005
+
+CERTSRV_E_INVALID_CA_CERTIFICATE
+
+
+The CA's certificate contains invalid data.
+
+0x80094006
+
+CERTSRV_E_SERVER_SUSPENDED
+
+
+Certificate service has been suspended for a database restore operation.
+
+0x80094007
+
+CERTSRV_E_ENCODING_LENGTH
+
+
+The certificate contains an encoded length that is potentially incompatible with older enrollment software.
+
+0x80094008
+
+CERTSRV_E_ROLECONFLICT
+
+
+The operation is denied. The user has multiple roles assigned, and the CA is configured to enforce role separation.
+
+0x80094009
+
+CERTSRV_E_RESTRICTEDOFFICER
+
+
+The operation is denied. It can only be performed by a certificate manager that is allowed to manage certificates for the current requester.
+
+0x8009400A
+
+CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED
+
+
+Cannot archive private key. The CA is not configured for key archival.
+
+0x8009400B
+
+CERTSRV_E_NO_VALID_KRA
+
+
+Cannot archive private key. The CA could not verify one or more key recovery certificates.
+
+0x8009400C
+
+CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL
+
+
+The request is incorrectly formatted. The encrypted private key must be in an unauthenticated attribute in an outermost signature.
+
+0x8009400D
+
+CERTSRV_E_NO_CAADMIN_DEFINED
+
+
+At least one security principal must have the permission to manage this CA.
+
+0x8009400E
+
+CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE
+
+
+The request contains an invalid renewal certificate attribute.
+
+0x8009400F
+
+CERTSRV_E_NO_DB_SESSIONS
+
+
+An attempt was made to open a CA database session, but there are already too many active sessions. The server needs to be configured to allow additional sessions.
+
+0x80094010
+
+CERTSRV_E_ALIGNMENT_FAULT
+
+
+A memory reference caused a data alignment fault.
+
+0x80094011
+
+CERTSRV_E_ENROLL_DENIED
+
+
+The permissions on this CA do not allow the current user to enroll for certificates.
+
+0x80094012
+
+CERTSRV_E_TEMPLATE_DENIED
+
+
+The permissions on the certificate template do not allow the current user to enroll for this type of certificate.
+
+0x80094013
+
+CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE
+
+
+The contacted domain controller cannot support signed Lightweight Directory Access Protocol (LDAP) traffic. Update the domain controller or configure Certificate Services to use SSL for Active Directory access.
+
+0x80094800
+
+CERTSRV_E_UNSUPPORTED_CERT_TYPE
+
+
+The requested certificate template is not supported by this CA.
+
+0x80094801
+
+CERTSRV_E_NO_CERT_TYPE
+
+
+The request contains no certificate template information.
+
+0x80094802
+
+CERTSRV_E_TEMPLATE_CONFLICT
+
+
+The request contains conflicting template information.
+
+0x80094803
+
+CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED
+
+
+The request is missing a required Subject Alternate name extension.
+
+0x80094804
+
+CERTSRV_E_ARCHIVED_KEY_REQUIRED
+
+
+The request is missing a required private key for archival by the server.
+
+0x80094805
+
+CERTSRV_E_SMIME_REQUIRED
+
+
+The request is missing a required SMIME capabilities extension.
+
+0x80094806
+
+CERTSRV_E_BAD_RENEWAL_SUBJECT
+
+
+The request was made on behalf of a subject other than the caller. The certificate template must be configured to require at least one signature to authorize the request.
+
+0x80094807
+
+CERTSRV_E_BAD_TEMPLATE_VERSION
+
+
+The request template version is newer than the supported template version.
+
+0x80094808
+
+CERTSRV_E_TEMPLATE_POLICY_REQUIRED
+
+
+The template is missing a required signature policy attribute.
+
+0x80094809
+
+CERTSRV_E_SIGNATURE_POLICY_REQUIRED
+
+
+The request is missing required signature policy information.
+
+0x8009480A
+
+CERTSRV_E_SIGNATURE_COUNT
+
+
+The request is missing one or more required signatures.
+
+0x8009480B
+
+CERTSRV_E_SIGNATURE_REJECTED
+
+
+One or more signatures did not include the required application or issuance policies. The request is missing one or more required valid signatures.
+
+0x8009480C
+
+CERTSRV_E_ISSUANCE_POLICY_REQUIRED
+
+
+The request is missing one or more required signature issuance policies.
+
+0x8009480D
+
+CERTSRV_E_SUBJECT_UPN_REQUIRED
+
+
+The UPN is unavailable and cannot be added to the Subject Alternate name.
+
+0x8009480E
+
+CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED
+
+
+The Active Directory GUID is unavailable and cannot be added to the Subject Alternate name.
+
+0x8009480F
+
+CERTSRV_E_SUBJECT_DNS_REQUIRED
+
+
+The Domain Name System (DNS) name is unavailable and cannot be added to the Subject Alternate name.
+
+0x80094810
+
+CERTSRV_E_ARCHIVED_KEY_UNEXPECTED
+
+
+The request includes a private key for archival by the server, but key archival is not enabled for the specified certificate template.
+
+0x80094811
+
+CERTSRV_E_KEY_LENGTH
+
+
+The public key does not meet the minimum size required by the specified certificate template.
+
+0x80094812
+
+CERTSRV_E_SUBJECT_EMAIL_REQUIRED
+
+
+The email name is unavailable and cannot be added to the Subject or Subject Alternate name.
+
+0x80094813
+
+CERTSRV_E_UNKNOWN_CERT_TYPE
+
+
+One or more certificate templates to be enabled on this CA could not be found.
+
+0x80094814
+
+CERTSRV_E_CERT_TYPE_OVERLAP
+
+
+The certificate template renewal period is longer than the certificate validity period. The template should be reconfigured or the CA certificate renewed.
+
+0x80094815
+
+CERTSRV_E_TOO_MANY_SIGNATURES
+
+
+The certificate template requires too many return authorization (RA) signatures. Only one RA signature is allowed.
+
+0x80094816
+
+CERTSRV_E_RENEWAL_BAD_PUBLIC_KEY
+
+
+The key used in a renewal request does not match one of the certificates being renewed.
+
+0x80094817
+
+CERTSRV_E_INVALID_EK
+
+
+The endorsement key certificate is not valid.
+
+0x8009481A
+
+CERTSRV_E_KEY_ATTESTATION
+
+
+Key attestation did not succeed.
+
+0x80095000
+
+XENROLL_E_KEY_NOT_EXPORTABLE
+
+
+The key is not exportable.
+
+0x80095001
+
+XENROLL_E_CANNOT_ADD_ROOT_CERT
+
+
+You cannot add the root CA certificate into your local store.
+
+0x80095002
+
+XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND
+
+
+The key archival hash attribute was not found in the response.
+
+0x80095003
+
+XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH
+
+
+An unexpected key archival hash attribute was found in the response.
+
+0x80095004
+
+XENROLL_E_RESPONSE_KA_HASH_MISMATCH
+
+
+There is a key archival hash mismatch between the request and the response.
+
+0x80095005
+
+XENROLL_E_KEYSPEC_SMIME_MISMATCH
+
+
+Signing certificate cannot include SMIME extension.
+
+0x80096001
+
+TRUST_E_SYSTEM_ERROR
+
+
+A system-level error occurred while verifying trust.
+
+0x80096002
+
+TRUST_E_NO_SIGNER_CERT
+
+
+The certificate for the signer of the message is invalid or not found.
+
+0x80096003
+
+TRUST_E_COUNTER_SIGNER
+
+
+One of the counter signatures was invalid.
+
+0x80096004
+
+TRUST_E_CERT_SIGNATURE
+
+
+The signature of the certificate cannot be verified.
+
+0x80096005
+
+TRUST_E_TIME_STAMP
+
+
+The time-stamp signature or certificate could not be verified or is malformed.
+
+0x80096010
+
+TRUST_E_BAD_DIGEST
+
+
+The digital signature of the object did not verify.
+
+0x80096019
+
+TRUST_E_BASIC_CONSTRAINTS
+
+
+A certificate's basic constraint extension has not been observed.
+
+0x8009601E
+
+TRUST_E_FINANCIAL_CRITERIA
+
+
+The certificate does not meet or contain the Authenticode financial extensions.
+
+0x80097001
+
+MSSIPOTF_E_OUTOFMEMRANGE
+
+
+Tried to reference a part of the file outside the proper range.
+
+0x80097002
+
+MSSIPOTF_E_CANTGETOBJECT
+
+
+Could not retrieve an object from the file.
+
+0x80097003
+
+MSSIPOTF_E_NOHEADTABLE
+
+
+Could not find the head table in the file.
+
+0x80097004
+
+MSSIPOTF_E_BAD_MAGICNUMBER
+
+
+The magic number in the head table is incorrect.
+
+0x80097005
+
+MSSIPOTF_E_BAD_OFFSET_TABLE
+
+
+The offset table has incorrect values.
+
+0x80097006
+
+MSSIPOTF_E_TABLE_TAGORDER
+
+
+Duplicate table tags or the tags are out of alphabetical order.
+
+0x80097007
+
+MSSIPOTF_E_TABLE_LONGWORD
+
+
+A table does not start on a long word boundary.
+
+0x80097008
+
+MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT
+
+
+First table does not appear after header information.
+
+0x80097009
+
+MSSIPOTF_E_TABLES_OVERLAP
+
+
+Two or more tables overlap.
+
+0x8009700A
+
+MSSIPOTF_E_TABLE_PADBYTES
+
+
+Too many pad bytes between tables, or pad bytes are not 0.
+
+0x8009700B
+
+MSSIPOTF_E_FILETOOSMALL
+
+
+File is too small to contain the last table.
+
+0x8009700C
+
+MSSIPOTF_E_TABLE_CHECKSUM
+
+
+A table checksum is incorrect.
+
+0x8009700D
+
+MSSIPOTF_E_FILE_CHECKSUM
+
+
+The file checksum is incorrect.
+
+0x80097010
+
+MSSIPOTF_E_FAILED_POLICY
+
+
+The signature does not have the correct attributes for the policy.
+
+0x80097011
+
+MSSIPOTF_E_FAILED_HINTS_CHECK
+
+
+The file did not pass the hints check.
+
+0x80097012
+
+MSSIPOTF_E_NOT_OPENTYPE
+
+
+The file is not an OpenType file.
+
+0x80097013
+
+MSSIPOTF_E_FILE
+
+
+Failed on a file operation (such as open, map, read, or write).
+
+0x80097014
+
+MSSIPOTF_E_CRYPT
+
+
+A call to a CryptoAPI function failed.
+
+0x80097015
+
+MSSIPOTF_E_BADVERSION
+
+
+There is a bad version number in the file.
+
+0x80097016
+
+MSSIPOTF_E_DSIG_STRUCTURE
+
+
+The structure of the DSIG table is incorrect.
+
+0x80097017
+
+MSSIPOTF_E_PCONST_CHECK
+
+
+A check failed in a partially constant table.
+
+0x80097018
+
+MSSIPOTF_E_STRUCTURE
+
+
+Some kind of structural error.
+
+0x80097019
+
+ERROR_CRED_REQUIRES_CONFIRMATION
+
+
+The requested credential requires confirmation.
+
+0x800B0001
+
+TRUST_E_PROVIDER_UNKNOWN
+
+
+Unknown trust provider.
+
+0x800B0002
+
+TRUST_E_ACTION_UNKNOWN
+
+
+The trust verification action specified is not supported by the specified trust provider.
+
+0x800B0003
+
+TRUST_E_SUBJECT_FORM_UNKNOWN
+
+
+The form specified for the subject is not one supported or known by the specified trust provider.
+
+0x800B0004
+
+TRUST_E_SUBJECT_NOT_TRUSTED
+
+
+The subject is not trusted for the specified action.
+
+0x800B0005
+
+DIGSIG_E_ENCODE
+
+
+Error due to problem in ASN.1 encoding process.
+
+0x800B0006
+
+DIGSIG_E_DECODE
+
+
+Error due to problem in ASN.1 decoding process.
+
+0x800B0007
+
+DIGSIG_E_EXTENSIBILITY
+
+
+Reading/writing extensions where attributes are appropriate, and vice versa.
+
+0x800B0008
+
+DIGSIG_E_CRYPTO
+
+
+Unspecified cryptographic failure.
+
+0x800B0009
+
+PERSIST_E_SIZEDEFINITE
+
+
+The size of the data could not be determined.
+
+0x800B000A
+
+PERSIST_E_SIZEINDEFINITE
+
+
+The size of the indefinite-sized data could not be determined.
+
+0x800B000B
+
+PERSIST_E_NOTSELFSIZING
+
+
+This object does not read and write self-sizing data.
+
+0x800B0100
+
+TRUST_E_NOSIGNATURE
+
+
+No signature was present in the subject.
+
+0x800B0101
+
+CERT_E_EXPIRED
+
+
+A required certificate is not within its validity period when verifying against the current system clock or the time stamp in the signed file.
+
+0x800B0102
+
+CERT_E_VALIDITYPERIODNESTING
+
+
+The validity periods of the certification chain do not nest correctly.
+
+0x800B0103
+
+CERT_E_ROLE
+
+
+A certificate that can only be used as an end entity is being used as a CA or vice versa.
+
+0x800B0104
+
+CERT_E_PATHLENCONST
+
+
+A path length constraint in the certification chain has been violated.
+
+0x800B0105
+
+CERT_E_CRITICAL
+
+
+A certificate contains an unknown extension that is marked "critical".
+
+0x800B0106
+
+CERT_E_PURPOSE
+
+
+A certificate is being used for a purpose other than the ones specified by its CA.
+
+0x800B0107
+
+CERT_E_ISSUERCHAINING
+
+
+A parent of a given certificate did not issue that child certificate.
+
+0x800B0108
+
+CERT_E_MALFORMED
+
+
+A certificate is missing or has an empty value for an important field, such as a subject or issuer name.
+
+0x800B0109
+
+CERT_E_UNTRUSTEDROOT
+
+
+A certificate chain processed, but terminated in a root certificate that is not trusted by the trust provider.
+
+0x800B010A
+
+CERT_E_CHAINING
+
+
+A certificate chain could not be built to a trusted root authority.
+
+0x800B010B
+
+TRUST_E_FAIL
+
+
+Generic trust failure.
+
+0x800B010C
+
+CERT_E_REVOKED
+
+
+A certificate was explicitly revoked by its issuer. If the certificate is Microsoft Windows PCA 2010, then the driver was signed by a certificate no longer recognized by Windows.
+
+0x800B010D
+
+CERT_E_UNTRUSTEDTESTROOT
+
+
+The certification path terminates with the test root that is not trusted with the current policy settings.
+
+0x800B010E
+
+CERT_E_REVOCATION_FAILURE
+
+
+The revocation process could not continue—the certificates could not be checked.
+
+0x800B010F
+
+CERT_E_CN_NO_MATCH
+
+
+The certificate's CN name does not match the passed value.
+
+0x800B0110
+
+CERT_E_WRONG_USAGE
+
+
+The certificate is not valid for the requested usage.
+
+0x800B0111
+
+TRUST_E_EXPLICIT_DISTRUST
+
+
+The certificate was explicitly marked as untrusted by the user.
+
+0x800B0112
+
+CERT_E_UNTRUSTEDCA
+
+
+A certification chain processed correctly, but one of the CA certificates is not trusted by the policy provider.
+
+0x800B0113
+
+CERT_E_INVALID_POLICY
+
+
+The certificate has invalid policy.
+
+0x800B0114
+
+CERT_E_INVALID_NAME
+
+
+The certificate has an invalid name. The name is not included in the permitted list or is explicitly excluded.
+
+0x800D0003
+
+NS_W_SERVER_BANDWIDTH_LIMIT
+
+
+The maximum filebitrate value specified is greater than the server's configured maximum bandwidth.
+
+0x800D0004
+
+NS_W_FILE_BANDWIDTH_LIMIT
+
+
+The maximum bandwidth value specified is less than the maximum filebitrate.
+
+0x800D0060
+
+NS_W_UNKNOWN_EVENT
+
+
+Unknown %1 event encountered.
+
+0x800D0199
+
+NS_I_CATATONIC_FAILURE
+
+
+Disk %1 ( %2 ) on Content Server %3, will be failed because it is catatonic.
+
+0x800D019A
+
+NS_I_CATATONIC_AUTO_UNFAIL
+
+
+Disk %1 ( %2 ) on Content Server %3, auto online from catatonic state.
+
+0x800F0000
+
+SPAPI_E_EXPECTED_SECTION_NAME
+
+
+A non-empty line was encountered in the INF before the start of a section.
+
+0x800F0001
+
+SPAPI_E_BAD_SECTION_NAME_LINE
+
+
+A section name marker in the information file (INF) is not complete or does not exist on a line by itself.
+
+0x800F0002
+
+SPAPI_E_SECTION_NAME_TOO_LONG
+
+
+An INF section was encountered whose name exceeds the maximum section name length.
+
+0x800F0003
+
+SPAPI_E_GENERAL_SYNTAX
+
+
+The syntax of the INF is invalid.
+
+0x800F0100
+
+SPAPI_E_WRONG_INF_STYLE
+
+
+The style of the INF is different than what was requested.
+
+0x800F0101
+
+SPAPI_E_SECTION_NOT_FOUND
+
+
+The required section was not found in the INF.
+
+0x800F0102
+
+SPAPI_E_LINE_NOT_FOUND
+
+
+The required line was not found in the INF.
+
+0x800F0103
+
+SPAPI_E_NO_BACKUP
+
+
+The files affected by the installation of this file queue have not been backed up for uninstall.
+
+0x800F0200
+
+SPAPI_E_NO_ASSOCIATED_CLASS
+
+
+The INF or the device information set or element does not have an associated install class.
+
+0x800F0201
+
+SPAPI_E_CLASS_MISMATCH
+
+
+The INF or the device information set or element does not match the specified install class.
+
+0x800F0202
+
+SPAPI_E_DUPLICATE_FOUND
+
+
+An existing device was found that is a duplicate of the device being manually installed.
+
+0x800F0203
+
+SPAPI_E_NO_DRIVER_SELECTED
+
+
+There is no driver selected for the device information set or element.
+
+0x800F0204
+
+SPAPI_E_KEY_DOES_NOT_EXIST
+
+
+The requested device registry key does not exist.
+
+0x800F0205
+
+SPAPI_E_INVALID_DEVINST_NAME
+
+
+The device instance name is invalid.
+
+0x800F0206
+
+SPAPI_E_INVALID_CLASS
+
+
+The install class is not present or is invalid.
+
+0x800F0207
+
+SPAPI_E_DEVINST_ALREADY_EXISTS
+
+
+The device instance cannot be created because it already exists.
+
+0x800F0208
+
+SPAPI_E_DEVINFO_NOT_REGISTERED
+
+
+The operation cannot be performed on a device information element that has not been registered.
+
+0x800F0209
+
+SPAPI_E_INVALID_REG_PROPERTY
+
+
+The device property code is invalid.
+
+0x800F020A
+
+SPAPI_E_NO_INF
+
+
+The INF from which a driver list is to be built does not exist.
+
+0x800F020B
+
+SPAPI_E_NO_SUCH_DEVINST
+
+
+The device instance does not exist in the hardware tree.
+
+0x800F020C
+
+SPAPI_E_CANT_LOAD_CLASS_ICON
+
+
+The icon representing this install class cannot be loaded.
+
+0x800F020D
+
+SPAPI_E_INVALID_CLASS_INSTALLER
+
+
+The class installer registry entry is invalid.
+
+0x800F020E
+
+SPAPI_E_DI_DO_DEFAULT
+
+
+The class installer has indicated that the default action should be performed for this installation request.
+
+0x800F020F
+
+SPAPI_E_DI_NOFILECOPY
+
+
+The operation does not require any files to be copied.
+
+0x800F0210
+
+SPAPI_E_INVALID_HWPROFILE
+
+
+The specified hardware profile does not exist.
+
+0x800F0211
+
+SPAPI_E_NO_DEVICE_SELECTED
+
+
+There is no device information element currently selected for this device information set.
+
+0x800F0212
+
+SPAPI_E_DEVINFO_LIST_LOCKED
+
+
+The operation cannot be performed because the device information set is locked.
+
+0x800F0213
+
+SPAPI_E_DEVINFO_DATA_LOCKED
+
+
+The operation cannot be performed because the device information element is locked.
+
+0x800F0214
+
+SPAPI_E_DI_BAD_PATH
+
+
+The specified path does not contain any applicable device INFs.
+
+0x800F0215
+
+SPAPI_E_NO_CLASSINSTALL_PARAMS
+
+
+No class installer parameters have been set for the device information set or element.
+
+0x800F0216
+
+SPAPI_E_FILEQUEUE_LOCKED
+
+
+The operation cannot be performed because the file queue is locked.
+
+0x800F0217
+
+SPAPI_E_BAD_SERVICE_INSTALLSECT
+
+
+A service installation section in this INF is invalid.
+
+0x800F0218
+
+SPAPI_E_NO_CLASS_DRIVER_LIST
+
+
+There is no class driver list for the device information element.
+
+0x800F0219
+
+SPAPI_E_NO_ASSOCIATED_SERVICE
+
+
+The installation failed because a function driver was not specified for this device instance.
+
+0x800F021A
+
+SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE
+
+
+There is presently no default device interface designated for this interface class.
+
+0x800F021B
+
+SPAPI_E_DEVICE_INTERFACE_ACTIVE
+
+
+The operation cannot be performed because the device interface is currently active.
+
+0x800F021C
+
+SPAPI_E_DEVICE_INTERFACE_REMOVED
+
+
+The operation cannot be performed because the device interface has been removed from the system.
+
+0x800F021D
+
+SPAPI_E_BAD_INTERFACE_INSTALLSECT
+
+
+An interface installation section in this INF is invalid.
+
+0x800F021E
+
+SPAPI_E_NO_SUCH_INTERFACE_CLASS
+
+
+This interface class does not exist in the system.
+
+0x800F021F
+
+SPAPI_E_INVALID_REFERENCE_STRING
+
+
+The reference string supplied for this interface device is invalid.
+
+0x800F0220
+
+SPAPI_E_INVALID_MACHINENAME
+
+
+The specified machine name does not conform to Universal Naming Convention (UNCs).
+
+0x800F0221
+
+SPAPI_E_REMOTE_COMM_FAILURE
+
+
+A general remote communication error occurred.
+
+0x800F0222
+
+SPAPI_E_MACHINE_UNAVAILABLE
+
+
+The machine selected for remote communication is not available at this time.
+
+0x800F0223
+
+SPAPI_E_NO_CONFIGMGR_SERVICES
+
+
+The Plug and Play service is not available on the remote machine.
+
+0x800F0224
+
+SPAPI_E_INVALID_PROPPAGE_PROVIDER
+
+
+The property page provider registry entry is invalid.
+
+0x800F0225
+
+SPAPI_E_NO_SUCH_DEVICE_INTERFACE
+
+
+The requested device interface is not present in the system.
+
+0x800F0226
+
+SPAPI_E_DI_POSTPROCESSING_REQUIRED
+
+
+The device's co-installer has additional work to perform after installation is complete.
+
+0x800F0227
+
+SPAPI_E_INVALID_COINSTALLER
+
+
+The device's co-installer is invalid.
+
+0x800F0228
+
+SPAPI_E_NO_COMPAT_DRIVERS
+
+
+There are no compatible drivers for this device.
+
+0x800F0229
+
+SPAPI_E_NO_DEVICE_ICON
+
+
+There is no icon that represents this device or device type.
+
+0x800F022A
+
+SPAPI_E_INVALID_INF_LOGCONFIG
+
+
+A logical configuration specified in this INF is invalid.
+
+0x800F022B
+
+SPAPI_E_DI_DONT_INSTALL
+
+
+The class installer has denied the request to install or upgrade this device.
+
+0x800F022C
+
+SPAPI_E_INVALID_FILTER_DRIVER
+
+
+One of the filter drivers installed for this device is invalid.
+
+0x800F022D
+
+SPAPI_E_NON_WINDOWS_NT_DRIVER
+
+
+The driver selected for this device does not support Windows XP operating system.
+
+0x800F022E
+
+SPAPI_E_NON_WINDOWS_DRIVER
+
+
+The driver selected for this device does not support Windows.
+
+0x800F022F
+
+SPAPI_E_NO_CATALOG_FOR_OEM_INF
+
+
+The third-party INF does not contain digital signature information.
+
+0x800F0230
+
+SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE
+
+
+An invalid attempt was made to use a device installation file queue for verification of digital signatures relative to other platforms.
+
+0x800F0231
+
+SPAPI_E_NOT_DISABLEABLE
+
+
+The device cannot be disabled.
+
+0x800F0232
+
+SPAPI_E_CANT_REMOVE_DEVINST
+
+
+The device could not be dynamically removed.
+
+0x800F0233
+
+SPAPI_E_INVALID_TARGET
+
+
+Cannot copy to specified target.
+
+0x800F0234
+
+SPAPI_E_DRIVER_NONNATIVE
+
+
+Driver is not intended for this platform.
+
+0x800F0235
+
+SPAPI_E_IN_WOW64
+
+
+Operation not allowed in WOW64.
+
+0x800F0236
+
+SPAPI_E_SET_SYSTEM_RESTORE_POINT
+
+
+The operation involving unsigned file copying was rolled back, so that a system restore point could be set.
+
+0x800F0237
+
+SPAPI_E_INCORRECTLY_COPIED_INF
+
+
+An INF was copied into the Windows INF directory in an improper manner.
+
+0x800F0238
+
+SPAPI_E_SCE_DISABLED
+
+
+The Security Configuration Editor (SCE) APIs have been disabled on this embedded product.
+
+0x800F0239
+
+SPAPI_E_UNKNOWN_EXCEPTION
+
+
+An unknown exception was encountered.
+
+0x800F023A
+
+SPAPI_E_PNP_REGISTRY_ERROR
+
+
+A problem was encountered when accessing the Plug and Play registry database.
+
+0x800F023B
+
+SPAPI_E_REMOTE_REQUEST_UNSUPPORTED
+
+
+The requested operation is not supported for a remote machine.
+
+0x800F023C
+
+SPAPI_E_NOT_AN_INSTALLED_OEM_INF
+
+
+The specified file is not an installed original equipment manufacturer (OEM) INF.
+
+0x800F023D
+
+SPAPI_E_INF_IN_USE_BY_DEVICES
+
+
+One or more devices are presently installed using the specified INF.
+
+0x800F023E
+
+SPAPI_E_DI_FUNCTION_OBSOLETE
+
+
+The requested device install operation is obsolete.
+
+0x800F023F
+
+SPAPI_E_NO_AUTHENTICODE_CATALOG
+
+
+A file could not be verified because it does not have an associated catalog signed via Authenticode.
+
+0x800F0240
+
+SPAPI_E_AUTHENTICODE_DISALLOWED
+
+
+Authenticode signature verification is not supported for the specified INF.
+
+0x800F0241
+
+SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER
+
+
+The INF was signed with an Authenticode catalog from a trusted publisher.
+
+0x800F0242
+
+SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED
+
+
+The publisher of an Authenticode-signed catalog has not yet been established as trusted.
+
+0x800F0243
+
+SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED
+
+
+The publisher of an Authenticode-signed catalog was not established as trusted.
+
+0x800F0244
+
+SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH
+
+
+The software was tested for compliance with Windows logo requirements on a different version of Windows and might not be compatible with this version.
+
+0x800F0245
+
+SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE
+
+
+The file can be validated only by a catalog signed via Authenticode.
+
+0x800F0246
+
+SPAPI_E_DEVICE_INSTALLER_NOT_READY
+
+
+One of the installers for this device cannot perform the installation at this time.
+
+0x800F0247
+
+SPAPI_E_DRIVER_STORE_ADD_FAILED
+
+
+A problem was encountered while attempting to add the driver to the store.
+
+0x800F0248
+
+SPAPI_E_DEVICE_INSTALL_BLOCKED
+
+
+The installation of this device is forbidden by system policy. Contact your system administrator.
+
+0x800F0249
+
+SPAPI_E_DRIVER_INSTALL_BLOCKED
+
+
+The installation of this driver is forbidden by system policy. Contact your system administrator.
+
+0x800F024A
+
+SPAPI_E_WRONG_INF_TYPE
+
+
+The specified INF is the wrong type for this operation.
+
+0x800F024B
+
+SPAPI_E_FILE_HASH_NOT_IN_CATALOG
+
+
+The hash for the file is not present in the specified catalog file. The file is likely corrupt or the victim of tampering.
+
+0x800F024C
+
+SPAPI_E_DRIVER_STORE_DELETE_FAILED
+
+
+A problem was encountered while attempting to delete the driver from the store.
+
+0x800F0300
+
+SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW
+
+
+An unrecoverable stack overflow was encountered.
+
+0x800F1000
+
+SPAPI_E_ERROR_NOT_INSTALLED
+
+
+No installed components were detected.
+
+0x80100001
+
+SCARD_F_INTERNAL_ERROR
+
+
+An internal consistency check failed.
+
+0x80100002
+
+SCARD_E_CANCELLED
+
+
+The action was canceled by an SCardCancel request.
+
+0x80100003
+
+SCARD_E_INVALID_HANDLE
+
+
+The supplied handle was invalid.
+
+0x80100004
+
+SCARD_E_INVALID_PARAMETER
+
+
+One or more of the supplied parameters could not be properly interpreted.
+
+0x80100005
+
+SCARD_E_INVALID_TARGET
+
+
+Registry startup information is missing or invalid.
+
+0x80100006
+
+SCARD_E_NO_MEMORY
+
+
+Not enough memory available to complete this command.
+
+0x80100007
+
+SCARD_F_WAITED_TOO_LONG
+
+
+An internal consistency timer has expired.
+
+0x80100008
+
+SCARD_E_INSUFFICIENT_BUFFER
+
+
+The data buffer to receive returned data is too small for the returned data.
+
+0x80100009
+
+SCARD_E_UNKNOWN_READER
+
+
+The specified reader name is not recognized.
+
+0x8010000A
+
+SCARD_E_TIMEOUT
+
+
+The user-specified time-out value has expired.
+
+0x8010000B
+
+SCARD_E_SHARING_VIOLATION
+
+
+The smart card cannot be accessed because of other connections outstanding.
+
+0x8010000C
+
+SCARD_E_NO_SMARTCARD
+
+
+The operation requires a smart card, but no smart card is currently in the device.
+
+0x8010000D
+
+SCARD_E_UNKNOWN_CARD
+
+
+The specified smart card name is not recognized.
+
+0x8010000E
+
+SCARD_E_CANT_DISPOSE
+
+
+The system could not dispose of the media in the requested manner.
+
+0x8010000F
+
+SCARD_E_PROTO_MISMATCH
+
+
+The requested protocols are incompatible with the protocol currently in use with the smart card.
+
+0x80100010
+
+SCARD_E_NOT_READY
+
+
+The reader or smart card is not ready to accept commands.
+
+0x80100011
+
+SCARD_E_INVALID_VALUE
+
+
+One or more of the supplied parameters values could not be properly interpreted.
+
+0x80100012
+
+SCARD_E_SYSTEM_CANCELLED
+
+
+The action was canceled by the system, presumably to log off or shut down.
+
+0x80100013
+
+SCARD_F_COMM_ERROR
+
+
+An internal communications error has been detected.
+
+0x80100014
+
+SCARD_F_UNKNOWN_ERROR
+
+
+An internal error has been detected, but the source is unknown.
+
+0x80100015
+
+SCARD_E_INVALID_ATR
+
+
+An automatic terminal recognition (ATR) obtained from the registry is not a valid ATR string.
+
+0x80100016
+
+SCARD_E_NOT_TRANSACTED
+
+
+An attempt was made to end a nonexistent transaction.
+
+0x80100017
+
+SCARD_E_READER_UNAVAILABLE
+
+
+The specified reader is not currently available for use.
+
+0x80100018
+
+SCARD_P_SHUTDOWN
+
+
+The operation has been aborted to allow the server application to exit.
+
+0x80100019
+
+SCARD_E_PCI_TOO_SMALL
+
+
+The peripheral component interconnect (PCI) Receive buffer was too small.
+
+0x8010001A
+
+SCARD_E_READER_UNSUPPORTED
+
+
+The reader driver does not meet minimal requirements for support.
+
+0x8010001B
+
+SCARD_E_DUPLICATE_READER
+
+
+The reader driver did not produce a unique reader name.
+
+0x8010001C
+
+SCARD_E_CARD_UNSUPPORTED
+
+
+The smart card does not meet minimal requirements for support.
+
+0x8010001D
+
+SCARD_E_NO_SERVICE
+
+
+The smart card resource manager is not running.
+
+0x8010001E
+
+SCARD_E_SERVICE_STOPPED
+
+
+The smart card resource manager has shut down.
+
+0x8010001F
+
+SCARD_E_UNEXPECTED
+
+
+An unexpected card error has occurred.
+
+0x80100020
+
+SCARD_E_ICC_INSTALLATION
+
+
+No primary provider can be found for the smart card.
+
+0x80100021
+
+SCARD_E_ICC_CREATEORDER
+
+
+The requested order of object creation is not supported.
+
+0x80100022
+
+SCARD_E_UNSUPPORTED_FEATURE
+
+
+This smart card does not support the requested feature.
+
+0x80100023
+
+SCARD_E_DIR_NOT_FOUND
+
+
+The identified directory does not exist in the smart card.
+
+0x80100024
+
+SCARD_E_FILE_NOT_FOUND
+
+
+The identified file does not exist in the smart card.
+
+0x80100025
+
+SCARD_E_NO_DIR
+
+
+The supplied path does not represent a smart card directory.
+
+0x80100026
+
+SCARD_E_NO_FILE
+
+
+The supplied path does not represent a smart card file.
+
+0x80100027
+
+SCARD_E_NO_ACCESS
+
+
+Access is denied to this file.
+
+0x80100028
+
+SCARD_E_WRITE_TOO_MANY
+
+
+The smart card does not have enough memory to store the information.
+
+0x80100029
+
+SCARD_E_BAD_SEEK
+
+
+There was an error trying to set the smart card file object pointer.
+
+0x8010002A
+
+SCARD_E_INVALID_CHV
+
+
+The supplied PIN is incorrect.
+
+0x8010002B
+
+SCARD_E_UNKNOWN_RES_MNG
+
+
+An unrecognized error code was returned from a layered component.
+
+0x8010002C
+
+SCARD_E_NO_SUCH_CERTIFICATE
+
+
+The requested certificate does not exist.
+
+0x8010002D
+
+SCARD_E_CERTIFICATE_UNAVAILABLE
+
+
+The requested certificate could not be obtained.
+
+0x8010002E
+
+SCARD_E_NO_READERS_AVAILABLE
+
+
+Cannot find a smart card reader.
+
+0x8010002F
+
+SCARD_E_COMM_DATA_LOST
+
+
+A communications error with the smart card has been detected. Retry the operation.
+
+0x80100030
+
+SCARD_E_NO_KEY_CONTAINER
+
+
+The requested key container does not exist on the smart card.
+
+0x80100031
+
+SCARD_E_SERVER_TOO_BUSY
+
+
+The smart card resource manager is too busy to complete this operation.
+
+0x80100065
+
+SCARD_W_UNSUPPORTED_CARD
+
+
+The reader cannot communicate with the smart card, due to ATR configuration conflicts.
+
+0x80100066
+
+SCARD_W_UNRESPONSIVE_CARD
+
+
+The smart card is not responding to a reset.
+
+0x80100067
+
+SCARD_W_UNPOWERED_CARD
+
+
+Power has been removed from the smart card, so that further communication is not possible.
+
+0x80100068
+
+SCARD_W_RESET_CARD
+
+
+The smart card has been reset, so any shared state information is invalid.
+
+0x80100069
+
+SCARD_W_REMOVED_CARD
+
+
+The smart card has been removed, so that further communication is not possible.
+
+0x8010006A
+
+SCARD_W_SECURITY_VIOLATION
+
+
+Access was denied because of a security violation.
+
+0x8010006B
+
+SCARD_W_WRONG_CHV
+
+
+The card cannot be accessed because the wrong PIN was presented.
+
+0x8010006C
+
+SCARD_W_CHV_BLOCKED
+
+
+The card cannot be accessed because the maximum number of PIN entry attempts has been reached.
+
+0x8010006D
+
+SCARD_W_EOF
+
+
+The end of the smart card file has been reached.
+
+0x8010006E
+
+SCARD_W_CANCELLED_BY_USER
+
+
+The action was canceled by the user.
+
+0x8010006F
+
+SCARD_W_CARD_NOT_AUTHENTICATED
+
+
+No PIN was presented to the smart card.
+
+0x80110401
+
+COMADMIN_E_OBJECTERRORS
+
+
+Errors occurred accessing one or more objects—the ErrorInfo collection contains more detail.
+
+0x80110402
+
+COMADMIN_E_OBJECTINVALID
+
+
+One or more of the object's properties are missing or invalid.
+
+0x80110403
+
+COMADMIN_E_KEYMISSING
+
+
+The object was not found in the catalog.
+
+0x80110404
+
+COMADMIN_E_ALREADYINSTALLED
+
+
+The object is already registered.
+
+0x80110407
+
+COMADMIN_E_APP_FILE_WRITEFAIL
+
+
+An error occurred writing to the application file.
+
+0x80110408
+
+COMADMIN_E_APP_FILE_READFAIL
+
+
+An error occurred reading the application file.
+
+0x80110409
+
+COMADMIN_E_APP_FILE_VERSION
+
+
+Invalid version number in application file.
+
+0x8011040A
+
+COMADMIN_E_BADPATH
+
+
+The file path is invalid.
+
+0x8011040B
+
+COMADMIN_E_APPLICATIONEXISTS
+
+
+The application is already installed.
+
+0x8011040C
+
+COMADMIN_E_ROLEEXISTS
+
+
+The role already exists.
+
+0x8011040D
+
+COMADMIN_E_CANTCOPYFILE
+
+
+An error occurred copying the file.
+
+0x8011040F
+
+COMADMIN_E_NOUSER
+
+
+One or more users are not valid.
+
+0x80110410
+
+COMADMIN_E_INVALIDUSERIDS
+
+
+One or more users in the application file are not valid.
+
+0x80110411
+
+COMADMIN_E_NOREGISTRYCLSID
+
+
+The component's CLSID is missing or corrupt.
+
+0x80110412
+
+COMADMIN_E_BADREGISTRYPROGID
+
+
+The component's programmatic ID is missing or corrupt.
+
+0x80110413
+
+COMADMIN_E_AUTHENTICATIONLEVEL
+
+
+Unable to set required authentication level for update request.
+
+0x80110414
+
+COMADMIN_E_USERPASSWDNOTVALID
+
+
+The identity or password set on the application is not valid.
+
+0x80110418
+
+COMADMIN_E_CLSIDORIIDMISMATCH
+
+
+Application file CLSIDs or instance identifiers (IIDs) do not match corresponding DLLs.
+
+0x80110419
+
+COMADMIN_E_REMOTEINTERFACE
+
+
+Interface information is either missing or changed.
+
+0x8011041A
+
+COMADMIN_E_DLLREGISTERSERVER
+
+
+DllRegisterServer failed on component install.
+
+0x8011041B
+
+COMADMIN_E_NOSERVERSHARE
+
+
+No server file share available.
+
+0x8011041D
+
+COMADMIN_E_DLLLOADFAILED
+
+
+DLL could not be loaded.
+
+0x8011041E
+
+COMADMIN_E_BADREGISTRYLIBID
+
+
+The registered TypeLib ID is not valid.
+
+0x8011041F
+
+COMADMIN_E_APPDIRNOTFOUND
+
+
+Application install directory not found.
+
+0x80110423
+
+COMADMIN_E_REGISTRARFAILED
+
+
+Errors occurred while in the component registrar.
+
+0x80110424
+
+COMADMIN_E_COMPFILE_DOESNOTEXIST
+
+
+The file does not exist.
+
+0x80110425
+
+COMADMIN_E_COMPFILE_LOADDLLFAIL
+
+
+The DLL could not be loaded.
+
+0x80110426
+
+COMADMIN_E_COMPFILE_GETCLASSOBJ
+
+
+GetClassObject failed in the DLL.
+
+0x80110427
+
+COMADMIN_E_COMPFILE_CLASSNOTAVAIL
+
+
+The DLL does not support the components listed in the TypeLib.
+
+0x80110428
+
+COMADMIN_E_COMPFILE_BADTLB
+
+
+The TypeLib could not be loaded.
+
+0x80110429
+
+COMADMIN_E_COMPFILE_NOTINSTALLABLE
+
+
+The file does not contain components or component information.
+
+0x8011042A
+
+COMADMIN_E_NOTCHANGEABLE
+
+
+Changes to this object and its subobjects have been disabled.
+
+0x8011042B
+
+COMADMIN_E_NOTDELETEABLE
+
+
+The delete function has been disabled for this object.
+
+0x8011042C
+
+COMADMIN_E_SESSION
+
+
+The server catalog version is not supported.
+
+0x8011042D
+
+COMADMIN_E_COMP_MOVE_LOCKED
+
+
+The component move was disallowed because the source or destination application is either a system application or currently locked against changes.
+
+0x8011042E
+
+COMADMIN_E_COMP_MOVE_BAD_DEST
+
+
+The component move failed because the destination application no longer exists.
+
+0x80110430
+
+COMADMIN_E_REGISTERTLB
+
+
+The system was unable to register the TypeLib.
+
+0x80110433
+
+COMADMIN_E_SYSTEMAPP
+
+
+This operation cannot be performed on the system application.
+
+0x80110434
+
+COMADMIN_E_COMPFILE_NOREGISTRAR
+
+
+The component registrar referenced in this file is not available.
+
+0x80110435
+
+COMADMIN_E_COREQCOMPINSTALLED
+
+
+A component in the same DLL is already installed.
+
+0x80110436
+
+COMADMIN_E_SERVICENOTINSTALLED
+
+
+The service is not installed.
+
+0x80110437
+
+COMADMIN_E_PROPERTYSAVEFAILED
+
+
+One or more property settings are either invalid or in conflict with each other.
+
+0x80110438
+
+COMADMIN_E_OBJECTEXISTS
+
+
+The object you are attempting to add or rename already exists.
+
+0x80110439
+
+COMADMIN_E_COMPONENTEXISTS
+
+
+The component already exists.
+
+0x8011043B
+
+COMADMIN_E_REGFILE_CORRUPT
+
+
+The registration file is corrupt.
+
+0x8011043C
+
+COMADMIN_E_PROPERTY_OVERFLOW
+
+
+The property value is too large.
+
+0x8011043E
+
+COMADMIN_E_NOTINREGISTRY
+
+
+Object was not found in registry.
+
+0x8011043F
+
+COMADMIN_E_OBJECTNOTPOOLABLE
+
+
+This object cannot be pooled.
+
+0x80110446
+
+COMADMIN_E_APPLID_MATCHES_CLSID
+
+
+A CLSID with the same GUID as the new application ID is already installed on this machine.
+
+0x80110447
+
+COMADMIN_E_ROLE_DOES_NOT_EXIST
+
+
+A role assigned to a component, interface, or method did not exist in the application.
+
+0x80110448
+
+COMADMIN_E_START_APP_NEEDS_COMPONENTS
+
+
+You must have components in an application to start the application.
+
+0x80110449
+
+COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM
+
+
+This operation is not enabled on this platform.
+
+0x8011044A
+
+COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY
+
+
+Application proxy is not exportable.
+
+0x8011044B
+
+COMADMIN_E_CAN_NOT_START_APP
+
+
+Failed to start application because it is either a library application or an application proxy.
+
+0x8011044C
+
+COMADMIN_E_CAN_NOT_EXPORT_SYS_APP
+
+
+System application is not exportable.
+
+0x8011044D
+
+COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT
+
+
+Cannot subscribe to this component (the component might have been imported).
+
+0x8011044E
+
+COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER
+
+
+An event class cannot also be a subscriber component.
+
+0x8011044F
+
+COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE
+
+
+Library applications and application proxies are incompatible.
+
+0x80110450
+
+COMADMIN_E_BASE_PARTITION_ONLY
+
+
+This function is valid for the base partition only.
+
+0x80110451
+
+COMADMIN_E_START_APP_DISABLED
+
+
+You cannot start an application that has been disabled.
+
+0x80110457
+
+COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME
+
+
+The specified partition name is already in use on this computer.
+
+0x80110458
+
+COMADMIN_E_CAT_INVALID_PARTITION_NAME
+
+
+The specified partition name is invalid. Check that the name contains at least one visible character.
+
+0x80110459
+
+COMADMIN_E_CAT_PARTITION_IN_USE
+
+
+The partition cannot be deleted because it is the default partition for one or more users.
+
+0x8011045A
+
+COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES
+
+
+The partition cannot be exported because one or more components in the partition have the same file name.
+
+0x8011045B
+
+COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED
+
+
+Applications that contain one or more imported components cannot be installed into a nonbase partition.
+
+0x8011045C
+
+COMADMIN_E_AMBIGUOUS_APPLICATION_NAME
+
+
+The application name is not unique and cannot be resolved to an application ID.
+
+0x8011045D
+
+COMADMIN_E_AMBIGUOUS_PARTITION_NAME
+
+
+The partition name is not unique and cannot be resolved to a partition ID.
+
+0x80110472
+
+COMADMIN_E_REGDB_NOTINITIALIZED
+
+
+The COM+ registry database has not been initialized.
+
+0x80110473
+
+COMADMIN_E_REGDB_NOTOPEN
+
+
+The COM+ registry database is not open.
+
+0x80110474
+
+COMADMIN_E_REGDB_SYSTEMERR
+
+
+The COM+ registry database detected a system error.
+
+0x80110475
+
+COMADMIN_E_REGDB_ALREADYRUNNING
+
+
+The COM+ registry database is already running.
+
+0x80110480
+
+COMADMIN_E_MIG_VERSIONNOTSUPPORTED
+
+
+This version of the COM+ registry database cannot be migrated.
+
+0x80110481
+
+COMADMIN_E_MIG_SCHEMANOTFOUND
+
+
+The schema version to be migrated could not be found in the COM+ registry database.
+
+0x80110482
+
+COMADMIN_E_CAT_BITNESSMISMATCH
+
+
+There was a type mismatch between binaries.
+
+0x80110483
+
+COMADMIN_E_CAT_UNACCEPTABLEBITNESS
+
+
+A binary of unknown or invalid type was provided.
+
+0x80110484
+
+COMADMIN_E_CAT_WRONGAPPBITNESS
+
+
+There was a type mismatch between a binary and an application.
+
+0x80110485
+
+COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED
+
+
+The application cannot be paused or resumed.
+
+0x80110486
+
+COMADMIN_E_CAT_SERVERFAULT
+
+
+The COM+ catalog server threw an exception during execution.
+
+0x80110600
+
+COMQC_E_APPLICATION_NOT_QUEUED
+
+
+Only COM+ applications marked "queued" can be invoked using the "queue" moniker.
+
+0x80110601
+
+COMQC_E_NO_QUEUEABLE_INTERFACES
+
+
+At least one interface must be marked "queued" to create a queued component instance with the "queue" moniker.
+
+0x80110602
+
+COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE
+
+
+Message Queuing is required for the requested operation and is not installed.
+
+0x80110603
+
+COMQC_E_NO_IPERSISTSTREAM
+
+
+Unable to marshal an interface that does not support IPersistStream.
+
+0x80110604
+
+COMQC_E_BAD_MESSAGE
+
+
+The message is improperly formatted or was damaged in transit.
+
+0x80110605
+
+COMQC_E_UNAUTHENTICATED
+
+
+An unauthenticated message was received by an application that accepts only authenticated messages.
+
+0x80110606
+
+COMQC_E_UNTRUSTED_ENQUEUER
+
+
+The message was requeued or moved by a user not in the QC Trusted User "role".
+
+0x80110701
+
+MSDTC_E_DUPLICATE_RESOURCE
+
+
+Cannot create a duplicate resource of type Distributed Transaction Coordinator.
+
+0x80110808
+
+COMADMIN_E_OBJECT_PARENT_MISSING
+
+
+One of the objects being inserted or updated does not belong to a valid parent collection.
+
+0x80110809
+
+COMADMIN_E_OBJECT_DOES_NOT_EXIST
+
+
+One of the specified objects cannot be found.
+
+0x8011080A
+
+COMADMIN_E_APP_NOT_RUNNING
+
+
+The specified application is not currently running.
+
+0x8011080B
+
+COMADMIN_E_INVALID_PARTITION
+
+
+The partitions specified are not valid.
+
+0x8011080D
+
+COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE
+
+
+COM+ applications that run as Windows NT service cannot be pooled or recycled.
+
+0x8011080E
+
+COMADMIN_E_USER_IN_SET
+
+
+One or more users are already assigned to a local partition set.
+
+0x8011080F
+
+COMADMIN_E_CANTRECYCLELIBRARYAPPS
+
+
+Library applications cannot be recycled.
+
+0x80110811
+
+COMADMIN_E_CANTRECYCLESERVICEAPPS
+
+
+Applications running as Windows NT services cannot be recycled.
+
+0x80110812
+
+COMADMIN_E_PROCESSALREADYRECYCLED
+
+
+The process has already been recycled.
+
+0x80110813
+
+COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED
+
+
+A paused process cannot be recycled.
+
+0x80110814
+
+COMADMIN_E_CANTMAKEINPROCSERVICE
+
+
+Library applications cannot be Windows NT services.
+
+0x80110815
+
+COMADMIN_E_PROGIDINUSEBYCLSID
+
+
+The ProgID provided to the copy operation is invalid. The ProgID is in use by another registered CLSID.
+
+0x80110816
+
+COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET
+
+
+The partition specified as the default is not a member of the partition set.
+
+0x80110817
+
+COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED
+
+
+A recycled process cannot be paused.
+
+0x80110818
+
+COMADMIN_E_PARTITION_ACCESSDENIED
+
+
+Access to the specified partition is denied.
+
+0x80110819
+
+COMADMIN_E_PARTITION_MSI_ONLY
+
+
+Only application files (*.msi files) can be installed into partitions.
+
+0x8011081A
+
+COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT
+
+
+Applications containing one or more legacy components cannot be exported to 1.0 format.
+
+0x8011081B
+
+COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS
+
+
+Legacy components cannot exist in nonbase partitions.
+
+0x8011081C
+
+COMADMIN_E_COMP_MOVE_SOURCE
+
+
+A component cannot be moved (or copied) from the System Application, an application proxy, or a nonchangeable application.
+
+0x8011081D
+
+COMADMIN_E_COMP_MOVE_DEST
+
+
+A component cannot be moved (or copied) to the System Application, an application proxy or a nonchangeable application.
+
+0x8011081E
+
+COMADMIN_E_COMP_MOVE_PRIVATE
+
+
+A private component cannot be moved (or copied) to a library application or to the base partition.
+
+0x8011081F
+
+COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET
+
+
+The Base Application Partition exists in all partition sets and cannot be removed.
+
+0x80110820
+
+COMADMIN_E_CANNOT_ALIAS_EVENTCLASS
+
+
+Alas, Event Class components cannot be aliased.
+
+0x80110821
+
+COMADMIN_E_PRIVATE_ACCESSDENIED
+
+
+Access is denied because the component is private.
+
+0x80110822
+
+COMADMIN_E_SAFERINVALID
+
+
+The specified SAFER level is invalid.
+
+0x80110823
+
+COMADMIN_E_REGISTRY_ACCESSDENIED
+
+
+The specified user cannot write to the system registry.
+
+0x80110824
+
+COMADMIN_E_PARTITIONS_DISABLED
+
+
+COM+ partitions are currently disabled.
+
+0x801F0001
+
+ERROR_FLT_NO_HANDLER_DEFINED
+
+
+A handler was not defined by the filter for this operation.
+
+0x801F0002
+
+ERROR_FLT_CONTEXT_ALREADY_DEFINED
+
+
+A context is already defined for this object.
+
+0x801F0003
+
+ERROR_FLT_INVALID_ASYNCHRONOUS_REQUEST
+
+
+Asynchronous requests are not valid for this operation.
+
+0x801F0004
+
+ERROR_FLT_DISALLOW_FAST_IO
+
+
+Disallow the Fast IO path for this operation.
+
+0x801F0005
+
+ERROR_FLT_INVALID_NAME_REQUEST
+
+
+An invalid name request was made. The name requested cannot be retrieved at this time.
+
+0x801F0006
+
+ERROR_FLT_NOT_SAFE_TO_POST_OPERATION
+
+
+Posting this operation to a worker thread for further processing is not safe at this time because it could lead to a system deadlock.
+
+0x801F0007
+
+ERROR_FLT_NOT_INITIALIZED
+
+
+The Filter Manager was not initialized when a filter tried to register. Be sure that the Filter Manager is being loaded as a driver.
+
+0x801F0008
+
+ERROR_FLT_FILTER_NOT_READY
+
+
+The filter is not ready for attachment to volumes because it has not finished initializing (FltStartFiltering has not been called).
+
+0x801F0009
+
+ERROR_FLT_POST_OPERATION_CLEANUP
+
+
+The filter must clean up any operation-specific context at this time because it is being removed from the system before the operation is completed by the lower drivers.
+
+0x801F000A
+
+ERROR_FLT_INTERNAL_ERROR
+
+
+The Filter Manager had an internal error from which it cannot recover; therefore, the operation has been failed. This is usually the result of a filter returning an invalid value from a preoperation callback.
+
+0x801F000B
+
+ERROR_FLT_DELETING_OBJECT
+
+
+The object specified for this action is in the process of being deleted; therefore, the action requested cannot be completed at this time.
+
+0x801F000C
+
+ERROR_FLT_MUST_BE_NONPAGED_POOL
+
+
+Nonpaged pool must be used for this type of context.
+
+0x801F000D
+
+ERROR_FLT_DUPLICATE_ENTRY
+
+
+A duplicate handler definition has been provided for an operation.
+
+0x801F000E
+
+ERROR_FLT_CBDQ_DISABLED
+
+
+The callback data queue has been disabled.
+
+0x801F000F
+
+ERROR_FLT_DO_NOT_ATTACH
+
+
+Do not attach the filter to the volume at this time.
+
+0x801F0010
+
+ERROR_FLT_DO_NOT_DETACH
+
+
+Do not detach the filter from the volume at this time.
+
+0x801F0011
+
+ERROR_FLT_INSTANCE_ALTITUDE_COLLISION
+
+
+An instance already exists at this altitude on the volume specified.
+
+0x801F0012
+
+ERROR_FLT_INSTANCE_NAME_COLLISION
+
+
+An instance already exists with this name on the volume specified.
+
+0x801F0013
+
+ERROR_FLT_FILTER_NOT_FOUND
+
+
+The system could not find the filter specified.
+
+0x801F0014
+
+ERROR_FLT_VOLUME_NOT_FOUND
+
+
+The system could not find the volume specified.
+
+0x801F0015
+
+ERROR_FLT_INSTANCE_NOT_FOUND
+
+
+The system could not find the instance specified.
+
+0x801F0016
+
+ERROR_FLT_CONTEXT_ALLOCATION_NOT_FOUND
+
+
+No registered context allocation definition was found for the given request.
+
+0x801F0017
+
+ERROR_FLT_INVALID_CONTEXT_REGISTRATION
+
+
+An invalid parameter was specified during context registration.
+
+0x801F0018
+
+ERROR_FLT_NAME_CACHE_MISS
+
+
+The name requested was not found in the Filter Manager name cache and could not be retrieved from the file system.
+
+0x801F0019
+
+ERROR_FLT_NO_DEVICE_OBJECT
+
+
+The requested device object does not exist for the given volume.
+
+0x801F001A
+
+ERROR_FLT_VOLUME_ALREADY_MOUNTED
+
+
+The specified volume is already mounted.
+
+0x801F001B
+
+ERROR_FLT_ALREADY_ENLISTED
+
+
+The specified Transaction Context is already enlisted in a transaction.
+
+0x801F001C
+
+ERROR_FLT_CONTEXT_ALREADY_LINKED
+
+
+The specified context is already attached to another object.
+
+0x801F0020
+
+ERROR_FLT_NO_WAITER_FOR_REPLY
+
+
+No waiter is present for the filter's reply to this message.
+
+0x80260001
+
+ERROR_HUNG_DISPLAY_DRIVER_THREAD
+
+
+{Display Driver Stopped Responding} The %hs display driver has stopped working normally. Save your work and reboot the system to restore full display functionality. The next time you reboot the machine a dialog will be displayed giving you a chance to report this failure to Microsoft.
+
+0x80261001
+
+ERROR_MONITOR_NO_DESCRIPTOR
+
+
+Monitor descriptor could not be obtained.
+
+0x80261002
+
+ERROR_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT
+
+
+Format of the obtained monitor descriptor is not supported by this release.
+
+0x80263001
+
+DWM_E_COMPOSITIONDISABLED
+
+
+{Desktop Composition is Disabled} The operation could not be completed because desktop composition is disabled.
+
+0x80263002
+
+DWM_E_REMOTING_NOT_SUPPORTED
+
+
+{Some Desktop Composition APIs Are Not Supported While Remoting} Some desktop composition APIs are not supported while remoting. The operation is not supported while running in a remote session.
+
+0x80263003
+
+DWM_E_NO_REDIRECTION_SURFACE_AVAILABLE
+
+
+{No DWM Redirection Surface is Available} The Desktop Window Manager (DWM) was unable to provide a redirection surface to complete the DirectX present.
+
+0x80263004
+
+DWM_E_NOT_QUEUING_PRESENTS
+
+
+{DWM Is Not Queuing Presents for the Specified Window} The window specified is not currently using queued presents.
+
+0x80280000
+
+TPM_E_ERROR_MASK
+
+
+This is an error mask to convert Trusted Platform Module (TPM) hardware errors to Win32 errors.
+
+0x80280001
+
+TPM_E_AUTHFAIL
+
+
+Authentication failed.
+
+0x80280002
+
+TPM_E_BADINDEX
+
+
+The index to a Platform Configuration Register (PCR), DIR, or other register is incorrect.
+
+0x80280003
+
+TPM_E_BAD_PARAMETER
+
+
+One or more parameters are bad.
+
+0x80280004
+
+TPM_E_AUDITFAILURE
+
+
+An operation completed successfully but the auditing of that operation failed.
+
+0x80280005
+
+TPM_E_CLEAR_DISABLED
+
+
+The clear disable flag is set and all clear operations now require physical access.
+
+0x80280006
+
+TPM_E_DEACTIVATED
+
+
+The TPM is deactivated.
+
+0x80280007
+
+TPM_E_DISABLED
+
+
+The TPM is disabled.
+
+0x80280008
+
+TPM_E_DISABLED_CMD
+
+
+The target command has been disabled.
+
+0x80280009
+
+TPM_E_FAIL
+
+
+The operation failed.
+
+0x8028000A
+
+TPM_E_BAD_ORDINAL
+
+
+The ordinal was unknown or inconsistent.
+
+0x8028000B
+
+TPM_E_INSTALL_DISABLED
+
+
+The ability to install an owner is disabled.
+
+0x8028000C
+
+TPM_E_INVALID_KEYHANDLE
+
+
+The key handle cannot be interpreted.
+
+0x8028000D
+
+TPM_E_KEYNOTFOUND
+
+
+The key handle points to an invalid key.
+
+0x8028000E
+
+TPM_E_INAPPROPRIATE_ENC
+
+
+Unacceptable encryption scheme.
+
+0x8028000F
+
+TPM_E_MIGRATEFAIL
+
+
+Migration authorization failed.
+
+0x80280010
+
+TPM_E_INVALID_PCR_INFO
+
+
+PCR information could not be interpreted.
+
+0x80280011
+
+TPM_E_NOSPACE
+
+
+No room to load key.
+
+0x80280012
+
+TPM_E_NOSRK
+
+
+There is no storage root key (SRK) set.
+
+0x80280013
+
+TPM_E_NOTSEALED_BLOB
+
+
+An encrypted blob is invalid or was not created by this TPM.
+
+0x80280014
+
+TPM_E_OWNER_SET
+
+
+There is already an owner.
+
+0x80280015
+
+TPM_E_RESOURCES
+
+
+The TPM has insufficient internal resources to perform the requested action.
+
+0x80280016
+
+TPM_E_SHORTRANDOM
+
+
+A random string was too short.
+
+0x80280017
+
+TPM_E_SIZE
+
+
+The TPM does not have the space to perform the operation.
+
+0x80280018
+
+TPM_E_WRONGPCRVAL
+
+
+The named PCR value does not match the current PCR value.
+
+0x80280019
+
+TPM_E_BAD_PARAM_SIZE
+
+
+The paramSize argument to the command has the incorrect value.
+
+0x8028001A
+
+TPM_E_SHA_THREAD
+
+
+There is no existing SHA-1 thread.
+
+0x8028001B
+
+TPM_E_SHA_ERROR
+
+
+The calculation is unable to proceed because the existing SHA-1 thread has already encountered an error.
+
+0x8028001C
+
+TPM_E_FAILEDSELFTEST
+
+
+Self-test has failed and the TPM has shut down.
+
+0x8028001D
+
+TPM_E_AUTH2FAIL
+
+
+The authorization for the second key in a two-key function failed authorization.
+
+0x8028001E
+
+TPM_E_BADTAG
+
+
+The tag value sent to for a command is invalid.
+
+0x8028001F
+
+TPM_E_IOERROR
+
+
+An I/O error occurred transmitting information to the TPM.
+
+0x80280020
+
+TPM_E_ENCRYPT_ERROR
+
+
+The encryption process had a problem.
+
+0x80280021
+
+TPM_E_DECRYPT_ERROR
+
+
+The decryption process did not complete.
+
+0x80280022
+
+TPM_E_INVALID_AUTHHANDLE
+
+
+An invalid handle was used.
+
+0x80280023
+
+TPM_E_NO_ENDORSEMENT
+
+
+The TPM does not have an endorsement key (EK) installed.
+
+0x80280024
+
+TPM_E_INVALID_KEYUSAGE
+
+
+The usage of a key is not allowed.
+
+0x80280025
+
+TPM_E_WRONG_ENTITYTYPE
+
+
+The submitted entity type is not allowed.
+
+0x80280026
+
+TPM_E_INVALID_POSTINIT
+
+
+The command was received in the wrong sequence relative to TPM_Init and a subsequent TPM_Startup.
+
+0x80280027
+
+TPM_E_INAPPROPRIATE_SIG
+
+
+Signed data cannot include additional DER information.
+
+0x80280028
+
+TPM_E_BAD_KEY_PROPERTY
+
+
+The key properties in TPM_KEY_PARMs are not supported by this TPM.
+
+0x80280029
+
+TPM_E_BAD_MIGRATION
+
+
+The migration properties of this key are incorrect.
+
+0x8028002A
+
+TPM_E_BAD_SCHEME
+
+
+The signature or encryption scheme for this key is incorrect or not permitted in this situation.
+
+0x8028002B
+
+TPM_E_BAD_DATASIZE
+
+
+The size of the data (or blob) parameter is bad or inconsistent with the referenced key.
+
+0x8028002C
+
+TPM_E_BAD_MODE
+
+
+A mode parameter is bad, such as capArea or subCapArea for TPM_GetCapability, physicalPresence parameter for TPM_PhysicalPresence, or migrationType for TPM_CreateMigrationBlob.
+
+0x8028002D
+
+TPM_E_BAD_PRESENCE
+
+
+Either the physicalPresence or physicalPresenceLock bits have the wrong value.
+
+0x8028002E
+
+TPM_E_BAD_VERSION
+
+
+The TPM cannot perform this version of the capability.
+
+0x8028002F
+
+TPM_E_NO_WRAP_TRANSPORT
+
+
+The TPM does not allow for wrapped transport sessions.
+
+0x80280030
+
+TPM_E_AUDITFAIL_UNSUCCESSFUL
+
+
+TPM audit construction failed and the underlying command was returning a failure code also.
+
+0x80280031
+
+TPM_E_AUDITFAIL_SUCCESSFUL
+
+
+TPM audit construction failed and the underlying command was returning success.
+
+0x80280032
+
+TPM_E_NOTRESETABLE
+
+
+Attempt to reset a PCR that does not have the resettable attribute.
+
+0x80280033
+
+TPM_E_NOTLOCAL
+
+
+Attempt to reset a PCR register that requires locality and the locality modifier not part of command transport.
+
+0x80280034
+
+TPM_E_BAD_TYPE
+
+
+Make identity blob not properly typed.
+
+0x80280035
+
+TPM_E_INVALID_RESOURCE
+
+
+When saving context identified resource type does not match actual resource.
+
+0x80280036
+
+TPM_E_NOTFIPS
+
+
+The TPM is attempting to execute a command only available when in Federal Information Processing Standards (FIPS) mode.
+
+0x80280037
+
+TPM_E_INVALID_FAMILY
+
+
+The command is attempting to use an invalid family ID.
+
+0x80280038
+
+TPM_E_NO_NV_PERMISSION
+
+
+The permission to manipulate the NV storage is not available.
+
+0x80280039
+
+TPM_E_REQUIRES_SIGN
+
+
+The operation requires a signed command.
+
+0x8028003A
+
+TPM_E_KEY_NOTSUPPORTED
+
+
+Wrong operation to load an NV key.
+
+0x8028003B
+
+TPM_E_AUTH_CONFLICT
+
+
+NV_LoadKey blob requires both owner and blob authorization.
+
+0x8028003C
+
+TPM_E_AREA_LOCKED
+
+
+The NV area is locked and not writable.
+
+0x8028003D
+
+TPM_E_BAD_LOCALITY
+
+
+The locality is incorrect for the attempted operation.
+
+0x8028003E
+
+TPM_E_READ_ONLY
+
+
+The NV area is read-only and cannot be written to.
+
+0x8028003F
+
+TPM_E_PER_NOWRITE
+
+
+There is no protection on the write to the NV area.
+
+0x80280040
+
+TPM_E_FAMILYCOUNT
+
+
+The family count value does not match.
+
+0x80280041
+
+TPM_E_WRITE_LOCKED
+
+
+The NV area has already been written to.
+
+0x80280042
+
+TPM_E_BAD_ATTRIBUTES
+
+
+The NV area attributes conflict.
+
+0x80280043
+
+TPM_E_INVALID_STRUCTURE
+
+
+The structure tag and version are invalid or inconsistent.
+
+0x80280044
+
+TPM_E_KEY_OWNER_CONTROL
+
+
+The key is under control of the TPM owner and can only be evicted by the TPM owner.
+
+0x80280045
+
+TPM_E_BAD_COUNTER
+
+
+The counter handle is incorrect.
+
+0x80280046
+
+TPM_E_NOT_FULLWRITE
+
+
+The write is not a complete write of the area.
+
+0x80280047
+
+TPM_E_CONTEXT_GAP
+
+
+The gap between saved context counts is too large.
+
+0x80280048
+
+TPM_E_MAXNVWRITES
+
+
+The maximum number of NV writes without an owner has been exceeded.
+
+0x80280049
+
+TPM_E_NOOPERATOR
+
+
+No operator AuthData value is set.
+
+0x8028004A
+
+TPM_E_RESOURCEMISSING
+
+
+The resource pointed to by context is not loaded.
+
+0x8028004B
+
+TPM_E_DELEGATE_LOCK
+
+
+The delegate administration is locked.
+
+0x8028004C
+
+TPM_E_DELEGATE_FAMILY
+
+
+Attempt to manage a family other then the delegated family.
+
+0x8028004D
+
+TPM_E_DELEGATE_ADMIN
+
+
+Delegation table management not enabled.
+
+0x8028004E
+
+TPM_E_TRANSPORT_NOTEXCLUSIVE
+
+
+There was a command executed outside an exclusive transport session.
+
+0x8028004F
+
+TPM_E_OWNER_CONTROL
+
+
+Attempt to context save an owner evict controlled key.
+
+0x80280050
+
+TPM_E_DAA_RESOURCES
+
+
+The DAA command has no resources available to execute the command.
+
+0x80280051
+
+TPM_E_DAA_INPUT_DATA0
+
+
+The consistency check on DAA parameter inputData0 has failed.
+
+0x80280052
+
+TPM_E_DAA_INPUT_DATA1
+
+
+The consistency check on DAA parameter inputData1 has failed.
+
+0x80280053
+
+TPM_E_DAA_ISSUER_SETTINGS
+
+
+The consistency check on DAA_issuerSettings has failed.
+
+0x80280054
+
+TPM_E_DAA_TPM_SETTINGS
+
+
+The consistency check on DAA_tpmSpecific has failed.
+
+0x80280055
+
+TPM_E_DAA_STAGE
+
+
+The atomic process indicated by the submitted DAA command is not the expected process.
+
+0x80280056
+
+TPM_E_DAA_ISSUER_VALIDITY
+
+
+The issuer's validity check has detected an inconsistency.
+
+0x80280057
+
+TPM_E_DAA_WRONG_W
+
+
+The consistency check on w has failed.
+
+0x80280058
+
+TPM_E_BAD_HANDLE
+
+
+The handle is incorrect.
+
+0x80280059
+
+TPM_E_BAD_DELEGATE
+
+
+Delegation is not correct.
+
+0x8028005A
+
+TPM_E_BADCONTEXT
+
+
+The context blob is invalid.
+
+0x8028005B
+
+TPM_E_TOOMANYCONTEXTS
+
+
+Too many contexts held by the TPM.
+
+0x8028005C
+
+TPM_E_MA_TICKET_SIGNATURE
+
+
+Migration authority signature validation failure.
+
+0x8028005D
+
+TPM_E_MA_DESTINATION
+
+
+Migration destination not authenticated.
+
+0x8028005E
+
+TPM_E_MA_SOURCE
+
+
+Migration source incorrect.
+
+0x8028005F
+
+TPM_E_MA_AUTHORITY
+
+
+Incorrect migration authority.
+
+0x80280061
+
+TPM_E_PERMANENTEK
+
+
+Attempt to revoke the EK and the EK is not revocable.
+
+0x80280062
+
+TPM_E_BAD_SIGNATURE
+
+
+Bad signature of CMK ticket.
+
+0x80280063
+
+TPM_E_NOCONTEXTSPACE
+
+
+There is no room in the context list for additional contexts.
+
+0x80280400
+
+TPM_E_COMMAND_BLOCKED
+
+
+The command was blocked.
+
+0x80280401
+
+TPM_E_INVALID_HANDLE
+
+
+The specified handle was not found.
+
+0x80280402
+
+TPM_E_DUPLICATE_VHANDLE
+
+
+The TPM returned a duplicate handle and the command needs to be resubmitted.
+
+0x80280403
+
+TPM_E_EMBEDDED_COMMAND_BLOCKED
+
+
+The command within the transport was blocked.
+
+0x80280404
+
+TPM_E_EMBEDDED_COMMAND_UNSUPPORTED
+
+
+The command within the transport is not supported.
+
+0x80280800
+
+TPM_E_RETRY
+
+
+The TPM is too busy to respond to the command immediately, but the command could be resubmitted at a later time.
+
+0x80280801
+
+TPM_E_NEEDS_SELFTEST
+
+
+SelfTestFull has not been run.
+
+0x80280802
+
+TPM_E_DOING_SELFTEST
+
+
+The TPM is currently executing a full self-test.
+
+0x80280803
+
+TPM_E_DEFEND_LOCK_RUNNING
+
+
+The TPM is defending against dictionary attacks and is in a time-out period.
+
+0x80284001
+
+TBS_E_INTERNAL_ERROR
+
+
+An internal software error has been detected.
+
+0x80284002
+
+TBS_E_BAD_PARAMETER
+
+
+One or more input parameters are bad.
+
+0x80284003
+
+TBS_E_INVALID_OUTPUT_POINTER
+
+
+A specified output pointer is bad.
+
+0x80284004
+
+TBS_E_INVALID_CONTEXT
+
+
+The specified context handle does not refer to a valid context.
+
+0x80284005
+
+TBS_E_INSUFFICIENT_BUFFER
+
+
+A specified output buffer is too small.
+
+0x80284006
+
+TBS_E_IOERROR
+
+
+An error occurred while communicating with the TPM.
+
+0x80284007
+
+TBS_E_INVALID_CONTEXT_PARAM
+
+
+One or more context parameters are invalid.
+
+0x80284008
+
+TBS_E_SERVICE_NOT_RUNNING
+
+
+The TPM Base Services (TBS) is not running and could not be started.
+
+0x80284009
+
+TBS_E_TOO_MANY_TBS_CONTEXTS
+
+
+A new context could not be created because there are too many open contexts.
+
+0x8028400A
+
+TBS_E_TOO_MANY_RESOURCES
+
+
+A new virtual resource could not be created because there are too many open virtual resources.
+
+0x8028400B
+
+TBS_E_SERVICE_START_PENDING
+
+
+The TBS service has been started but is not yet running.
+
+0x8028400C
+
+TBS_E_PPI_NOT_SUPPORTED
+
+
+The physical presence interface is not supported.
+
+0x8028400D
+
+TBS_E_COMMAND_CANCELED
+
+
+The command was canceled.
+
+0x8028400E
+
+TBS_E_BUFFER_TOO_LARGE
+
+
+The input or output buffer is too large.
+
+0x80290100
+
+TPMAPI_E_INVALID_STATE
+
+
+The command buffer is not in the correct state.
+
+0x80290101
+
+TPMAPI_E_NOT_ENOUGH_DATA
+
+
+The command buffer does not contain enough data to satisfy the request.
+
+0x80290102
+
+TPMAPI_E_TOO_MUCH_DATA
+
+
+The command buffer cannot contain any more data.
+
+0x80290103
+
+TPMAPI_E_INVALID_OUTPUT_POINTER
+
+
+One or more output parameters was null or invalid.
+
+0x80290104
+
+TPMAPI_E_INVALID_PARAMETER
+
+
+One or more input parameters are invalid.
+
+0x80290105
+
+TPMAPI_E_OUT_OF_MEMORY
+
+
+Not enough memory was available to satisfy the request.
+
+0x80290106
+
+TPMAPI_E_BUFFER_TOO_SMALL
+
+
+The specified buffer was too small.
+
+0x80290107
+
+TPMAPI_E_INTERNAL_ERROR
+
+
+An internal error was detected.
+
+0x80290108
+
+TPMAPI_E_ACCESS_DENIED
+
+
+The caller does not have the appropriate rights to perform the requested operation.
+
+0x80290109
+
+TPMAPI_E_AUTHORIZATION_FAILED
+
+
+The specified authorization information was invalid.
+
+0x8029010A
+
+TPMAPI_E_INVALID_CONTEXT_HANDLE
+
+
+The specified context handle was not valid.
+
+0x8029010B
+
+TPMAPI_E_TBS_COMMUNICATION_ERROR
+
+
+An error occurred while communicating with the TBS.
+
+0x8029010C
+
+TPMAPI_E_TPM_COMMAND_ERROR
+
+
+The TPM returned an unexpected result.
+
+0x8029010D
+
+TPMAPI_E_MESSAGE_TOO_LARGE
+
+
+The message was too large for the encoding scheme.
+
+0x8029010E
+
+TPMAPI_E_INVALID_ENCODING
+
+
+The encoding in the binary large object (BLOB) was not recognized.
+
+0x8029010F
+
+TPMAPI_E_INVALID_KEY_SIZE
+
+
+The key size is not valid.
+
+0x80290110
+
+TPMAPI_E_ENCRYPTION_FAILED
+
+
+The encryption operation failed.
+
+0x80290111
+
+TPMAPI_E_INVALID_KEY_PARAMS
+
+
+The key parameters structure was not valid.
+
+0x80290112
+
+TPMAPI_E_INVALID_MIGRATION_AUTHORIZATION_BLOB
+
+
+The requested supplied data does not appear to be a valid migration authorization BLOB.
+
+0x80290113
+
+TPMAPI_E_INVALID_PCR_INDEX
+
+
+The specified PCR index was invalid.
+
+0x80290114
+
+TPMAPI_E_INVALID_DELEGATE_BLOB
+
+
+The data given does not appear to be a valid delegate BLOB.
+
+0x80290115
+
+TPMAPI_E_INVALID_CONTEXT_PARAMS
+
+
+One or more of the specified context parameters was not valid.
+
+0x80290116
+
+TPMAPI_E_INVALID_KEY_BLOB
+
+
+The data given does not appear to be a valid key BLOB.
+
+0x80290117
+
+TPMAPI_E_INVALID_PCR_DATA
+
+
+The specified PCR data was invalid.
+
+0x80290118
+
+TPMAPI_E_INVALID_OWNER_AUTH
+
+
+The format of the owner authorization data was invalid.
+
+0x80290200
+
+TBSIMP_E_BUFFER_TOO_SMALL
+
+
+The specified buffer was too small.
+
+0x80290201
+
+TBSIMP_E_CLEANUP_FAILED
+
+
+The context could not be cleaned up.
+
+0x80290202
+
+TBSIMP_E_INVALID_CONTEXT_HANDLE
+
+
+The specified context handle is invalid.
+
+0x80290203
+
+TBSIMP_E_INVALID_CONTEXT_PARAM
+
+
+An invalid context parameter was specified.
+
+0x80290204
+
+TBSIMP_E_TPM_ERROR
+
+
+An error occurred while communicating with the TPM.
+
+0x80290205
+
+TBSIMP_E_HASH_BAD_KEY
+
+
+No entry with the specified key was found.
+
+0x80290206
+
+TBSIMP_E_DUPLICATE_VHANDLE
+
+
+The specified virtual handle matches a virtual handle already in use.
+
+0x80290207
+
+TBSIMP_E_INVALID_OUTPUT_POINTER
+
+
+The pointer to the returned handle location was null or invalid.
+
+0x80290208
+
+TBSIMP_E_INVALID_PARAMETER
+
+
+One or more parameters are invalid.
+
+0x80290209
+
+TBSIMP_E_RPC_INIT_FAILED
+
+
+The RPC subsystem could not be initialized.
+
+0x8029020A
+
+TBSIMP_E_SCHEDULER_NOT_RUNNING
+
+
+The TBS scheduler is not running.
+
+0x8029020B
+
+TBSIMP_E_COMMAND_CANCELED
+
+
+The command was canceled.
+
+0x8029020C
+
+TBSIMP_E_OUT_OF_MEMORY
+
+
+There was not enough memory to fulfill the request.
+
+0x8029020D
+
+TBSIMP_E_LIST_NO_MORE_ITEMS
+
+
+The specified list is empty, or the iteration has reached the end of the list.
+
+0x8029020E
+
+TBSIMP_E_LIST_NOT_FOUND
+
+
+The specified item was not found in the list.
+
+0x8029020F
+
+TBSIMP_E_NOT_ENOUGH_SPACE
+
+
+The TPM does not have enough space to load the requested resource.
+
+0x80290210
+
+TBSIMP_E_NOT_ENOUGH_TPM_CONTEXTS
+
+
+There are too many TPM contexts in use.
+
+0x80290211
+
+TBSIMP_E_COMMAND_FAILED
+
+
+The TPM command failed.
+
+0x80290212
+
+TBSIMP_E_UNKNOWN_ORDINAL
+
+
+The TBS does not recognize the specified ordinal.
+
+0x80290213
+
+TBSIMP_E_RESOURCE_EXPIRED
+
+
+The requested resource is no longer available.
+
+0x80290214
+
+TBSIMP_E_INVALID_RESOURCE
+
+
+The resource type did not match.
+
+0x80290215
+
+TBSIMP_E_NOTHING_TO_UNLOAD
+
+
+No resources can be unloaded.
+
+0x80290216
+
+TBSIMP_E_HASH_TABLE_FULL
+
+
+No new entries can be added to the hash table.
+
+0x80290217
+
+TBSIMP_E_TOO_MANY_TBS_CONTEXTS
+
+
+A new TBS context could not be created because there are too many open contexts.
+
+0x80290218
+
+TBSIMP_E_TOO_MANY_RESOURCES
+
+
+A new virtual resource could not be created because there are too many open virtual resources.
+
+0x80290219
+
+TBSIMP_E_PPI_NOT_SUPPORTED
+
+
+The physical presence interface is not supported.
+
+0x8029021A
+
+TBSIMP_E_TPM_INCOMPATIBLE
+
+
+TBS is not compatible with the version of TPM found on the system.
+
+0x80290300
+
+TPM_E_PPI_ACPI_FAILURE
+
+
+A general error was detected when attempting to acquire the BIOS response to a physical presence command.
+
+0x80290301
+
+TPM_E_PPI_USER_ABORT
+
+
+The user failed to confirm the TPM operation request.
+
+0x80290302
+
+TPM_E_PPI_BIOS_FAILURE
+
+
+The BIOS failure prevented the successful execution of the requested TPM operation (for example, invalid TPM operation request, BIOS communication error with the TPM).
+
+0x80290303
+
+TPM_E_PPI_NOT_SUPPORTED
+
+
+The BIOS does not support the physical presence interface.
+
+0x80300002
+
+PLA_E_DCS_NOT_FOUND
+
+
+A Data Collector Set was not found.
+
+0x80300045
+
+PLA_E_TOO_MANY_FOLDERS
+
+
+Unable to start Data Collector Set because there are too many folders.
+
+0x80300070
+
+PLA_E_NO_MIN_DISK
+
+
+Not enough free disk space to start Data Collector Set.
+
+0x803000AA
+
+PLA_E_DCS_IN_USE
+
+
+Data Collector Set is in use.
+
+0x803000B7
+
+PLA_E_DCS_ALREADY_EXISTS
+
+
+Data Collector Set already exists.
+
+0x80300101
+
+PLA_E_PROPERTY_CONFLICT
+
+
+Property value conflict.
+
+0x80300102
+
+PLA_E_DCS_SINGLETON_REQUIRED
+
+
+The current configuration for this Data Collector Set requires that it contain exactly one Data Collector.
+
+0x80300103
+
+PLA_E_CREDENTIALS_REQUIRED
+
+
+A user account is required to commit the current Data Collector Set properties.
+
+0x80300104
+
+PLA_E_DCS_NOT_RUNNING
+
+
+Data Collector Set is not running.
+
+0x80300105
+
+PLA_E_CONFLICT_INCL_EXCL_API
+
+
+A conflict was detected in the list of include and exclude APIs. Do not specify the same API in both the include list and the exclude list.
+
+0x80300106
+
+PLA_E_NETWORK_EXE_NOT_VALID
+
+
+The executable path specified refers to a network share or UNC path.
+
+0x80300107
+
+PLA_E_EXE_ALREADY_CONFIGURED
+
+
+The executable path specified is already configured for API tracing.
+
+0x80300108
+
+PLA_E_EXE_PATH_NOT_VALID
+
+
+The executable path specified does not exist. Verify that the specified path is correct.
+
+0x80300109
+
+PLA_E_DC_ALREADY_EXISTS
+
+
+Data Collector already exists.
+
+0x8030010A
+
+PLA_E_DCS_START_WAIT_TIMEOUT
+
+
+The wait for the Data Collector Set start notification has timed out.
+
+0x8030010B
+
+PLA_E_DC_START_WAIT_TIMEOUT
+
+
+The wait for the Data Collector to start has timed out.
+
+0x8030010C
+
+PLA_E_REPORT_WAIT_TIMEOUT
+
+
+The wait for the report generation tool to finish has timed out.
+
+0x8030010D
+
+PLA_E_NO_DUPLICATES
+
+
+Duplicate items are not allowed.
+
+0x8030010E
+
+PLA_E_EXE_FULL_PATH_REQUIRED
+
+
+When specifying the executable to trace, you must specify a full path to the executable and not just a file name.
+
+0x8030010F
+
+PLA_E_INVALID_SESSION_NAME
+
+
+The session name provided is invalid.
+
+0x80300110
+
+PLA_E_PLA_CHANNEL_NOT_ENABLED
+
+
+The Event Log channel Microsoft-Windows-Diagnosis-PLA/Operational must be enabled to perform this operation.
+
+0x80300111
+
+PLA_E_TASKSCHED_CHANNEL_NOT_ENABLED
+
+
+The Event Log channel Microsoft-Windows-TaskScheduler must be enabled to perform this operation.
+
+0x80310000
+
+FVE_E_LOCKED_VOLUME
+
+
+The volume must be unlocked before it can be used.
+
+0x80310001
+
+FVE_E_NOT_ENCRYPTED
+
+
+The volume is fully decrypted and no key is available.
+
+0x80310002
+
+FVE_E_NO_TPM_BIOS
+
+
+The firmware does not support using a TPM during boot.
+
+0x80310003
+
+FVE_E_NO_MBR_METRIC
+
+
+The firmware does not use a TPM to perform initial program load (IPL) measurement.
+
+0x80310004
+
+FVE_E_NO_BOOTSECTOR_METRIC
+
+
+The master boot record (MBR) is not TPM-aware.
+
+0x80310005
+
+FVE_E_NO_BOOTMGR_METRIC
+
+
+The BOOTMGR is not being measured by the TPM.
+
+0x80310006
+
+FVE_E_WRONG_BOOTMGR
+
+
+The BOOTMGR component does not perform expected TPM measurements.
+
+0x80310007
+
+FVE_E_SECURE_KEY_REQUIRED
+
+
+No secure key protection mechanism has been defined.
+
+0x80310008
+
+FVE_E_NOT_ACTIVATED
+
+
+This volume has not been provisioned for encryption.
+
+0x80310009
+
+FVE_E_ACTION_NOT_ALLOWED
+
+
+Requested action was denied by the full-volume encryption (FVE) control engine.
+
+0x8031000A
+
+FVE_E_AD_SCHEMA_NOT_INSTALLED
+
+
+The Active Directory forest does not contain the required attributes and classes to host FVE or TPM information.
+
+0x8031000B
+
+FVE_E_AD_INVALID_DATATYPE
+
+
+The type of data obtained from Active Directory was not expected.
+
+0x8031000C
+
+FVE_E_AD_INVALID_DATASIZE
+
+
+The size of the data obtained from Active Directory was not expected.
+
+0x8031000D
+
+FVE_E_AD_NO_VALUES
+
+
+The attribute read from Active Directory has no (zero) values.
+
+0x8031000E
+
+FVE_E_AD_ATTR_NOT_SET
+
+
+The attribute was not set.
+
+0x8031000F
+
+FVE_E_AD_GUID_NOT_FOUND
+
+
+The specified GUID could not be found.
+
+0x80310010
+
+FVE_E_BAD_INFORMATION
+
+
+The control block for the encrypted volume is not valid.
+
+0x80310011
+
+FVE_E_TOO_SMALL
+
+
+Not enough free space remaining on volume to allow encryption.
+
+0x80310012
+
+FVE_E_SYSTEM_VOLUME
+
+
+The volume cannot be encrypted because it is required to boot the operating system.
+
+0x80310013
+
+FVE_E_FAILED_WRONG_FS
+
+
+The volume cannot be encrypted because the file system is not supported.
+
+0x80310014
+
+FVE_E_FAILED_BAD_FS
+
+
+The file system is inconsistent. Run CHKDSK.
+
+0x80310015
+
+FVE_E_NOT_SUPPORTED
+
+
+This volume cannot be encrypted.
+
+0x80310016
+
+FVE_E_BAD_DATA
+
+
+Data supplied is malformed.
+
+0x80310017
+
+FVE_E_VOLUME_NOT_BOUND
+
+
+Volume is not bound to the system.
+
+0x80310018
+
+FVE_E_TPM_NOT_OWNED
+
+
+TPM must be owned before a volume can be bound to it.
+
+0x80310019
+
+FVE_E_NOT_DATA_VOLUME
+
+
+The volume specified is not a data volume.
+
+0x8031001A
+
+FVE_E_AD_INSUFFICIENT_BUFFER
+
+
+The buffer supplied to a function was insufficient to contain the returned data.
+
+0x8031001B
+
+FVE_E_CONV_READ
+
+
+A read operation failed while converting the volume.
+
+0x8031001C
+
+FVE_E_CONV_WRITE
+
+
+A write operation failed while converting the volume.
+
+0x8031001D
+
+FVE_E_KEY_REQUIRED
+
+
+One or more key protection mechanisms are required for this volume.
+
+0x8031001E
+
+FVE_E_CLUSTERING_NOT_SUPPORTED
+
+
+Cluster configurations are not supported.
+
+0x8031001F
+
+FVE_E_VOLUME_BOUND_ALREADY
+
+
+The volume is already bound to the system.
+
+0x80310020
+
+FVE_E_OS_NOT_PROTECTED
+
+
+The boot OS volume is not being protected via FVE.
+
+0x80310021
+
+FVE_E_PROTECTION_DISABLED
+
+
+All protection mechanisms are effectively disabled (clear key exists).
+
+0x80310022
+
+FVE_E_RECOVERY_KEY_REQUIRED
+
+
+A recovery key protection mechanism is required.
+
+0x80310023
+
+FVE_E_FOREIGN_VOLUME
+
+
+This volume cannot be bound to a TPM.
+
+0x80310024
+
+FVE_E_OVERLAPPED_UPDATE
+
+
+The control block for the encrypted volume was updated by another thread. Try again.
+
+0x80310025
+
+FVE_E_TPM_SRK_AUTH_NOT_ZERO
+
+
+The SRK authentication of the TPM is not zero and, therefore, is not compatible.
+
+0x80310026
+
+FVE_E_FAILED_SECTOR_SIZE
+
+
+The volume encryption algorithm cannot be used on this sector size.
+
+0x80310027
+
+FVE_E_FAILED_AUTHENTICATION
+
+
+BitLocker recovery authentication failed.
+
+0x80310028
+
+FVE_E_NOT_OS_VOLUME
+
+
+The volume specified is not the boot OS volume.
+
+0x80310029
+
+FVE_E_AUTOUNLOCK_ENABLED
+
+
+Auto-unlock information for data volumes is present on the boot OS volume.
+
+0x8031002A
+
+FVE_E_WRONG_BOOTSECTOR
+
+
+The system partition boot sector does not perform TPM measurements.
+
+0x8031002B
+
+FVE_E_WRONG_SYSTEM_FS
+
+
+The system partition file system must be NTFS.
+
+0x8031002C
+
+FVE_E_POLICY_PASSWORD_REQUIRED
+
+
+Group policy requires a recovery password before encryption can begin.
+
+0x8031002D
+
+FVE_E_CANNOT_SET_FVEK_ENCRYPTED
+
+
+The volume encryption algorithm and key cannot be set on an encrypted volume.
+
+0x8031002E
+
+FVE_E_CANNOT_ENCRYPT_NO_KEY
+
+
+A key must be specified before encryption can begin.
+
+0x80310030
+
+FVE_E_BOOTABLE_CDDVD
+
+
+A bootable CD/DVD is in the system. Remove the CD/DVD and reboot the system.
+
+0x80310031
+
+FVE_E_PROTECTOR_EXISTS
+
+
+An instance of this key protector already exists on the volume.
+
+0x80310032
+
+FVE_E_RELATIVE_PATH
+
+
+The file cannot be saved to a relative path.
+
+0x80320001
+
+FWP_E_CALLOUT_NOT_FOUND
+
+
+The callout does not exist.
+
+0x80320002
+
+FWP_E_CONDITION_NOT_FOUND
+
+
+The filter condition does not exist.
+
+0x80320003
+
+FWP_E_FILTER_NOT_FOUND
+
+
+The filter does not exist.
+
+0x80320004
+
+FWP_E_LAYER_NOT_FOUND
+
+
+The layer does not exist.
+
+0x80320005
+
+FWP_E_PROVIDER_NOT_FOUND
+
+
+The provider does not exist.
+
+0x80320006
+
+FWP_E_PROVIDER_CONTEXT_NOT_FOUND
+
+
+The provider context does not exist.
+
+0x80320007
+
+FWP_E_SUBLAYER_NOT_FOUND
+
+
+The sublayer does not exist.
+
+0x80320008
+
+FWP_E_NOT_FOUND
+
+
+The object does not exist.
+
+0x80320009
+
+FWP_E_ALREADY_EXISTS
+
+
+An object with that GUID or LUID already exists.
+
+0x8032000A
+
+FWP_E_IN_USE
+
+
+The object is referenced by other objects and, therefore, cannot be deleted.
+
+0x8032000B
+
+FWP_E_DYNAMIC_SESSION_IN_PROGRESS
+
+
+The call is not allowed from within a dynamic session.
+
+0x8032000C
+
+FWP_E_WRONG_SESSION
+
+
+The call was made from the wrong session and, therefore, cannot be completed.
+
+0x8032000D
+
+FWP_E_NO_TXN_IN_PROGRESS
+
+
+The call must be made from within an explicit transaction.
+
+0x8032000E
+
+FWP_E_TXN_IN_PROGRESS
+
+
+The call is not allowed from within an explicit transaction.
+
+0x8032000F
+
+FWP_E_TXN_ABORTED
+
+
+The explicit transaction has been forcibly canceled.
+
+0x80320010
+
+FWP_E_SESSION_ABORTED
+
+
+The session has been canceled.
+
+0x80320011
+
+FWP_E_INCOMPATIBLE_TXN
+
+
+The call is not allowed from within a read-only transaction.
+
+0x80320012
+
+FWP_E_TIMEOUT
+
+
+The call timed out while waiting to acquire the transaction lock.
+
+0x80320013
+
+FWP_E_NET_EVENTS_DISABLED
+
+
+Collection of network diagnostic events is disabled.
+
+0x80320014
+
+FWP_E_INCOMPATIBLE_LAYER
+
+
+The operation is not supported by the specified layer.
+
+0x80320015
+
+FWP_E_KM_CLIENTS_ONLY
+
+
+The call is allowed for kernel-mode callers only.
+
+0x80320016
+
+FWP_E_LIFETIME_MISMATCH
+
+
+The call tried to associate two objects with incompatible lifetimes.
+
+0x80320017
+
+FWP_E_BUILTIN_OBJECT
+
+
+The object is built in and, therefore, cannot be deleted.
+
+0x80320018
+
+FWP_E_TOO_MANY_BOOTTIME_FILTERS
+
+
+The maximum number of boot-time filters has been reached.
+
+0x80320019
+
+FWP_E_NOTIFICATION_DROPPED
+
+
+A notification could not be delivered because a message queue is at its maximum capacity.
+
+0x8032001A
+
+FWP_E_TRAFFIC_MISMATCH
+
+
+The traffic parameters do not match those for the security association context.
+
+0x8032001B
+
+FWP_E_INCOMPATIBLE_SA_STATE
+
+
+The call is not allowed for the current security association state.
+
+0x8032001C
+
+FWP_E_NULL_POINTER
+
+
+A required pointer is null.
+
+0x8032001D
+
+FWP_E_INVALID_ENUMERATOR
+
+
+An enumerator is not valid.
+
+0x8032001E
+
+FWP_E_INVALID_FLAGS
+
+
+The flags field contains an invalid value.
+
+0x8032001F
+
+FWP_E_INVALID_NET_MASK
+
+
+A network mask is not valid.
+
+0x80320020
+
+FWP_E_INVALID_RANGE
+
+
+An FWP_RANGE is not valid.
+
+0x80320021
+
+FWP_E_INVALID_INTERVAL
+
+
+The time interval is not valid.
+
+0x80320022
+
+FWP_E_ZERO_LENGTH_ARRAY
+
+
+An array that must contain at least one element that is zero-length.
+
+0x80320023
+
+FWP_E_NULL_DISPLAY_NAME
+
+
+The displayData.name field cannot be null.
+
+0x80320024
+
+FWP_E_INVALID_ACTION_TYPE
+
+
+The action type is not one of the allowed action types for a filter.
+
+0x80320025
+
+FWP_E_INVALID_WEIGHT
+
+
+The filter weight is not valid.
+
+0x80320026
+
+FWP_E_MATCH_TYPE_MISMATCH
+
+
+A filter condition contains a match type that is not compatible with the operands.
+
+0x80320027
+
+FWP_E_TYPE_MISMATCH
+
+
+An FWP_VALUE or FWPM_CONDITION_VALUE is of the wrong type.
+
+0x80320028
+
+FWP_E_OUT_OF_BOUNDS
+
+
+An integer value is outside the allowed range.
+
+0x80320029
+
+FWP_E_RESERVED
+
+
+A reserved field is nonzero.
+
+0x8032002A
+
+FWP_E_DUPLICATE_CONDITION
+
+
+A filter cannot contain multiple conditions operating on a single field.
+
+0x8032002B
+
+FWP_E_DUPLICATE_KEYMOD
+
+
+A policy cannot contain the same keying module more than once.
+
+0x8032002C
+
+FWP_E_ACTION_INCOMPATIBLE_WITH_LAYER
+
+
+The action type is not compatible with the layer.
+
+0x8032002D
+
+FWP_E_ACTION_INCOMPATIBLE_WITH_SUBLAYER
+
+
+The action type is not compatible with the sublayer.
+
+0x8032002E
+
+FWP_E_CONTEXT_INCOMPATIBLE_WITH_LAYER
+
+
+The raw context or the provider context is not compatible with the layer.
+
+0x8032002F
+
+FWP_E_CONTEXT_INCOMPATIBLE_WITH_CALLOUT
+
+
+The raw context or the provider context is not compatible with the callout.
+
+0x80320030
+
+FWP_E_INCOMPATIBLE_AUTH_METHOD
+
+
+The authentication method is not compatible with the policy type.
+
+0x80320031
+
+FWP_E_INCOMPATIBLE_DH_GROUP
+
+
+The Diffie-Hellman group is not compatible with the policy type.
+
+0x80320032
+
+FWP_E_EM_NOT_SUPPORTED
+
+
+An Internet Key Exchange (IKE) policy cannot contain an Extended Mode policy.
+
+0x80320033
+
+FWP_E_NEVER_MATCH
+
+
+The enumeration template or subscription will never match any objects.
+
+0x80320034
+
+FWP_E_PROVIDER_CONTEXT_MISMATCH
+
+
+The provider context is of the wrong type.
+
+0x80320035
+
+FWP_E_INVALID_PARAMETER
+
+
+The parameter is incorrect.
+
+0x80320036
+
+FWP_E_TOO_MANY_SUBLAYERS
+
+
+The maximum number of sublayers has been reached.
+
+0x80320037
+
+FWP_E_CALLOUT_NOTIFICATION_FAILED
+
+
+The notification function for a callout returned an error.
+
+0x80320038
+
+FWP_E_INCOMPATIBLE_AUTH_CONFIG
+
+
+The IPsec authentication configuration is not compatible with the authentication type.
+
+0x80320039
+
+FWP_E_INCOMPATIBLE_CIPHER_CONFIG
+
+
+The IPsec cipher configuration is not compatible with the cipher type.
+
+0x80340002
+
+ERROR_NDIS_INTERFACE_CLOSING
+
+
+The binding to the network interface is being closed.
+
+0x80340004
+
+ERROR_NDIS_BAD_VERSION
+
+
+An invalid version was specified.
+
+0x80340005
+
+ERROR_NDIS_BAD_CHARACTERISTICS
+
+
+An invalid characteristics table was used.
+
+0x80340006
+
+ERROR_NDIS_ADAPTER_NOT_FOUND
+
+
+Failed to find the network interface, or the network interface is not ready.
+
+0x80340007
+
+ERROR_NDIS_OPEN_FAILED
+
+
+Failed to open the network interface.
+
+0x80340008
+
+ERROR_NDIS_DEVICE_FAILED
+
+
+The network interface has encountered an internal unrecoverable failure.
+
+0x80340009
+
+ERROR_NDIS_MULTICAST_FULL
+
+
+The multicast list on the network interface is full.
+
+0x8034000A
+
+ERROR_NDIS_MULTICAST_EXISTS
+
+
+An attempt was made to add a duplicate multicast address to the list.
+
+0x8034000B
+
+ERROR_NDIS_MULTICAST_NOT_FOUND
+
+
+At attempt was made to remove a multicast address that was never added.
+
+0x8034000C
+
+ERROR_NDIS_REQUEST_ABORTED
+
+
+The network interface aborted the request.
+
+0x8034000D
+
+ERROR_NDIS_RESET_IN_PROGRESS
+
+
+The network interface cannot process the request because it is being reset.
+
+0x8034000F
+
+ERROR_NDIS_INVALID_PACKET
+
+
+An attempt was made to send an invalid packet on a network interface.
+
+0x80340010
+
+ERROR_NDIS_INVALID_DEVICE_REQUEST
+
+
+The specified request is not a valid operation for the target device.
+
+0x80340011
+
+ERROR_NDIS_ADAPTER_NOT_READY
+
+
+The network interface is not ready to complete this operation.
+
+0x80340014
+
+ERROR_NDIS_INVALID_LENGTH
+
+
+The length of the buffer submitted for this operation is not valid.
+
+0x80340015
+
+ERROR_NDIS_INVALID_DATA
+
+
+The data used for this operation is not valid.
+
+0x80340016
+
+ERROR_NDIS_BUFFER_TOO_SHORT
+
+
+The length of the buffer submitted for this operation is too small.
+
+0x80340017
+
+ERROR_NDIS_INVALID_OID
+
+
+The network interface does not support this OID.
+
+0x80340018
+
+ERROR_NDIS_ADAPTER_REMOVED
+
+
+The network interface has been removed.
+
+0x80340019
+
+ERROR_NDIS_UNSUPPORTED_MEDIA
+
+
+The network interface does not support this media type.
+
+0x8034001A
+
+ERROR_NDIS_GROUP_ADDRESS_IN_USE
+
+
+An attempt was made to remove a token ring group address that is in use by other components.
+
+0x8034001B
+
+ERROR_NDIS_FILE_NOT_FOUND
+
+
+An attempt was made to map a file that cannot be found.
+
+0x8034001C
+
+ERROR_NDIS_ERROR_READING_FILE
+
+
+An error occurred while the NDIS tried to map the file.
+
+0x8034001D
+
+ERROR_NDIS_ALREADY_MAPPED
+
+
+An attempt was made to map a file that is already mapped.
+
+0x8034001E
+
+ERROR_NDIS_RESOURCE_CONFLICT
+
+
+An attempt to allocate a hardware resource failed because the resource is used by another component.
+
+0x8034001F
+
+ERROR_NDIS_MEDIA_DISCONNECTED
+
+
+The I/O operation failed because network media is disconnected or the wireless access point is out of range.
+
+0x80340022
+
+ERROR_NDIS_INVALID_ADDRESS
+
+
+The network address used in the request is invalid.
+
+0x8034002A
+
+ERROR_NDIS_PAUSED
+
+
+The offload operation on the network interface has been paused.
+
+0x8034002B
+
+ERROR_NDIS_INTERFACE_NOT_FOUND
+
+
+The network interface was not found.
+
+0x8034002C
+
+ERROR_NDIS_UNSUPPORTED_REVISION
+
+
+The revision number specified in the structure is not supported.
+
+0x8034002D
+
+ERROR_NDIS_INVALID_PORT
+
+
+The specified port does not exist on this network interface.
+
+0x8034002E
+
+ERROR_NDIS_INVALID_PORT_STATE
+
+
+The current state of the specified port on this network interface does not support the requested operation.
+
+0x803400BB
+
+ERROR_NDIS_NOT_SUPPORTED
+
+
+The network interface does not support this request.
+
+0x80342000
+
+ERROR_NDIS_DOT11_AUTO_CONFIG_ENABLED
+
+
+The wireless local area network (LAN) interface is in auto-configuration mode and does not support the requested parameter change operation.
+
+0x80342001
+
+ERROR_NDIS_DOT11_MEDIA_IN_USE
+
+
+The wireless LAN interface is busy and cannot perform the requested operation.
+
+0x80342002
+
+ERROR_NDIS_DOT11_POWER_STATE_INVALID
+
+
+The wireless LAN interface is shutting down and does not support the requested operation.
+
+0x8DEAD01B
+
+TRK_E_NOT_FOUND
+
+
+A requested object was not found.
+
+0x8DEAD01C
+
+TRK_E_VOLUME_QUOTA_EXCEEDED
+
+
+The server received a CREATE_VOLUME subrequest of a SYNC_VOLUMES request, but the ServerVolumeTable size limit for the RequestMachine has already been reached.
+
+0x8DEAD01E
+
+TRK_SERVER_TOO_BUSY
+
+
+The server is busy, and the client should retry the request at a later time.
+
+0xC0090001
+
+ERROR_AUDITING_DISABLED
+
+
+The specified event is currently not being audited.
+
+0xC0090002
+
+ERROR_ALL_SIDS_FILTERED
+
+
+The SID filtering operation removed all SIDs.
+
+0xC0090003
+
+ERROR_BIZRULES_NOT_ENABLED
+
+
+Business rule scripts are disabled for the calling application.
+
+0xC00D0005
+
+NS_E_NOCONNECTION
+
+
+There is no connection established with the Windows Media server. The operation failed.
+
+0xC00D0006
+
+NS_E_CANNOTCONNECT
+
+
+Unable to establish a connection to the server.
+
+0xC00D0007
+
+NS_E_CANNOTDESTROYTITLE
+
+
+Unable to destroy the title.
+
+0xC00D0008
+
+NS_E_CANNOTRENAMETITLE
+
+
+Unable to rename the title.
+
+0xC00D0009
+
+NS_E_CANNOTOFFLINEDISK
+
+
+Unable to offline disk.
+
+0xC00D000A
+
+NS_E_CANNOTONLINEDISK
+
+
+Unable to online disk.
+
+0xC00D000B
+
+NS_E_NOREGISTEREDWALKER
+
+
+There is no file parser registered for this type of file.
+
+0xC00D000C
+
+NS_E_NOFUNNEL
+
+
+There is no data connection established.
+
+0xC00D000D
+
+NS_E_NO_LOCALPLAY
+
+
+Failed to load the local play DLL.
+
+0xC00D000E
+
+NS_E_NETWORK_BUSY
+
+
+The network is busy.
+
+0xC00D000F
+
+NS_E_TOO_MANY_SESS
+
+
+The server session limit was exceeded.
+
+0xC00D0010
+
+NS_E_ALREADY_CONNECTED
+
+
+The network connection already exists.
+
+0xC00D0011
+
+NS_E_INVALID_INDEX
+
+
+Index %1 is invalid.
+
+0xC00D0012
+
+NS_E_PROTOCOL_MISMATCH
+
+
+There is no protocol or protocol version supported by both the client and the server.
+
+0xC00D0013
+
+NS_E_TIMEOUT
+
+
+The server, a computer set up to offer multimedia content to other computers, could not handle your request for multimedia content in a timely manner. Please try again later.
+
+0xC00D0014
+
+NS_E_NET_WRITE
+
+
+Error writing to the network.
+
+0xC00D0015
+
+NS_E_NET_READ
+
+
+Error reading from the network.
+
+0xC00D0016
+
+NS_E_DISK_WRITE
+
+
+Error writing to a disk.
+
+0xC00D0017
+
+NS_E_DISK_READ
+
+
+Error reading from a disk.
+
+0xC00D0018
+
+NS_E_FILE_WRITE
+
+
+Error writing to a file.
+
+0xC00D0019
+
+NS_E_FILE_READ
+
+
+Error reading from a file.
+
+0xC00D001A
+
+NS_E_FILE_NOT_FOUND
+
+
+The system cannot find the file specified.
+
+0xC00D001B
+
+NS_E_FILE_EXISTS
+
+
+The file already exists.
+
+0xC00D001C
+
+NS_E_INVALID_NAME
+
+
+The file name, directory name, or volume label syntax is incorrect.
+
+0xC00D001D
+
+NS_E_FILE_OPEN_FAILED
+
+
+Failed to open a file.
+
+0xC00D001E
+
+NS_E_FILE_ALLOCATION_FAILED
+
+
+Unable to allocate a file.
+
+0xC00D001F
+
+NS_E_FILE_INIT_FAILED
+
+
+Unable to initialize a file.
+
+0xC00D0020
+
+NS_E_FILE_PLAY_FAILED
+
+
+Unable to play a file.
+
+0xC00D0021
+
+NS_E_SET_DISK_UID_FAILED
+
+
+Could not set the disk UID.
+
+0xC00D0022
+
+NS_E_INDUCED
+
+
+An error was induced for testing purposes.
+
+0xC00D0023
+
+NS_E_CCLINK_DOWN
+
+
+Two Content Servers failed to communicate.
+
+0xC00D0024
+
+NS_E_INTERNAL
+
+
+An unknown error occurred.
+
+0xC00D0025
+
+NS_E_BUSY
+
+
+The requested resource is in use.
+
+0xC00D0026
+
+NS_E_UNRECOGNIZED_STREAM_TYPE
+
+
+The specified protocol is not recognized. Be sure that the file name and syntax, such as slashes, are correct for the protocol.
+
+0xC00D0027
+
+NS_E_NETWORK_SERVICE_FAILURE
+
+
+The network service provider failed.
+
+0xC00D0028
+
+NS_E_NETWORK_RESOURCE_FAILURE
+
+
+An attempt to acquire a network resource failed.
+
+0xC00D0029
+
+NS_E_CONNECTION_FAILURE
+
+
+The network connection has failed.
+
+0xC00D002A
+
+NS_E_SHUTDOWN
+
+
+The session is being terminated locally.
+
+0xC00D002B
+
+NS_E_INVALID_REQUEST
+
+
+The request is invalid in the current state.
+
+0xC00D002C
+
+NS_E_INSUFFICIENT_BANDWIDTH
+
+
+There is insufficient bandwidth available to fulfill the request.
+
+0xC00D002D
+
+NS_E_NOT_REBUILDING
+
+
+The disk is not rebuilding.
+
+0xC00D002E
+
+NS_E_LATE_OPERATION
+
+
+An operation requested for a particular time could not be carried out on schedule.
+
+0xC00D002F
+
+NS_E_INVALID_DATA
+
+
+Invalid or corrupt data was encountered.
+
+0xC00D0030
+
+NS_E_FILE_BANDWIDTH_LIMIT
+
+
+The bandwidth required to stream a file is higher than the maximum file bandwidth allowed on the server.
+
+0xC00D0031
+
+NS_E_OPEN_FILE_LIMIT
+
+
+The client cannot have any more files open simultaneously.
+
+0xC00D0032
+
+NS_E_BAD_CONTROL_DATA
+
+
+The server received invalid data from the client on the control connection.
+
+0xC00D0033
+
+NS_E_NO_STREAM
+
+
+There is no stream available.
+
+0xC00D0034
+
+NS_E_STREAM_END
+
+
+There is no more data in the stream.
+
+0xC00D0035
+
+NS_E_SERVER_NOT_FOUND
+
+
+The specified server could not be found.
+
+0xC00D0036
+
+NS_E_DUPLICATE_NAME
+
+
+The specified name is already in use.
+
+0xC00D0037
+
+NS_E_DUPLICATE_ADDRESS
+
+
+The specified address is already in use.
+
+0xC00D0038
+
+NS_E_BAD_MULTICAST_ADDRESS
+
+
+The specified address is not a valid multicast address.
+
+0xC00D0039
+
+NS_E_BAD_ADAPTER_ADDRESS
+
+
+The specified adapter address is invalid.
+
+0xC00D003A
+
+NS_E_BAD_DELIVERY_MODE
+
+
+The specified delivery mode is invalid.
+
+0xC00D003B
+
+NS_E_INVALID_CHANNEL
+
+
+The specified station does not exist.
+
+0xC00D003C
+
+NS_E_INVALID_STREAM
+
+
+The specified stream does not exist.
+
+0xC00D003D
+
+NS_E_INVALID_ARCHIVE
+
+
+The specified archive could not be opened.
+
+0xC00D003E
+
+NS_E_NOTITLES
+
+
+The system cannot find any titles on the server.
+
+0xC00D003F
+
+NS_E_INVALID_CLIENT
+
+
+The system cannot find the client specified.
+
+0xC00D0040
+
+NS_E_INVALID_BLACKHOLE_ADDRESS
+
+
+The Blackhole Address is not initialized.
+
+0xC00D0041
+
+NS_E_INCOMPATIBLE_FORMAT
+
+
+The station does not support the stream format.
+
+0xC00D0042
+
+NS_E_INVALID_KEY
+
+
+The specified key is not valid.
+
+0xC00D0043
+
+NS_E_INVALID_PORT
+
+
+The specified port is not valid.
+
+0xC00D0044
+
+NS_E_INVALID_TTL
+
+
+The specified TTL is not valid.
+
+0xC00D0045
+
+NS_E_STRIDE_REFUSED
+
+
+The request to fast forward or rewind could not be fulfilled.
+
+0xC00D0046
+
+NS_E_MMSAUTOSERVER_CANTFINDWALKER
+
+
+Unable to load the appropriate file parser.
+
+0xC00D0047
+
+NS_E_MAX_BITRATE
+
+
+Cannot exceed the maximum bandwidth limit.
+
+0xC00D0048
+
+NS_E_LOGFILEPERIOD
+
+
+Invalid value for LogFilePeriod.
+
+0xC00D0049
+
+NS_E_MAX_CLIENTS
+
+
+Cannot exceed the maximum client limit.
+
+0xC00D004A
+
+NS_E_LOG_FILE_SIZE
+
+
+The maximum log file size has been reached.
+
+0xC00D004B
+
+NS_E_MAX_FILERATE
+
+
+Cannot exceed the maximum file rate.
+
+0xC00D004C
+
+NS_E_WALKER_UNKNOWN
+
+
+Unknown file type.
+
+0xC00D004D
+
+NS_E_WALKER_SERVER
+
+
+The specified file, %1, cannot be loaded onto the specified server, %2.
+
+0xC00D004E
+
+NS_E_WALKER_USAGE
+
+
+There was a usage error with file parser.
+
+0xC00D0050
+
+NS_E_TIGER_FAIL
+
+
+The Title Server %1 has failed.
+
+0xC00D0053
+
+NS_E_CUB_FAIL
+
+
+Content Server %1 (%2) has failed.
+
+0xC00D0055
+
+NS_E_DISK_FAIL
+
+
+Disk %1 ( %2 ) on Content Server %3, has failed.
+
+0xC00D0060
+
+NS_E_MAX_FUNNELS_ALERT
+
+
+The NetShow data stream limit of %1 streams was reached.
+
+0xC00D0061
+
+NS_E_ALLOCATE_FILE_FAIL
+
+
+The NetShow Video Server was unable to allocate a %1 block file named %2.
+
+0xC00D0062
+
+NS_E_PAGING_ERROR
+
+
+A Content Server was unable to page a block.
+
+0xC00D0063
+
+NS_E_BAD_BLOCK0_VERSION
+
+
+Disk %1 has unrecognized control block version %2.
+
+0xC00D0064
+
+NS_E_BAD_DISK_UID
+
+
+Disk %1 has incorrect uid %2.
+
+0xC00D0065
+
+NS_E_BAD_FSMAJOR_VERSION
+
+
+Disk %1 has unsupported file system major version %2.
+
+0xC00D0066
+
+NS_E_BAD_STAMPNUMBER
+
+
+Disk %1 has bad stamp number in control block.
+
+0xC00D0067
+
+NS_E_PARTIALLY_REBUILT_DISK
+
+
+Disk %1 is partially reconstructed.
+
+0xC00D0068
+
+NS_E_ENACTPLAN_GIVEUP
+
+
+EnactPlan gives up.
+
+0xC00D006A
+
+MCMADM_E_REGKEY_NOT_FOUND
+
+
+The key was not found in the registry.
+
+0xC00D006B
+
+NS_E_NO_FORMATS
+
+
+The publishing point cannot be started because the server does not have the appropriate stream formats. Use the Multicast Announcement Wizard to create a new announcement for this publishing point.
+
+0xC00D006C
+
+NS_E_NO_REFERENCES
+
+
+No reference URLs were found in an ASX file.
+
+0xC00D006D
+
+NS_E_WAVE_OPEN
+
+
+Error opening wave device, the device might be in use.
+
+0xC00D006F
+
+NS_E_CANNOTCONNECTEVENTS
+
+
+Unable to establish a connection to the NetShow event monitor service.
+
+0xC00D0071
+
+NS_E_NO_DEVICE
+
+
+No device driver is present on the system.
+
+0xC00D0072
+
+NS_E_NO_SPECIFIED_DEVICE
+
+
+No specified device driver is present.
+
+0xC00D00C8
+
+NS_E_MONITOR_GIVEUP
+
+
+Netshow Events Monitor is not operational and has been disconnected.
+
+0xC00D00C9
+
+NS_E_REMIRRORED_DISK
+
+
+Disk %1 is remirrored.
+
+0xC00D00CA
+
+NS_E_INSUFFICIENT_DATA
+
+
+Insufficient data found.
+
+0xC00D00CB
+
+NS_E_ASSERT
+
+
+1 failed in file %2 line %3.
+
+0xC00D00CC
+
+NS_E_BAD_ADAPTER_NAME
+
+
+The specified adapter name is invalid.
+
+0xC00D00CD
+
+NS_E_NOT_LICENSED
+
+
+The application is not licensed for this feature.
+
+0xC00D00CE
+
+NS_E_NO_SERVER_CONTACT
+
+
+Unable to contact the server.
+
+0xC00D00CF
+
+NS_E_TOO_MANY_TITLES
+
+
+Maximum number of titles exceeded.
+
+0xC00D00D0
+
+NS_E_TITLE_SIZE_EXCEEDED
+
+
+Maximum size of a title exceeded.
+
+0xC00D00D1
+
+NS_E_UDP_DISABLED
+
+
+UDP protocol not enabled. Not trying %1!ls!.
+
+0xC00D00D2
+
+NS_E_TCP_DISABLED
+
+
+TCP protocol not enabled. Not trying %1!ls!.
+
+0xC00D00D3
+
+NS_E_HTTP_DISABLED
+
+
+HTTP protocol not enabled. Not trying %1!ls!.
+
+0xC00D00D4
+
+NS_E_LICENSE_EXPIRED
+
+
+The product license has expired.
+
+0xC00D00D5
+
+NS_E_TITLE_BITRATE
+
+
+Source file exceeds the per title maximum bitrate. See NetShow Theater documentation for more information.
+
+0xC00D00D6
+
+NS_E_EMPTY_PROGRAM_NAME
+
+
+The program name cannot be empty.
+
+0xC00D00D7
+
+NS_E_MISSING_CHANNEL
+
+
+Station %1 does not exist.
+
+0xC00D00D8
+
+NS_E_NO_CHANNELS
+
+
+You need to define at least one station before this operation can complete.
+
+0xC00D00D9
+
+NS_E_INVALID_INDEX2
+
+
+The index specified is invalid.
+
+0xC00D0190
+
+NS_E_CUB_FAIL_LINK
+
+
+Content Server %1 (%2) has failed its link to Content Server %3.
+
+0xC00D0192
+
+NS_E_BAD_CUB_UID
+
+
+Content Server %1 (%2) has incorrect uid %3.
+
+0xC00D0195
+
+NS_E_GLITCH_MODE
+
+
+Server unreliable because multiple components failed.
+
+0xC00D019B
+
+NS_E_NO_MEDIA_PROTOCOL
+
+
+Content Server %1 (%2) is unable to communicate with the Media System Network Protocol.
+
+0xC00D07F1
+
+NS_E_NOTHING_TO_DO
+
+
+Nothing to do.
+
+0xC00D07F2
+
+NS_E_NO_MULTICAST
+
+
+Not receiving data from the server.
+
+0xC00D0BB8
+
+NS_E_INVALID_INPUT_FORMAT
+
+
+The input media format is invalid.
+
+0xC00D0BB9
+
+NS_E_MSAUDIO_NOT_INSTALLED
+
+
+The MSAudio codec is not installed on this system.
+
+0xC00D0BBA
+
+NS_E_UNEXPECTED_MSAUDIO_ERROR
+
+
+An unexpected error occurred with the MSAudio codec.
+
+0xC00D0BBB
+
+NS_E_INVALID_OUTPUT_FORMAT
+
+
+The output media format is invalid.
+
+0xC00D0BBC
+
+NS_E_NOT_CONFIGURED
+
+
+The object must be fully configured before audio samples can be processed.
+
+0xC00D0BBD
+
+NS_E_PROTECTED_CONTENT
+
+
+You need a license to perform the requested operation on this media file.
+
+0xC00D0BBE
+
+NS_E_LICENSE_REQUIRED
+
+
+You need a license to perform the requested operation on this media file.
+
+0xC00D0BBF
+
+NS_E_TAMPERED_CONTENT
+
+
+This media file is corrupted or invalid. Contact the content provider for a new file.
+
+0xC00D0BC0
+
+NS_E_LICENSE_OUTOFDATE
+
+
+The license for this media file has expired. Get a new license or contact the content provider for further assistance.
+
+0xC00D0BC1
+
+NS_E_LICENSE_INCORRECT_RIGHTS
+
+
+You are not allowed to open this file. Contact the content provider for further assistance.
+
+0xC00D0BC2
+
+NS_E_AUDIO_CODEC_NOT_INSTALLED
+
+
+The requested audio codec is not installed on this system.
+
+0xC00D0BC3
+
+NS_E_AUDIO_CODEC_ERROR
+
+
+An unexpected error occurred with the audio codec.
+
+0xC00D0BC4
+
+NS_E_VIDEO_CODEC_NOT_INSTALLED
+
+
+The requested video codec is not installed on this system.
+
+0xC00D0BC5
+
+NS_E_VIDEO_CODEC_ERROR
+
+
+An unexpected error occurred with the video codec.
+
+0xC00D0BC6
+
+NS_E_INVALIDPROFILE
+
+
+The Profile is invalid.
+
+0xC00D0BC7
+
+NS_E_INCOMPATIBLE_VERSION
+
+
+A new version of the SDK is needed to play the requested content.
+
+0xC00D0BCA
+
+NS_E_OFFLINE_MODE
+
+
+The requested URL is not available in offline mode.
+
+0xC00D0BCB
+
+NS_E_NOT_CONNECTED
+
+
+The requested URL cannot be accessed because there is no network connection.
+
+0xC00D0BCC
+
+NS_E_TOO_MUCH_DATA
+
+
+The encoding process was unable to keep up with the amount of supplied data.
+
+0xC00D0BCD
+
+NS_E_UNSUPPORTED_PROPERTY
+
+
+The given property is not supported.
+
+0xC00D0BCE
+
+NS_E_8BIT_WAVE_UNSUPPORTED
+
+
+Windows Media Player cannot copy the files to the CD because they are 8-bit. Convert the files to 16-bit, 44-kHz stereo files by using Sound Recorder or another audio-processing program, and then try again.
+
+0xC00D0BCF
+
+NS_E_NO_MORE_SAMPLES
+
+
+There are no more samples in the current range.
+
+0xC00D0BD0
+
+NS_E_INVALID_SAMPLING_RATE
+
+
+The given sampling rate is invalid.
+
+0xC00D0BD1
+
+NS_E_MAX_PACKET_SIZE_TOO_SMALL
+
+
+The given maximum packet size is too small to accommodate this profile.)
+
+0xC00D0BD2
+
+NS_E_LATE_PACKET
+
+
+The packet arrived too late to be of use.
+
+0xC00D0BD3
+
+NS_E_DUPLICATE_PACKET
+
+
+The packet is a duplicate of one received before.
+
+0xC00D0BD4
+
+NS_E_SDK_BUFFERTOOSMALL
+
+
+Supplied buffer is too small.
+
+0xC00D0BD5
+
+NS_E_INVALID_NUM_PASSES
+
+
+The wrong number of preprocessing passes was used for the stream's output type.
+
+0xC00D0BD6
+
+NS_E_ATTRIBUTE_READ_ONLY
+
+
+An attempt was made to add, modify, or delete a read only attribute.
+
+0xC00D0BD7
+
+NS_E_ATTRIBUTE_NOT_ALLOWED
+
+
+An attempt was made to add attribute that is not allowed for the given media type.
+
+0xC00D0BD8
+
+NS_E_INVALID_EDL
+
+
+The EDL provided is invalid.
+
+0xC00D0BD9
+
+NS_E_DATA_UNIT_EXTENSION_TOO_LARGE
+
+
+The Data Unit Extension data was too large to be used.
+
+0xC00D0BDA
+
+NS_E_CODEC_DMO_ERROR
+
+
+An unexpected error occurred with a DMO codec.
+
+0xC00D0BDC
+
+NS_E_FEATURE_DISABLED_BY_GROUP_POLICY
+
+
+This feature has been disabled by group policy.
+
+0xC00D0BDD
+
+NS_E_FEATURE_DISABLED_IN_SKU
+
+
+This feature is disabled in this SKU.
+
+0xC00D0FA0
+
+NS_E_NO_CD
+
+
+There is no CD in the CD drive. Insert a CD, and then try again.
+
+0xC00D0FA1
+
+NS_E_CANT_READ_DIGITAL
+
+
+Windows Media Player could not use digital playback to play the CD. To switch to analog playback, on the Tools menu, click Options, and then click the Devices tab. Double-click the CD drive, and then in the Playback area, click Analog. For additional assistance, click Web Help.
+
+0xC00D0FA2
+
+NS_E_DEVICE_DISCONNECTED
+
+
+Windows Media Player no longer detects a connected portable device. Reconnect your portable device, and then try synchronizing the file again.
+
+0xC00D0FA3
+
+NS_E_DEVICE_NOT_SUPPORT_FORMAT
+
+
+Windows Media Player cannot play the file. The portable device does not support the specified file type.
+
+0xC00D0FA4
+
+NS_E_SLOW_READ_DIGITAL
+
+
+Windows Media Player could not use digital playback to play the CD. The Player has automatically switched the CD drive to analog playback. To switch back to digital CD playback, use the Devices tab. For additional assistance, click Web Help.
+
+0xC00D0FA5
+
+NS_E_MIXER_INVALID_LINE
+
+
+An invalid line error occurred in the mixer.
+
+0xC00D0FA6
+
+NS_E_MIXER_INVALID_CONTROL
+
+
+An invalid control error occurred in the mixer.
+
+0xC00D0FA7
+
+NS_E_MIXER_INVALID_VALUE
+
+
+An invalid value error occurred in the mixer.
+
+0xC00D0FA8
+
+NS_E_MIXER_UNKNOWN_MMRESULT
+
+
+An unrecognized MMRESULT occurred in the mixer.
+
+0xC00D0FA9
+
+NS_E_USER_STOP
+
+
+User has stopped the operation.
+
+0xC00D0FAA
+
+NS_E_MP3_FORMAT_NOT_FOUND
+
+
+Windows Media Player cannot rip the track because a compatible MP3 encoder is not installed on your computer. Install a compatible MP3 encoder or choose a different format to rip to (such as Windows Media Audio).
+
+0xC00D0FAB
+
+NS_E_CD_READ_ERROR_NO_CORRECTION
+
+
+Windows Media Player cannot read the CD. The disc might be dirty or damaged. Turn on error correction, and then try again.
+
+0xC00D0FAC
+
+NS_E_CD_READ_ERROR
+
+
+Windows Media Player cannot read the CD. The disc might be dirty or damaged or the CD drive might be malfunctioning.
+
+0xC00D0FAD
+
+NS_E_CD_SLOW_COPY
+
+
+For best performance, do not play CD tracks while ripping them.
+
+0xC00D0FAE
+
+NS_E_CD_COPYTO_CD
+
+
+It is not possible to directly burn tracks from one CD to another CD. You must first rip the tracks from the CD to your computer, and then burn the files to a blank CD.
+
+0xC00D0FAF
+
+NS_E_MIXER_NODRIVER
+
+
+Could not open a sound mixer driver.
+
+0xC00D0FB0
+
+NS_E_REDBOOK_ENABLED_WHILE_COPYING
+
+
+Windows Media Player cannot rip tracks from the CD correctly because the CD drive settings in Device Manager do not match the CD drive settings in the Player.
+
+0xC00D0FB1
+
+NS_E_CD_REFRESH
+
+
+Windows Media Player is busy reading the CD.
+
+0xC00D0FB2
+
+NS_E_CD_DRIVER_PROBLEM
+
+
+Windows Media Player could not use digital playback to play the CD. The Player has automatically switched the CD drive to analog playback. To switch back to digital CD playback, use the Devices tab. For additional assistance, click Web Help.
+
+0xC00D0FB3
+
+NS_E_WONT_DO_DIGITAL
+
+
+Windows Media Player could not use digital playback to play the CD. The Player has automatically switched the CD drive to analog playback. To switch back to digital CD playback, use the Devices tab. For additional assistance, click Web Help.
+
+0xC00D0FB4
+
+NS_E_WMPXML_NOERROR
+
+
+A call was made to GetParseError on the XML parser but there was no error to retrieve.
+
+0xC00D0FB5
+
+NS_E_WMPXML_ENDOFDATA
+
+
+The XML Parser ran out of data while parsing.
+
+0xC00D0FB6
+
+NS_E_WMPXML_PARSEERROR
+
+
+A generic parse error occurred in the XML parser but no information is available.
+
+0xC00D0FB7
+
+NS_E_WMPXML_ATTRIBUTENOTFOUND
+
+
+A call get GetNamedAttribute or GetNamedAttributeIndex on the XML parser resulted in the index not being found.
+
+0xC00D0FB8
+
+NS_E_WMPXML_PINOTFOUND
+
+
+A call was made go GetNamedPI on the XML parser, but the requested Processing Instruction was not found.
+
+0xC00D0FB9
+
+NS_E_WMPXML_EMPTYDOC
+
+
+Persist was called on the XML parser, but the parser has no data to persist.
+
+0xC00D0FBA
+
+NS_E_WMP_PATH_ALREADY_IN_LIBRARY
+
+
+This file path is already in the library.
+
+0xC00D0FBE
+
+NS_E_WMP_FILESCANALREADYSTARTED
+
+
+Windows Media Player is already searching for files to add to your library. Wait for the current process to finish before attempting to search again.
+
+0xC00D0FBF
+
+NS_E_WMP_HME_INVALIDOBJECTID
+
+
+Windows Media Player is unable to find the media you are looking for.
+
+0xC00D0FC0
+
+NS_E_WMP_MF_CODE_EXPIRED
+
+
+A component of Windows Media Player is out-of-date. If you are running a pre-release version of Windows, try upgrading to a more recent version.
+
+0xC00D0FC1
+
+NS_E_WMP_HME_NOTSEARCHABLEFORITEMS
+
+
+This container does not support search on items.
+
+0xC00D0FC7
+
+NS_E_WMP_ADDTOLIBRARY_FAILED
+
+
+Windows Media Player encountered a problem while adding one or more files to the library. For additional assistance, click Web Help.
+
+0xC00D0FC8
+
+NS_E_WMP_WINDOWSAPIFAILURE
+
+
+A Windows API call failed but no error information was available.
+
+0xC00D0FC9
+
+NS_E_WMP_RECORDING_NOT_ALLOWED
+
+
+This file does not have burn rights. If you obtained this file from an online store, go to the online store to get burn rights.
+
+0xC00D0FCA
+
+NS_E_DEVICE_NOT_READY
+
+
+Windows Media Player no longer detects a connected portable device. Reconnect your portable device, and then try to sync the file again.
+
+0xC00D0FCB
+
+NS_E_DAMAGED_FILE
+
+
+Windows Media Player cannot play the file because it is corrupted.
+
+0xC00D0FCC
+
+NS_E_MPDB_GENERIC
+
+
+Windows Media Player encountered an error while attempting to access information in the library. Try restarting the Player.
+
+0xC00D0FCD
+
+NS_E_FILE_FAILED_CHECKS
+
+
+The file cannot be added to the library because it is smaller than the "Skip files smaller than" setting. To add the file, change the setting on the Library tab. For additional assistance, click Web Help.
+
+0xC00D0FCE
+
+NS_E_MEDIA_LIBRARY_FAILED
+
+
+Windows Media Player cannot create the library. You must be logged on as an administrator or a member of the Administrators group to install the Player. For more information, contact your system administrator.
+
+0xC00D0FCF
+
+NS_E_SHARING_VIOLATION
+
+
+The file is already in use. Close other programs that might be using the file, or stop playing the file, and then try again.
+
+0xC00D0FD0
+
+NS_E_NO_ERROR_STRING_FOUND
+
+
+Windows Media Player has encountered an unknown error.
+
+0xC00D0FD1
+
+NS_E_WMPOCX_NO_REMOTE_CORE
+
+
+The Windows Media Player ActiveX control cannot connect to remote media services, but will continue with local media services.
+
+0xC00D0FD2
+
+NS_E_WMPOCX_NO_ACTIVE_CORE
+
+
+The requested method or property is not available because the Windows Media Player ActiveX control has not been properly activated.
+
+0xC00D0FD3
+
+NS_E_WMPOCX_NOT_RUNNING_REMOTELY
+
+
+The Windows Media Player ActiveX control is not running in remote mode.
+
+0xC00D0FD4
+
+NS_E_WMPOCX_NO_REMOTE_WINDOW
+
+
+An error occurred while trying to get the remote Windows Media Player window.
+
+0xC00D0FD5
+
+NS_E_WMPOCX_ERRORMANAGERNOTAVAILABLE
+
+
+Windows Media Player has encountered an unknown error.
+
+0xC00D0FD6
+
+NS_E_PLUGIN_NOTSHUTDOWN
+
+
+Windows Media Player was not closed properly. A damaged or incompatible plug-in might have caused the problem to occur. As a precaution, all optional plug-ins have been disabled.
+
+0xC00D0FD7
+
+NS_E_WMP_CANNOT_FIND_FOLDER
+
+
+Windows Media Player cannot find the specified path. Verify that the path is typed correctly. If it is, the path does not exist in the specified location, or the computer where the path is located is not available.
+
+0xC00D0FD8
+
+NS_E_WMP_STREAMING_RECORDING_NOT_ALLOWED
+
+
+Windows Media Player cannot save a file that is being streamed.
+
+0xC00D0FD9
+
+NS_E_WMP_PLUGINDLL_NOTFOUND
+
+
+Windows Media Player cannot find the selected plug-in. The Player will try to remove it from the menu. To use this plug-in, install it again.
+
+0xC00D0FDA
+
+NS_E_NEED_TO_ASK_USER
+
+
+Action requires input from the user.
+
+0xC00D0FDB
+
+NS_E_WMPOCX_PLAYER_NOT_DOCKED
+
+
+The Windows Media Player ActiveX control must be in a docked state for this action to be performed.
+
+0xC00D0FDC
+
+NS_E_WMP_EXTERNAL_NOTREADY
+
+
+The Windows Media Player external object is not ready.
+
+0xC00D0FDD
+
+NS_E_WMP_MLS_STALE_DATA
+
+
+Windows Media Player cannot perform the requested action. Your computer's time and date might not be set correctly.
+
+0xC00D0FDE
+
+NS_E_WMP_UI_SUBCONTROLSNOTSUPPORTED
+
+
+The control (%s) does not support creation of sub-controls, yet (%d) sub-controls have been specified.
+
+0xC00D0FDF
+
+NS_E_WMP_UI_VERSIONMISMATCH
+
+
+Version mismatch: (%.1f required, %.1f found).
+
+0xC00D0FE0
+
+NS_E_WMP_UI_NOTATHEMEFILE
+
+
+The layout manager was given valid XML that wasn't a theme file.
+
+0xC00D0FE1
+
+NS_E_WMP_UI_SUBELEMENTNOTFOUND
+
+
+The %s subelement could not be found on the %s object.
+
+0xC00D0FE2
+
+NS_E_WMP_UI_VERSIONPARSE
+
+
+An error occurred parsing the version tag. Valid version tags are of the form: <?wmp version='1.0'?>.
+
+0xC00D0FE3
+
+NS_E_WMP_UI_VIEWIDNOTFOUND
+
+
+The view specified in for the 'currentViewID' property (%s) was not found in this theme file.
+
+0xC00D0FE4
+
+NS_E_WMP_UI_PASSTHROUGH
+
+
+This error used internally for hit testing.
+
+0xC00D0FE5
+
+NS_E_WMP_UI_OBJECTNOTFOUND
+
+
+Attributes were specified for the %s object, but the object was not available to send them to.
+
+0xC00D0FE6
+
+NS_E_WMP_UI_SECONDHANDLER
+
+
+The %s event already has a handler, the second handler was ignored.
+
+0xC00D0FE7
+
+NS_E_WMP_UI_NOSKININZIP
+
+
+No .wms file found in skin archive.
+
+0xC00D0FEA
+
+NS_E_WMP_URLDOWNLOADFAILED
+
+
+Windows Media Player encountered a problem while downloading the file. For additional assistance, click Web Help.
+
+0xC00D0FEB
+
+NS_E_WMPOCX_UNABLE_TO_LOAD_SKIN
+
+
+The Windows Media Player ActiveX control cannot load the requested uiMode and cannot roll back to the existing uiMode.
+
+0xC00D0FEC
+
+NS_E_WMP_INVALID_SKIN
+
+
+Windows Media Player encountered a problem with the skin file. The skin file might not be valid.
+
+0xC00D0FED
+
+NS_E_WMP_SENDMAILFAILED
+
+
+Windows Media Player cannot send the link because your email program is not responding. Verify that your email program is configured properly, and then try again. For more information about email, see Windows Help.
+
+0xC00D0FEE
+
+NS_E_WMP_LOCKEDINSKINMODE
+
+
+Windows Media Player cannot switch to full mode because your computer administrator has locked this skin.
+
+0xC00D0FEF
+
+NS_E_WMP_FAILED_TO_SAVE_FILE
+
+
+Windows Media Player encountered a problem while saving the file. For additional assistance, click Web Help.
+
+0xC00D0FF0
+
+NS_E_WMP_SAVEAS_READONLY
+
+
+Windows Media Player cannot overwrite a read-only file. Try using a different file name.
+
+0xC00D0FF1
+
+NS_E_WMP_FAILED_TO_SAVE_PLAYLIST
+
+
+Windows Media Player encountered a problem while creating or saving the playlist. For additional assistance, click Web Help.
+
+0xC00D0FF2
+
+NS_E_WMP_FAILED_TO_OPEN_WMD
+
+
+Windows Media Player cannot open the Windows Media Download file. The file might be damaged.
+
+0xC00D0FF3
+
+NS_E_WMP_CANT_PLAY_PROTECTED
+
+
+The file cannot be added to the library because it is a protected DVR-MS file. This content cannot be played back by Windows Media Player.
+
+0xC00D0FF4
+
+NS_E_SHARING_STATE_OUT_OF_SYNC
+
+
+Media sharing has been turned off because a required Windows setting or component has changed. For additional assistance, click Web Help.
+
+0xC00D0FFA
+
+NS_E_WMPOCX_REMOTE_PLAYER_ALREADY_RUNNING
+
+
+Exclusive Services launch failed because the Windows Media Player is already running.
+
+0xC00D1004
+
+NS_E_WMP_RBC_JPGMAPPINGIMAGE
+
+
+JPG Images are not recommended for use as a mappingImage.
+
+0xC00D1005
+
+NS_E_WMP_JPGTRANSPARENCY
+
+
+JPG Images are not recommended when using a transparencyColor.
+
+0xC00D1009
+
+NS_E_WMP_INVALID_MAX_VAL
+
+
+The Max property cannot be less than Min property.
+
+0xC00D100A
+
+NS_E_WMP_INVALID_MIN_VAL
+
+
+The Min property cannot be greater than Max property.
+
+0xC00D100E
+
+NS_E_WMP_CS_JPGPOSITIONIMAGE
+
+
+JPG Images are not recommended for use as a positionImage.
+
+0xC00D100F
+
+NS_E_WMP_CS_NOTEVENLYDIVISIBLE
+
+
+The (%s) image's size is not evenly divisible by the positionImage's size.
+
+0xC00D1018
+
+NS_E_WMPZIP_NOTAZIPFILE
+
+
+The ZIP reader opened a file and its signature did not match that of the ZIP files.
+
+0xC00D1019
+
+NS_E_WMPZIP_CORRUPT
+
+
+The ZIP reader has detected that the file is corrupted.
+
+0xC00D101A
+
+NS_E_WMPZIP_FILENOTFOUND
+
+
+GetFileStream, SaveToFile, or SaveTemp file was called on the ZIP reader with a file name that was not found in the ZIP file.
+
+0xC00D1022
+
+NS_E_WMP_IMAGE_FILETYPE_UNSUPPORTED
+
+
+Image type not supported.
+
+0xC00D1023
+
+NS_E_WMP_IMAGE_INVALID_FORMAT
+
+
+Image file might be corrupt.
+
+0xC00D1024
+
+NS_E_WMP_GIF_UNEXPECTED_ENDOFFILE
+
+
+Unexpected end of file. GIF file might be corrupt.
+
+0xC00D1025
+
+NS_E_WMP_GIF_INVALID_FORMAT
+
+
+Invalid GIF file.
+
+0xC00D1026
+
+NS_E_WMP_GIF_BAD_VERSION_NUMBER
+
+
+Invalid GIF version. Only 87a or 89a supported.
+
+0xC00D1027
+
+NS_E_WMP_GIF_NO_IMAGE_IN_FILE
+
+
+No images found in GIF file.
+
+0xC00D1028
+
+NS_E_WMP_PNG_INVALIDFORMAT
+
+
+Invalid PNG image file format.
+
+0xC00D1029
+
+NS_E_WMP_PNG_UNSUPPORTED_BITDEPTH
+
+
+PNG bitdepth not supported.
+
+0xC00D102A
+
+NS_E_WMP_PNG_UNSUPPORTED_COMPRESSION
+
+
+Compression format defined in PNG file not supported,
+
+0xC00D102B
+
+NS_E_WMP_PNG_UNSUPPORTED_FILTER
+
+
+Filter method defined in PNG file not supported.
+
+0xC00D102C
+
+NS_E_WMP_PNG_UNSUPPORTED_INTERLACE
+
+
+Interlace method defined in PNG file not supported.
+
+0xC00D102D
+
+NS_E_WMP_PNG_UNSUPPORTED_BAD_CRC
+
+
+Bad CRC in PNG file.
+
+0xC00D102E
+
+NS_E_WMP_BMP_INVALID_BITMASK
+
+
+Invalid bitmask in BMP file.
+
+0xC00D102F
+
+NS_E_WMP_BMP_TOPDOWN_DIB_UNSUPPORTED
+
+
+Topdown DIB not supported.
+
+0xC00D1030
+
+NS_E_WMP_BMP_BITMAP_NOT_CREATED
+
+
+Bitmap could not be created.
+
+0xC00D1031
+
+NS_E_WMP_BMP_COMPRESSION_UNSUPPORTED
+
+
+Compression format defined in BMP not supported.
+
+0xC00D1032
+
+NS_E_WMP_BMP_INVALID_FORMAT
+
+
+Invalid Bitmap format.
+
+0xC00D1033
+
+NS_E_WMP_JPG_JERR_ARITHCODING_NOTIMPL
+
+
+JPEG Arithmetic coding not supported.
+
+0xC00D1034
+
+NS_E_WMP_JPG_INVALID_FORMAT
+
+
+Invalid JPEG format.
+
+0xC00D1035
+
+NS_E_WMP_JPG_BAD_DCTSIZE
+
+
+Invalid JPEG format.
+
+0xC00D1036
+
+NS_E_WMP_JPG_BAD_VERSION_NUMBER
+
+
+Internal version error. Unexpected JPEG library version.
+
+0xC00D1037
+
+NS_E_WMP_JPG_BAD_PRECISION
+
+
+Internal JPEG Library error. Unsupported JPEG data precision.
+
+0xC00D1038
+
+NS_E_WMP_JPG_CCIR601_NOTIMPL
+
+
+JPEG CCIR601 not supported.
+
+0xC00D1039
+
+NS_E_WMP_JPG_NO_IMAGE_IN_FILE
+
+
+No image found in JPEG file.
+
+0xC00D103A
+
+NS_E_WMP_JPG_READ_ERROR
+
+
+Could not read JPEG file.
+
+0xC00D103B
+
+NS_E_WMP_JPG_FRACT_SAMPLE_NOTIMPL
+
+
+JPEG Fractional sampling not supported.
+
+0xC00D103C
+
+NS_E_WMP_JPG_IMAGE_TOO_BIG
+
+
+JPEG image too large. Maximum image size supported is 65500 X 65500.
+
+0xC00D103D
+
+NS_E_WMP_JPG_UNEXPECTED_ENDOFFILE
+
+
+Unexpected end of file reached in JPEG file.
+
+0xC00D103E
+
+NS_E_WMP_JPG_SOF_UNSUPPORTED
+
+
+Unsupported JPEG SOF marker found.
+
+0xC00D103F
+
+NS_E_WMP_JPG_UNKNOWN_MARKER
+
+
+Unknown JPEG marker found.
+
+0xC00D1044
+
+NS_E_WMP_FAILED_TO_OPEN_IMAGE
+
+
+Windows Media Player cannot display the picture file. The player either does not support the picture type or the picture is corrupted.
+
+0xC00D1049
+
+NS_E_WMP_DAI_SONGTOOSHORT
+
+
+Windows Media Player cannot compute a Digital Audio Id for the song. It is too short.
+
+0xC00D104A
+
+NS_E_WMG_RATEUNAVAILABLE
+
+
+Windows Media Player cannot play the file at the requested speed.
+
+0xC00D104B
+
+NS_E_WMG_PLUGINUNAVAILABLE
+
+
+The rendering or digital signal processing plug-in cannot be instantiated.
+
+0xC00D104C
+
+NS_E_WMG_CANNOTQUEUE
+
+
+The file cannot be queued for seamless playback.
+
+0xC00D104D
+
+NS_E_WMG_PREROLLLICENSEACQUISITIONNOTALLOWED
+
+
+Windows Media Player cannot download media usage rights for a file in the playlist.
+
+0xC00D104E
+
+NS_E_WMG_UNEXPECTEDPREROLLSTATUS
+
+
+Windows Media Player encountered an error while trying to queue a file.
+
+0xC00D1051
+
+NS_E_WMG_INVALID_COPP_CERTIFICATE
+
+
+Windows Media Player cannot play the protected file. The Player cannot verify that the connection to your video card is secure. Try installing an updated device driver for your video card.
+
+0xC00D1052
+
+NS_E_WMG_COPP_SECURITY_INVALID
+
+
+Windows Media Player cannot play the protected file. The Player detected that the connection to your hardware might not be secure.
+
+0xC00D1053
+
+NS_E_WMG_COPP_UNSUPPORTED
+
+
+Windows Media Player output link protection is unsupported on this system.
+
+0xC00D1054
+
+NS_E_WMG_INVALIDSTATE
+
+
+Operation attempted in an invalid graph state.
+
+0xC00D1055
+
+NS_E_WMG_SINKALREADYEXISTS
+
+
+A renderer cannot be inserted in a stream while one already exists.
+
+0xC00D1056
+
+NS_E_WMG_NOSDKINTERFACE
+
+
+The Windows Media SDK interface needed to complete the operation does not exist at this time.
+
+0xC00D1057
+
+NS_E_WMG_NOTALLOUTPUTSRENDERED
+
+
+Windows Media Player cannot play a portion of the file because it requires a codec that either could not be downloaded or that is not supported by the Player.
+
+0xC00D1058
+
+NS_E_WMG_FILETRANSFERNOTALLOWED
+
+
+File transfer streams are not allowed in the standalone Player.
+
+0xC00D1059
+
+NS_E_WMR_UNSUPPORTEDSTREAM
+
+
+Windows Media Player cannot play the file. The Player does not support the format you are trying to play.
+
+0xC00D105A
+
+NS_E_WMR_PINNOTFOUND
+
+
+An operation was attempted on a pin that does not exist in the DirectShow filter graph.
+
+0xC00D105B
+
+NS_E_WMR_WAITINGONFORMATSWITCH
+
+
+Specified operation cannot be completed while waiting for a media format change from the SDK.
+
+0xC00D105C
+
+NS_E_WMR_NOSOURCEFILTER
+
+
+Specified operation cannot be completed because the source filter does not exist.
+
+0xC00D105D
+
+NS_E_WMR_PINTYPENOMATCH
+
+
+The specified type does not match this pin.
+
+0xC00D105E
+
+NS_E_WMR_NOCALLBACKAVAILABLE
+
+
+The WMR Source Filter does not have a callback available.
+
+0xC00D1062
+
+NS_E_WMR_SAMPLEPROPERTYNOTSET
+
+
+The specified property has not been set on this sample.
+
+0xC00D1063
+
+NS_E_WMR_CANNOT_RENDER_BINARY_STREAM
+
+
+A plug-in is required to correctly play the file. To determine if the plug-in is available to download, click Web Help.
+
+0xC00D1064
+
+NS_E_WMG_LICENSE_TAMPERED
+
+
+Windows Media Player cannot play the file because your media usage rights are corrupted. If you previously backed up your media usage rights, try restoring them.
+
+0xC00D1065
+
+NS_E_WMR_WILLNOT_RENDER_BINARY_STREAM
+
+
+Windows Media Player cannot play protected files that contain binary streams.
+
+0xC00D1068
+
+NS_E_WMX_UNRECOGNIZED_PLAYLIST_FORMAT
+
+
+Windows Media Player cannot play the playlist because it is not valid.
+
+0xC00D1069
+
+NS_E_ASX_INVALIDFORMAT
+
+
+Windows Media Player cannot play the playlist because it is not valid.
+
+0xC00D106A
+
+NS_E_ASX_INVALIDVERSION
+
+
+A later version of Windows Media Player might be required to play this playlist.
+
+0xC00D106B
+
+NS_E_ASX_INVALID_REPEAT_BLOCK
+
+
+The format of a REPEAT loop within the current playlist file is not valid.
+
+0xC00D106C
+
+NS_E_ASX_NOTHING_TO_WRITE
+
+
+Windows Media Player cannot save the playlist because it does not contain any items.
+
+0xC00D106D
+
+NS_E_URLLIST_INVALIDFORMAT
+
+
+Windows Media Player cannot play the playlist because it is not valid.
+
+0xC00D106E
+
+NS_E_WMX_ATTRIBUTE_DOES_NOT_EXIST
+
+
+The specified attribute does not exist.
+
+0xC00D106F
+
+NS_E_WMX_ATTRIBUTE_ALREADY_EXISTS
+
+
+The specified attribute already exists.
+
+0xC00D1070
+
+NS_E_WMX_ATTRIBUTE_UNRETRIEVABLE
+
+
+Cannot retrieve the specified attribute.
+
+0xC00D1071
+
+NS_E_WMX_ITEM_DOES_NOT_EXIST
+
+
+The specified item does not exist in the current playlist.
+
+0xC00D1072
+
+NS_E_WMX_ITEM_TYPE_ILLEGAL
+
+
+Items of the specified type cannot be created within the current playlist.
+
+0xC00D1073
+
+NS_E_WMX_ITEM_UNSETTABLE
+
+
+The specified item cannot be set in the current playlist.
+
+0xC00D1074
+
+NS_E_WMX_PLAYLIST_EMPTY
+
+
+Windows Media Player cannot perform the requested action because the playlist does not contain any items.
+
+0xC00D1075
+
+NS_E_MLS_SMARTPLAYLIST_FILTER_NOT_REGISTERED
+
+
+The specified auto playlist contains a filter type that is either not valid or is not installed on this computer.
+
+0xC00D1076
+
+NS_E_WMX_INVALID_FORMAT_OVER_NESTING
+
+
+Windows Media Player cannot play the file because the associated playlist contains too many nested playlists.
+
+0xC00D107C
+
+NS_E_WMPCORE_NOSOURCEURLSTRING
+
+
+Windows Media Player cannot find the file. Verify that the path is typed correctly. If it is, the file might not exist in the specified location, or the computer where the file is stored might not be available.
+
+0xC00D107D
+
+NS_E_WMPCORE_COCREATEFAILEDFORGITOBJECT
+
+
+Failed to create the Global Interface Table.
+
+0xC00D107E
+
+NS_E_WMPCORE_FAILEDTOGETMARSHALLEDEVENTHANDLERINTERFACE
+
+
+Failed to get the marshaled graph event handler interface.
+
+0xC00D107F
+
+NS_E_WMPCORE_BUFFERTOOSMALL
+
+
+Buffer is too small for copying media type.
+
+0xC00D1080
+
+NS_E_WMPCORE_UNAVAILABLE
+
+
+The current state of the Player does not allow this operation.
+
+0xC00D1081
+
+NS_E_WMPCORE_INVALIDPLAYLISTMODE
+
+
+The playlist manager does not understand the current play mode (for example, shuffle or normal).
+
+0xC00D1086
+
+NS_E_WMPCORE_ITEMNOTINPLAYLIST
+
+
+Windows Media Player cannot play the file because it is not in the current playlist.
+
+0xC00D1087
+
+NS_E_WMPCORE_PLAYLISTEMPTY
+
+
+There are no items in the playlist. Add items to the playlist, and then try again.
+
+0xC00D1088
+
+NS_E_WMPCORE_NOBROWSER
+
+
+The web page cannot be displayed because no web browser is installed on your computer.
+
+0xC00D1089
+
+NS_E_WMPCORE_UNRECOGNIZED_MEDIA_URL
+
+
+Windows Media Player cannot find the specified file. Verify the path is typed correctly. If it is, the file does not exist in the specified location, or the computer where the file is stored is not available.
+
+0xC00D108A
+
+NS_E_WMPCORE_GRAPH_NOT_IN_LIST
+
+
+Graph with the specified URL was not found in the prerolled graph list.
+
+0xC00D108B
+
+NS_E_WMPCORE_PLAYLIST_EMPTY_OR_SINGLE_MEDIA
+
+
+Windows Media Player cannot perform the requested operation because there is only one item in the playlist.
+
+0xC00D108C
+
+NS_E_WMPCORE_ERRORSINKNOTREGISTERED
+
+
+An error sink was never registered for the calling object.
+
+0xC00D108D
+
+NS_E_WMPCORE_ERRORMANAGERNOTAVAILABLE
+
+
+The error manager is not available to respond to errors.
+
+0xC00D108E
+
+NS_E_WMPCORE_WEBHELPFAILED
+
+
+The Web Help URL cannot be opened.
+
+0xC00D108F
+
+NS_E_WMPCORE_MEDIA_ERROR_RESUME_FAILED
+
+
+Could not resume playing next item in playlist.
+
+0xC00D1090
+
+NS_E_WMPCORE_NO_REF_IN_ENTRY
+
+
+Windows Media Player cannot play the file because the associated playlist does not contain any items or the playlist is not valid.
+
+0xC00D1091
+
+NS_E_WMPCORE_WMX_LIST_ATTRIBUTE_NAME_EMPTY
+
+
+An empty string for playlist attribute name was found.
+
+0xC00D1092
+
+NS_E_WMPCORE_WMX_LIST_ATTRIBUTE_NAME_ILLEGAL
+
+
+A playlist attribute name that is not valid was found.
+
+0xC00D1093
+
+NS_E_WMPCORE_WMX_LIST_ATTRIBUTE_VALUE_EMPTY
+
+
+An empty string for a playlist attribute value was found.
+
+0xC00D1094
+
+NS_E_WMPCORE_WMX_LIST_ATTRIBUTE_VALUE_ILLEGAL
+
+
+An illegal value for a playlist attribute was found.
+
+0xC00D1095
+
+NS_E_WMPCORE_WMX_LIST_ITEM_ATTRIBUTE_NAME_EMPTY
+
+
+An empty string for a playlist item attribute name was found.
+
+0xC00D1096
+
+NS_E_WMPCORE_WMX_LIST_ITEM_ATTRIBUTE_NAME_ILLEGAL
+
+
+An illegal value for a playlist item attribute name was found.
+
+0xC00D1097
+
+NS_E_WMPCORE_WMX_LIST_ITEM_ATTRIBUTE_VALUE_EMPTY
+
+
+An illegal value for a playlist item attribute was found.
+
+0xC00D1098
+
+NS_E_WMPCORE_LIST_ENTRY_NO_REF
+
+
+The playlist does not contain any items.
+
+0xC00D1099
+
+NS_E_WMPCORE_MISNAMED_FILE
+
+
+Windows Media Player cannot play the file. The file is either corrupted or the Player does not support the format you are trying to play.
+
+0xC00D109A
+
+NS_E_WMPCORE_CODEC_NOT_TRUSTED
+
+
+The codec downloaded for this file does not appear to be properly signed, so it cannot be installed.
+
+0xC00D109B
+
+NS_E_WMPCORE_CODEC_NOT_FOUND
+
+
+Windows Media Player cannot play the file. One or more codecs required to play the file could not be found.
+
+0xC00D109C
+
+NS_E_WMPCORE_CODEC_DOWNLOAD_NOT_ALLOWED
+
+
+Windows Media Player cannot play the file because a required codec is not installed on your computer. To try downloading the codec, turn on the "Download codecs automatically" option.
+
+0xC00D109D
+
+NS_E_WMPCORE_ERROR_DOWNLOADING_PLAYLIST
+
+
+Windows Media Player encountered a problem while downloading the playlist. For additional assistance, click Web Help.
+
+0xC00D109E
+
+NS_E_WMPCORE_FAILED_TO_BUILD_PLAYLIST
+
+
+Failed to build the playlist.
+
+0xC00D109F
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_NONE
+
+
+Playlist has no alternates to switch into.
+
+0xC00D10A0
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_EXHAUSTED
+
+
+No more playlist alternates available to switch to.
+
+0xC00D10A1
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_NAME_NOT_FOUND
+
+
+Could not find the name of the alternate playlist to switch into.
+
+0xC00D10A2
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_MORPH_FAILED
+
+
+Failed to switch to an alternate for this media.
+
+0xC00D10A3
+
+NS_E_WMPCORE_PLAYLIST_ITEM_ALTERNATE_INIT_FAILED
+
+
+Failed to initialize an alternate for the media.
+
+0xC00D10A4
+
+NS_E_WMPCORE_MEDIA_ALTERNATE_REF_EMPTY
+
+
+No URL specified for the roll over Refs in the playlist file.
+
+0xC00D10A5
+
+NS_E_WMPCORE_PLAYLIST_NO_EVENT_NAME
+
+
+Encountered a playlist with no name.
+
+0xC00D10A6
+
+NS_E_WMPCORE_PLAYLIST_EVENT_ATTRIBUTE_ABSENT
+
+
+A required attribute in the event block of the playlist was not found.
+
+0xC00D10A7
+
+NS_E_WMPCORE_PLAYLIST_EVENT_EMPTY
+
+
+No items were found in the event block of the playlist.
+
+0xC00D10A8
+
+NS_E_WMPCORE_PLAYLIST_STACK_EMPTY
+
+
+No playlist was found while returning from a nested playlist.
+
+0xC00D10A9
+
+NS_E_WMPCORE_CURRENT_MEDIA_NOT_ACTIVE
+
+
+The media item is not active currently.
+
+0xC00D10AB
+
+NS_E_WMPCORE_USER_CANCEL
+
+
+Windows Media Player cannot perform the requested action because you chose to cancel it.
+
+0xC00D10AC
+
+NS_E_WMPCORE_PLAYLIST_REPEAT_EMPTY
+
+
+Windows Media Player encountered a problem with the playlist. The format of the playlist is not valid.
+
+0xC00D10AD
+
+NS_E_WMPCORE_PLAYLIST_REPEAT_START_MEDIA_NONE
+
+
+Media object corresponding to start of a playlist repeat block was not found.
+
+0xC00D10AE
+
+NS_E_WMPCORE_PLAYLIST_REPEAT_END_MEDIA_NONE
+
+
+Media object corresponding to the end of a playlist repeat block was not found.
+
+0xC00D10AF
+
+NS_E_WMPCORE_INVALID_PLAYLIST_URL
+
+
+The playlist URL supplied to the playlist manager is not valid.
+
+0xC00D10B0
+
+NS_E_WMPCORE_MISMATCHED_RUNTIME
+
+
+Windows Media Player cannot play the file because it is corrupted.
+
+0xC00D10B1
+
+NS_E_WMPCORE_PLAYLIST_IMPORT_FAILED_NO_ITEMS
+
+
+Windows Media Player cannot add the playlist to the library because the playlist does not contain any items.
+
+0xC00D10B2
+
+NS_E_WMPCORE_VIDEO_TRANSFORM_FILTER_INSERTION
+
+
+An error has occurred that could prevent the changing of the video contrast on this media.
+
+0xC00D10B3
+
+NS_E_WMPCORE_MEDIA_UNAVAILABLE
+
+
+Windows Media Player cannot play the file. If the file is located on the Internet, connect to the Internet. If the file is located on a removable storage card, insert the storage card.
+
+0xC00D10B4
+
+NS_E_WMPCORE_WMX_ENTRYREF_NO_REF
+
+
+The playlist contains an ENTRYREF for which no href was parsed. Check the syntax of playlist file.
+
+0xC00D10B5
+
+NS_E_WMPCORE_NO_PLAYABLE_MEDIA_IN_PLAYLIST
+
+
+Windows Media Player cannot play any items in the playlist. To find information about the problem, click the Now Playing tab, and then click the icon next to each file in the List pane.
+
+0xC00D10B6
+
+NS_E_WMPCORE_PLAYLIST_EMPTY_NESTED_PLAYLIST_SKIPPED_ITEMS
+
+
+Windows Media Player cannot play some or all of the items in the playlist because the playlist is nested.
+
+0xC00D10B7
+
+NS_E_WMPCORE_BUSY
+
+
+Windows Media Player cannot play the file at this time. Try again later.
+
+0xC00D10B8
+
+NS_E_WMPCORE_MEDIA_CHILD_PLAYLIST_UNAVAILABLE
+
+
+There is no child playlist available for this media item at this time.
+
+0xC00D10B9
+
+NS_E_WMPCORE_MEDIA_NO_CHILD_PLAYLIST
+
+
+There is no child playlist for this media item.
+
+0xC00D10BA
+
+NS_E_WMPCORE_FILE_NOT_FOUND
+
+
+Windows Media Player cannot find the file. The link from the item in the library to its associated digital media file might be broken. To fix the problem, try repairing the link or removing the item from the library.
+
+0xC00D10BB
+
+NS_E_WMPCORE_TEMP_FILE_NOT_FOUND
+
+
+The temporary file was not found.
+
+0xC00D10BC
+
+NS_E_WMDM_REVOKED
+
+
+Windows Media Player cannot sync the file because the device needs to be updated.
+
+0xC00D10BD
+
+NS_E_DDRAW_GENERIC
+
+
+Windows Media Player cannot play the video because there is a problem with your video card.
+
+0xC00D10BE
+
+NS_E_DISPLAY_MODE_CHANGE_FAILED
+
+
+Windows Media Player failed to change the screen mode for full-screen video playback.
+
+0xC00D10BF
+
+NS_E_PLAYLIST_CONTAINS_ERRORS
+
+
+Windows Media Player cannot play one or more files. For additional information, right-click an item that cannot be played, and then click Error Details.
+
+0xC00D10C0
+
+NS_E_CHANGING_PROXY_NAME
+
+
+Cannot change the proxy name if the proxy setting is not set to custom.
+
+0xC00D10C1
+
+NS_E_CHANGING_PROXY_PORT
+
+
+Cannot change the proxy port if the proxy setting is not set to custom.
+
+0xC00D10C2
+
+NS_E_CHANGING_PROXY_EXCEPTIONLIST
+
+
+Cannot change the proxy exception list if the proxy setting is not set to custom.
+
+0xC00D10C3
+
+NS_E_CHANGING_PROXYBYPASS
+
+
+Cannot change the proxy bypass flag if the proxy setting is not set to custom.
+
+0xC00D10C4
+
+NS_E_CHANGING_PROXY_PROTOCOL_NOT_FOUND
+
+
+Cannot find the specified protocol.
+
+0xC00D10C5
+
+NS_E_GRAPH_NOAUDIOLANGUAGE
+
+
+Cannot change the language settings. Either the graph has no audio or the audio only supports one language.
+
+0xC00D10C6
+
+NS_E_GRAPH_NOAUDIOLANGUAGESELECTED
+
+
+The graph has no audio language selected.
+
+0xC00D10C7
+
+NS_E_CORECD_NOTAMEDIACD
+
+
+This is not a media CD.
+
+0xC00D10C8
+
+NS_E_WMPCORE_MEDIA_URL_TOO_LONG
+
+
+Windows Media Player cannot play the file because the URL is too long.
+
+0xC00D10C9
+
+NS_E_WMPFLASH_CANT_FIND_COM_SERVER
+
+
+To play the selected item, you must install the Macromedia Flash Player. To download the Macromedia Flash Player, go to the Adobe website.
+
+0xC00D10CA
+
+NS_E_WMPFLASH_INCOMPATIBLEVERSION
+
+
+To play the selected item, you must install a later version of the Macromedia Flash Player. To download the Macromedia Flash Player, go to the Adobe website.
+
+0xC00D10CB
+
+NS_E_WMPOCXGRAPH_IE_DISALLOWS_ACTIVEX_CONTROLS
+
+
+Windows Media Player cannot play the file because your Internet security settings prohibit the use of ActiveX controls.
+
+0xC00D10CC
+
+NS_E_NEED_CORE_REFERENCE
+
+
+The use of this method requires an existing reference to the Player object.
+
+0xC00D10CD
+
+NS_E_MEDIACD_READ_ERROR
+
+
+Windows Media Player cannot play the CD. The disc might be dirty or damaged.
+
+0xC00D10CE
+
+NS_E_IE_DISALLOWS_ACTIVEX_CONTROLS
+
+
+Windows Media Player cannot play the file because your Internet security settings prohibit the use of ActiveX controls.
+
+0xC00D10CF
+
+NS_E_FLASH_PLAYBACK_NOT_ALLOWED
+
+
+Flash playback has been turned off in Windows Media Player.
+
+0xC00D10D0
+
+NS_E_UNABLE_TO_CREATE_RIP_LOCATION
+
+
+Windows Media Player cannot rip the CD because a valid rip location cannot be created.
+
+0xC00D10D1
+
+NS_E_WMPCORE_SOME_CODECS_MISSING
+
+
+Windows Media Player cannot play the file because a required codec is not installed on your computer.
+
+0xC00D10D2
+
+NS_E_WMP_RIP_FAILED
+
+
+Windows Media Player cannot rip one or more tracks from the CD.
+
+0xC00D10D3
+
+NS_E_WMP_FAILED_TO_RIP_TRACK
+
+
+Windows Media Player encountered a problem while ripping the track from the CD. For additional assistance, click Web Help.
+
+0xC00D10D4
+
+NS_E_WMP_ERASE_FAILED
+
+
+Windows Media Player encountered a problem while erasing the disc. For additional assistance, click Web Help.
+
+0xC00D10D5
+
+NS_E_WMP_FORMAT_FAILED
+
+
+Windows Media Player encountered a problem while formatting the device. For additional assistance, click Web Help.
+
+0xC00D10D6
+
+NS_E_WMP_CANNOT_BURN_NON_LOCAL_FILE
+
+
+This file cannot be burned to a CD because it is not located on your computer.
+
+0xC00D10D7
+
+NS_E_WMP_FILE_TYPE_CANNOT_BURN_TO_AUDIO_CD
+
+
+It is not possible to burn this file type to an audio CD. Windows Media Player can burn the following file types to an audio CD: WMA, MP3, or WAV.
+
+0xC00D10D8
+
+NS_E_WMP_FILE_DOES_NOT_FIT_ON_CD
+
+
+This file is too large to fit on a disc.
+
+0xC00D10D9
+
+NS_E_WMP_FILE_NO_DURATION
+
+
+It is not possible to determine if this file can fit on a disc because Windows Media Player cannot detect the length of the file. Playing the file before burning might enable the Player to detect the file length.
+
+0xC00D10DA
+
+NS_E_PDA_FAILED_TO_BURN
+
+
+Windows Media Player encountered a problem while burning the file to the disc. For additional assistance, click Web Help.
+
+0xC00D10DC
+
+NS_E_FAILED_DOWNLOAD_ABORT_BURN
+
+
+Windows Media Player cannot burn the audio CD because some items in the list that you chose to buy could not be downloaded from the online store.
+
+0xC00D10DD
+
+NS_E_WMPCORE_DEVICE_DRIVERS_MISSING
+
+
+Windows Media Player cannot play the file. Try using Windows Update or Device Manager to update the device drivers for your audio and video cards. For information about using Windows Update or Device Manager, see Windows Help.
+
+0xC00D1126
+
+NS_E_WMPIM_USEROFFLINE
+
+
+Windows Media Player has detected that you are not connected to the Internet. Connect to the Internet, and then try again.
+
+0xC00D1127
+
+NS_E_WMPIM_USERCANCELED
+
+
+The attempt to connect to the Internet was canceled.
+
+0xC00D1128
+
+NS_E_WMPIM_DIALUPFAILED
+
+
+The attempt to connect to the Internet failed.
+
+0xC00D1129
+
+NS_E_WINSOCK_ERROR_STRING
+
+
+Windows Media Player has encountered an unknown network error.
+
+0xC00D1130
+
+NS_E_WMPBR_NOLISTENER
+
+
+No window is currently listening to Backup and Restore events.
+
+0xC00D1131
+
+NS_E_WMPBR_BACKUPCANCEL
+
+
+Your media usage rights were not backed up because the backup was canceled.
+
+0xC00D1132
+
+NS_E_WMPBR_RESTORECANCEL
+
+
+Your media usage rights were not restored because the restoration was canceled.
+
+0xC00D1133
+
+NS_E_WMPBR_ERRORWITHURL
+
+
+An error occurred while backing up or restoring your media usage rights. A required web page cannot be displayed.
+
+0xC00D1134
+
+NS_E_WMPBR_NAMECOLLISION
+
+
+Your media usage rights were not backed up because the backup was canceled.
+
+0xC00D1137
+
+NS_E_WMPBR_DRIVE_INVALID
+
+
+Windows Media Player cannot restore your media usage rights from the specified location. Choose another location, and then try again.
+
+0xC00D1138
+
+NS_E_WMPBR_BACKUPRESTOREFAILED
+
+
+Windows Media Player cannot backup or restore your media usage rights.
+
+0xC00D1158
+
+NS_E_WMP_CONVERT_FILE_FAILED
+
+
+Windows Media Player cannot add the file to the library.
+
+0xC00D1159
+
+NS_E_WMP_CONVERT_NO_RIGHTS_ERRORURL
+
+
+Windows Media Player cannot add the file to the library because the content provider prohibits it. For assistance, contact the company that provided the file.
+
+0xC00D115A
+
+NS_E_WMP_CONVERT_NO_RIGHTS_NOERRORURL
+
+
+Windows Media Player cannot add the file to the library because the content provider prohibits it. For assistance, contact the company that provided the file.
+
+0xC00D115B
+
+NS_E_WMP_CONVERT_FILE_CORRUPT
+
+
+Windows Media Player cannot add the file to the library. The file might not be valid.
+
+0xC00D115C
+
+NS_E_WMP_CONVERT_PLUGIN_UNAVAILABLE_ERRORURL
+
+
+Windows Media Player cannot add the file to the library. The plug-in required to add the file is not installed properly. For assistance, click Web Help to display the website of the company that provided the file.
+
+0xC00D115D
+
+NS_E_WMP_CONVERT_PLUGIN_UNAVAILABLE_NOERRORURL
+
+
+Windows Media Player cannot add the file to the library. The plug-in required to add the file is not installed properly. For assistance, contact the company that provided the file.
+
+0xC00D115E
+
+NS_E_WMP_CONVERT_PLUGIN_UNKNOWN_FILE_OWNER
+
+
+Windows Media Player cannot add the file to the library. The plug-in required to add the file is not installed properly. For assistance, contact the company that provided the file.
+
+0xC00D1160
+
+NS_E_DVD_DISC_COPY_PROTECT_OUTPUT_NS
+
+
+Windows Media Player cannot play this DVD. Try installing an updated driver for your video card or obtaining a newer video card.
+
+0xC00D1161
+
+NS_E_DVD_DISC_COPY_PROTECT_OUTPUT_FAILED
+
+
+This DVD's resolution exceeds the maximum allowed by your component video outputs. Try reducing your screen resolution to 640 x 480, or turn off analog component outputs and use a VGA connection to your monitor.
+
+0xC00D1162
+
+NS_E_DVD_NO_SUBPICTURE_STREAM
+
+
+Windows Media Player cannot display subtitles or highlights in DVD menus. Reinstall the DVD decoder or contact the DVD drive manufacturer to obtain an updated decoder.
+
+0xC00D1163
+
+NS_E_DVD_COPY_PROTECT
+
+
+Windows Media Player cannot play this DVD because there is a problem with digital copy protection between your DVD drive, decoder, and video card. Try installing an updated driver for your video card.
+
+0xC00D1164
+
+NS_E_DVD_AUTHORING_PROBLEM
+
+
+Windows Media Player cannot play the DVD. The disc was created in a manner that the Player does not support.
+
+0xC00D1165
+
+NS_E_DVD_INVALID_DISC_REGION
+
+
+Windows Media Player cannot play the DVD because the disc prohibits playback in your region of the world. You must obtain a disc that is intended for your geographic region.
+
+0xC00D1166
+
+NS_E_DVD_COMPATIBLE_VIDEO_CARD
+
+
+Windows Media Player cannot play the DVD because your video card does not support DVD playback.
+
+0xC00D1167
+
+NS_E_DVD_MACROVISION
+
+
+Windows Media Player cannot play this DVD because it is not possible to turn on analog copy protection on the output display. Try installing an updated driver for your video card.
+
+0xC00D1168
+
+NS_E_DVD_SYSTEM_DECODER_REGION
+
+
+Windows Media Player cannot play the DVD because the region assigned to your DVD drive does not match the region assigned to your DVD decoder.
+
+0xC00D1169
+
+NS_E_DVD_DISC_DECODER_REGION
+
+
+Windows Media Player cannot play the DVD because the disc prohibits playback in your region of the world. You must obtain a disc that is intended for your geographic region.
+
+0xC00D116A
+
+NS_E_DVD_NO_VIDEO_STREAM
+
+
+Windows Media Player cannot play DVD video. You might need to adjust your Windows display settings. Open display settings in Control Panel, and then try lowering your screen resolution and color quality settings.
+
+0xC00D116B
+
+NS_E_DVD_NO_AUDIO_STREAM
+
+
+Windows Media Player cannot play DVD audio. Verify that your sound card is set up correctly, and then try again.
+
+0xC00D116C
+
+NS_E_DVD_GRAPH_BUILDING
+
+
+Windows Media Player cannot play DVD video. Close any open files and quit any other programs, and then try again. If the problem persists, restart your computer.
+
+0xC00D116D
+
+NS_E_DVD_NO_DECODER
+
+
+Windows Media Player cannot play the DVD because a compatible DVD decoder is not installed on your computer.
+
+0xC00D116E
+
+NS_E_DVD_PARENTAL
+
+
+Windows Media Player cannot play the scene because it has a parental rating higher than the rating that you are authorized to view.
+
+0xC00D116F
+
+NS_E_DVD_CANNOT_JUMP
+
+
+Windows Media Player cannot skip to the requested location on the DVD.
+
+0xC00D1170
+
+NS_E_DVD_DEVICE_CONTENTION
+
+
+Windows Media Player cannot play the DVD because it is currently in use by another program. Quit the other program that is using the DVD, and then try again.
+
+0xC00D1171
+
+NS_E_DVD_NO_VIDEO_MEMORY
+
+
+Windows Media Player cannot play DVD video. You might need to adjust your Windows display settings. Open display settings in Control Panel, and then try lowering your screen resolution and color quality settings.
+
+0xC00D1172
+
+NS_E_DVD_CANNOT_COPY_PROTECTED
+
+
+Windows Media Player cannot rip the DVD because it is copy protected.
+
+0xC00D1173
+
+NS_E_DVD_REQUIRED_PROPERTY_NOT_SET
+
+
+One of more of the required properties has not been set.
+
+0xC00D1174
+
+NS_E_DVD_INVALID_TITLE_CHAPTER
+
+
+The specified title and/or chapter number does not exist on this DVD.
+
+0xC00D1176
+
+NS_E_NO_CD_BURNER
+
+
+Windows Media Player cannot burn the files because the Player cannot find a burner. If the burner is connected properly, try using Windows Update to install the latest device driver.
+
+0xC00D1177
+
+NS_E_DEVICE_IS_NOT_READY
+
+
+Windows Media Player does not detect storage media in the selected device. Insert storage media into the device, and then try again.
+
+0xC00D1178
+
+NS_E_PDA_UNSUPPORTED_FORMAT
+
+
+Windows Media Player cannot sync this file. The Player might not support the file type.
+
+0xC00D1179
+
+NS_E_NO_PDA
+
+
+Windows Media Player does not detect a portable device. Connect your portable device, and then try again.
+
+0xC00D117A
+
+NS_E_PDA_UNSPECIFIED_ERROR
+
+
+Windows Media Player encountered an error while communicating with the device. The storage card on the device might be full, the device might be turned off, or the device might not allow playlists or folders to be created on it.
+
+0xC00D117B
+
+NS_E_MEMSTORAGE_BAD_DATA
+
+
+Windows Media Player encountered an error while burning a CD.
+
+0xC00D117C
+
+NS_E_PDA_FAIL_SELECT_DEVICE
+
+
+Windows Media Player encountered an error while communicating with a portable device or CD drive.
+
+0xC00D117D
+
+NS_E_PDA_FAIL_READ_WAVE_FILE
+
+
+Windows Media Player cannot open the WAV file.
+
+0xC00D117E
+
+NS_E_IMAPI_LOSSOFSTREAMING
+
+
+Windows Media Player failed to burn all the files to the CD. Select a slower recording speed, and then try again.
+
+0xC00D117F
+
+NS_E_PDA_DEVICE_FULL
+
+
+There is not enough storage space on the portable device to complete this operation. Delete some unneeded files on the portable device, and then try again.
+
+0xC00D1180
+
+NS_E_FAIL_LAUNCH_ROXIO_PLUGIN
+
+
+Windows Media Player cannot burn the files. Verify that your burner is connected properly, and then try again. If the problem persists, reinstall the Player.
+
+0xC00D1181
+
+NS_E_PDA_DEVICE_FULL_IN_SESSION
+
+
+Windows Media Player did not sync some files to the device because there is not enough storage space on the device.
+
+0xC00D1182
+
+NS_E_IMAPI_MEDIUM_INVALIDTYPE
+
+
+The disc in the burner is not valid. Insert a blank disc into the burner, and then try again.
+
+0xC00D1183
+
+NS_E_PDA_MANUALDEVICE
+
+
+Windows Media Player cannot perform the requested action because the device does not support sync.
+
+0xC00D1184
+
+NS_E_PDA_PARTNERSHIPNOTEXIST
+
+
+To perform the requested action, you must first set up sync with the device.
+
+0xC00D1185
+
+NS_E_PDA_CANNOT_CREATE_ADDITIONAL_SYNC_RELATIONSHIP
+
+
+You have already created sync partnerships with 16 devices. To create a new sync partnership, you must first end an existing partnership.
+
+0xC00D1186
+
+NS_E_PDA_NO_TRANSCODE_OF_DRM
+
+
+Windows Media Player cannot sync the file because protected files cannot be converted to the required quality level or file format.
+
+0xC00D1187
+
+NS_E_PDA_TRANSCODECACHEFULL
+
+
+The folder that stores converted files is full. Either empty the folder or increase its size, and then try again.
+
+0xC00D1188
+
+NS_E_PDA_TOO_MANY_FILE_COLLISIONS
+
+
+There are too many files with the same name in the folder on the device. Change the file name or sync to a different folder.
+
+0xC00D1189
+
+NS_E_PDA_CANNOT_TRANSCODE
+
+
+Windows Media Player cannot convert the file to the format required by the device.
+
+0xC00D118A
+
+NS_E_PDA_TOO_MANY_FILES_IN_DIRECTORY
+
+
+You have reached the maximum number of files your device allows in a folder. If your device supports playback from subfolders, try creating subfolders on the device and storing some files in them.
+
+0xC00D118B
+
+NS_E_PROCESSINGSHOWSYNCWIZARD
+
+
+Windows Media Player is already trying to start the Device Setup Wizard.
+
+0xC00D118C
+
+NS_E_PDA_TRANSCODE_NOT_PERMITTED
+
+
+Windows Media Player cannot convert this file format. If an updated version of the codec used to compress this file is available, install it and then try to sync the file again.
+
+0xC00D118D
+
+NS_E_PDA_INITIALIZINGDEVICES
+
+
+Windows Media Player is busy setting up devices. Try again later.
+
+0xC00D118E
+
+NS_E_PDA_OBSOLETE_SP
+
+
+Your device is using an outdated driver that is no longer supported by Windows Media Player. For additional assistance, click Web Help.
+
+0xC00D118F
+
+NS_E_PDA_TITLE_COLLISION
+
+
+Windows Media Player cannot sync the file because a file with the same name already exists on the device. Change the file name or try to sync the file to a different folder.
+
+0xC00D1190
+
+NS_E_PDA_DEVICESUPPORTDISABLED
+
+
+Automatic and manual sync have been turned off temporarily. To sync to a device, restart Windows Media Player.
+
+0xC00D1191
+
+NS_E_PDA_NO_LONGER_AVAILABLE
+
+
+This device is not available. Connect the device to the computer, and then try again.
+
+0xC00D1192
+
+NS_E_PDA_ENCODER_NOT_RESPONDING
+
+
+Windows Media Player cannot sync the file because an error occurred while converting the file to another quality level or format. If the problem persists, remove the file from the list of files to sync.
+
+0xC00D1193
+
+NS_E_PDA_CANNOT_SYNC_FROM_LOCATION
+
+
+Windows Media Player cannot sync the file to your device. The file might be stored in a location that is not supported. Copy the file from its current location to your hard disk, add it to your library, and then try to sync the file again.
+
+0xC00D1194
+
+NS_E_WMP_PROTOCOL_PROBLEM
+
+
+Windows Media Player cannot open the specified URL. Verify that the Player is configured to use all available protocols, and then try again.
+
+0xC00D1195
+
+NS_E_WMP_NO_DISK_SPACE
+
+
+Windows Media Player cannot perform the requested action because there is not enough storage space on your computer. Delete some unneeded files on your hard disk, and then try again.
+
+0xC00D1196
+
+NS_E_WMP_LOGON_FAILURE
+
+
+The server denied access to the file. Verify that you are using the correct user name and password.
+
+0xC00D1197
+
+NS_E_WMP_CANNOT_FIND_FILE
+
+
+Windows Media Player cannot find the file. If you are trying to play, burn, or sync an item that is in your library, the item might point to a file that has been moved, renamed, or deleted.
+
+0xC00D1198
+
+NS_E_WMP_SERVER_INACCESSIBLE
+
+
+Windows Media Player cannot connect to the server. The server name might not be correct, the server might not be available, or your proxy settings might not be correct.
+
+0xC00D1199
+
+NS_E_WMP_UNSUPPORTED_FORMAT
+
+
+Windows Media Player cannot play the file. The Player might not support the file type or might not support the codec that was used to compress the file.
+
+0xC00D119A
+
+NS_E_WMP_DSHOW_UNSUPPORTED_FORMAT
+
+
+Windows Media Player cannot play the file. The Player might not support the file type or a required codec might not be installed on your computer.
+
+0xC00D119B
+
+NS_E_WMP_PLAYLIST_EXISTS
+
+
+Windows Media Player cannot create the playlist because the name already exists. Type a different playlist name.
+
+0xC00D119C
+
+NS_E_WMP_NONMEDIA_FILES
+
+
+Windows Media Player cannot delete the playlist because it contains items that are not digital media files. Any digital media files in the playlist were deleted.
+
+0xC00D119D
+
+NS_E_WMP_INVALID_ASX
+
+
+The playlist cannot be opened because it is stored in a shared folder on another computer. If possible, move the playlist to the playlists folder on your computer.
+
+0xC00D119E
+
+NS_E_WMP_ALREADY_IN_USE
+
+
+Windows Media Player is already in use. Stop playing any items, close all Player dialog boxes, and then try again.
+
+0xC00D119F
+
+NS_E_WMP_IMAPI_FAILURE
+
+
+Windows Media Player encountered an error while burning. Verify that the burner is connected properly and that the disc is clean and not damaged.
+
+0xC00D11A0
+
+NS_E_WMP_WMDM_FAILURE
+
+
+Windows Media Player has encountered an unknown error with your portable device. Reconnect your portable device, and then try again.
+
+0xC00D11A1
+
+NS_E_WMP_CODEC_NEEDED_WITH_4CC
+
+
+A codec is required to play this file. To determine if this codec is available to download from the web, click Web Help.
+
+0xC00D11A2
+
+NS_E_WMP_CODEC_NEEDED_WITH_FORMATTAG
+
+
+An audio codec is needed to play this file. To determine if this codec is available to download from the web, click Web Help.
+
+0xC00D11A3
+
+NS_E_WMP_MSSAP_NOT_AVAILABLE
+
+
+To play the file, you must install the latest Windows service pack. To install the service pack from the Windows Update website, click Web Help.
+
+0xC00D11A4
+
+NS_E_WMP_WMDM_INTERFACEDEAD
+
+
+Windows Media Player no longer detects a portable device. Reconnect your portable device, and then try again.
+
+0xC00D11A5
+
+NS_E_WMP_WMDM_NOTCERTIFIED
+
+
+Windows Media Player cannot sync the file because the portable device does not support protected files.
+
+0xC00D11A6
+
+NS_E_WMP_WMDM_LICENSE_NOTEXIST
+
+
+This file does not have sync rights. If you obtained this file from an online store, go to the online store to get sync rights.
+
+0xC00D11A7
+
+NS_E_WMP_WMDM_LICENSE_EXPIRED
+
+
+Windows Media Player cannot sync the file because the sync rights have expired. Go to the content provider's online store to get new sync rights.
+
+0xC00D11A8
+
+NS_E_WMP_WMDM_BUSY
+
+
+The portable device is already in use. Wait until the current task finishes or quit other programs that might be using the portable device, and then try again.
+
+0xC00D11A9
+
+NS_E_WMP_WMDM_NORIGHTS
+
+
+Windows Media Player cannot sync the file because the content provider or device prohibits it. You might be able to resolve this problem by going to the content provider's online store to get sync rights.
+
+0xC00D11AA
+
+NS_E_WMP_WMDM_INCORRECT_RIGHTS
+
+
+The content provider has not granted you the right to sync this file. Go to the content provider's online store to get sync rights.
+
+0xC00D11AB
+
+NS_E_WMP_IMAPI_GENERIC
+
+
+Windows Media Player cannot burn the files to the CD. Verify that the disc is clean and not damaged. If necessary, select a slower recording speed or try a different brand of blank discs.
+
+0xC00D11AD
+
+NS_E_WMP_IMAPI_DEVICE_NOTPRESENT
+
+
+Windows Media Player cannot burn the files. Verify that the burner is connected properly, and then try again.
+
+0xC00D11AE
+
+NS_E_WMP_IMAPI_DEVICE_BUSY
+
+
+Windows Media Player cannot burn the files. Verify that the burner is connected properly and that the disc is clean and not damaged. If the burner is already in use, wait until the current task finishes or quit other programs that might be using the burner.
+
+0xC00D11AF
+
+NS_E_WMP_IMAPI_LOSS_OF_STREAMING
+
+
+Windows Media Player cannot burn the files to the CD.
+
+0xC00D11B0
+
+NS_E_WMP_SERVER_UNAVAILABLE
+
+
+Windows Media Player cannot play the file. The server might not be available or there might be a problem with your network or firewall settings.
+
+0xC00D11B1
+
+NS_E_WMP_FILE_OPEN_FAILED
+
+
+Windows Media Player encountered a problem while playing the file. For additional assistance, click Web Help.
+
+0xC00D11B2
+
+NS_E_WMP_VERIFY_ONLINE
+
+
+Windows Media Player must connect to the Internet to verify the file's media usage rights. Connect to the Internet, and then try again.
+
+0xC00D11B3
+
+NS_E_WMP_SERVER_NOT_RESPONDING
+
+
+Windows Media Player cannot play the file because a network error occurred. The server might not be available. Verify that you are connected to the network and that your proxy settings are correct.
+
+0xC00D11B4
+
+NS_E_WMP_DRM_CORRUPT_BACKUP
+
+
+Windows Media Player cannot restore your media usage rights because it could not find any backed up rights on your computer.
+
+0xC00D11B5
+
+NS_E_WMP_DRM_LICENSE_SERVER_UNAVAILABLE
+
+
+Windows Media Player cannot download media usage rights because the server is not available (for example, the server might be busy or not online).
+
+0xC00D11B6
+
+NS_E_WMP_NETWORK_FIREWALL
+
+
+Windows Media Player cannot play the file. A network firewall might be preventing the Player from opening the file by using the UDP transport protocol. If you typed a URL in the Open URL dialog box, try using a different transport protocol (for example, "http:").
+
+0xC00D11B7
+
+NS_E_WMP_NO_REMOVABLE_MEDIA
+
+
+Insert the removable media, and then try again.
+
+0xC00D11B8
+
+NS_E_WMP_PROXY_CONNECT_TIMEOUT
+
+
+Windows Media Player cannot play the file because the proxy server is not responding. The proxy server might be temporarily unavailable or your Player proxy settings might not be valid.
+
+0xC00D11B9
+
+NS_E_WMP_NEED_UPGRADE
+
+
+To play the file, you might need to install a later version of Windows Media Player. On the Help menu, click Check for Updates, and then follow the instructions. For additional assistance, click Web Help.
+
+0xC00D11BA
+
+NS_E_WMP_AUDIO_HW_PROBLEM
+
+
+Windows Media Player cannot play the file because there is a problem with your sound device. There might not be a sound device installed on your computer, it might be in use by another program, or it might not be functioning properly.
+
+0xC00D11BB
+
+NS_E_WMP_INVALID_PROTOCOL
+
+
+Windows Media Player cannot play the file because the specified protocol is not supported. If you typed a URL in the Open URL dialog box, try using a different transport protocol (for example, "http:" or "rtsp:").
+
+0xC00D11BC
+
+NS_E_WMP_INVALID_LIBRARY_ADD
+
+
+Windows Media Player cannot add the file to the library because the file format is not supported.
+
+0xC00D11BD
+
+NS_E_WMP_MMS_NOT_SUPPORTED
+
+
+Windows Media Player cannot play the file because the specified protocol is not supported. If you typed a URL in the Open URL dialog box, try using a different transport protocol (for example, "mms:").
+
+0xC00D11BE
+
+NS_E_WMP_NO_PROTOCOLS_SELECTED
+
+
+Windows Media Player cannot play the file because there are no streaming protocols selected. Select one or more protocols, and then try again.
+
+0xC00D11BF
+
+NS_E_WMP_GOFULLSCREEN_FAILED
+
+
+Windows Media Player cannot switch to Full Screen. You might need to adjust your Windows display settings. Open display settings in Control Panel, and then try setting Hardware acceleration to Full.
+
+0xC00D11C0
+
+NS_E_WMP_NETWORK_ERROR
+
+
+Windows Media Player cannot play the file because a network error occurred. The server might not be available (for example, the server is busy or not online) or you might not be connected to the network.
+
+0xC00D11C1
+
+NS_E_WMP_CONNECT_TIMEOUT
+
+
+Windows Media Player cannot play the file because the server is not responding. Verify that you are connected to the network, and then try again later.
+
+0xC00D11C2
+
+NS_E_WMP_MULTICAST_DISABLED
+
+
+Windows Media Player cannot play the file because the multicast protocol is not enabled. On the Tools menu, click Options, click the Network tab, and then select the Multicast check box. For additional assistance, click Web Help.
+
+0xC00D11C3
+
+NS_E_WMP_SERVER_DNS_TIMEOUT
+
+
+Windows Media Player cannot play the file because a network problem occurred. Verify that you are connected to the network, and then try again later.
+
+0xC00D11C4
+
+NS_E_WMP_PROXY_NOT_FOUND
+
+
+Windows Media Player cannot play the file because the network proxy server cannot be found. Verify that your proxy settings are correct, and then try again.
+
+0xC00D11C5
+
+NS_E_WMP_TAMPERED_CONTENT
+
+
+Windows Media Player cannot play the file because it is corrupted.
+
+0xC00D11C6
+
+NS_E_WMP_OUTOFMEMORY
+
+
+Your computer is running low on memory. Quit other programs, and then try again.
+
+0xC00D11C7
+
+NS_E_WMP_AUDIO_CODEC_NOT_INSTALLED
+
+
+Windows Media Player cannot play, burn, rip, or sync the file because a required audio codec is not installed on your computer.
+
+0xC00D11C8
+
+NS_E_WMP_VIDEO_CODEC_NOT_INSTALLED
+
+
+Windows Media Player cannot play the file because the required video codec is not installed on your computer.
+
+0xC00D11C9
+
+NS_E_WMP_IMAPI_DEVICE_INVALIDTYPE
+
+
+Windows Media Player cannot burn the files. If the burner is busy, wait for the current task to finish. If necessary, verify that the burner is connected properly and that you have installed the latest device driver.
+
+0xC00D11CA
+
+NS_E_WMP_DRM_DRIVER_AUTH_FAILURE
+
+
+Windows Media Player cannot play the protected file because there is a problem with your sound device. Try installing a new device driver or use a different sound device.
+
+0xC00D11CB
+
+NS_E_WMP_NETWORK_RESOURCE_FAILURE
+
+
+Windows Media Player encountered a network error. Restart the Player.
+
+0xC00D11CC
+
+NS_E_WMP_UPGRADE_APPLICATION
+
+
+Windows Media Player is not installed properly. Reinstall the Player.
+
+0xC00D11CD
+
+NS_E_WMP_UNKNOWN_ERROR
+
+
+Windows Media Player encountered an unknown error. For additional assistance, click Web Help.
+
+0xC00D11CE
+
+NS_E_WMP_INVALID_KEY
+
+
+Windows Media Player cannot play the file because the required codec is not valid.
+
+0xC00D11CF
+
+NS_E_WMP_CD_ANOTHER_USER
+
+
+The CD drive is in use by another user. Wait for the task to complete, and then try again.
+
+0xC00D11D0
+
+NS_E_WMP_DRM_NEEDS_AUTHORIZATION
+
+
+Windows Media Player cannot play, sync, or burn the protected file because a problem occurred with the Windows Media Digital Rights Management (DRM) system. You might need to connect to the Internet to update your DRM components. For additional assistance, click Web Help.
+
+0xC00D11D1
+
+NS_E_WMP_BAD_DRIVER
+
+
+Windows Media Player cannot play the file because there might be a problem with your sound or video device. Try installing an updated device driver.
+
+0xC00D11D2
+
+NS_E_WMP_ACCESS_DENIED
+
+
+Windows Media Player cannot access the file. The file might be in use, you might not have access to the computer where the file is stored, or your proxy settings might not be correct.
+
+0xC00D11D3
+
+NS_E_WMP_LICENSE_RESTRICTS
+
+
+The content provider prohibits this action. Go to the content provider's online store to get new media usage rights.
+
+0xC00D11D4
+
+NS_E_WMP_INVALID_REQUEST
+
+
+Windows Media Player cannot perform the requested action at this time.
+
+0xC00D11D5
+
+NS_E_WMP_CD_STASH_NO_SPACE
+
+
+Windows Media Player cannot burn the files because there is not enough free disk space to store the temporary files. Delete some unneeded files on your hard disk, and then try again.
+
+0xC00D11D6
+
+NS_E_WMP_DRM_NEW_HARDWARE
+
+
+Your media usage rights have become corrupted or are no longer valid. This might happen if you have replaced hardware components in your computer.
+
+0xC00D11D7
+
+NS_E_WMP_DRM_INVALID_SIG
+
+
+The required Windows Media Digital Rights Management (DRM) component cannot be validated. You might be able resolve the problem by reinstalling the Player.
+
+0xC00D11D8
+
+NS_E_WMP_DRM_CANNOT_RESTORE
+
+
+You have exceeded your restore limit for the day. Try restoring your media usage rights tomorrow.
+
+0xC00D11D9
+
+NS_E_WMP_BURN_DISC_OVERFLOW
+
+
+Some files might not fit on the CD. The required space cannot be calculated accurately because some files might be missing duration information. To ensure the calculation is accurate, play the files that are missing duration information.
+
+0xC00D11DA
+
+NS_E_WMP_DRM_GENERIC_LICENSE_FAILURE
+
+
+Windows Media Player cannot verify the file's media usage rights. If you obtained this file from an online store, go to the online store to get the necessary rights.
+
+0xC00D11DB
+
+NS_E_WMP_DRM_NO_SECURE_CLOCK
+
+
+It is not possible to sync because this device's internal clock is not set correctly. To set the clock, select the option to set the device clock on the Privacy tab of the Options dialog box, connect to the Internet, and then sync the device again. For additional assistance, click Web Help.
+
+0xC00D11DC
+
+NS_E_WMP_DRM_NO_RIGHTS
+
+
+Windows Media Player cannot play, burn, rip, or sync the protected file because you do not have the appropriate rights.
+
+0xC00D11DD
+
+NS_E_WMP_DRM_INDIV_FAILED
+
+
+Windows Media Player encountered an error during upgrade.
+
+0xC00D11DE
+
+NS_E_WMP_SERVER_NONEWCONNECTIONS
+
+
+Windows Media Player cannot connect to the server because it is not accepting any new connections. This could be because it has reached its maximum connection limit. Please try again later.
+
+0xC00D11DF
+
+NS_E_WMP_MULTIPLE_ERROR_IN_PLAYLIST
+
+
+A number of queued files cannot be played. To find information about the problem, click the Now Playing tab, and then click the icon next to each file in the List pane.
+
+0xC00D11E0
+
+NS_E_WMP_IMAPI2_ERASE_FAIL
+
+
+Windows Media Player encountered an error while erasing the rewritable CD or DVD. Verify that the CD or DVD burner is connected properly and that the disc is clean and not damaged.
+
+0xC00D11E1
+
+NS_E_WMP_IMAPI2_ERASE_DEVICE_BUSY
+
+
+Windows Media Player cannot erase the rewritable CD or DVD. Verify that the CD or DVD burner is connected properly and that the disc is clean and not damaged. If the burner is already in use, wait until the current task finishes or quit other programs that might be using the burner.
+
+0xC00D11E2
+
+NS_E_WMP_DRM_COMPONENT_FAILURE
+
+
+A Windows Media Digital Rights Management (DRM) component encountered a problem. If you are trying to use a file that you obtained from an online store, try going to the online store and getting the appropriate usage rights.
+
+0xC00D11E3
+
+NS_E_WMP_DRM_NO_DEVICE_CERT
+
+
+It is not possible to obtain device's certificate. Please contact the device manufacturer for a firmware update or for other steps to resolve this problem.
+
+0xC00D11E4
+
+NS_E_WMP_SERVER_SECURITY_ERROR
+
+
+Windows Media Player encountered an error when connecting to the server. The security information from the server could not be validated.
+
+0xC00D11E5
+
+NS_E_WMP_AUDIO_DEVICE_LOST
+
+
+An audio device was disconnected or reconfigured. Verify that the audio device is connected, and then try to play the item again.
+
+0xC00D11E6
+
+NS_E_WMP_IMAPI_MEDIA_INCOMPATIBLE
+
+
+Windows Media Player could not complete burning because the disc is not compatible with your drive. Try inserting a different kind of recordable media or use a disc that supports a write speed that is compatible with your drive.
+
+0xC00D11EE
+
+NS_E_SYNCWIZ_DEVICE_FULL
+
+
+Windows Media Player cannot save the sync settings because your device is full. Delete some unneeded files on your device and then try again.
+
+0xC00D11EF
+
+NS_E_SYNCWIZ_CANNOT_CHANGE_SETTINGS
+
+
+It is not possible to change sync settings at this time. Try again later.
+
+0xC00D11F0
+
+NS_E_TRANSCODE_DELETECACHEERROR
+
+
+Windows Media Player cannot delete these files currently. If the Player is synchronizing, wait until it is complete and then try again.
+
+0xC00D11F8
+
+NS_E_CD_NO_BUFFERS_READ
+
+
+Windows Media Player could not use digital mode to read the CD. The Player has automatically switched the CD drive to analog mode. To switch back to digital mode, use the Devices tab. For additional assistance, click Web Help.
+
+0xC00D11F9
+
+NS_E_CD_EMPTY_TRACK_QUEUE
+
+
+No CD track was specified for playback.
+
+0xC00D11FA
+
+NS_E_CD_NO_READER
+
+
+The CD filter was not able to create the CD reader.
+
+0xC00D11FB
+
+NS_E_CD_ISRC_INVALID
+
+
+Invalid ISRC code.
+
+0xC00D11FC
+
+NS_E_CD_MEDIA_CATALOG_NUMBER_INVALID
+
+
+Invalid Media Catalog Number.
+
+0xC00D11FD
+
+NS_E_SLOW_READ_DIGITAL_WITH_ERRORCORRECTION
+
+
+Windows Media Player cannot play audio CDs correctly because the CD drive is slow and error correction is turned on. To increase performance, turn off playback error correction for this drive.
+
+0xC00D11FE
+
+NS_E_CD_SPEEDDETECT_NOT_ENOUGH_READS
+
+
+Windows Media Player cannot estimate the CD drive's playback speed because the CD track is too short.
+
+0xC00D11FF
+
+NS_E_CD_QUEUEING_DISABLED
+
+
+Cannot queue the CD track because queuing is not enabled.
+
+0xC00D1202
+
+NS_E_WMP_DRM_ACQUIRING_LICENSE
+
+
+Windows Media Player cannot download additional media usage rights until the current download is complete.
+
+0xC00D1203
+
+NS_E_WMP_DRM_LICENSE_EXPIRED
+
+
+The media usage rights for this file have expired or are no longer valid. If you obtained the file from an online store, sign in to the store, and then try again.
+
+0xC00D1204
+
+NS_E_WMP_DRM_LICENSE_NOTACQUIRED
+
+
+Windows Media Player cannot download the media usage rights for the file. If you obtained the file from an online store, sign in to the store, and then try again.
+
+0xC00D1205
+
+NS_E_WMP_DRM_LICENSE_NOTENABLED
+
+
+The media usage rights for this file are not yet valid. To see when they will become valid, right-click the file in the library, click Properties, and then click the Media Usage Rights tab.
+
+0xC00D1206
+
+NS_E_WMP_DRM_LICENSE_UNUSABLE
+
+
+The media usage rights for this file are not valid. If you obtained this file from an online store, contact the store for assistance.
+
+0xC00D1207
+
+NS_E_WMP_DRM_LICENSE_CONTENT_REVOKED
+
+
+The content provider has revoked the media usage rights for this file. If you obtained this file from an online store, ask the store if a new version of the file is available.
+
+0xC00D1208
+
+NS_E_WMP_DRM_LICENSE_NOSAP
+
+
+The media usage rights for this file require a feature that is not supported in your current version of Windows Media Player or your current version of Windows. Try installing the latest version of the Player. If you obtained this file from an online store, contact the store for further assistance.
+
+0xC00D1209
+
+NS_E_WMP_DRM_UNABLE_TO_ACQUIRE_LICENSE
+
+
+Windows Media Player cannot download media usage rights at this time. Try again later.
+
+0xC00D120A
+
+NS_E_WMP_LICENSE_REQUIRED
+
+
+Windows Media Player cannot play, burn, or sync the file because the media usage rights are missing. If you obtained the file from an online store, sign in to the store, and then try again.
+
+0xC00D120B
+
+NS_E_WMP_PROTECTED_CONTENT
+
+
+Windows Media Player cannot play, burn, or sync the file because the media usage rights are missing. If you obtained the file from an online store, sign in to the store, and then try again.
+
+0xC00D122A
+
+NS_E_WMP_POLICY_VALUE_NOT_CONFIGURED
+
+
+Windows Media Player cannot read a policy. This can occur when the policy does not exist in the registry or when the registry cannot be read.
+
+0xC00D1234
+
+NS_E_PDA_CANNOT_SYNC_FROM_INTERNET
+
+
+Windows Media Player cannot sync content streamed directly from the Internet. If possible, download the file to your computer, and then try to sync the file.
+
+0xC00D1235
+
+NS_E_PDA_CANNOT_SYNC_INVALID_PLAYLIST
+
+
+This playlist is not valid or is corrupted. Create a new playlist using Windows Media Player, then sync the new playlist instead.
+
+0xC00D1236
+
+NS_E_PDA_FAILED_TO_SYNCHRONIZE_FILE
+
+
+Windows Media Player encountered a problem while synchronizing the file to the device. For additional assistance, click Web Help.
+
+0xC00D1237
+
+NS_E_PDA_SYNC_FAILED
+
+
+Windows Media Player encountered an error while synchronizing to the device.
+
+0xC00D1238
+
+NS_E_PDA_DELETE_FAILED
+
+
+Windows Media Player cannot delete a file from the device.
+
+0xC00D1239
+
+NS_E_PDA_FAILED_TO_RETRIEVE_FILE
+
+
+Windows Media Player cannot copy a file from the device to your library.
+
+0xC00D123A
+
+NS_E_PDA_DEVICE_NOT_RESPONDING
+
+
+Windows Media Player cannot communicate with the device because the device is not responding. Try reconnecting the device, resetting the device, or contacting the device manufacturer for updated firmware.
+
+0xC00D123B
+
+NS_E_PDA_FAILED_TO_TRANSCODE_PHOTO
+
+
+Windows Media Player cannot sync the picture to the device because a problem occurred while converting the file to another quality level or format. The original file might be damaged or corrupted.
+
+0xC00D123C
+
+NS_E_PDA_FAILED_TO_ENCRYPT_TRANSCODED_FILE
+
+
+Windows Media Player cannot convert the file. The file might have been encrypted by the Encrypted File System (EFS). Try decrypting the file first and then synchronizing it. For information about how to decrypt a file, see Windows Help and Support.
+
+0xC00D123D
+
+NS_E_PDA_CANNOT_TRANSCODE_TO_AUDIO
+
+
+Your device requires that this file be converted in order to play on the device. However, the device either does not support playing audio, or Windows Media Player cannot convert the file to an audio format that is supported by the device.
+
+0xC00D123E
+
+NS_E_PDA_CANNOT_TRANSCODE_TO_VIDEO
+
+
+Your device requires that this file be converted in order to play on the device. However, the device either does not support playing video, or Windows Media Player cannot convert the file to a video format that is supported by the device.
+
+0xC00D123F
+
+NS_E_PDA_CANNOT_TRANSCODE_TO_IMAGE
+
+
+Your device requires that this file be converted in order to play on the device. However, the device either does not support displaying pictures, or Windows Media Player cannot convert the file to a picture format that is supported by the device.
+
+0xC00D1240
+
+NS_E_PDA_RETRIEVED_FILE_FILENAME_TOO_LONG
+
+
+Windows Media Player cannot sync the file to your computer because the file name is too long. Try renaming the file on the device.
+
+0xC00D1241
+
+NS_E_PDA_CEWMDM_DRM_ERROR
+
+
+Windows Media Player cannot sync the file because the device is not responding. This typically occurs when there is a problem with the device firmware. For additional assistance, click Web Help.
+
+0xC00D1242
+
+NS_E_INCOMPLETE_PLAYLIST
+
+
+Incomplete playlist.
+
+0xC00D1243
+
+NS_E_PDA_SYNC_RUNNING
+
+
+It is not possible to perform the requested action because sync is in progress. You can either stop sync or wait for it to complete, and then try again.
+
+0xC00D1244
+
+NS_E_PDA_SYNC_LOGIN_ERROR
+
+
+Windows Media Player cannot sync the subscription content because you are not signed in to the online store that provided it. Sign in to the online store, and then try again.
+
+0xC00D1245
+
+NS_E_PDA_TRANSCODE_CODEC_NOT_FOUND
+
+
+Windows Media Player cannot convert the file to the format required by the device. One or more codecs required to convert the file could not be found.
+
+0xC00D1246
+
+NS_E_CANNOT_SYNC_DRM_TO_NON_JANUS_DEVICE
+
+
+It is not possible to sync subscription files to this device.
+
+0xC00D1247
+
+NS_E_CANNOT_SYNC_PREVIOUS_SYNC_RUNNING
+
+
+Your device is operating slowly or is not responding. Until the device responds, it is not possible to sync again. To return the device to normal operation, try disconnecting it from the computer or resetting it.
+
+0xC00D125C
+
+NS_E_WMP_HWND_NOTFOUND
+
+
+The Windows Media Player download manager cannot function properly because the Player main window cannot be found. Try restarting the Player.
+
+0xC00D125D
+
+NS_E_BKGDOWNLOAD_WRONG_NO_FILES
+
+
+Windows Media Player encountered a download that has the wrong number of files. This might occur if another program is trying to create jobs with the same signature as the Player.
+
+0xC00D125E
+
+NS_E_BKGDOWNLOAD_COMPLETECANCELLEDJOB
+
+
+Windows Media Player tried to complete a download that was already canceled. The file will not be available.
+
+0xC00D125F
+
+NS_E_BKGDOWNLOAD_CANCELCOMPLETEDJOB
+
+
+Windows Media Player tried to cancel a download that was already completed. The file will not be removed.
+
+0xC00D1260
+
+NS_E_BKGDOWNLOAD_NOJOBPOINTER
+
+
+Windows Media Player is trying to access a download that is not valid.
+
+0xC00D1261
+
+NS_E_BKGDOWNLOAD_INVALIDJOBSIGNATURE
+
+
+This download was not created by Windows Media Player.
+
+0xC00D1262
+
+NS_E_BKGDOWNLOAD_FAILED_TO_CREATE_TEMPFILE
+
+
+The Windows Media Player download manager cannot create a temporary file name. This might occur if the path is not valid or if the disk is full.
+
+0xC00D1263
+
+NS_E_BKGDOWNLOAD_PLUGIN_FAILEDINITIALIZE
+
+
+The Windows Media Player download manager plug-in cannot start. This might occur if the system is out of resources.
+
+0xC00D1264
+
+NS_E_BKGDOWNLOAD_PLUGIN_FAILEDTOMOVEFILE
+
+
+The Windows Media Player download manager cannot move the file.
+
+0xC00D1265
+
+NS_E_BKGDOWNLOAD_CALLFUNCFAILED
+
+
+The Windows Media Player download manager cannot perform a task because the system has no resources to allocate.
+
+0xC00D1266
+
+NS_E_BKGDOWNLOAD_CALLFUNCTIMEOUT
+
+
+The Windows Media Player download manager cannot perform a task because the task took too long to run.
+
+0xC00D1267
+
+NS_E_BKGDOWNLOAD_CALLFUNCENDED
+
+
+The Windows Media Player download manager cannot perform a task because the Player is terminating the service. The task will be recovered when the Player restarts.
+
+0xC00D1268
+
+NS_E_BKGDOWNLOAD_WMDUNPACKFAILED
+
+
+The Windows Media Player download manager cannot expand a WMD file. The file will be deleted and the operation will not be completed successfully.
+
+0xC00D1269
+
+NS_E_BKGDOWNLOAD_FAILEDINITIALIZE
+
+
+The Windows Media Player download manager cannot start. This might occur if the system is out of resources.
+
+0xC00D126A
+
+NS_E_INTERFACE_NOT_REGISTERED_IN_GIT
+
+
+Windows Media Player cannot access a required functionality. This might occur if the wrong system files or Player DLLs are loaded.
+
+0xC00D126B
+
+NS_E_BKGDOWNLOAD_INVALID_FILE_NAME
+
+
+Windows Media Player cannot get the file name of the requested download. The requested download will be canceled.
+
+0xC00D128E
+
+NS_E_IMAGE_DOWNLOAD_FAILED
+
+
+Windows Media Player encountered an error while downloading an image.
+
+0xC00D12C0
+
+NS_E_WMP_UDRM_NOUSERLIST
+
+
+Windows Media Player cannot update your media usage rights because the Player cannot verify the list of activated users of this computer.
+
+0xC00D12C1
+
+NS_E_WMP_DRM_NOT_ACQUIRING
+
+
+Windows Media Player is trying to acquire media usage rights for a file that is no longer being used. Rights acquisition will stop.
+
+0xC00D12F2
+
+NS_E_WMP_BSTR_TOO_LONG
+
+
+The parameter is not valid.
+
+0xC00D12FC
+
+NS_E_WMP_AUTOPLAY_INVALID_STATE
+
+
+The state is not valid for this request.
+
+0xC00D1306
+
+NS_E_WMP_COMPONENT_REVOKED
+
+
+Windows Media Player cannot play this file until you complete the software component upgrade. After the component has been upgraded, try to play the file again.
+
+0xC00D1324
+
+NS_E_CURL_NOTSAFE
+
+
+The URL is not safe for the operation specified.
+
+0xC00D1325
+
+NS_E_CURL_INVALIDCHAR
+
+
+The URL contains one or more characters that are not valid.
+
+0xC00D1326
+
+NS_E_CURL_INVALIDHOSTNAME
+
+
+The URL contains a host name that is not valid.
+
+0xC00D1327
+
+NS_E_CURL_INVALIDPATH
+
+
+The URL contains a path that is not valid.
+
+0xC00D1328
+
+NS_E_CURL_INVALIDSCHEME
+
+
+The URL contains a scheme that is not valid.
+
+0xC00D1329
+
+NS_E_CURL_INVALIDURL
+
+
+The URL is not valid.
+
+0xC00D132B
+
+NS_E_CURL_CANTWALK
+
+
+Windows Media Player cannot play the file. If you clicked a link on a web page, the link might not be valid.
+
+0xC00D132C
+
+NS_E_CURL_INVALIDPORT
+
+
+The URL port is not valid.
+
+0xC00D132D
+
+NS_E_CURLHELPER_NOTADIRECTORY
+
+
+The URL is not a directory.
+
+0xC00D132E
+
+NS_E_CURLHELPER_NOTAFILE
+
+
+The URL is not a file.
+
+0xC00D132F
+
+NS_E_CURL_CANTDECODE
+
+
+The URL contains characters that cannot be decoded. The URL might be truncated or incomplete.
+
+0xC00D1330
+
+NS_E_CURLHELPER_NOTRELATIVE
+
+
+The specified URL is not a relative URL.
+
+0xC00D1331
+
+NS_E_CURL_INVALIDBUFFERSIZE
+
+
+The buffer is smaller than the size specified.
+
+0xC00D1356
+
+NS_E_SUBSCRIPTIONSERVICE_PLAYBACK_DISALLOWED
+
+
+The content provider has not granted you the right to play this file. Go to the content provider's online store to get play rights.
+
+0xC00D1357
+
+NS_E_CANNOT_BUY_OR_DOWNLOAD_FROM_MULTIPLE_SERVICES
+
+
+Windows Media Player cannot purchase or download content from multiple online stores.
+
+0xC00D1358
+
+NS_E_CANNOT_BUY_OR_DOWNLOAD_CONTENT
+
+
+The file cannot be purchased or downloaded. The file might not be available from the online store.
+
+0xC00D135A
+
+NS_E_NOT_CONTENT_PARTNER_TRACK
+
+
+The provider of this file cannot be identified.
+
+0xC00D135B
+
+NS_E_TRACK_DOWNLOAD_REQUIRES_ALBUM_PURCHASE
+
+
+The file is only available for download when you buy the entire album.
+
+0xC00D135C
+
+NS_E_TRACK_DOWNLOAD_REQUIRES_PURCHASE
+
+
+You must buy the file before you can download it.
+
+0xC00D135D
+
+NS_E_TRACK_PURCHASE_MAXIMUM_EXCEEDED
+
+
+You have exceeded the maximum number of files that can be purchased in a single transaction.
+
+0xC00D135F
+
+NS_E_SUBSCRIPTIONSERVICE_LOGIN_FAILED
+
+
+Windows Media Player cannot sign in to the online store. Verify that you are using the correct user name and password. If the problem persists, the store might be temporarily unavailable.
+
+0xC00D1360
+
+NS_E_SUBSCRIPTIONSERVICE_DOWNLOAD_TIMEOUT
+
+
+Windows Media Player cannot download this item because the server is not responding. The server might be temporarily unavailable or the Internet connection might be lost.
+
+0xC00D1362
+
+NS_E_CONTENT_PARTNER_STILL_INITIALIZING
+
+
+Content Partner still initializing.
+
+0xC00D1363
+
+NS_E_OPEN_CONTAINING_FOLDER_FAILED
+
+
+The folder could not be opened. The folder might have been moved or deleted.
+
+0xC00D136A
+
+NS_E_ADVANCEDEDIT_TOO_MANY_PICTURES
+
+
+Windows Media Player could not add all of the images to the file because the images exceeded the 7 megabyte (MB) limit.
+
+0xC00D1388
+
+NS_E_REDIRECT
+
+
+The client redirected to another server.
+
+0xC00D1389
+
+NS_E_STALE_PRESENTATION
+
+
+The streaming media description is no longer current.
+
+0xC00D138A
+
+NS_E_NAMESPACE_WRONG_PERSIST
+
+
+It is not possible to create a persistent namespace node under a transient parent node.
+
+0xC00D138B
+
+NS_E_NAMESPACE_WRONG_TYPE
+
+
+It is not possible to store a value in a namespace node that has a different value type.
+
+0xC00D138C
+
+NS_E_NAMESPACE_NODE_CONFLICT
+
+
+It is not possible to remove the root namespace node.
+
+0xC00D138D
+
+NS_E_NAMESPACE_NODE_NOT_FOUND
+
+
+The specified namespace node could not be found.
+
+0xC00D138E
+
+NS_E_NAMESPACE_BUFFER_TOO_SMALL
+
+
+The buffer supplied to hold namespace node string is too small.
+
+0xC00D138F
+
+NS_E_NAMESPACE_TOO_MANY_CALLBACKS
+
+
+The callback list on a namespace node is at the maximum size.
+
+0xC00D1390
+
+NS_E_NAMESPACE_DUPLICATE_CALLBACK
+
+
+It is not possible to register an already-registered callback on a namespace node.
+
+0xC00D1391
+
+NS_E_NAMESPACE_CALLBACK_NOT_FOUND
+
+
+Cannot find the callback in the namespace when attempting to remove the callback.
+
+0xC00D1392
+
+NS_E_NAMESPACE_NAME_TOO_LONG
+
+
+The namespace node name exceeds the allowed maximum length.
+
+0xC00D1393
+
+NS_E_NAMESPACE_DUPLICATE_NAME
+
+
+Cannot create a namespace node that already exists.
+
+0xC00D1394
+
+NS_E_NAMESPACE_EMPTY_NAME
+
+
+The namespace node name cannot be a null string.
+
+0xC00D1395
+
+NS_E_NAMESPACE_INDEX_TOO_LARGE
+
+
+Finding a child namespace node by index failed because the index exceeded the number of children.
+
+0xC00D1396
+
+NS_E_NAMESPACE_BAD_NAME
+
+
+The namespace node name is invalid.
+
+0xC00D1397
+
+NS_E_NAMESPACE_WRONG_SECURITY
+
+
+It is not possible to store a value in a namespace node that has a different security type.
+
+0xC00D13EC
+
+NS_E_CACHE_ARCHIVE_CONFLICT
+
+
+The archive request conflicts with other requests in progress.
+
+0xC00D13ED
+
+NS_E_CACHE_ORIGIN_SERVER_NOT_FOUND
+
+
+The specified origin server cannot be found.
+
+0xC00D13EE
+
+NS_E_CACHE_ORIGIN_SERVER_TIMEOUT
+
+
+The specified origin server is not responding.
+
+0xC00D13EF
+
+NS_E_CACHE_NOT_BROADCAST
+
+
+The internal code for HTTP status code 412 Precondition Failed due to not broadcast type.
+
+0xC00D13F0
+
+NS_E_CACHE_CANNOT_BE_CACHED
+
+
+The internal code for HTTP status code 403 Forbidden due to not cacheable.
+
+0xC00D13F1
+
+NS_E_CACHE_NOT_MODIFIED
+
+
+The internal code for HTTP status code 304 Not Modified.
+
+0xC00D1450
+
+NS_E_CANNOT_REMOVE_PUBLISHING_POINT
+
+
+It is not possible to remove a cache or proxy publishing point.
+
+0xC00D1451
+
+NS_E_CANNOT_REMOVE_PLUGIN
+
+
+It is not possible to remove the last instance of a type of plug-in.
+
+0xC00D1452
+
+NS_E_WRONG_PUBLISHING_POINT_TYPE
+
+
+Cache and proxy publishing points do not support this property or method.
+
+0xC00D1453
+
+NS_E_UNSUPPORTED_LOAD_TYPE
+
+
+The plug-in does not support the specified load type.
+
+0xC00D1454
+
+NS_E_INVALID_PLUGIN_LOAD_TYPE_CONFIGURATION
+
+
+The plug-in does not support any load types. The plug-in must support at least one load type.
+
+0xC00D1455
+
+NS_E_INVALID_PUBLISHING_POINT_NAME
+
+
+The publishing point name is invalid.
+
+0xC00D1456
+
+NS_E_TOO_MANY_MULTICAST_SINKS
+
+
+Only one multicast data writer plug-in can be enabled for a publishing point.
+
+0xC00D1457
+
+NS_E_PUBLISHING_POINT_INVALID_REQUEST_WHILE_STARTED
+
+
+The requested operation cannot be completed while the publishing point is started.
+
+0xC00D1458
+
+NS_E_MULTICAST_PLUGIN_NOT_ENABLED
+
+
+A multicast data writer plug-in must be enabled in order for this operation to be completed.
+
+0xC00D1459
+
+NS_E_INVALID_OPERATING_SYSTEM_VERSION
+
+
+This feature requires Windows Server 2003, Enterprise Edition.
+
+0xC00D145A
+
+NS_E_PUBLISHING_POINT_REMOVED
+
+
+The requested operation cannot be completed because the specified publishing point has been removed.
+
+0xC00D145B
+
+NS_E_INVALID_PUSH_PUBLISHING_POINT_START_REQUEST
+
+
+Push publishing points are started when the encoder starts pushing the stream. This publishing point cannot be started by the server administrator.
+
+0xC00D145C
+
+NS_E_UNSUPPORTED_LANGUAGE
+
+
+The specified language is not supported.
+
+0xC00D145D
+
+NS_E_WRONG_OS_VERSION
+
+
+Windows Media Services will only run on Windows Server 2003, Standard Edition and Windows Server 2003, Enterprise Edition.
+
+0xC00D145E
+
+NS_E_PUBLISHING_POINT_STOPPED
+
+
+The operation cannot be completed because the publishing point has been stopped.
+
+0xC00D14B4
+
+NS_E_PLAYLIST_ENTRY_ALREADY_PLAYING
+
+
+The playlist entry is already playing.
+
+0xC00D14B5
+
+NS_E_EMPTY_PLAYLIST
+
+
+The playlist or directory you are requesting does not contain content.
+
+0xC00D14B6
+
+NS_E_PLAYLIST_PARSE_FAILURE
+
+
+The server was unable to parse the requested playlist file.
+
+0xC00D14B7
+
+NS_E_PLAYLIST_UNSUPPORTED_ENTRY
+
+
+The requested operation is not supported for this type of playlist entry.
+
+0xC00D14B8
+
+NS_E_PLAYLIST_ENTRY_NOT_IN_PLAYLIST
+
+
+Cannot jump to a playlist entry that is not inserted in the playlist.
+
+0xC00D14B9
+
+NS_E_PLAYLIST_ENTRY_SEEK
+
+
+Cannot seek to the desired playlist entry.
+
+0xC00D14BA
+
+NS_E_PLAYLIST_RECURSIVE_PLAYLISTS
+
+
+Cannot play recursive playlist.
+
+0xC00D14BB
+
+NS_E_PLAYLIST_TOO_MANY_NESTED_PLAYLISTS
+
+
+The number of nested playlists exceeded the limit the server can handle.
+
+0xC00D14BC
+
+NS_E_PLAYLIST_SHUTDOWN
+
+
+Cannot execute the requested operation because the playlist has been shut down by the Media Server.
+
+0xC00D14BD
+
+NS_E_PLAYLIST_END_RECEDING
+
+
+The playlist has ended while receding.
+
+0xC00D1518
+
+NS_E_DATAPATH_NO_SINK
+
+
+The data path does not have an associated data writer plug-in.
+
+0xC00D151A
+
+NS_E_INVALID_PUSH_TEMPLATE
+
+
+The specified push template is invalid.
+
+0xC00D151B
+
+NS_E_INVALID_PUSH_PUBLISHING_POINT
+
+
+The specified push publishing point is invalid.
+
+0xC00D151C
+
+NS_E_CRITICAL_ERROR
+
+
+The requested operation cannot be performed because the server or publishing point is in a critical error state.
+
+0xC00D151D
+
+NS_E_NO_NEW_CONNECTIONS
+
+
+The content cannot be played because the server is not currently accepting connections. Try connecting at a later time.
+
+0xC00D151E
+
+NS_E_WSX_INVALID_VERSION
+
+
+The version of this playlist is not supported by the server.
+
+0xC00D151F
+
+NS_E_HEADER_MISMATCH
+
+
+The command does not apply to the current media header user by a server component.
+
+0xC00D1520
+
+NS_E_PUSH_DUPLICATE_PUBLISHING_POINT_NAME
+
+
+The specified publishing point name is already in use.
+
+0xC00D157C
+
+NS_E_NO_SCRIPT_ENGINE
+
+
+There is no script engine available for this file.
+
+0xC00D157D
+
+NS_E_PLUGIN_ERROR_REPORTED
+
+
+The plug-in has reported an error. See the Troubleshooting tab or the NT Application Event Log for details.
+
+0xC00D157E
+
+NS_E_SOURCE_PLUGIN_NOT_FOUND
+
+
+No enabled data source plug-in is available to access the requested content.
+
+0xC00D157F
+
+NS_E_PLAYLIST_PLUGIN_NOT_FOUND
+
+
+No enabled playlist parser plug-in is available to access the requested content.
+
+0xC00D1580
+
+NS_E_DATA_SOURCE_ENUMERATION_NOT_SUPPORTED
+
+
+The data source plug-in does not support enumeration.
+
+0xC00D1581
+
+NS_E_MEDIA_PARSER_INVALID_FORMAT
+
+
+The server cannot stream the selected file because it is either damaged or corrupt. Select a different file.
+
+0xC00D1582
+
+NS_E_SCRIPT_DEBUGGER_NOT_INSTALLED
+
+
+The plug-in cannot be enabled because a compatible script debugger is not installed on this system. Install a script debugger, or disable the script debugger option on the general tab of the plug-in's properties page and try again.
+
+0xC00D1583
+
+NS_E_FEATURE_REQUIRES_ENTERPRISE_SERVER
+
+
+The plug-in cannot be loaded because it requires Windows Server 2003, Enterprise Edition.
+
+0xC00D1584
+
+NS_E_WIZARD_RUNNING
+
+
+Another wizard is currently running. Please close the other wizard or wait until it finishes before attempting to run this wizard again.
+
+0xC00D1585
+
+NS_E_INVALID_LOG_URL
+
+
+Invalid log URL. Multicast logging URL must look like "http://servername/isapibackend.dll".
+
+0xC00D1586
+
+NS_E_INVALID_MTU_RANGE
+
+
+Invalid MTU specified. The valid range for maximum packet size is between 36 and 65507 bytes.
+
+0xC00D1587
+
+NS_E_INVALID_PLAY_STATISTICS
+
+
+Invalid play statistics for logging.
+
+0xC00D1588
+
+NS_E_LOG_NEED_TO_BE_SKIPPED
+
+
+The log needs to be skipped.
+
+0xC00D1589
+
+NS_E_HTTP_TEXT_DATACONTAINER_SIZE_LIMIT_EXCEEDED
+
+
+The size of the data exceeded the limit the WMS HTTP Download Data Source plugin can handle.
+
+0xC00D158A
+
+NS_E_PORT_IN_USE
+
+
+One usage of each socket address (protocol/network address/port) is permitted. Verify that other services or applications are not attempting to use the same port and then try to enable the plug-in again.
+
+0xC00D158B
+
+NS_E_PORT_IN_USE_HTTP
+
+
+One usage of each socket address (protocol/network address/port) is permitted. Verify that other services (such as IIS) or applications are not attempting to use the same port and then try to enable the plug-in again.
+
+0xC00D158C
+
+NS_E_HTTP_TEXT_DATACONTAINER_INVALID_SERVER_RESPONSE
+
+
+The WMS HTTP Download Data Source plugin was unable to receive the remote server's response.
+
+0xC00D158D
+
+NS_E_ARCHIVE_REACH_QUOTA
+
+
+The archive plug-in has reached its quota.
+
+0xC00D158E
+
+NS_E_ARCHIVE_ABORT_DUE_TO_BCAST
+
+
+The archive plug-in aborted because the source was from broadcast.
+
+0xC00D158F
+
+NS_E_ARCHIVE_GAP_DETECTED
+
+
+The archive plug-in detected an interrupt in the source.
+
+0xC00D1590
+
+NS_E_AUTHORIZATION_FILE_NOT_FOUND
+
+
+The system cannot find the file specified.
+
+0xC00D1B58
+
+NS_E_BAD_MARKIN
+
+
+The mark-in time should be greater than 0 and less than the mark-out time.
+
+0xC00D1B59
+
+NS_E_BAD_MARKOUT
+
+
+The mark-out time should be greater than the mark-in time and less than the file duration.
+
+0xC00D1B5A
+
+NS_E_NOMATCHING_MEDIASOURCE
+
+
+No matching media type is found in the source %1.
+
+0xC00D1B5B
+
+NS_E_UNSUPPORTED_SOURCETYPE
+
+
+The specified source type is not supported.
+
+0xC00D1B5C
+
+NS_E_TOO_MANY_AUDIO
+
+
+It is not possible to specify more than one audio input.
+
+0xC00D1B5D
+
+NS_E_TOO_MANY_VIDEO
+
+
+It is not possible to specify more than two video inputs.
+
+0xC00D1B5E
+
+NS_E_NOMATCHING_ELEMENT
+
+
+No matching element is found in the list.
+
+0xC00D1B5F
+
+NS_E_MISMATCHED_MEDIACONTENT
+
+
+The profile's media types must match the media types defined for the session.
+
+0xC00D1B60
+
+NS_E_CANNOT_DELETE_ACTIVE_SOURCEGROUP
+
+
+It is not possible to remove an active source while encoding.
+
+0xC00D1B61
+
+NS_E_AUDIODEVICE_BUSY
+
+
+It is not possible to open the specified audio capture device because it is currently in use.
+
+0xC00D1B62
+
+NS_E_AUDIODEVICE_UNEXPECTED
+
+
+It is not possible to open the specified audio capture device because an unexpected error has occurred.
+
+0xC00D1B63
+
+NS_E_AUDIODEVICE_BADFORMAT
+
+
+The audio capture device does not support the specified audio format.
+
+0xC00D1B64
+
+NS_E_VIDEODEVICE_BUSY
+
+
+It is not possible to open the specified video capture device because it is currently in use.
+
+0xC00D1B65
+
+NS_E_VIDEODEVICE_UNEXPECTED
+
+
+It is not possible to open the specified video capture device because an unexpected error has occurred.
+
+0xC00D1B66
+
+NS_E_INVALIDCALL_WHILE_ENCODER_RUNNING
+
+
+This operation is not allowed while encoding.
+
+0xC00D1B67
+
+NS_E_NO_PROFILE_IN_SOURCEGROUP
+
+
+No profile is set for the source.
+
+0xC00D1B68
+
+NS_E_VIDEODRIVER_UNSTABLE
+
+
+The video capture driver returned an unrecoverable error. It is now in an unstable state.
+
+0xC00D1B69
+
+NS_E_VIDCAPSTARTFAILED
+
+
+It was not possible to start the video device.
+
+0xC00D1B6A
+
+NS_E_VIDSOURCECOMPRESSION
+
+
+The video source does not support the requested output format or color depth.
+
+0xC00D1B6B
+
+NS_E_VIDSOURCESIZE
+
+
+The video source does not support the requested capture size.
+
+0xC00D1B6C
+
+NS_E_ICMQUERYFORMAT
+
+
+It was not possible to obtain output information from the video compressor.
+
+0xC00D1B6D
+
+NS_E_VIDCAPCREATEWINDOW
+
+
+It was not possible to create a video capture window.
+
+0xC00D1B6E
+
+NS_E_VIDCAPDRVINUSE
+
+
+There is already a stream active on this video device.
+
+0xC00D1B6F
+
+NS_E_NO_MEDIAFORMAT_IN_SOURCE
+
+
+No media format is set in source.
+
+0xC00D1B70
+
+NS_E_NO_VALID_OUTPUT_STREAM
+
+
+Cannot find a valid output stream from the source.
+
+0xC00D1B71
+
+NS_E_NO_VALID_SOURCE_PLUGIN
+
+
+It was not possible to find a valid source plug-in for the specified source.
+
+0xC00D1B72
+
+NS_E_NO_ACTIVE_SOURCEGROUP
+
+
+No source is currently active.
+
+0xC00D1B73
+
+NS_E_NO_SCRIPT_STREAM
+
+
+No script stream is set in the current source.
+
+0xC00D1B74
+
+NS_E_INVALIDCALL_WHILE_ARCHIVAL_RUNNING
+
+
+This operation is not allowed while archiving.
+
+0xC00D1B75
+
+NS_E_INVALIDPACKETSIZE
+
+
+The setting for the maximum packet size is not valid.
+
+0xC00D1B76
+
+NS_E_PLUGIN_CLSID_INVALID
+
+
+The plug-in CLSID specified is not valid.
+
+0xC00D1B77
+
+NS_E_UNSUPPORTED_ARCHIVETYPE
+
+
+This archive type is not supported.
+
+0xC00D1B78
+
+NS_E_UNSUPPORTED_ARCHIVEOPERATION
+
+
+This archive operation is not supported.
+
+0xC00D1B79
+
+NS_E_ARCHIVE_FILENAME_NOTSET
+
+
+The local archive file name was not set.
+
+0xC00D1B7A
+
+NS_E_SOURCEGROUP_NOTPREPARED
+
+
+The source is not yet prepared.
+
+0xC00D1B7B
+
+NS_E_PROFILE_MISMATCH
+
+
+Profiles on the sources do not match.
+
+0xC00D1B7C
+
+NS_E_INCORRECTCLIPSETTINGS
+
+
+The specified crop values are not valid.
+
+0xC00D1B7D
+
+NS_E_NOSTATSAVAILABLE
+
+
+No statistics are available at this time.
+
+0xC00D1B7E
+
+NS_E_NOTARCHIVING
+
+
+The encoder is not archiving.
+
+0xC00D1B7F
+
+NS_E_INVALIDCALL_WHILE_ENCODER_STOPPED
+
+
+This operation is only allowed during encoding.
+
+0xC00D1B80
+
+NS_E_NOSOURCEGROUPS
+
+
+This SourceGroupCollection doesn't contain any SourceGroups.
+
+0xC00D1B81
+
+NS_E_INVALIDINPUTFPS
+
+
+This source does not have a frame rate of 30 fps. Therefore, it is not possible to apply the inverse telecine filter to the source.
+
+0xC00D1B82
+
+NS_E_NO_DATAVIEW_SUPPORT
+
+
+It is not possible to display your source or output video in the Video panel.
+
+0xC00D1B83
+
+NS_E_CODEC_UNAVAILABLE
+
+
+One or more codecs required to open this content could not be found.
+
+0xC00D1B84
+
+NS_E_ARCHIVE_SAME_AS_INPUT
+
+
+The archive file has the same name as an input file. Change one of the names before continuing.
+
+0xC00D1B85
+
+NS_E_SOURCE_NOTSPECIFIED
+
+
+The source has not been set up completely.
+
+0xC00D1B86
+
+NS_E_NO_REALTIME_TIMECOMPRESSION
+
+
+It is not possible to apply time compression to a broadcast session.
+
+0xC00D1B87
+
+NS_E_UNSUPPORTED_ENCODER_DEVICE
+
+
+It is not possible to open this device.
+
+0xC00D1B88
+
+NS_E_UNEXPECTED_DISPLAY_SETTINGS
+
+
+It is not possible to start encoding because the display size or color has changed since the current session was defined. Restore the previous settings or create a new session.
+
+0xC00D1B89
+
+NS_E_NO_AUDIODATA
+
+
+No audio data has been received for several seconds. Check the audio source and restart the encoder.
+
+0xC00D1B8A
+
+NS_E_INPUTSOURCE_PROBLEM
+
+
+One or all of the specified sources are not working properly. Check that the sources are configured correctly.
+
+0xC00D1B8B
+
+NS_E_WME_VERSION_MISMATCH
+
+
+The supplied configuration file is not supported by this version of the encoder.
+
+0xC00D1B8C
+
+NS_E_NO_REALTIME_PREPROCESS
+
+
+It is not possible to use image preprocessing with live encoding.
+
+0xC00D1B8D
+
+NS_E_NO_REPEAT_PREPROCESS
+
+
+It is not possible to use two-pass encoding when the source is set to loop.
+
+0xC00D1B8E
+
+NS_E_CANNOT_PAUSE_LIVEBROADCAST
+
+
+It is not possible to pause encoding during a broadcast.
+
+0xC00D1B8F
+
+NS_E_DRM_PROFILE_NOT_SET
+
+
+A DRM profile has not been set for the current session.
+
+0xC00D1B90
+
+NS_E_DUPLICATE_DRMPROFILE
+
+
+The profile ID is already used by a DRM profile. Specify a different profile ID.
+
+0xC00D1B91
+
+NS_E_INVALID_DEVICE
+
+
+The setting of the selected device does not support control for playing back tapes.
+
+0xC00D1B92
+
+NS_E_SPEECHEDL_ON_NON_MIXEDMODE
+
+
+You must specify a mixed voice and audio mode in order to use an optimization definition file.
+
+0xC00D1B93
+
+NS_E_DRM_PASSWORD_TOO_LONG
+
+
+The specified password is too long. Type a password with fewer than 8 characters.
+
+0xC00D1B94
+
+NS_E_DEVCONTROL_FAILED_SEEK
+
+
+It is not possible to seek to the specified mark-in point.
+
+0xC00D1B95
+
+NS_E_INTERLACE_REQUIRE_SAMESIZE
+
+
+When you choose to maintain the interlacing in your video, the output video size must match the input video size.
+
+0xC00D1B96
+
+NS_E_TOO_MANY_DEVICECONTROL
+
+
+Only one device control plug-in can control a device.
+
+0xC00D1B97
+
+NS_E_NO_MULTIPASS_FOR_LIVEDEVICE
+
+
+You must also enable storing content to hard disk temporarily in order to use two-pass encoding with the input device.
+
+0xC00D1B98
+
+NS_E_MISSING_AUDIENCE
+
+
+An audience is missing from the output stream configuration.
+
+0xC00D1B99
+
+NS_E_AUDIENCE_CONTENTTYPE_MISMATCH
+
+
+All audiences in the output tree must have the same content type.
+
+0xC00D1B9A
+
+NS_E_MISSING_SOURCE_INDEX
+
+
+A source index is missing from the output stream configuration.
+
+0xC00D1B9B
+
+NS_E_NUM_LANGUAGE_MISMATCH
+
+
+The same source index in different audiences should have the same number of languages.
+
+0xC00D1B9C
+
+NS_E_LANGUAGE_MISMATCH
+
+
+The same source index in different audiences should have the same languages.
+
+0xC00D1B9D
+
+NS_E_VBRMODE_MISMATCH
+
+
+The same source index in different audiences should use the same VBR encoding mode.
+
+0xC00D1B9E
+
+NS_E_INVALID_INPUT_AUDIENCE_INDEX
+
+
+The bit rate index specified is not valid.
+
+0xC00D1B9F
+
+NS_E_INVALID_INPUT_LANGUAGE
+
+
+The specified language is not valid.
+
+0xC00D1BA0
+
+NS_E_INVALID_INPUT_STREAM
+
+
+The specified source type is not valid.
+
+0xC00D1BA1
+
+NS_E_EXPECT_MONO_WAV_INPUT
+
+
+The source must be a mono channel .wav file.
+
+0xC00D1BA2
+
+NS_E_INPUT_WAVFORMAT_MISMATCH
+
+
+All the source .wav files must have the same format.
+
+0xC00D1BA3
+
+NS_E_RECORDQ_DISK_FULL
+
+
+The hard disk being used for temporary storage of content has reached the minimum allowed disk space. Create more space on the hard disk and restart encoding.
+
+0xC00D1BA4
+
+NS_E_NO_PAL_INVERSE_TELECINE
+
+
+It is not possible to apply the inverse telecine feature to PAL content.
+
+0xC00D1BA5
+
+NS_E_ACTIVE_SG_DEVICE_DISCONNECTED
+
+
+A capture device in the current active source is no longer available.
+
+0xC00D1BA6
+
+NS_E_ACTIVE_SG_DEVICE_CONTROL_DISCONNECTED
+
+
+A device used in the current active source for device control is no longer available.
+
+0xC00D1BA7
+
+NS_E_NO_FRAMES_SUBMITTED_TO_ANALYZER
+
+
+No frames have been submitted to the analyzer for analysis.
+
+0xC00D1BA8
+
+NS_E_INPUT_DOESNOT_SUPPORT_SMPTE
+
+
+The source video does not support time codes.
+
+0xC00D1BA9
+
+NS_E_NO_SMPTE_WITH_MULTIPLE_SOURCEGROUPS
+
+
+It is not possible to generate a time code when there are multiple sources in a session.
+
+0xC00D1BAA
+
+NS_E_BAD_CONTENTEDL
+
+
+The voice codec optimization definition file cannot be found or is corrupted.
+
+0xC00D1BAB
+
+NS_E_INTERLACEMODE_MISMATCH
+
+
+The same source index in different audiences should have the same interlace mode.
+
+0xC00D1BAC
+
+NS_E_NONSQUAREPIXELMODE_MISMATCH
+
+
+The same source index in different audiences should have the same nonsquare pixel mode.
+
+0xC00D1BAD
+
+NS_E_SMPTEMODE_MISMATCH
+
+
+The same source index in different audiences should have the same time code mode.
+
+0xC00D1BAE
+
+NS_E_END_OF_TAPE
+
+
+Either the end of the tape has been reached or there is no tape. Check the device and tape.
+
+0xC00D1BAF
+
+NS_E_NO_MEDIA_IN_AUDIENCE
+
+
+No audio or video input has been specified.
+
+0xC00D1BB0
+
+NS_E_NO_AUDIENCES
+
+
+The profile must contain a bit rate.
+
+0xC00D1BB1
+
+NS_E_NO_AUDIO_COMPAT
+
+
+You must specify at least one audio stream to be compatible with Windows Media Player 7.1.
+
+0xC00D1BB2
+
+NS_E_INVALID_VBR_COMPAT
+
+
+Using a VBR encoding mode is not compatible with Windows Media Player 7.1.
+
+0xC00D1BB3
+
+NS_E_NO_PROFILE_NAME
+
+
+You must specify a profile name.
+
+0xC00D1BB4
+
+NS_E_INVALID_VBR_WITH_UNCOMP
+
+
+It is not possible to use a VBR encoding mode with uncompressed audio or video.
+
+0xC00D1BB5
+
+NS_E_MULTIPLE_VBR_AUDIENCES
+
+
+It is not possible to use MBR encoding with VBR encoding.
+
+0xC00D1BB6
+
+NS_E_UNCOMP_COMP_COMBINATION
+
+
+It is not possible to mix uncompressed and compressed content in a session.
+
+0xC00D1BB7
+
+NS_E_MULTIPLE_AUDIO_CODECS
+
+
+All audiences must use the same audio codec.
+
+0xC00D1BB8
+
+NS_E_MULTIPLE_AUDIO_FORMATS
+
+
+All audiences should use the same audio format to be compatible with Windows Media Player 7.1.
+
+0xC00D1BB9
+
+NS_E_AUDIO_BITRATE_STEPDOWN
+
+
+The audio bit rate for an audience with a higher total bit rate must be greater than one with a lower total bit rate.
+
+0xC00D1BBA
+
+NS_E_INVALID_AUDIO_PEAKRATE
+
+
+The audio peak bit rate setting is not valid.
+
+0xC00D1BBB
+
+NS_E_INVALID_AUDIO_PEAKRATE_2
+
+
+The audio peak bit rate setting must be greater than the audio bit rate setting.
+
+0xC00D1BBC
+
+NS_E_INVALID_AUDIO_BUFFERMAX
+
+
+The setting for the maximum buffer size for audio is not valid.
+
+0xC00D1BBD
+
+NS_E_MULTIPLE_VIDEO_CODECS
+
+
+All audiences must use the same video codec.
+
+0xC00D1BBE
+
+NS_E_MULTIPLE_VIDEO_SIZES
+
+
+All audiences should use the same video size to be compatible with Windows Media Player 7.1.
+
+0xC00D1BBF
+
+NS_E_INVALID_VIDEO_BITRATE
+
+
+The video bit rate setting is not valid.
+
+0xC00D1BC0
+
+NS_E_VIDEO_BITRATE_STEPDOWN
+
+
+The video bit rate for an audience with a higher total bit rate must be greater than one with a lower total bit rate.
+
+0xC00D1BC1
+
+NS_E_INVALID_VIDEO_PEAKRATE
+
+
+The video peak bit rate setting is not valid.
+
+0xC00D1BC2
+
+NS_E_INVALID_VIDEO_PEAKRATE_2
+
+
+The video peak bit rate setting must be greater than the video bit rate setting.
+
+0xC00D1BC3
+
+NS_E_INVALID_VIDEO_WIDTH
+
+
+The video width setting is not valid.
+
+0xC00D1BC4
+
+NS_E_INVALID_VIDEO_HEIGHT
+
+
+The video height setting is not valid.
+
+0xC00D1BC5
+
+NS_E_INVALID_VIDEO_FPS
+
+
+The video frame rate setting is not valid.
+
+0xC00D1BC6
+
+NS_E_INVALID_VIDEO_KEYFRAME
+
+
+The video key frame setting is not valid.
+
+0xC00D1BC7
+
+NS_E_INVALID_VIDEO_IQUALITY
+
+
+The video image quality setting is not valid.
+
+0xC00D1BC8
+
+NS_E_INVALID_VIDEO_CQUALITY
+
+
+The video codec quality setting is not valid.
+
+0xC00D1BC9
+
+NS_E_INVALID_VIDEO_BUFFER
+
+
+The video buffer setting is not valid.
+
+0xC00D1BCA
+
+NS_E_INVALID_VIDEO_BUFFERMAX
+
+
+The setting for the maximum buffer size for video is not valid.
+
+0xC00D1BCB
+
+NS_E_INVALID_VIDEO_BUFFERMAX_2
+
+
+The value of the video maximum buffer size setting must be greater than the video buffer size setting.
+
+0xC00D1BCC
+
+NS_E_INVALID_VIDEO_WIDTH_ALIGN
+
+
+The alignment of the video width is not valid.
+
+0xC00D1BCD
+
+NS_E_INVALID_VIDEO_HEIGHT_ALIGN
+
+
+The alignment of the video height is not valid.
+
+0xC00D1BCE
+
+NS_E_MULTIPLE_SCRIPT_BITRATES
+
+
+All bit rates must have the same script bit rate.
+
+0xC00D1BCF
+
+NS_E_INVALID_SCRIPT_BITRATE
+
+
+The script bit rate specified is not valid.
+
+0xC00D1BD0
+
+NS_E_MULTIPLE_FILE_BITRATES
+
+
+All bit rates must have the same file transfer bit rate.
+
+0xC00D1BD1
+
+NS_E_INVALID_FILE_BITRATE
+
+
+The file transfer bit rate is not valid.
+
+0xC00D1BD2
+
+NS_E_SAME_AS_INPUT_COMBINATION
+
+
+All audiences in a profile should either be same as input or have video width and height specified.
+
+0xC00D1BD3
+
+NS_E_SOURCE_CANNOT_LOOP
+
+
+This source type does not support looping.
+
+0xC00D1BD4
+
+NS_E_INVALID_FOLDDOWN_COEFFICIENTS
+
+
+The fold-down value needs to be between -144 and 0.
+
+0xC00D1BD5
+
+NS_E_DRMPROFILE_NOTFOUND
+
+
+The specified DRM profile does not exist in the system.
+
+0xC00D1BD6
+
+NS_E_INVALID_TIMECODE
+
+
+The specified time code is not valid.
+
+0xC00D1BD7
+
+NS_E_NO_AUDIO_TIMECOMPRESSION
+
+
+It is not possible to apply time compression to a video-only session.
+
+0xC00D1BD8
+
+NS_E_NO_TWOPASS_TIMECOMPRESSION
+
+
+It is not possible to apply time compression to a session that is using two-pass encoding.
+
+0xC00D1BD9
+
+NS_E_TIMECODE_REQUIRES_VIDEOSTREAM
+
+
+It is not possible to generate a time code for an audio-only session.
+
+0xC00D1BDA
+
+NS_E_NO_MBR_WITH_TIMECODE
+
+
+It is not possible to generate a time code when you are encoding content at multiple bit rates.
+
+0xC00D1BDB
+
+NS_E_INVALID_INTERLACEMODE
+
+
+The video codec selected does not support maintaining interlacing in video.
+
+0xC00D1BDC
+
+NS_E_INVALID_INTERLACE_COMPAT
+
+
+Maintaining interlacing in video is not compatible with Windows Media Player 7.1.
+
+0xC00D1BDD
+
+NS_E_INVALID_NONSQUAREPIXEL_COMPAT
+
+
+Allowing nonsquare pixel output is not compatible with Windows Media Player 7.1.
+
+0xC00D1BDE
+
+NS_E_INVALID_SOURCE_WITH_DEVICE_CONTROL
+
+
+Only capture devices can be used with device control.
+
+0xC00D1BDF
+
+NS_E_CANNOT_GENERATE_BROADCAST_INFO_FOR_QUALITYVBR
+
+
+It is not possible to generate the stream format file if you are using quality-based VBR encoding for the audio or video stream. Instead use the Windows Media file generated after encoding to create the announcement file.
+
+0xC00D1BE0
+
+NS_E_EXCEED_MAX_DRM_PROFILE_LIMIT
+
+
+It is not possible to create a DRM profile because the maximum number of profiles has been reached. You must delete some DRM profiles before creating new ones.
+
+0xC00D1BE1
+
+NS_E_DEVICECONTROL_UNSTABLE
+
+
+The device is in an unstable state. Check that the device is functioning properly and a tape is in place.
+
+0xC00D1BE2
+
+NS_E_INVALID_PIXEL_ASPECT_RATIO
+
+
+The pixel aspect ratio value must be between 1 and 255.
+
+0xC00D1BE3
+
+NS_E_AUDIENCE__LANGUAGE_CONTENTTYPE_MISMATCH
+
+
+All streams with different languages in the same audience must have same properties.
+
+0xC00D1BE4
+
+NS_E_INVALID_PROFILE_CONTENTTYPE
+
+
+The profile must contain at least one audio or video stream.
+
+0xC00D1BE5
+
+NS_E_TRANSFORM_PLUGIN_NOT_FOUND
+
+
+The transform plug-in could not be found.
+
+0xC00D1BE6
+
+NS_E_TRANSFORM_PLUGIN_INVALID
+
+
+The transform plug-in is not valid. It might be damaged or you might not have the required permissions to access the plug-in.
+
+0xC00D1BE7
+
+NS_E_EDL_REQUIRED_FOR_DEVICE_MULTIPASS
+
+
+To use two-pass encoding, you must enable device control and setup an edit decision list (EDL) that has at least one entry.
+
+0xC00D1BE8
+
+NS_E_INVALID_VIDEO_WIDTH_FOR_INTERLACED_ENCODING
+
+
+When you choose to maintain the interlacing in your video, the output video size must be a multiple of 4.
+
+0xC00D1BE9
+
+NS_E_MARKIN_UNSUPPORTED
+
+
+Markin/Markout is unsupported with this source type.
+
+0xC00D2711
+
+NS_E_DRM_INVALID_APPLICATION
+
+
+A problem has occurred in the Digital Rights Management component. Contact product support for this application.
+
+0xC00D2712
+
+NS_E_DRM_LICENSE_STORE_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D2713
+
+NS_E_DRM_SECURE_STORE_ERROR
+
+
+Secure storage is not working. Contact Microsoft product support.
+
+0xC00D2714
+
+NS_E_DRM_LICENSE_STORE_SAVE_ERROR
+
+
+License acquisition did not work. Acquire a new license or contact the content provider for further assistance.
+
+0xC00D2715
+
+NS_E_DRM_SECURE_STORE_UNLOCK_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2716
+
+NS_E_DRM_INVALID_CONTENT
+
+
+The media file is corrupted. Contact the content provider to get a new file.
+
+0xC00D2717
+
+NS_E_DRM_UNABLE_TO_OPEN_LICENSE
+
+
+The license is corrupted. Acquire a new license.
+
+0xC00D2718
+
+NS_E_DRM_INVALID_LICENSE
+
+
+The license is corrupted or invalid. Acquire a new license
+
+0xC00D2719
+
+NS_E_DRM_INVALID_MACHINE
+
+
+Licenses cannot be copied from one computer to another. Use License Management to transfer licenses, or get a new license for the media file.
+
+0xC00D271B
+
+NS_E_DRM_ENUM_LICENSE_FAILED
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D271C
+
+NS_E_DRM_INVALID_LICENSE_REQUEST
+
+
+The media file is corrupted. Contact the content provider to get a new file.
+
+0xC00D271D
+
+NS_E_DRM_UNABLE_TO_INITIALIZE
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D271E
+
+NS_E_DRM_UNABLE_TO_ACQUIRE_LICENSE
+
+
+The license could not be acquired. Try again later.
+
+0xC00D271F
+
+NS_E_DRM_INVALID_LICENSE_ACQUIRED
+
+
+License acquisition did not work. Acquire a new license or contact the content provider for further assistance.
+
+0xC00D2720
+
+NS_E_DRM_NO_RIGHTS
+
+
+The requested operation cannot be performed on this file.
+
+0xC00D2721
+
+NS_E_DRM_KEY_ERROR
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2722
+
+NS_E_DRM_ENCRYPT_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2723
+
+NS_E_DRM_DECRYPT_ERROR
+
+
+The media file is corrupted. Contact the content provider to get a new file.
+
+0xC00D2725
+
+NS_E_DRM_LICENSE_INVALID_XML
+
+
+The license is corrupted. Acquire a new license.
+
+0xC00D2728
+
+NS_E_DRM_NEEDS_INDIVIDUALIZATION
+
+
+A security upgrade is required to perform the operation on this media file.
+
+0xC00D2729
+
+NS_E_DRM_ALREADY_INDIVIDUALIZED
+
+
+You already have the latest security components. No upgrade is necessary at this time.
+
+0xC00D272A
+
+NS_E_DRM_ACTION_NOT_QUERIED
+
+
+The application cannot perform this action. Contact product support for this application.
+
+0xC00D272B
+
+NS_E_DRM_ACQUIRING_LICENSE
+
+
+You cannot begin a new license acquisition process until the current one has been completed.
+
+0xC00D272C
+
+NS_E_DRM_INDIVIDUALIZING
+
+
+You cannot begin a new security upgrade until the current one has been completed.
+
+0xC00D272D
+
+NS_E_BACKUP_RESTORE_FAILURE
+
+
+Failure in Backup-Restore.
+
+0xC00D272E
+
+NS_E_BACKUP_RESTORE_BAD_REQUEST_ID
+
+
+Bad Request ID in Backup-Restore.
+
+0xC00D272F
+
+NS_E_DRM_PARAMETERS_MISMATCHED
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2730
+
+NS_E_DRM_UNABLE_TO_CREATE_LICENSE_OBJECT
+
+
+A license cannot be created for this media file. Reinstall the application.
+
+0xC00D2731
+
+NS_E_DRM_UNABLE_TO_CREATE_INDI_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2732
+
+NS_E_DRM_UNABLE_TO_CREATE_ENCRYPT_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2733
+
+NS_E_DRM_UNABLE_TO_CREATE_DECRYPT_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2734
+
+NS_E_DRM_UNABLE_TO_CREATE_PROPERTIES_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2735
+
+NS_E_DRM_UNABLE_TO_CREATE_BACKUP_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2736
+
+NS_E_DRM_INDIVIDUALIZE_ERROR
+
+
+The security upgrade failed. Try again later.
+
+0xC00D2737
+
+NS_E_DRM_LICENSE_OPEN_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D2738
+
+NS_E_DRM_LICENSE_CLOSE_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D2739
+
+NS_E_DRM_GET_LICENSE_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D273A
+
+NS_E_DRM_QUERY_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D273B
+
+NS_E_DRM_REPORT_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Contact product support for this application.
+
+0xC00D273C
+
+NS_E_DRM_GET_LICENSESTRING_ERROR
+
+
+License storage is not working. Contact Microsoft product support.
+
+0xC00D273D
+
+NS_E_DRM_GET_CONTENTSTRING_ERROR
+
+
+The media file is corrupted. Contact the content provider to get a new file.
+
+0xC00D273E
+
+NS_E_DRM_MONITOR_ERROR
+
+
+A problem has occurred in the Digital Rights Management component. Try again later.
+
+0xC00D273F
+
+NS_E_DRM_UNABLE_TO_SET_PARAMETER
+
+
+The application has made an invalid call to the Digital Rights Management component. Contact product support for this application.
+
+0xC00D2740
+
+NS_E_DRM_INVALID_APPDATA
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2741
+
+NS_E_DRM_INVALID_APPDATA_VERSION
+
+
+A problem has occurred in the Digital Rights Management component. Contact product support for this application.
+
+0xC00D2742
+
+NS_E_DRM_BACKUP_EXISTS
+
+
+Licenses are already backed up in this location.
+
+0xC00D2743
+
+NS_E_DRM_BACKUP_CORRUPT
+
+
+One or more backed-up licenses are missing or corrupt.
+
+0xC00D2744
+
+NS_E_DRM_BACKUPRESTORE_BUSY
+
+
+You cannot begin a new backup process until the current process has been completed.
+
+0xC00D2745
+
+NS_E_BACKUP_RESTORE_BAD_DATA
+
+
+Bad Data sent to Backup-Restore.
+
+0xC00D2748
+
+NS_E_DRM_LICENSE_UNUSABLE
+
+
+The license is invalid. Contact the content provider for further assistance.
+
+0xC00D2749
+
+NS_E_DRM_INVALID_PROPERTY
+
+
+A required property was not set by the application. Contact product support for this application.
+
+0xC00D274A
+
+NS_E_DRM_SECURE_STORE_NOT_FOUND
+
+
+A problem has occurred in the Digital Rights Management component of this application. Try to acquire a license again.
+
+0xC00D274B
+
+NS_E_DRM_CACHED_CONTENT_ERROR
+
+
+A license cannot be found for this media file. Use License Management to transfer a license for this file from the original computer, or acquire a new license.
+
+0xC00D274C
+
+NS_E_DRM_INDIVIDUALIZATION_INCOMPLETE
+
+
+A problem occurred during the security upgrade. Try again later.
+
+0xC00D274D
+
+NS_E_DRM_DRIVER_AUTH_FAILURE
+
+
+Certified driver components are required to play this media file. Contact Windows Update to see whether updated drivers are available for your hardware.
+
+0xC00D274E
+
+NS_E_DRM_NEED_UPGRADE_MSSAP
+
+
+One or more of the Secure Audio Path components were not found or an entry point in those components was not found.
+
+0xC00D274F
+
+NS_E_DRM_REOPEN_CONTENT
+
+
+Status message: Reopen the file.
+
+0xC00D2750
+
+NS_E_DRM_DRIVER_DIGIOUT_FAILURE
+
+
+Certain driver functionality is required to play this media file. Contact Windows Update to see whether updated drivers are available for your hardware.
+
+0xC00D2751
+
+NS_E_DRM_INVALID_SECURESTORE_PASSWORD
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2752
+
+NS_E_DRM_APPCERT_REVOKED
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2753
+
+NS_E_DRM_RESTORE_FRAUD
+
+
+You cannot restore your license(s).
+
+0xC00D2754
+
+NS_E_DRM_HARDWARE_INCONSISTENT
+
+
+The licenses for your media files are corrupted. Contact Microsoft product support.
+
+0xC00D2755
+
+NS_E_DRM_SDMI_TRIGGER
+
+
+To transfer this media file, you must upgrade the application.
+
+0xC00D2756
+
+NS_E_DRM_SDMI_NOMORECOPIES
+
+
+You cannot make any more copies of this media file.
+
+0xC00D2757
+
+NS_E_DRM_UNABLE_TO_CREATE_HEADER_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2758
+
+NS_E_DRM_UNABLE_TO_CREATE_KEYS_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2759
+
+NS_E_DRM_LICENSE_NOTACQUIRED
+
+
+Unable to obtain license.
+
+0xC00D275A
+
+NS_E_DRM_UNABLE_TO_CREATE_CODING_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D275B
+
+NS_E_DRM_UNABLE_TO_CREATE_STATE_DATA_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D275C
+
+NS_E_DRM_BUFFER_TOO_SMALL
+
+
+The buffer supplied is not sufficient.
+
+0xC00D275D
+
+NS_E_DRM_UNSUPPORTED_PROPERTY
+
+
+The property requested is not supported.
+
+0xC00D275E
+
+NS_E_DRM_ERROR_BAD_NET_RESP
+
+
+The specified server cannot perform the requested operation.
+
+0xC00D275F
+
+NS_E_DRM_STORE_NOTALLSTORED
+
+
+Some of the licenses could not be stored.
+
+0xC00D2760
+
+NS_E_DRM_SECURITY_COMPONENT_SIGNATURE_INVALID
+
+
+The Digital Rights Management security upgrade component could not be validated. Contact Microsoft product support.
+
+0xC00D2761
+
+NS_E_DRM_INVALID_DATA
+
+
+Invalid or corrupt data was encountered.
+
+0xC00D2762
+
+NS_E_DRM_POLICY_DISABLE_ONLINE
+
+
+The Windows Media Digital Rights Management system cannot perform the requested action because your computer or network administrator has enabled the group policy Prevent Windows Media DRM Internet Access. For assistance, contact your administrator.
+
+0xC00D2763
+
+NS_E_DRM_UNABLE_TO_CREATE_AUTHENTICATION_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2764
+
+NS_E_DRM_NOT_CONFIGURED
+
+
+Not all of the necessary properties for DRM have been set.
+
+0xC00D2765
+
+NS_E_DRM_DEVICE_ACTIVATION_CANCELED
+
+
+The portable device does not have the security required to copy protected files to it. To obtain the additional security, try to copy the file to your portable device again. When a message appears, click OK.
+
+0xC00D2766
+
+NS_E_BACKUP_RESTORE_TOO_MANY_RESETS
+
+
+Too many resets in Backup-Restore.
+
+0xC00D2767
+
+NS_E_DRM_DEBUGGING_NOT_ALLOWED
+
+
+Running this process under a debugger while using DRM content is not allowed.
+
+0xC00D2768
+
+NS_E_DRM_OPERATION_CANCELED
+
+
+The user canceled the DRM operation.
+
+0xC00D2769
+
+NS_E_DRM_RESTRICTIONS_NOT_RETRIEVED
+
+
+The license you are using has assocaited output restrictions. This license is unusable until these restrictions are queried.
+
+0xC00D276A
+
+NS_E_DRM_UNABLE_TO_CREATE_PLAYLIST_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D276B
+
+NS_E_DRM_UNABLE_TO_CREATE_PLAYLIST_BURN_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D276C
+
+NS_E_DRM_UNABLE_TO_CREATE_DEVICE_REGISTRATION_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D276D
+
+NS_E_DRM_UNABLE_TO_CREATE_METERING_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2770
+
+NS_E_DRM_TRACK_EXCEEDED_PLAYLIST_RESTICTION
+
+
+The specified track has exceeded it's specified playlist burn limit in this playlist.
+
+0xC00D2771
+
+NS_E_DRM_TRACK_EXCEEDED_TRACKBURN_RESTRICTION
+
+
+The specified track has exceeded it's track burn limit.
+
+0xC00D2772
+
+NS_E_DRM_UNABLE_TO_GET_DEVICE_CERT
+
+
+A problem has occurred in obtaining the device's certificate. Contact Microsoft product support.
+
+0xC00D2773
+
+NS_E_DRM_UNABLE_TO_GET_SECURE_CLOCK
+
+
+A problem has occurred in obtaining the device's secure clock. Contact Microsoft product support.
+
+0xC00D2774
+
+NS_E_DRM_UNABLE_TO_SET_SECURE_CLOCK
+
+
+A problem has occurred in setting the device's secure clock. Contact Microsoft product support.
+
+0xC00D2775
+
+NS_E_DRM_UNABLE_TO_GET_SECURE_CLOCK_FROM_SERVER
+
+
+A problem has occurred in obtaining the secure clock from server. Contact Microsoft product support.
+
+0xC00D2776
+
+NS_E_DRM_POLICY_METERING_DISABLED
+
+
+This content requires the metering policy to be enabled.
+
+0xC00D2777
+
+NS_E_DRM_TRANSFER_CHAINED_LICENSES_UNSUPPORTED
+
+
+Transfer of chained licenses unsupported.
+
+0xC00D2778
+
+NS_E_DRM_SDK_VERSIONMISMATCH
+
+
+The Digital Rights Management component is not installed properly. Reinstall the Player.
+
+0xC00D2779
+
+NS_E_DRM_LIC_NEEDS_DEVICE_CLOCK_SET
+
+
+The file could not be transferred because the device clock is not set.
+
+0xC00D277A
+
+NS_E_LICENSE_HEADER_MISSING_URL
+
+
+The content header is missing an acquisition URL.
+
+0xC00D277B
+
+NS_E_DEVICE_NOT_WMDRM_DEVICE
+
+
+The current attached device does not support WMDRM.
+
+0xC00D277C
+
+NS_E_DRM_INVALID_APPCERT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D277D
+
+NS_E_DRM_PROTOCOL_FORCEFUL_TERMINATION_ON_PETITION
+
+
+The client application has been forcefully terminated during a DRM petition.
+
+0xC00D277E
+
+NS_E_DRM_PROTOCOL_FORCEFUL_TERMINATION_ON_CHALLENGE
+
+
+The client application has been forcefully terminated during a DRM challenge.
+
+0xC00D277F
+
+NS_E_DRM_CHECKPOINT_FAILED
+
+
+Secure storage protection error. Restore your licenses from a previous backup and try again.
+
+0xC00D2780
+
+NS_E_DRM_BB_UNABLE_TO_INITIALIZE
+
+
+A problem has occurred in the Digital Rights Management root of trust. Contact Microsoft product support.
+
+0xC00D2781
+
+NS_E_DRM_UNABLE_TO_LOAD_HARDWARE_ID
+
+
+A problem has occurred in retrieving the Digital Rights Management machine identification. Contact Microsoft product support.
+
+0xC00D2782
+
+NS_E_DRM_UNABLE_TO_OPEN_DATA_STORE
+
+
+A problem has occurred in opening the Digital Rights Management data storage file. Contact Microsoft product.
+
+0xC00D2783
+
+NS_E_DRM_DATASTORE_CORRUPT
+
+
+The Digital Rights Management data storage is not functioning properly. Contact Microsoft product support.
+
+0xC00D2784
+
+NS_E_DRM_UNABLE_TO_CREATE_INMEMORYSTORE_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2785
+
+NS_E_DRM_STUBLIB_REQUIRED
+
+
+A secured library is required to access the requested functionality.
+
+0xC00D2786
+
+NS_E_DRM_UNABLE_TO_CREATE_CERTIFICATE_OBJECT
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2787
+
+NS_E_DRM_MIGRATION_TARGET_NOT_ONLINE
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D2788
+
+NS_E_DRM_INVALID_MIGRATION_IMAGE
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D2789
+
+NS_E_DRM_MIGRATION_TARGET_STATES_CORRUPTED
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D278A
+
+NS_E_DRM_MIGRATION_IMPORTER_NOT_AVAILABLE
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D278B
+
+NS_DRM_E_MIGRATION_UPGRADE_WITH_DIFF_SID
+
+
+A problem has occurred in the Digital Rights Management component during license migration. Contact Microsoft product support.
+
+0xC00D278C
+
+NS_DRM_E_MIGRATION_SOURCE_MACHINE_IN_USE
+
+
+The Digital Rights Management component is in use during license migration. Contact Microsoft product support.
+
+0xC00D278D
+
+NS_DRM_E_MIGRATION_TARGET_MACHINE_LESS_THAN_LH
+
+
+Licenses are being migrated to a machine running XP or downlevel OS. This operation can only be performed on Windows Vista or a later OS. Contact Microsoft product support.
+
+0xC00D278E
+
+NS_DRM_E_MIGRATION_IMAGE_ALREADY_EXISTS
+
+
+Migration Image already exists. Contact Microsoft product support.
+
+0xC00D278F
+
+NS_E_DRM_HARDWAREID_MISMATCH
+
+
+The requested action cannot be performed because a hardware configuration change has been detected by the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2790
+
+NS_E_INVALID_DRMV2CLT_STUBLIB
+
+
+The wrong stublib has been linked to an application or DLL using drmv2clt.dll.
+
+0xC00D2791
+
+NS_E_DRM_MIGRATION_INVALID_LEGACYV2_DATA
+
+
+The legacy V2 data being imported is invalid.
+
+0xC00D2792
+
+NS_E_DRM_MIGRATION_LICENSE_ALREADY_EXISTS
+
+
+The license being imported already exists.
+
+0xC00D2793
+
+NS_E_DRM_MIGRATION_INVALID_LEGACYV2_SST_PASSWORD
+
+
+The password of the Legacy V2 SST entry being imported is incorrect.
+
+0xC00D2794
+
+NS_E_DRM_MIGRATION_NOT_SUPPORTED
+
+
+Migration is not supported by the plugin.
+
+0xC00D2795
+
+NS_E_DRM_UNABLE_TO_CREATE_MIGRATION_IMPORTER_OBJECT
+
+
+A migration importer cannot be created for this media file. Reinstall the application.
+
+0xC00D2796
+
+NS_E_DRM_CHECKPOINT_MISMATCH
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2797
+
+NS_E_DRM_CHECKPOINT_CORRUPT
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2798
+
+NS_E_REG_FLUSH_FAILURE
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D2799
+
+NS_E_HDS_KEY_MISMATCH
+
+
+The requested action cannot be performed because a problem occurred with the Windows Media Digital Rights Management (DRM) components on your computer.
+
+0xC00D279A
+
+NS_E_DRM_MIGRATION_OPERATION_CANCELLED
+
+
+Migration was canceled by the user.
+
+0xC00D279B
+
+NS_E_DRM_MIGRATION_OBJECT_IN_USE
+
+
+Migration object is already in use and cannot be called until the current operation completes.
+
+0xC00D279C
+
+NS_E_DRM_MALFORMED_CONTENT_HEADER
+
+
+The content header does not comply with DRM requirements and cannot be used.
+
+0xC00D27D8
+
+NS_E_DRM_LICENSE_EXPIRED
+
+
+The license for this file has expired and is no longer valid. Contact your content provider for further assistance.
+
+0xC00D27D9
+
+NS_E_DRM_LICENSE_NOTENABLED
+
+
+The license for this file is not valid yet, but will be at a future date.
+
+0xC00D27DA
+
+NS_E_DRM_LICENSE_APPSECLOW
+
+
+The license for this file requires a higher level of security than the player you are currently using has. Try using a different player or download a newer version of your current player.
+
+0xC00D27DB
+
+NS_E_DRM_STORE_NEEDINDI
+
+
+The license cannot be stored as it requires security upgrade of Digital Rights Management component.
+
+0xC00D27DC
+
+NS_E_DRM_STORE_NOTALLOWED
+
+
+Your machine does not meet the requirements for storing the license.
+
+0xC00D27DD
+
+NS_E_DRM_LICENSE_APP_NOTALLOWED
+
+
+The license for this file requires an upgraded version of your player or a different player.
+
+0xC00D27DF
+
+NS_E_DRM_LICENSE_CERT_EXPIRED
+
+
+The license server's certificate expired. Make sure your system clock is set correctly. Contact your content provider for further assistance.
+
+0xC00D27E0
+
+NS_E_DRM_LICENSE_SECLOW
+
+
+The license for this file requires a higher level of security than the player you are currently using has. Try using a different player or download a newer version of your current player.
+
+0xC00D27E1
+
+NS_E_DRM_LICENSE_CONTENT_REVOKED
+
+
+The content owner for the license you just acquired is no longer supporting their content. Contact the content owner for a newer version of the content.
+
+0xC00D27E2
+
+NS_E_DRM_DEVICE_NOT_REGISTERED
+
+
+The content owner for the license you just acquired requires your device to register to the current machine.
+
+0xC00D280A
+
+NS_E_DRM_LICENSE_NOSAP
+
+
+The license for this file requires a feature that is not supported in your current player or operating system. You can try with newer version of your current player or contact your content provider for further assistance.
+
+0xC00D280B
+
+NS_E_DRM_LICENSE_NOSVP
+
+
+The license for this file requires a feature that is not supported in your current player or operating system. You can try with newer version of your current player or contact your content provider for further assistance.
+
+0xC00D280C
+
+NS_E_DRM_LICENSE_NOWDM
+
+
+The license for this file requires Windows Driver Model (WDM) audio drivers. Contact your sound card manufacturer for further assistance.
+
+0xC00D280D
+
+NS_E_DRM_LICENSE_NOTRUSTEDCODEC
+
+
+The license for this file requires a higher level of security than the player you are currently using has. Try using a different player or download a newer version of your current player.
+
+0xC00D280E
+
+NS_E_DRM_SOURCEID_NOT_SUPPORTED
+
+
+The license for this file is not supported by your current player. You can try with newer version of your current player or contact your content provider for further assistance.
+
+0xC00D283D
+
+NS_E_DRM_NEEDS_UPGRADE_TEMPFILE
+
+
+An updated version of your media player is required to play the selected content.
+
+0xC00D283E
+
+NS_E_DRM_NEED_UPGRADE_PD
+
+
+A new version of the Digital Rights Management component is required. Contact product support for this application to get the latest version.
+
+0xC00D283F
+
+NS_E_DRM_SIGNATURE_FAILURE
+
+
+Failed to either create or verify the content header.
+
+0xC00D2840
+
+NS_E_DRM_LICENSE_SERVER_INFO_MISSING
+
+
+Could not read the necessary information from the system registry.
+
+0xC00D2841
+
+NS_E_DRM_BUSY
+
+
+The DRM subsystem is currently locked by another application or user. Try again later.
+
+0xC00D2842
+
+NS_E_DRM_PD_TOO_MANY_DEVICES
+
+
+There are too many target devices registered on the portable media.
+
+0xC00D2843
+
+NS_E_DRM_INDIV_FRAUD
+
+
+The security upgrade cannot be completed because the allowed number of daily upgrades has been exceeded. Try again tomorrow.
+
+0xC00D2844
+
+NS_E_DRM_INDIV_NO_CABS
+
+
+The security upgrade cannot be completed because the server is unable to perform the operation. Try again later.
+
+0xC00D2845
+
+NS_E_DRM_INDIV_SERVICE_UNAVAILABLE
+
+
+The security upgrade cannot be performed because the server is not available. Try again later.
+
+0xC00D2846
+
+NS_E_DRM_RESTORE_SERVICE_UNAVAILABLE
+
+
+Windows Media Player cannot restore your licenses because the server is not available. Try again later.
+
+0xC00D2847
+
+NS_E_DRM_CLIENT_CODE_EXPIRED
+
+
+Windows Media Player cannot play the protected file. Verify that your computer's date is set correctly. If it is correct, on the Help menu, click Check for Player Updates to install the latest version of the Player.
+
+0xC00D2848
+
+NS_E_DRM_NO_UPLINK_LICENSE
+
+
+The chained license cannot be created because the referenced uplink license does not exist.
+
+0xC00D2849
+
+NS_E_DRM_INVALID_KID
+
+
+The specified KID is invalid.
+
+0xC00D284A
+
+NS_E_DRM_LICENSE_INITIALIZATION_ERROR
+
+
+License initialization did not work. Contact Microsoft product support.
+
+0xC00D284C
+
+NS_E_DRM_CHAIN_TOO_LONG
+
+
+The uplink license of a chained license cannot itself be a chained license.
+
+0xC00D284D
+
+NS_E_DRM_UNSUPPORTED_ALGORITHM
+
+
+The specified encryption algorithm is unsupported.
+
+0xC00D284E
+
+NS_E_DRM_LICENSE_DELETION_ERROR
+
+
+License deletion did not work. Contact Microsoft product support.
+
+0xC00D28A0
+
+NS_E_DRM_INVALID_CERTIFICATE
+
+
+The client's certificate is corrupted or the signature cannot be verified.
+
+0xC00D28A1
+
+NS_E_DRM_CERTIFICATE_REVOKED
+
+
+The client's certificate has been revoked.
+
+0xC00D28A2
+
+NS_E_DRM_LICENSE_UNAVAILABLE
+
+
+There is no license available for the requested action.
+
+0xC00D28A3
+
+NS_E_DRM_DEVICE_LIMIT_REACHED
+
+
+The maximum number of devices in use has been reached. Unable to open additional devices.
+
+0xC00D28A4
+
+NS_E_DRM_UNABLE_TO_VERIFY_PROXIMITY
+
+
+The proximity detection procedure could not confirm that the receiver is near the transmitter in the network.
+
+0xC00D28A5
+
+NS_E_DRM_MUST_REGISTER
+
+
+The client must be registered before executing the intended operation.
+
+0xC00D28A6
+
+NS_E_DRM_MUST_APPROVE
+
+
+The client must be approved before executing the intended operation.
+
+0xC00D28A7
+
+NS_E_DRM_MUST_REVALIDATE
+
+
+The client must be revalidated before executing the intended operation.
+
+0xC00D28A8
+
+NS_E_DRM_INVALID_PROXIMITY_RESPONSE
+
+
+The response to the proximity detection challenge is invalid.
+
+0xC00D28A9
+
+NS_E_DRM_INVALID_SESSION
+
+
+The requested session is invalid.
+
+0xC00D28AA
+
+NS_E_DRM_DEVICE_NOT_OPEN
+
+
+The device must be opened before it can be used to receive content.
+
+0xC00D28AB
+
+NS_E_DRM_DEVICE_ALREADY_REGISTERED
+
+
+Device registration failed because the device is already registered.
+
+0xC00D28AC
+
+NS_E_DRM_UNSUPPORTED_PROTOCOL_VERSION
+
+
+Unsupported WMDRM-ND protocol version.
+
+0xC00D28AD
+
+NS_E_DRM_UNSUPPORTED_ACTION
+
+
+The requested action is not supported.
+
+0xC00D28AE
+
+NS_E_DRM_CERTIFICATE_SECURITY_LEVEL_INADEQUATE
+
+
+The certificate does not have an adequate security level for the requested action.
+
+0xC00D28AF
+
+NS_E_DRM_UNABLE_TO_OPEN_PORT
+
+
+Unable to open the specified port for receiving Proximity messages.
+
+0xC00D28B0
+
+NS_E_DRM_BAD_REQUEST
+
+
+The message format is invalid.
+
+0xC00D28B1
+
+NS_E_DRM_INVALID_CRL
+
+
+The Certificate Revocation List is invalid or corrupted.
+
+0xC00D28B2
+
+NS_E_DRM_ATTRIBUTE_TOO_LONG
+
+
+The length of the attribute name or value is too long.
+
+0xC00D28B3
+
+NS_E_DRM_EXPIRED_LICENSEBLOB
+
+
+The license blob passed in the cardea request is expired.
+
+0xC00D28B4
+
+NS_E_DRM_INVALID_LICENSEBLOB
+
+
+The license blob passed in the cardea request is invalid. Contact Microsoft product support.
+
+0xC00D28B5
+
+NS_E_DRM_INCLUSION_LIST_REQUIRED
+
+
+The requested operation cannot be performed because the license does not contain an inclusion list.
+
+0xC00D28B6
+
+NS_E_DRM_DRMV2CLT_REVOKED
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D28B7
+
+NS_E_DRM_RIV_TOO_SMALL
+
+
+A problem has occurred in the Digital Rights Management component. Contact Microsoft product support.
+
+0xC00D2904
+
+NS_E_OUTPUT_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of output protection required by the content.
+
+0xC00D2905
+
+NS_E_COMPRESSED_DIGITAL_VIDEO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for compressed digital video.
+
+0xC00D2906
+
+NS_E_UNCOMPRESSED_DIGITAL_VIDEO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for uncompressed digital video.
+
+0xC00D2907
+
+NS_E_ANALOG_VIDEO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for analog video.
+
+0xC00D2908
+
+NS_E_COMPRESSED_DIGITAL_AUDIO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for compressed digital audio.
+
+0xC00D2909
+
+NS_E_UNCOMPRESSED_DIGITAL_AUDIO_PROTECTION_LEVEL_UNSUPPORTED
+
+
+Windows Media Player does not support the level of protection required for uncompressed digital audio.
+
+0xC00D290A
+
+NS_E_OUTPUT_PROTECTION_SCHEME_UNSUPPORTED
+
+
+Windows Media Player does not support the scheme of output protection required by the content.
+
+0xC00D2AFA
+
+NS_E_REBOOT_RECOMMENDED
+
+
+Installation was not successful and some file cleanup is not complete. For best results, restart your computer.
+
+0xC00D2AFB
+
+NS_E_REBOOT_REQUIRED
+
+
+Installation was not successful. To continue, you must restart your computer.
+
+0xC00D2AFC
+
+NS_E_SETUP_INCOMPLETE
+
+
+Installation was not successful.
+
+0xC00D2AFD
+
+NS_E_SETUP_DRM_MIGRATION_FAILED
+
+
+Setup cannot migrate the Windows Media Digital Rights Management (DRM) components.
+
+0xC00D2AFE
+
+NS_E_SETUP_IGNORABLE_FAILURE
+
+
+Some skin or playlist components cannot be installed.
+
+0xC00D2AFF
+
+NS_E_SETUP_DRM_MIGRATION_FAILED_AND_IGNORABLE_FAILURE
+
+
+Setup cannot migrate the Windows Media Digital Rights Management (DRM) components. In addition, some skin or playlist components cannot be installed.
+
+0xC00D2B00
+
+NS_E_SETUP_BLOCKED
+
+
+Installation is blocked because your computer does not meet one or more of the setup requirements.
+
+0xC00D2EE0
+
+NS_E_UNKNOWN_PROTOCOL
+
+
+The specified protocol is not supported.
+
+0xC00D2EE1
+
+NS_E_REDIRECT_TO_PROXY
+
+
+The client is redirected to a proxy server.
+
+0xC00D2EE2
+
+NS_E_INTERNAL_SERVER_ERROR
+
+
+The server encountered an unexpected condition which prevented it from fulfilling the request.
+
+0xC00D2EE3
+
+NS_E_BAD_REQUEST
+
+
+The request could not be understood by the server.
+
+0xC00D2EE4
+
+NS_E_ERROR_FROM_PROXY
+
+
+The proxy experienced an error while attempting to contact the media server.
+
+0xC00D2EE5
+
+NS_E_PROXY_TIMEOUT
+
+
+The proxy did not receive a timely response while attempting to contact the media server.
+
+0xC00D2EE6
+
+NS_E_SERVER_UNAVAILABLE
+
+
+The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.
+
+0xC00D2EE7
+
+NS_E_REFUSED_BY_SERVER
+
+
+The server is refusing to fulfill the requested operation.
+
+0xC00D2EE8
+
+NS_E_INCOMPATIBLE_SERVER
+
+
+The server is not a compatible streaming media server.
+
+0xC00D2EE9
+
+NS_E_MULTICAST_DISABLED
+
+
+The content cannot be streamed because the Multicast protocol has been disabled.
+
+0xC00D2EEA
+
+NS_E_INVALID_REDIRECT
+
+
+The server redirected the player to an invalid location.
+
+0xC00D2EEB
+
+NS_E_ALL_PROTOCOLS_DISABLED
+
+
+The content cannot be streamed because all protocols have been disabled.
+
+0xC00D2EEC
+
+NS_E_MSBD_NO_LONGER_SUPPORTED
+
+
+The MSBD protocol is no longer supported. Please use HTTP to connect to the Windows Media stream.
+
+0xC00D2EED
+
+NS_E_PROXY_NOT_FOUND
+
+
+The proxy server could not be located. Please check your proxy server configuration.
+
+0xC00D2EEE
+
+NS_E_CANNOT_CONNECT_TO_PROXY
+
+
+Unable to establish a connection to the proxy server. Please check your proxy server configuration.
+
+0xC00D2EEF
+
+NS_E_SERVER_DNS_TIMEOUT
+
+
+Unable to locate the media server. The operation timed out.
+
+0xC00D2EF0
+
+NS_E_PROXY_DNS_TIMEOUT
+
+
+Unable to locate the proxy server. The operation timed out.
+
+0xC00D2EF1
+
+NS_E_CLOSED_ON_SUSPEND
+
+
+Media closed because Windows was shut down.
+
+0xC00D2EF2
+
+NS_E_CANNOT_READ_PLAYLIST_FROM_MEDIASERVER
+
+
+Unable to read the contents of a playlist file from a media server.
+
+0xC00D2EF3
+
+NS_E_SESSION_NOT_FOUND
+
+
+Session not found.
+
+0xC00D2EF4
+
+NS_E_REQUIRE_STREAMING_CLIENT
+
+
+Content requires a streaming media client.
+
+0xC00D2EF5
+
+NS_E_PLAYLIST_ENTRY_HAS_CHANGED
+
+
+A command applies to a previous playlist entry.
+
+0xC00D2EF6
+
+NS_E_PROXY_ACCESSDENIED
+
+
+The proxy server is denying access. The username and/or password might be incorrect.
+
+0xC00D2EF7
+
+NS_E_PROXY_SOURCE_ACCESSDENIED
+
+
+The proxy could not provide valid authentication credentials to the media server.
+
+0xC00D2EF8
+
+NS_E_NETWORK_SINK_WRITE
+
+
+The network sink failed to write data to the network.
+
+0xC00D2EF9
+
+NS_E_FIREWALL
+
+
+Packets are not being received from the server. The packets might be blocked by a filtering device, such as a network firewall.
+
+0xC00D2EFA
+
+NS_E_MMS_NOT_SUPPORTED
+
+
+The MMS protocol is not supported. Please use HTTP or RTSP to connect to the Windows Media stream.
+
+0xC00D2EFB
+
+NS_E_SERVER_ACCESSDENIED
+
+
+The Windows Media server is denying access. The username and/or password might be incorrect.
+
+0xC00D2EFC
+
+NS_E_RESOURCE_GONE
+
+
+The Publishing Point or file on the Windows Media Server is no longer available.
+
+0xC00D2EFD
+
+NS_E_NO_EXISTING_PACKETIZER
+
+
+There is no existing packetizer plugin for a stream.
+
+0xC00D2EFE
+
+NS_E_BAD_SYNTAX_IN_SERVER_RESPONSE
+
+
+The response from the media server could not be understood. This might be caused by an incompatible proxy server or media server.
+
+0xC00D2F00
+
+NS_E_RESET_SOCKET_CONNECTION
+
+
+The Windows Media Server reset the network connection.
+
+0xC00D2F02
+
+NS_E_TOO_MANY_HOPS
+
+
+The request could not reach the media server (too many hops).
+
+0xC00D2F05
+
+NS_E_TOO_MUCH_DATA_FROM_SERVER
+
+
+The server is sending too much data. The connection has been terminated.
+
+0xC00D2F06
+
+NS_E_CONNECT_TIMEOUT
+
+
+It was not possible to establish a connection to the media server in a timely manner. The media server might be down for maintenance, or it might be necessary to use a proxy server to access this media server.
+
+0xC00D2F07
+
+NS_E_PROXY_CONNECT_TIMEOUT
+
+
+It was not possible to establish a connection to the proxy server in a timely manner. Please check your proxy server configuration.
+
+0xC00D2F08
+
+NS_E_SESSION_INVALID
+
+
+Session not found.
+
+0xC00D2F0A
+
+NS_E_PACKETSINK_UNKNOWN_FEC_STREAM
+
+
+Unknown packet sink stream.
+
+0xC00D2F0B
+
+NS_E_PUSH_CANNOTCONNECT
+
+
+Unable to establish a connection to the server. Ensure Windows Media Services is started and the HTTP Server control protocol is properly enabled.
+
+0xC00D2F0C
+
+NS_E_INCOMPATIBLE_PUSH_SERVER
+
+
+The Server service that received the HTTP push request is not a compatible version of Windows Media Services (WMS). This error might indicate the push request was received by IIS instead of WMS. Ensure WMS is started and has the HTTP Server control protocol properly enabled and try again.
+
+0xC00D32C8
+
+NS_E_END_OF_PLAYLIST
+
+
+The playlist has reached its end.
+
+0xC00D32C9
+
+NS_E_USE_FILE_SOURCE
+
+
+Use file source.
+
+0xC00D32CA
+
+NS_E_PROPERTY_NOT_FOUND
+
+
+The property was not found.
+
+0xC00D32CC
+
+NS_E_PROPERTY_READ_ONLY
+
+
+The property is read only.
+
+0xC00D32CD
+
+NS_E_TABLE_KEY_NOT_FOUND
+
+
+The table key was not found.
+
+0xC00D32CF
+
+NS_E_INVALID_QUERY_OPERATOR
+
+
+Invalid query operator.
+
+0xC00D32D0
+
+NS_E_INVALID_QUERY_PROPERTY
+
+
+Invalid query property.
+
+0xC00D32D2
+
+NS_E_PROPERTY_NOT_SUPPORTED
+
+
+The property is not supported.
+
+0xC00D32D4
+
+NS_E_SCHEMA_CLASSIFY_FAILURE
+
+
+Schema classification failure.
+
+0xC00D32D5
+
+NS_E_METADATA_FORMAT_NOT_SUPPORTED
+
+
+The metadata format is not supported.
+
+0xC00D32D6
+
+NS_E_METADATA_NO_EDITING_CAPABILITY
+
+
+Cannot edit the metadata.
+
+0xC00D32D7
+
+NS_E_METADATA_CANNOT_SET_LOCALE
+
+
+Cannot set the locale id.
+
+0xC00D32D8
+
+NS_E_METADATA_LANGUAGE_NOT_SUPORTED
+
+
+The language is not supported in the format.
+
+0xC00D32D9
+
+NS_E_METADATA_NO_RFC1766_NAME_FOR_LOCALE
+
+
+There is no RFC1766 name translation for the supplied locale id.
+
+0xC00D32DA
+
+NS_E_METADATA_NOT_AVAILABLE
+
+
+The metadata (or metadata item) is not available.
+
+0xC00D32DB
+
+NS_E_METADATA_CACHE_DATA_NOT_AVAILABLE
+
+
+The cached metadata (or metadata item) is not available.
+
+0xC00D32DC
+
+NS_E_METADATA_INVALID_DOCUMENT_TYPE
+
+
+The metadata document is invalid.
+
+0xC00D32DD
+
+NS_E_METADATA_IDENTIFIER_NOT_AVAILABLE
+
+
+The metadata content identifier is not available.
+
+0xC00D32DE
+
+NS_E_METADATA_CANNOT_RETRIEVE_FROM_OFFLINE_CACHE
+
+
+Cannot retrieve metadata from the offline metadata cache.
+
+0xC0261003
+
+ERROR_MONITOR_INVALID_DESCRIPTOR_CHECKSUM
+
+
+Checksum of the obtained monitor descriptor is invalid.
+
+0xC0261004
+
+ERROR_MONITOR_INVALID_STANDARD_TIMING_BLOCK
+
+
+Monitor descriptor contains an invalid standard timing block.
+
+0xC0261005
+
+ERROR_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED
+
+
+Windows Management Instrumentation (WMI) data block registration failed for one of the MSMonitorClass WMI subclasses.
+
+0xC0261006
+
+ERROR_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK
+
+
+Provided monitor descriptor block is either corrupted or does not contain the monitor's detailed serial number.
+
+0xC0261007
+
+ERROR_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK
+
+
+Provided monitor descriptor block is either corrupted or does not contain the monitor's user-friendly name.
+
+0xC0261008
+
+ERROR_MONITOR_NO_MORE_DESCRIPTOR_DATA
+
+
+There is no monitor descriptor data at the specified (offset, size) region.
+
+0xC0261009
+
+ERROR_MONITOR_INVALID_DETAILED_TIMING_BLOCK
+
+
+Monitor descriptor contains an invalid detailed timing block.
+
+0xC0262000
+
+ERROR_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER
+
+
+Exclusive mode ownership is needed to create unmanaged primary allocation.
+
+0xC0262001
+
+ERROR_GRAPHICS_INSUFFICIENT_DMA_BUFFER
+
+
+The driver needs more direct memory access (DMA) buffer space to complete the requested operation.
+
+0xC0262002
+
+ERROR_GRAPHICS_INVALID_DISPLAY_ADAPTER
+
+
+Specified display adapter handle is invalid.
+
+0xC0262003
+
+ERROR_GRAPHICS_ADAPTER_WAS_RESET
+
+
+Specified display adapter and all of its state has been reset.
+
+0xC0262004
+
+ERROR_GRAPHICS_INVALID_DRIVER_MODEL
+
+
+The driver stack does not match the expected driver model.
+
+0xC0262005
+
+ERROR_GRAPHICS_PRESENT_MODE_CHANGED
+
+
+Present happened but ended up into the changed desktop mode.
+
+0xC0262006
+
+ERROR_GRAPHICS_PRESENT_OCCLUDED
+
+
+Nothing to present due to desktop occlusion.
+
+0xC0262007
+
+ERROR_GRAPHICS_PRESENT_DENIED
+
+
+Not able to present due to denial of desktop access.
+
+0xC0262008
+
+ERROR_GRAPHICS_CANNOTCOLORCONVERT
+
+
+Not able to present with color conversion.
+
+0xC0262100
+
+ERROR_GRAPHICS_NO_VIDEO_MEMORY
+
+
+Not enough video memory available to complete the operation.
+
+0xC0262101
+
+ERROR_GRAPHICS_CANT_LOCK_MEMORY
+
+
+Could not probe and lock the underlying memory of an allocation.
+
+0xC0262102
+
+ERROR_GRAPHICS_ALLOCATION_BUSY
+
+
+The allocation is currently busy.
+
+0xC0262103
+
+ERROR_GRAPHICS_TOO_MANY_REFERENCES
+
+
+An object being referenced has reach the maximum reference count already and cannot be referenced further.
+
+0xC0262104
+
+ERROR_GRAPHICS_TRY_AGAIN_LATER
+
+
+A problem could not be solved due to some currently existing condition. The problem should be tried again later.
+
+0xC0262105
+
+ERROR_GRAPHICS_TRY_AGAIN_NOW
+
+
+A problem could not be solved due to some currently existing condition. The problem should be tried again immediately.
+
+0xC0262106
+
+ERROR_GRAPHICS_ALLOCATION_INVALID
+
+
+The allocation is invalid.
+
+0xC0262107
+
+ERROR_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE
+
+
+No more unswizzling apertures are currently available.
+
+0xC0262108
+
+ERROR_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED
+
+
+The current allocation cannot be unswizzled by an aperture.
+
+0xC0262109
+
+ERROR_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION
+
+
+The request failed because a pinned allocation cannot be evicted.
+
+0xC0262110
+
+ERROR_GRAPHICS_INVALID_ALLOCATION_USAGE
+
+
+The allocation cannot be used from its current segment location for the specified operation.
+
+0xC0262111
+
+ERROR_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION
+
+
+A locked allocation cannot be used in the current command buffer.
+
+0xC0262112
+
+ERROR_GRAPHICS_ALLOCATION_CLOSED
+
+
+The allocation being referenced has been closed permanently.
+
+0xC0262113
+
+ERROR_GRAPHICS_INVALID_ALLOCATION_INSTANCE
+
+
+An invalid allocation instance is being referenced.
+
+0xC0262114
+
+ERROR_GRAPHICS_INVALID_ALLOCATION_HANDLE
+
+
+An invalid allocation handle is being referenced.
+
+0xC0262115
+
+ERROR_GRAPHICS_WRONG_ALLOCATION_DEVICE
+
+
+The allocation being referenced does not belong to the current device.
+
+0xC0262116
+
+ERROR_GRAPHICS_ALLOCATION_CONTENT_LOST
+
+
+The specified allocation lost its content.
+
+0xC0262200
+
+ERROR_GRAPHICS_GPU_EXCEPTION_ON_DEVICE
+
+
+Graphics processing unit (GPU) exception is detected on the given device. The device is not able to be scheduled.
+
+0xC0262300
+
+ERROR_GRAPHICS_INVALID_VIDPN_TOPOLOGY
+
+
+Specified video present network (VidPN) topology is invalid.
+
+0xC0262301
+
+ERROR_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED
+
+
+Specified VidPN topology is valid but is not supported by this model of the display adapter.
+
+0xC0262302
+
+ERROR_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED
+
+
+Specified VidPN topology is valid but is not supported by the display adapter at this time, due to current allocation of its resources.
+
+0xC0262303
+
+ERROR_GRAPHICS_INVALID_VIDPN
+
+
+Specified VidPN handle is invalid.
+
+0xC0262304
+
+ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE
+
+
+Specified video present source is invalid.
+
+0xC0262305
+
+ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET
+
+
+Specified video present target is invalid.
+
+0xC0262306
+
+ERROR_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED
+
+
+Specified VidPN modality is not supported (for example, at least two of the pinned modes are not cofunctional).
+
+0xC0262308
+
+ERROR_GRAPHICS_INVALID_VIDPN_SOURCEMODESET
+
+
+Specified VidPN source mode set is invalid.
+
+0xC0262309
+
+ERROR_GRAPHICS_INVALID_VIDPN_TARGETMODESET
+
+
+Specified VidPN target mode set is invalid.
+
+0xC026230A
+
+ERROR_GRAPHICS_INVALID_FREQUENCY
+
+
+Specified video signal frequency is invalid.
+
+0xC026230B
+
+ERROR_GRAPHICS_INVALID_ACTIVE_REGION
+
+
+Specified video signal active region is invalid.
+
+0xC026230C
+
+ERROR_GRAPHICS_INVALID_TOTAL_REGION
+
+
+Specified video signal total region is invalid.
+
+0xC0262310
+
+ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE
+
+
+Specified video present source mode is invalid.
+
+0xC0262311
+
+ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE
+
+
+Specified video present target mode is invalid.
+
+0xC0262312
+
+ERROR_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET
+
+
+Pinned mode must remain in the set on VidPN's cofunctional modality enumeration.
+
+0xC0262313
+
+ERROR_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY
+
+
+Specified video present path is already in the VidPN topology.
+
+0xC0262314
+
+ERROR_GRAPHICS_MODE_ALREADY_IN_MODESET
+
+
+Specified mode is already in the mode set.
+
+0xC0262315
+
+ERROR_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET
+
+
+Specified video present source set is invalid.
+
+0xC0262316
+
+ERROR_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET
+
+
+Specified video present target set is invalid.
+
+0xC0262317
+
+ERROR_GRAPHICS_SOURCE_ALREADY_IN_SET
+
+
+Specified video present source is already in the video present source set.
+
+0xC0262318
+
+ERROR_GRAPHICS_TARGET_ALREADY_IN_SET
+
+
+Specified video present target is already in the video present target set.
+
+0xC0262319
+
+ERROR_GRAPHICS_INVALID_VIDPN_PRESENT_PATH
+
+
+Specified VidPN present path is invalid.
+
+0xC026231A
+
+ERROR_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY
+
+
+Miniport has no recommendation for augmentation of the specified VidPN topology.
+
+0xC026231B
+
+ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET
+
+
+Specified monitor frequency range set is invalid.
+
+0xC026231C
+
+ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE
+
+
+Specified monitor frequency range is invalid.
+
+0xC026231D
+
+ERROR_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET
+
+
+Specified frequency range is not in the specified monitor frequency range set.
+
+0xC026231F
+
+ERROR_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET
+
+
+Specified frequency range is already in the specified monitor frequency range set.
+
+0xC0262320
+
+ERROR_GRAPHICS_STALE_MODESET
+
+
+Specified mode set is stale. Reacquire the new mode set.
+
+0xC0262321
+
+ERROR_GRAPHICS_INVALID_MONITOR_SOURCEMODESET
+
+
+Specified monitor source mode set is invalid.
+
+0xC0262322
+
+ERROR_GRAPHICS_INVALID_MONITOR_SOURCE_MODE
+
+
+Specified monitor source mode is invalid.
+
+0xC0262323
+
+ERROR_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN
+
+
+Miniport does not have any recommendation regarding the request to provide a functional VidPN given the current display adapter configuration.
+
+0xC0262324
+
+ERROR_GRAPHICS_MODE_ID_MUST_BE_UNIQUE
+
+
+ID of the specified mode is already used by another mode in the set.
+
+0xC0262325
+
+ERROR_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION
+
+
+System failed to determine a mode that is supported by both the display adapter and the monitor connected to it.
+
+0xC0262326
+
+ERROR_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES
+
+
+Number of video present targets must be greater than or equal to the number of video present sources.
+
+0xC0262327
+
+ERROR_GRAPHICS_PATH_NOT_IN_TOPOLOGY
+
+
+Specified present path is not in the VidPN topology.
+
+0xC0262328
+
+ERROR_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE
+
+
+Display adapter must have at least one video present source.
+
+0xC0262329
+
+ERROR_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET
+
+
+Display adapter must have at least one video present target.
+
+0xC026232A
+
+ERROR_GRAPHICS_INVALID_MONITORDESCRIPTORSET
+
+
+Specified monitor descriptor set is invalid.
+
+0xC026232B
+
+ERROR_GRAPHICS_INVALID_MONITORDESCRIPTOR
+
+
+Specified monitor descriptor is invalid.
+
+0xC026232C
+
+ERROR_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET
+
+
+Specified descriptor is not in the specified monitor descriptor set.
+
+0xC026232D
+
+ERROR_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET
+
+
+Specified descriptor is already in the specified monitor descriptor set.
+
+0xC026232E
+
+ERROR_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE
+
+
+ID of the specified monitor descriptor is already used by another descriptor in the set.
+
+0xC026232F
+
+ERROR_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE
+
+
+Specified video present target subset type is invalid.
+
+0xC0262330
+
+ERROR_GRAPHICS_RESOURCES_NOT_RELATED
+
+
+Two or more of the specified resources are not related to each other, as defined by the interface semantics.
+
+0xC0262331
+
+ERROR_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE
+
+
+ID of the specified video present source is already used by another source in the set.
+
+0xC0262332
+
+ERROR_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE
+
+
+ID of the specified video present target is already used by another target in the set.
+
+0xC0262333
+
+ERROR_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET
+
+
+Specified VidPN source cannot be used because there is no available VidPN target to connect it to.
+
+0xC0262334
+
+ERROR_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER
+
+
+Newly arrived monitor could not be associated with a display adapter.
+
+0xC0262335
+
+ERROR_GRAPHICS_NO_VIDPNMGR
+
+
+Display adapter in question does not have an associated VidPN manager.
+
+0xC0262336
+
+ERROR_GRAPHICS_NO_ACTIVE_VIDPN
+
+
+VidPN manager of the display adapter in question does not have an active VidPN.
+
+0xC0262337
+
+ERROR_GRAPHICS_STALE_VIDPN_TOPOLOGY
+
+
+Specified VidPN topology is stale. Re-acquire the new topology.
+
+0xC0262338
+
+ERROR_GRAPHICS_MONITOR_NOT_CONNECTED
+
+
+There is no monitor connected on the specified video present target.
+
+0xC0262339
+
+ERROR_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY
+
+
+Specified source is not part of the specified VidPN topology.
+
+0xC026233A
+
+ERROR_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE
+
+
+Specified primary surface size is invalid.
+
+0xC026233B
+
+ERROR_GRAPHICS_INVALID_VISIBLEREGION_SIZE
+
+
+Specified visible region size is invalid.
+
+0xC026233C
+
+ERROR_GRAPHICS_INVALID_STRIDE
+
+
+Specified stride is invalid.
+
+0xC026233D
+
+ERROR_GRAPHICS_INVALID_PIXELFORMAT
+
+
+Specified pixel format is invalid.
+
+0xC026233E
+
+ERROR_GRAPHICS_INVALID_COLORBASIS
+
+
+Specified color basis is invalid.
+
+0xC026233F
+
+ERROR_GRAPHICS_INVALID_PIXELVALUEACCESSMODE
+
+
+Specified pixel value access mode is invalid.
+
+0xC0262340
+
+ERROR_GRAPHICS_TARGET_NOT_IN_TOPOLOGY
+
+
+Specified target is not part of the specified VidPN topology.
+
+0xC0262341
+
+ERROR_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT
+
+
+Failed to acquire display mode management interface.
+
+0xC0262342
+
+ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE
+
+
+Specified VidPN source is already owned by a display mode manager (DMM) client and cannot be used until that client releases it.
+
+0xC0262343
+
+ERROR_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN
+
+
+Specified VidPN is active and cannot be accessed.
+
+0xC0262344
+
+ERROR_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL
+
+
+Specified VidPN present path importance ordinal is invalid.
+
+0xC0262345
+
+ERROR_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION
+
+
+Specified VidPN present path content geometry transformation is invalid.
+
+0xC0262346
+
+ERROR_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED
+
+
+Specified content geometry transformation is not supported on the respective VidPN present path.
+
+0xC0262347
+
+ERROR_GRAPHICS_INVALID_GAMMA_RAMP
+
+
+Specified gamma ramp is invalid.
+
+0xC0262348
+
+ERROR_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED
+
+
+Specified gamma ramp is not supported on the respective VidPN present path.
+
+0xC0262349
+
+ERROR_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED
+
+
+Multisampling is not supported on the respective VidPN present path.
+
+0xC026234A
+
+ERROR_GRAPHICS_MODE_NOT_IN_MODESET
+
+
+Specified mode is not in the specified mode set.
+
+0xC026234D
+
+ERROR_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON
+
+
+Specified VidPN topology recommendation reason is invalid.
+
+0xC026234E
+
+ERROR_GRAPHICS_INVALID_PATH_CONTENT_TYPE
+
+
+Specified VidPN present path content type is invalid.
+
+0xC026234F
+
+ERROR_GRAPHICS_INVALID_COPYPROTECTION_TYPE
+
+
+Specified VidPN present path copy protection type is invalid.
+
+0xC0262350
+
+ERROR_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS
+
+
+No more than one unassigned mode set can exist at any given time for a given VidPN source or target.
+
+0xC0262352
+
+ERROR_GRAPHICS_INVALID_SCANLINE_ORDERING
+
+
+The specified scan line ordering type is invalid.
+
+0xC0262353
+
+ERROR_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED
+
+
+Topology changes are not allowed for the specified VidPN.
+
+0xC0262354
+
+ERROR_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS
+
+
+All available importance ordinals are already used in the specified topology.
+
+0xC0262355
+
+ERROR_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT
+
+
+Specified primary surface has a different private format attribute than the current primary surface.
+
+0xC0262356
+
+ERROR_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM
+
+
+Specified mode pruning algorithm is invalid.
+
+0xC0262400
+
+ERROR_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED
+
+
+Specified display adapter child device already has an external device connected to it.
+
+0xC0262401
+
+ERROR_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED
+
+
+The display adapter child device does not support reporting a descriptor.
+
+0xC0262430
+
+ERROR_GRAPHICS_NOT_A_LINKED_ADAPTER
+
+
+The display adapter is not linked to any other adapters.
+
+0xC0262431
+
+ERROR_GRAPHICS_LEADLINK_NOT_ENUMERATED
+
+
+Lead adapter in a linked configuration was not enumerated yet.
+
+0xC0262432
+
+ERROR_GRAPHICS_CHAINLINKS_NOT_ENUMERATED
+
+
+Some chain adapters in a linked configuration were not enumerated yet.
+
+0xC0262433
+
+ERROR_GRAPHICS_ADAPTER_CHAIN_NOT_READY
+
+
+The chain of linked adapters is not ready to start because of an unknown failure.
+
+0xC0262434
+
+ERROR_GRAPHICS_CHAINLINKS_NOT_STARTED
+
+
+An attempt was made to start a lead link display adapter when the chain links were not started yet.
+
+0xC0262435
+
+ERROR_GRAPHICS_CHAINLINKS_NOT_POWERED_ON
+
+
+An attempt was made to turn on a lead link display adapter when the chain links were turned off.
+
+0xC0262436
+
+ERROR_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE
+
+
+The adapter link was found to be in an inconsistent state. Not all adapters are in an expected PNP or power state.
+
+0xC0262438
+
+ERROR_GRAPHICS_NOT_POST_DEVICE_DRIVER
+
+
+The driver trying to start is not the same as the driver for the posted display adapter.
+
+0xC0262500
+
+ERROR_GRAPHICS_OPM_NOT_SUPPORTED
+
+
+The driver does not support Output Protection Manager (OPM).
+
+0xC0262501
+
+ERROR_GRAPHICS_COPP_NOT_SUPPORTED
+
+
+The driver does not support Certified Output Protection Protocol (COPP).
+
+0xC0262502
+
+ERROR_GRAPHICS_UAB_NOT_SUPPORTED
+
+
+The driver does not support a user-accessible bus (UAB).
+
+0xC0262503
+
+ERROR_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS
+
+
+The specified encrypted parameters are invalid.
+
+0xC0262504
+
+ERROR_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL
+
+
+An array passed to a function cannot hold all of the data that the function wants to put in it.
+
+0xC0262505
+
+ERROR_GRAPHICS_OPM_NO_VIDEO_OUTPUTS_EXIST
+
+
+The GDI display device passed to this function does not have any active video outputs.
+
+0xC0262506
+
+ERROR_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME
+
+
+The protected video path (PVP) cannot find an actual GDI display device that corresponds to the passed-in GDI display device name.
+
+0xC0262507
+
+ERROR_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP
+
+
+This function failed because the GDI display device passed to it was not attached to the Windows desktop.
+
+0xC0262508
+
+ERROR_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED
+
+
+The PVP does not support mirroring display devices because they do not have video outputs.
+
+0xC026250A
+
+ERROR_GRAPHICS_OPM_INVALID_POINTER
+
+
+The function failed because an invalid pointer parameter was passed to it. A pointer parameter is invalid if it is null, it points to an invalid address, it points to a kernel mode address, or it is not correctly aligned.
+
+0xC026250B
+
+ERROR_GRAPHICS_OPM_INTERNAL_ERROR
+
+
+An internal error caused this operation to fail.
+
+0xC026250C
+
+ERROR_GRAPHICS_OPM_INVALID_HANDLE
+
+
+The function failed because the caller passed in an invalid OPM user mode handle.
+
+0xC026250D
+
+ERROR_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE
+
+
+This function failed because the GDI device passed to it did not have any monitors associated with it.
+
+0xC026250E
+
+ERROR_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH
+
+
+A certificate could not be returned because the certificate buffer passed to the function was too small.
+
+0xC026250F
+
+ERROR_GRAPHICS_OPM_SPANNING_MODE_ENABLED
+
+
+A video output could not be created because the frame buffer is in spanning mode.
+
+0xC0262510
+
+ERROR_GRAPHICS_OPM_THEATER_MODE_ENABLED
+
+
+A video output could not be created because the frame buffer is in theater mode.
+
+0xC0262511
+
+ERROR_GRAPHICS_PVP_HFS_FAILED
+
+
+The function call failed because the display adapter's hardware functionality scan failed to validate the graphics hardware.
+
+0xC0262512
+
+ERROR_GRAPHICS_OPM_INVALID_SRM
+
+
+The High-Bandwidth Digital Content Protection (HDCP) System Renewability Message (SRM) passed to this function did not comply with section 5 of the HDCP 1.1 specification.
+
+0xC0262513
+
+ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP
+
+
+The video output cannot enable the HDCP system because it does not support it.
+
+0xC0262514
+
+ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP
+
+
+The video output cannot enable analog copy protection because it does not support it.
+
+0xC0262515
+
+ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA
+
+
+The video output cannot enable the Content Generation Management System Analog (CGMS-A) protection technology because it does not support it.
+
+0xC0262516
+
+ERROR_GRAPHICS_OPM_HDCP_SRM_NEVER_SET
+
+
+IOPMVideoOutput's GetInformation() method cannot return the version of the SRM being used because the application never successfully passed an SRM to the video output.
+
+0xC0262517
+
+ERROR_GRAPHICS_OPM_RESOLUTION_TOO_HIGH
+
+
+IOPMVideoOutput's Configure() method cannot enable the specified output protection technology because the output's screen resolution is too high.
+
+0xC0262518
+
+ERROR_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE
+
+
+IOPMVideoOutput's Configure() method cannot enable HDCP because the display adapter's HDCP hardware is already being used by other physical outputs.
+
+0xC0262519
+
+ERROR_GRAPHICS_OPM_VIDEO_OUTPUT_NO_LONGER_EXISTS
+
+
+The operating system asynchronously destroyed this OPM video output because the operating system's state changed. This error typically occurs because the monitor physical device object (PDO) associated with this video output was removed, the monitor PDO associated with this video output was stopped, the video output's session became a nonconsole session or the video output's desktop became an inactive desktop.
+
+0xC026251A
+
+ERROR_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS
+
+
+IOPMVideoOutput's methods cannot be called when a session is changing its type. There are currently three types of sessions: console, disconnected and remote (remote desktop protocol [RDP] or Independent Computing Architecture [ICA]).
+
+0xC0262580
+
+ERROR_GRAPHICS_I2C_NOT_SUPPORTED
+
+
+The monitor connected to the specified video output does not have an I2C bus.
+
+0xC0262581
+
+ERROR_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST
+
+
+No device on the I2C bus has the specified address.
+
+0xC0262582
+
+ERROR_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA
+
+
+An error occurred while transmitting data to the device on the I2C bus.
+
+0xC0262583
+
+ERROR_GRAPHICS_I2C_ERROR_RECEIVING_DATA
+
+
+An error occurred while receiving data from the device on the I2C bus.
+
+0xC0262584
+
+ERROR_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED
+
+
+The monitor does not support the specified Virtual Control Panel (VCP) code.
+
+0xC0262585
+
+ERROR_GRAPHICS_DDCCI_INVALID_DATA
+
+
+The data received from the monitor is invalid.
+
+0xC0262586
+
+ERROR_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE
+
+
+A function call failed because a monitor returned an invalid Timing Status byte when the operating system used the Display Data Channel Command Interface (DDC/CI) Get Timing Report and Timing Message command to get a timing report from a monitor.
+
+0xC0262587
+
+ERROR_GRAPHICS_MCA_INVALID_CAPABILITIES_STRING
+
+
+The monitor returned a DDC/CI capabilities string that did not comply with the ACCESS.bus 3.0, DDC/CI 1.1 or MCCS 2 Revision 1 specification.
+
+0xC0262588
+
+ERROR_GRAPHICS_MCA_INTERNAL_ERROR
+
+
+An internal Monitor Configuration API error occurred.
+
+0xC0262589
+
+ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND
+
+
+An operation failed because a DDC/CI message had an invalid value in its command field.
+
+0xC026258A
+
+ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH
+
+
+This error occurred because a DDC/CI message length field contained an invalid value.
+
+0xC026258B
+
+ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM
+
+
+This error occurred because the value in a DDC/CI message checksum field did not match the message's computed checksum value. This error implies that the data was corrupted while it was being transmitted from a monitor to a computer.
+
+0xC02625D6
+
+ERROR_GRAPHICS_PMEA_INVALID_MONITOR
+
+
+The HMONITOR no longer exists, is not attached to the desktop, or corresponds to a mirroring device.
+
+0xC02625D7
+
+ERROR_GRAPHICS_PMEA_INVALID_D3D_DEVICE
+
+
+The Direct3D (D3D) device's GDI display device no longer exists, is not attached to the desktop, or is a mirroring display device.
+
+0xC02625D8
+
+ERROR_GRAPHICS_DDCCI_CURRENT_CURRENT_VALUE_GREATER_THAN_MAXIMUM_VALUE
+
+
+A continuous VCP code's current value is greater than its maximum value. This error code indicates that a monitor returned an invalid value.
+
+0xC02625D9
+
+ERROR_GRAPHICS_MCA_INVALID_VCP_VERSION
+
+
+The monitor's VCP Version (0xDF) VCP code returned an invalid version value.
+
+0xC02625DA
+
+ERROR_GRAPHICS_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION
+
+
+The monitor does not comply with the Monitor Control Command Set (MCCS) specification it claims to support.
+
+0xC02625DB
+
+ERROR_GRAPHICS_MCA_MCCS_VERSION_MISMATCH
+
+
+The MCCS version in a monitor's mccs_ver capability does not match the MCCS version the monitor reports when the VCP Version (0xDF) VCP code is used.
+
+0xC02625DC
+
+ERROR_GRAPHICS_MCA_UNSUPPORTED_MCCS_VERSION
+
+
+The Monitor Configuration API only works with monitors that support the MCCS 1.0 specification, the MCCS 2.0 specification, or the MCCS 2.0 Revision 1 specification.
+
+0xC02625DE
+
+ERROR_GRAPHICS_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED
+
+
+The monitor returned an invalid monitor technology type. CRT, plasma, and LCD (TFT) are examples of monitor technology types. This error implies that the monitor violated the MCCS 2.0 or MCCS 2.0 Revision 1 specification.
+
+0xC02625DF
+
+ERROR_GRAPHICS_MCA_UNSUPPORTED_COLOR_TEMPERATURE
+
+
+The SetMonitorColorTemperature() caller passed a color temperature to it that the current monitor did not support. CRT, plasma, and LCD (TFT) are examples of monitor technology types. This error implies that the monitor violated the MCCS 2.0 or MCCS 2.0 Revision 1 specification.
+
+0xC02625E0
+
+ERROR_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED
+
+
+This function can be used only if a program is running in the local console session. It cannot be used if the program is running on a remote desktop session or on a terminal server session.
diff --git a/libcli/util/nterr.c b/libcli/util/nterr.c
new file mode 100644
index 0000000..cfe89f2
--- /dev/null
+++ b/libcli/util/nterr.c
@@ -0,0 +1,377 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ *
+ * Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
+ * Copyright (C) Andrew Bartlett
+ * Copyright (C) Andrew Tridgell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* NT error codes. please read nterr.h */
+
+#include "includes.h"
+#include "../libcli/ldap/ldap_errors.h"
+#undef strcasecmp
+
+#if !defined(N_)
+#define N_(string) string
+#endif
+
+#define DOS_CODE(class, code) { #class ":" #code, NT_STATUS_DOS(class, code) }
+#define LDAP_CODE(code) { #code, NT_STATUS_LDAP(code) }
+
+typedef struct
+{
+ const char *nt_errstr;
+ NTSTATUS nt_errcode;
+} nt_err_code_struct;
+
+#include "nterr_gen.c"
+
+/* Errors which aren't in the generated code because they're not in the
+ * same table as the other ones. */
+static const nt_err_code_struct special_errs[] =
+{
+ { "STATUS_NO_MORE_FILES", STATUS_NO_MORE_FILES },
+ { "STATUS_INVALID_EA_NAME", STATUS_INVALID_EA_NAME },
+ { "STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW },
+ { "STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES },
+ { "STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED },
+ { "NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS", NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS },
+ { "NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION", NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION },
+ { "NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP", NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP },
+ { "NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT },
+ { "NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST },
+ { "NT_STATUS_ABIOS_LID_ALREADY_OWNED", NT_STATUS_ABIOS_LID_ALREADY_OWNED },
+ { "NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER },
+ { "NT_STATUS_ABIOS_INVALID_COMMAND", NT_STATUS_ABIOS_INVALID_COMMAND },
+ { "NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID },
+ { "NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE },
+ { "NT_STATUS_ABIOS_INVALID_SELECTOR", NT_STATUS_ABIOS_INVALID_SELECTOR },
+ { "NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE },
+ { "NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE },
+ { "NT_STATUS_VHD_SHARED", NT_STATUS_VHD_SHARED },
+ { "NT_STATUS_SMB_BAD_CLUSTER_DIALECT", NT_STATUS_SMB_BAD_CLUSTER_DIALECT },
+ { "NT_STATUS_NO_SUCH_JOB", NT_STATUS_NO_SUCH_JOB },
+
+ DOS_CODE(ERRDOS, ERRsuccess),
+ DOS_CODE(ERRDOS, ERRbadfunc),
+ DOS_CODE(ERRDOS, ERRbadfile),
+ DOS_CODE(ERRDOS, ERRbadpath),
+ DOS_CODE(ERRDOS, ERRnofids),
+ DOS_CODE(ERRDOS, ERRnoaccess),
+ DOS_CODE(ERRDOS, ERRbadfid),
+ DOS_CODE(ERRDOS, ERRbadmcb),
+ DOS_CODE(ERRDOS, ERRnomem),
+ DOS_CODE(ERRDOS, ERRbadmem),
+ DOS_CODE(ERRDOS, ERRbadenv),
+ DOS_CODE(ERRDOS, ERRbadaccess),
+ DOS_CODE(ERRDOS, ERRbaddata),
+ DOS_CODE(ERRDOS, ERRres),
+ DOS_CODE(ERRDOS, ERRbaddrive),
+ DOS_CODE(ERRDOS, ERRremcd),
+ DOS_CODE(ERRDOS, ERRdiffdevice),
+ DOS_CODE(ERRDOS, ERRnofiles),
+ DOS_CODE(ERRDOS, ERRgeneral),
+ DOS_CODE(ERRDOS, ERRbadshare),
+ DOS_CODE(ERRDOS, ERRlock),
+ DOS_CODE(ERRDOS, ERRunsup),
+ DOS_CODE(ERRDOS, ERRnetnamedel),
+ DOS_CODE(ERRDOS, ERRnosuchshare),
+ DOS_CODE(ERRDOS, ERRfilexists),
+ DOS_CODE(ERRDOS, ERRinvalidparam),
+ DOS_CODE(ERRDOS, ERRcannotopen),
+ DOS_CODE(ERRDOS, ERRinsufficientbuffer),
+ DOS_CODE(ERRDOS, ERRinvalidname),
+ DOS_CODE(ERRDOS, ERRunknownlevel),
+ DOS_CODE(ERRDOS, ERRnotlocked),
+ DOS_CODE(ERRDOS, ERRinvalidpath),
+ DOS_CODE(ERRDOS, ERRcancelviolation),
+ DOS_CODE(ERRDOS, ERRnoatomiclocks),
+ DOS_CODE(ERRDOS, ERRrename),
+ DOS_CODE(ERRDOS, ERRbadpipe),
+ DOS_CODE(ERRDOS, ERRpipebusy),
+ DOS_CODE(ERRDOS, ERRpipeclosing),
+ DOS_CODE(ERRDOS, ERRnotconnected),
+ DOS_CODE(ERRDOS, ERRmoredata),
+ DOS_CODE(ERRDOS, ERRnomoreitems),
+ DOS_CODE(ERRDOS, ERRbaddirectory),
+ DOS_CODE(ERRDOS, ERReasnotsupported),
+ DOS_CODE(ERRDOS, ERRlogonfailure),
+ DOS_CODE(ERRDOS, ERRbuftoosmall),
+ DOS_CODE(ERRDOS, ERRunknownipc),
+ DOS_CODE(ERRDOS, ERRnosuchprintjob),
+ DOS_CODE(ERRDOS, ERRinvgroup),
+ DOS_CODE(ERRDOS, ERRnoipc),
+ DOS_CODE(ERRDOS, ERRdriveralreadyinstalled),
+ DOS_CODE(ERRDOS, ERRunknownprinterport),
+ DOS_CODE(ERRDOS, ERRunknownprinterdriver),
+ DOS_CODE(ERRDOS, ERRunknownprintprocessor),
+ DOS_CODE(ERRDOS, ERRinvalidseparatorfile),
+ DOS_CODE(ERRDOS, ERRinvalidjobpriority),
+ DOS_CODE(ERRDOS, ERRinvalidprintername),
+ DOS_CODE(ERRDOS, ERRprinteralreadyexists),
+ DOS_CODE(ERRDOS, ERRinvalidprintercommand),
+ DOS_CODE(ERRDOS, ERRinvaliddatatype),
+ DOS_CODE(ERRDOS, ERRinvalidenvironment),
+ DOS_CODE(ERRDOS, ERRunknownprintmonitor),
+ DOS_CODE(ERRDOS, ERRprinterdriverinuse),
+ DOS_CODE(ERRDOS, ERRspoolfilenotfound),
+ DOS_CODE(ERRDOS, ERRnostartdoc),
+ DOS_CODE(ERRDOS, ERRnoaddjob),
+ DOS_CODE(ERRDOS, ERRprintprocessoralreadyinstalled),
+ DOS_CODE(ERRDOS, ERRprintmonitoralreadyinstalled),
+ DOS_CODE(ERRDOS, ERRinvalidprintmonitor),
+ DOS_CODE(ERRDOS, ERRprintmonitorinuse),
+ DOS_CODE(ERRDOS, ERRprinterhasjobsqueued),
+ DOS_CODE(ERRDOS, ERReainconsistent),
+
+ DOS_CODE(ERRSRV, ERRerror),
+ DOS_CODE(ERRSRV, ERRbadpw),
+ DOS_CODE(ERRSRV, ERRbadtype),
+ DOS_CODE(ERRSRV, ERRaccess),
+ DOS_CODE(ERRSRV, ERRinvnid),
+ DOS_CODE(ERRSRV, ERRinvnetname),
+ DOS_CODE(ERRSRV, ERRinvdevice),
+ DOS_CODE(ERRSRV, ERRqfull),
+ DOS_CODE(ERRSRV, ERRqtoobig),
+ DOS_CODE(ERRSRV, ERRinvpfid),
+ DOS_CODE(ERRSRV, ERRsmbcmd),
+ DOS_CODE(ERRSRV, ERRsrverror),
+ DOS_CODE(ERRSRV, ERRfilespecs),
+ DOS_CODE(ERRSRV, ERRbadlink),
+ DOS_CODE(ERRSRV, ERRbadpermits),
+ DOS_CODE(ERRSRV, ERRbadpid),
+ DOS_CODE(ERRSRV, ERRsetattrmode),
+ DOS_CODE(ERRSRV, ERRpaused),
+ DOS_CODE(ERRSRV, ERRmsgoff),
+ DOS_CODE(ERRSRV, ERRnoroom),
+ DOS_CODE(ERRSRV, ERRrmuns),
+ DOS_CODE(ERRSRV, ERRtimeout),
+ DOS_CODE(ERRSRV, ERRnoresource),
+ DOS_CODE(ERRSRV, ERRtoomanyuids),
+ DOS_CODE(ERRSRV, ERRbaduid),
+ DOS_CODE(ERRSRV, ERRuseMPX),
+ DOS_CODE(ERRSRV, ERRuseSTD),
+ DOS_CODE(ERRSRV, ERRcontMPX),
+ DOS_CODE(ERRSRV, ERRnosupport),
+ DOS_CODE(ERRSRV, ERRunknownsmb),
+
+ DOS_CODE(ERRHRD, ERRnowrite),
+ DOS_CODE(ERRHRD, ERRbadunit),
+ DOS_CODE(ERRHRD, ERRnotready),
+ DOS_CODE(ERRHRD, ERRbadcmd),
+ DOS_CODE(ERRHRD, ERRdata),
+ DOS_CODE(ERRHRD, ERRbadreq),
+ DOS_CODE(ERRHRD, ERRseek),
+ DOS_CODE(ERRHRD, ERRbadmedia),
+ DOS_CODE(ERRHRD, ERRbadsector),
+ DOS_CODE(ERRHRD, ERRnopaper),
+ DOS_CODE(ERRHRD, ERRwrite),
+ DOS_CODE(ERRHRD, ERRread),
+ DOS_CODE(ERRHRD, ERRgeneral),
+ DOS_CODE(ERRHRD, ERRwrongdisk),
+ DOS_CODE(ERRHRD, ERRFCBunavail),
+ DOS_CODE(ERRHRD, ERRsharebufexc),
+ DOS_CODE(ERRHRD, ERRdiskfull),
+
+ LDAP_CODE(LDAP_SUCCESS),
+ LDAP_CODE(LDAP_OPERATIONS_ERROR),
+ LDAP_CODE(LDAP_PROTOCOL_ERROR),
+ LDAP_CODE(LDAP_TIME_LIMIT_EXCEEDED),
+ LDAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED),
+ LDAP_CODE(LDAP_COMPARE_FALSE),
+ LDAP_CODE(LDAP_COMPARE_TRUE),
+ LDAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED),
+ LDAP_CODE(LDAP_STRONG_AUTH_REQUIRED),
+ LDAP_CODE(LDAP_REFERRAL),
+ LDAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED),
+ LDAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION),
+ LDAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED),
+ LDAP_CODE(LDAP_SASL_BIND_IN_PROGRESS),
+ LDAP_CODE(LDAP_NO_SUCH_ATTRIBUTE),
+ LDAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE),
+ LDAP_CODE(LDAP_INAPPROPRIATE_MATCHING),
+ LDAP_CODE(LDAP_CONSTRAINT_VIOLATION),
+ LDAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS),
+ LDAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX),
+ LDAP_CODE(LDAP_NO_SUCH_OBJECT),
+ LDAP_CODE(LDAP_ALIAS_PROBLEM),
+ LDAP_CODE(LDAP_INVALID_DN_SYNTAX),
+ LDAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM),
+ LDAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION),
+ LDAP_CODE(LDAP_INVALID_CREDENTIALS),
+ LDAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTS),
+ LDAP_CODE(LDAP_BUSY),
+ LDAP_CODE(LDAP_UNAVAILABLE),
+ LDAP_CODE(LDAP_UNWILLING_TO_PERFORM),
+ LDAP_CODE(LDAP_LOOP_DETECT),
+ LDAP_CODE(LDAP_NAMING_VIOLATION),
+ LDAP_CODE(LDAP_OBJECT_CLASS_VIOLATION),
+ LDAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF),
+ LDAP_CODE(LDAP_NOT_ALLOWED_ON_RDN),
+ LDAP_CODE(LDAP_ENTRY_ALREADY_EXISTS),
+ LDAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED),
+ LDAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS),
+ LDAP_CODE(LDAP_OTHER),
+
+ { NULL, NT_STATUS(0) }
+};
+
+/*****************************************************************************
+ Returns an NT_STATUS constant as a string for inclusion in autogen C code.
+ *****************************************************************************/
+
+const char *get_nt_error_c_code(TALLOC_CTX *mem_ctx, NTSTATUS nt_code)
+{
+ char *result;
+ int idx = 0;
+
+ while (special_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(special_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ result = talloc_strdup(mem_ctx, special_errs[idx].nt_errstr);
+ return result;
+ }
+ idx++;
+ }
+
+ idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ result = talloc_strdup(mem_ctx, nt_errs[idx].nt_errstr);
+ return result;
+ }
+ idx++;
+ }
+
+ result = talloc_asprintf(mem_ctx, "NT_STATUS(0x%08x)",
+ NT_STATUS_V(nt_code));
+ return result;
+}
+
+/*****************************************************************************
+ Returns the NT_STATUS constant matching the string supplied (as an NTSTATUS)
+ *****************************************************************************/
+
+NTSTATUS nt_status_string_to_code(const char *nt_status_str)
+{
+ int idx = 0;
+
+ while (special_errs[idx].nt_errstr != NULL) {
+ if (strcasecmp(special_errs[idx].nt_errstr, nt_status_str) == 0) {
+ return special_errs[idx].nt_errcode;
+ }
+ idx++;
+ }
+
+ idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (strcasecmp(nt_errs[idx].nt_errstr, nt_status_str) == 0) {
+ return nt_errs[idx].nt_errcode;
+ }
+ idx++;
+ }
+
+ return NT_STATUS_UNSUCCESSFUL;
+}
+
+/**
+ * Squash an NT_STATUS in line with security requirements.
+ * In an attempt to avoid giving the whole game away when users
+ * are authenticating, NT replaces both NT_STATUS_NO_SUCH_USER and
+ * NT_STATUS_WRONG_PASSWORD with NT_STATUS_LOGON_FAILURE in certain situations
+ * (session setups in particular).
+ *
+ * @param nt_status NTSTATUS input for squashing.
+ * @return the 'squashed' nt_status
+ **/
+
+NTSTATUS nt_status_squash(NTSTATUS nt_status)
+{
+ if NT_STATUS_IS_OK(nt_status) {
+ return nt_status;
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
+
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
+ } else {
+ return nt_status;
+ }
+}
+
+/*****************************************************************************
+ Returns an NT error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+
+const char *nt_errstr(NTSTATUS nt_code)
+{
+ static char msg[20];
+ int idx = 0;
+
+ while (special_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(special_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ return special_errs[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ idx = 0;
+
+ while (nt_errs[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_errs[idx].nt_errcode) ==
+ NT_STATUS_V(nt_code)) {
+ return nt_errs[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ /*
+ * This should not really happen, we should have all error codes
+ * available. We have a problem that this might get wrongly
+ * overwritten by later calls in the same DEBUG statement.
+ */
+
+ snprintf(msg, sizeof(msg), "NT code 0x%08x", NT_STATUS_V(nt_code));
+ return msg;
+}
+
+/************************************************************************
+ Print friendlier version of NT error code
+ ***********************************************************************/
+
+const char *get_friendly_nt_error_msg(NTSTATUS nt_code)
+{
+ int idx = 0;
+
+ while (nt_err_desc[idx].nt_errstr != NULL) {
+ if (NT_STATUS_V(nt_err_desc[idx].nt_errcode) == NT_STATUS_V(nt_code)) {
+ return nt_err_desc[idx].nt_errstr;
+ }
+ idx++;
+ }
+
+ /* fall back to NT_STATUS_XXX string */
+
+ return nt_errstr(nt_code);
+}
diff --git a/libcli/util/ntstatus.h b/libcli/util/ntstatus.h
new file mode 100644
index 0000000..566d75f
--- /dev/null
+++ b/libcli/util/ntstatus.h
@@ -0,0 +1,199 @@
+/*
+ Unix SMB/CIFS implementation.
+ NT error code constants
+ Copyright (C) Andrew Tridgell 1992-2000
+ Copyright (C) John H Terpstra 1996-2000
+ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+ Copyright (C) Paul Ashton 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/>.
+*/
+
+#ifndef _NTSTATUS_H
+#define _NTSTATUS_H
+
+#include <stdint.h>
+
+#include "libcli/util/ntstatus_gen.h"
+
+/* the following rather strange looking definitions of NTSTATUS
+ are there in order to catch common coding errors where different error types
+ are mixed up. This is especially important as we slowly convert Samba
+ from using bool for internal functions
+*/
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32_t v;} NTSTATUS;
+#define NT_STATUS(x) ((NTSTATUS) { x })
+#define NT_STATUS_V(x) ((x).v)
+#else
+typedef uint32_t NTSTATUS;
+#define NT_STATUS(x) (x)
+#define NT_STATUS_V(x) (x)
+#endif
+
+/* Win32 status codes. */
+#define ERROR_INVALID_PARAMETER NT_STATUS(0x0057)
+#define ERROR_INSUFFICIENT_BUFFER NT_STATUS(0x007a)
+#define NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS NT_STATUS(0x2071)
+#define NT_STATUS_ERROR_DS_INCOMPATIBLE_VERSION NT_STATUS(0x2177)
+#define NT_STATUS_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP NT_STATUS(0xC05D0000)
+
+/* Other error codes that aren't in the list we use */
+#define STATUS_MORE_ENTRIES NT_STATUS_MORE_ENTRIES
+#define STATUS_BUFFER_OVERFLOW NT_STATUS_BUFFER_OVERFLOW
+#define STATUS_NO_MORE_FILES NT_STATUS_NO_MORE_FILES
+#define STATUS_INVALID_EA_NAME NT_STATUS_INVALID_EA_NAME
+#define STATUS_SOME_UNMAPPED NT_STATUS_SOME_NOT_MAPPED
+
+#define NT_STATUS_ABIOS_NOT_PRESENT NT_STATUS(0xC0000000 | 0x010f)
+#define NT_STATUS_ABIOS_LID_NOT_EXIST NT_STATUS(0xC0000000 | 0x0110)
+#define NT_STATUS_ABIOS_LID_ALREADY_OWNED NT_STATUS(0xC0000000 | 0x0111)
+#define NT_STATUS_ABIOS_NOT_LID_OWNER NT_STATUS(0xC0000000 | 0x0112)
+#define NT_STATUS_ABIOS_INVALID_COMMAND NT_STATUS(0xC0000000 | 0x0113)
+#define NT_STATUS_ABIOS_INVALID_LID NT_STATUS(0xC0000000 | 0x0114)
+#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE NT_STATUS(0xC0000000 | 0x0115)
+#define NT_STATUS_ABIOS_INVALID_SELECTOR NT_STATUS(0xC0000000 | 0x0116)
+
+#define NT_STATUS_HANDLE_NOT_WAITABLE NT_STATUS(0xC0000000 | 0x0036)
+#define NT_STATUS_DEVICE_POWER_FAILURE NT_STATUS(0xC0000000 | 0x009e)
+#define NT_STATUS_VHD_SHARED NT_STATUS(0xC05CFF0A)
+#define NT_STATUS_SMB_BAD_CLUSTER_DIALECT NT_STATUS(0xC05D0001)
+#define NT_STATUS_NO_SUCH_JOB NT_STATUS(0xC0000000 | 0xEDE)
+
+/*
+ --------------
+ / \
+ / REST \
+ / IN \
+ / PEACE \
+ / \
+ | NT_STATUS_NOPROBLEMO |
+ | |
+ | |
+ | 4 September |
+ | |
+ | 2001 |
+ *| * * * | *
+ _________)/\\_//(\/(/\)/\//\/\///|_)_______
+*/
+
+/* I use NT_STATUS_FOOBAR when I have no idea what error code to use -
+ * this means we need a torture test */
+#define NT_STATUS_FOOBAR NT_STATUS_UNSUCCESSFUL
+
+/*****************************************************************************
+ returns an NT error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+const char *nt_errstr(NTSTATUS nt_code);
+
+/************************************************************************
+ Print friendlier version of NT error code
+ ***********************************************************************/
+const char *get_friendly_nt_error_msg(NTSTATUS nt_code);
+
+/*****************************************************************************
+ returns an NT_STATUS constant as a string for inclusion in autogen C code
+ *****************************************************************************/
+const char *get_nt_error_c_code(void *mem_ctx, NTSTATUS nt_code);
+
+/*****************************************************************************
+ returns the NT_STATUS constant matching the string supplied (as an NTSTATUS)
+ *****************************************************************************/
+NTSTATUS nt_status_string_to_code(const char *nt_status_str);
+
+/* we need these here for openchange */
+#ifndef likely
+#define likely(x) (x)
+#endif
+#ifndef unlikely
+#define unlikely(x) (x)
+#endif
+
+#define NT_STATUS_IS_OK(x) (likely(NT_STATUS_V(x) == 0))
+#define NT_STATUS_IS_ERR(x) (unlikely((NT_STATUS_V(x) & 0xc0000000) == 0xc0000000))
+#define NT_STATUS_EQUAL(x,y) (NT_STATUS_V(x) == NT_STATUS_V(y))
+
+/*
+ * These macros (with the embedded return) are considered poor coding
+ * style per README.Coding
+ *
+ * Please do not use them in new code, and do not rely on them in
+ * projects external to Samba as they will go away at some point.
+ */
+
+#define NT_STATUS_HAVE_NO_MEMORY(x) do { \
+ if (unlikely(!(x))) { \
+ return NT_STATUS_NO_MEMORY;\
+ }\
+} while (0)
+
+/* This variant is for when you want to free a local
+ temporary memory context in the error path */
+#define NT_STATUS_HAVE_NO_MEMORY_AND_FREE(x, ctx) do { \
+ if (!(x)) {\
+ talloc_free(ctx); \
+ return NT_STATUS_NO_MEMORY;\
+ }\
+} while (0)
+
+#define NT_STATUS_IS_OK_RETURN(x) do { \
+ if (NT_STATUS_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define NT_STATUS_NOT_OK_RETURN(x) do { \
+ if (!NT_STATUS_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define NT_STATUS_NOT_OK_RETURN_AND_FREE(x, ctx) do { \
+ if (!NT_STATUS_IS_OK(x)) {\
+ talloc_free(ctx); \
+ return x;\
+ }\
+} while (0)
+
+#define NT_STATUS_IS_ERR_RETURN(x) do { \
+ if (NT_STATUS_IS_ERR(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define NT_STATUS_NOT_ERR_RETURN(x) do { \
+ if (!NT_STATUS_IS_ERR(x)) {\
+ return x;\
+ }\
+} while (0)
+
+/* this defines special NTSTATUS codes to represent DOS errors. I
+ have chosen this macro to produce status codes in the invalid
+ NTSTATUS range */
+#define NT_STATUS_DOS(class, code) NT_STATUS(0xF1000000 | ((class)<<16) | code)
+#define NT_STATUS_IS_DOS(status) ((NT_STATUS_V(status) & 0xFF000000) == 0xF1000000)
+#define NT_STATUS_DOS_CLASS(status) ((NT_STATUS_V(status) >> 16) & 0xFF)
+#define NT_STATUS_DOS_CODE(status) (NT_STATUS_V(status) & 0xFFFF)
+
+/* define ldap error codes as NTSTATUS codes */
+#define NT_STATUS_LDAP(code) NT_STATUS(0xF2000000 | code)
+#define NT_STATUS_IS_LDAP(status) ((NT_STATUS_V(status) & 0xFF000000) == 0xF2000000)
+#define NT_STATUS_LDAP_CODE(status) (NT_STATUS_V(status) & ~0xFF000000)
+
+#define NT_STATUS_IS_RPC(status) \
+ (((NT_STATUS_V(status) & 0xFFFF) == 0xC0020000) || \
+ ((NT_STATUS_V(status) & 0xFFFF) == 0xC0030000))
+
+#endif /* _NTSTATUS_H */
diff --git a/libcli/util/ntstatus_err_table.txt b/libcli/util/ntstatus_err_table.txt
new file mode 100644
index 0000000..195e5ae
--- /dev/null
+++ b/libcli/util/ntstatus_err_table.txt
@@ -0,0 +1,12629 @@
+Errors retrieved from https://msdn.microsoft.com/en-us/library/cc704588.aspx.
+License retrieved from https://msdn.microsoft.com/en-us/library/cc231196.aspx:
+
+Intellectual Property Rights Notice for Open Specifications Documentation
+
+ - Technical Documentation. Microsoft publishes Open Specifications documentation (“this documentation”) for protocols, file formats, data portability, computer languages, and standards support. Additionally, overview documents cover inter-protocol relationships and interactions.
+
+ - Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other terms that are contained in the terms of use for the Microsoft website that hosts this documentation, you can make copies of it in order to develop implementations of the technologies that are described in this documentation and can distribute portions of it in your implementations that use these technologies or in your documentation as necessary to properly document the implementation. You can also distribute in your implementation, with or without modification, any schemas, IDLs, or code samples that are included in the documentation. This permission also applies to any documents that are referenced in the Open Specifications documentation.
+
+ - No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation.
+
+ - Patents. Microsoft has patents that might cover your implementations of the technologies described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of this documentation grants any licenses under those patents or any other Microsoft patents. However, a given Open Specifications document might be covered by the Microsoft Open Specifications Promise or the Microsoft Community Promise. If you would prefer a written license, or if the technologies described in this documentation are not covered by the Open Specifications Promise or Community Promise, as applicable, patent licenses are available by contacting iplg@microsoft.com.
+
+ - Trademarks. The names of companies and products contained in this documentation might be covered by trademarks or similar intellectual property rights. This notice does not grant any licenses under those rights. For a list of Microsoft trademarks, visit www.microsoft.com/trademarks.
+
+ - Fictitious Names. The example companies, organizations, products, domain names, email addresses, logos, people, places, and events that are depicted in this documentation are fictitious. No association with any real company, organization, product, domain name, email address, logo, person, place, or event is intended or should be inferred.
+
+Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other than as specifically described above, whether by implication, estoppel, or otherwise.
+
+Tools. The Open Specifications documentation does not require the use of Microsoft programming tools or programming environments in order for you to develop an implementation. If you have access to Microsoft programming tools and environments, you are free to take advantage of them. Certain Open Specifications documents are intended for use in conjunction with publicly available standards specifications and network programming art and, as such, assume that the reader either is familiar with the aforementioned material or has immediate access to it.
+
+===========
+
+0x00000000
+
+STATUS_SUCCESS
+
+
+The operation completed successfully.
+
+0x00000000
+
+STATUS_WAIT_0
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x00000001
+
+STATUS_WAIT_1
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x00000002
+
+STATUS_WAIT_2
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x00000003
+
+STATUS_WAIT_3
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x0000003F
+
+STATUS_WAIT_63
+
+
+The caller specified WaitAny for WaitType and one of the dispatcher objects in the Object array has been set to the signaled state.
+
+0x00000080
+
+STATUS_ABANDONED
+
+
+The caller attempted to wait for a mutex that has been abandoned.
+
+0x00000080
+
+STATUS_ABANDONED_WAIT_0
+
+
+The caller attempted to wait for a mutex that has been abandoned.
+
+0x000000BF
+
+STATUS_ABANDONED_WAIT_63
+
+
+The caller attempted to wait for a mutex that has been abandoned.
+
+0x000000C0
+
+STATUS_USER_APC
+
+
+A user-mode APC was delivered before the given Interval expired.
+
+0x00000101
+
+STATUS_ALERTED
+
+
+The delay completed because the thread was alerted.
+
+0x00000102
+
+STATUS_TIMEOUT
+
+
+The given Timeout interval expired.
+
+0x00000103
+
+STATUS_PENDING
+
+
+The operation that was requested is pending completion.
+
+0x00000104
+
+STATUS_REPARSE
+
+
+A reparse should be performed by the Object Manager because the name of the file resulted in a symbolic link.
+
+0x00000105
+
+STATUS_MORE_ENTRIES
+
+
+Returned by enumeration APIs to indicate more information is available to successive calls.
+
+0x00000106
+
+STATUS_NOT_ALL_ASSIGNED
+
+
+Indicates not all privileges or groups that are referenced are assigned to the caller. This allows, for example, all privileges to be disabled without having to know exactly which privileges are assigned.
+
+0x00000107
+
+STATUS_SOME_NOT_MAPPED
+
+
+Some of the information to be translated has not been translated.
+
+0x00000108
+
+STATUS_OPLOCK_BREAK_IN_PROGRESS
+
+
+An open/create operation completed while an opportunistic lock (oplock) break is underway.
+
+0x00000109
+
+STATUS_VOLUME_MOUNTED
+
+
+A new volume has been mounted by a file system.
+
+0x0000010A
+
+STATUS_RXACT_COMMITTED
+
+
+This success level status indicates that the transaction state already exists for the registry subtree but that a transaction commit was previously aborted. The commit has now been completed.
+
+0x0000010B
+
+STATUS_NOTIFY_CLEANUP
+
+
+Indicates that a notify change request has been completed due to closing the handle that made the notify change request.
+
+0x0000010C
+
+STATUS_NOTIFY_ENUM_DIR
+
+
+Indicates that a notify change request is being completed and that the information is not being returned in the caller's buffer. The caller now needs to enumerate the files to find the changes.
+
+0x0000010D
+
+STATUS_NO_QUOTAS_FOR_ACCOUNT
+
+
+{No Quotas} No system quota limits are specifically set for this account.
+
+0x0000010E
+
+STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED
+
+
+{Connect Failure on Primary Transport} An attempt was made to connect to the remote server %hs on the primary transport, but the connection failed. The computer WAS able to connect on a secondary transport.
+
+0x00000110
+
+STATUS_PAGE_FAULT_TRANSITION
+
+
+The page fault was a transition fault.
+
+0x00000111
+
+STATUS_PAGE_FAULT_DEMAND_ZERO
+
+
+The page fault was a demand zero fault.
+
+0x00000112
+
+STATUS_PAGE_FAULT_COPY_ON_WRITE
+
+
+The page fault was a demand zero fault.
+
+0x00000113
+
+STATUS_PAGE_FAULT_GUARD_PAGE
+
+
+The page fault was a demand zero fault.
+
+0x00000114
+
+STATUS_PAGE_FAULT_PAGING_FILE
+
+
+The page fault was satisfied by reading from a secondary storage device.
+
+0x00000115
+
+STATUS_CACHE_PAGE_LOCKED
+
+
+The cached page was locked during operation.
+
+0x00000116
+
+STATUS_CRASH_DUMP
+
+
+The crash dump exists in a paging file.
+
+0x00000117
+
+STATUS_BUFFER_ALL_ZEROS
+
+
+The specified buffer contains all zeros.
+
+0x00000118
+
+STATUS_REPARSE_OBJECT
+
+
+A reparse should be performed by the Object Manager because the name of the file resulted in a symbolic link.
+
+0x00000119
+
+STATUS_RESOURCE_REQUIREMENTS_CHANGED
+
+
+The device has succeeded a query-stop and its resource requirements have changed.
+
+0x00000120
+
+STATUS_TRANSLATION_COMPLETE
+
+
+The translator has translated these resources into the global space and no additional translations should be performed.
+
+0x00000121
+
+STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY
+
+
+The directory service evaluated group memberships locally, because it was unable to contact a global catalog server.
+
+0x00000122
+
+STATUS_NOTHING_TO_TERMINATE
+
+
+A process being terminated has no threads to terminate.
+
+0x00000123
+
+STATUS_PROCESS_NOT_IN_JOB
+
+
+The specified process is not part of a job.
+
+0x00000124
+
+STATUS_PROCESS_IN_JOB
+
+
+The specified process is part of a job.
+
+0x00000125
+
+STATUS_VOLSNAP_HIBERNATE_READY
+
+
+{Volume Shadow Copy Service} The system is now ready for hibernation.
+
+0x00000126
+
+STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY
+
+
+A file system or file system filter driver has successfully completed an FsFilter operation.
+
+0x00000127
+
+STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED
+
+
+The specified interrupt vector was already connected.
+
+0x00000128
+
+STATUS_INTERRUPT_STILL_CONNECTED
+
+
+The specified interrupt vector is still connected.
+
+0x00000129
+
+STATUS_PROCESS_CLONED
+
+
+The current process is a cloned process.
+
+0x0000012A
+
+STATUS_FILE_LOCKED_WITH_ONLY_READERS
+
+
+The file was locked and all users of the file can only read.
+
+0x0000012B
+
+STATUS_FILE_LOCKED_WITH_WRITERS
+
+
+The file was locked and at least one user of the file can write.
+
+0x00000202
+
+STATUS_RESOURCEMANAGER_READ_ONLY
+
+
+The specified ResourceManager made no changes or updates to the resource under this transaction.
+
+0x00000367
+
+STATUS_WAIT_FOR_OPLOCK
+
+
+An operation is blocked and waiting for an oplock.
+
+0x00010001
+
+DBG_EXCEPTION_HANDLED
+
+
+Debugger handled the exception.
+
+0x00010002
+
+DBG_CONTINUE
+
+
+The debugger continued.
+
+0x001C0001
+
+STATUS_FLT_IO_COMPLETE
+
+
+The IO was completed by a filter.
+
+0xC0000467
+
+STATUS_FILE_NOT_AVAILABLE
+
+
+The file is temporarily unavailable.
+
+0xC0000480
+
+STATUS_SHARE_UNAVAILABLE
+
+
+The share is temporarily unavailable.
+
+0xC0000721
+
+STATUS_CALLBACK_RETURNED_THREAD_AFFINITY
+
+
+A threadpool worker thread entered a callback at thread affinity %p and exited at affinity %p.
+
+This is unexpected, indicating that the callback missed restoring the priority.
+
+0x40000000
+
+STATUS_OBJECT_NAME_EXISTS
+
+
+{Object Exists} An attempt was made to create an object but the object name already exists.
+
+0x40000001
+
+STATUS_THREAD_WAS_SUSPENDED
+
+
+{Thread Suspended} A thread termination occurred while the thread was suspended. The thread resumed, and termination proceeded.
+
+0x40000002
+
+STATUS_WORKING_SET_LIMIT_RANGE
+
+
+{Working Set Range Error} An attempt was made to set the working set minimum or maximum to values that are outside the allowable range.
+
+0x40000003
+
+STATUS_IMAGE_NOT_AT_BASE
+
+
+{Image Relocated} An image file could not be mapped at the address that is specified in the image file. Local fixes must be performed on this image.
+
+0x40000004
+
+STATUS_RXACT_STATE_CREATED
+
+
+This informational level status indicates that a specified registry subtree transaction state did not yet exist and had to be created.
+
+0x40000005
+
+STATUS_SEGMENT_NOTIFICATION
+
+
+{Segment Load} A virtual DOS machine (VDM) is loading, unloading, or moving an MS-DOS or Win16 program segment image. An exception is raised so that a debugger can load, unload, or track symbols and breakpoints within these 16-bit segments.
+
+0x40000006
+
+STATUS_LOCAL_USER_SESSION_KEY
+
+
+{Local Session Key} A user session key was requested for a local remote procedure call (RPC) connection. The session key that is returned is a constant value and not unique to this connection.
+
+0x40000007
+
+STATUS_BAD_CURRENT_DIRECTORY
+
+
+{Invalid Current Directory} The process cannot switch to the startup current directory %hs. Select OK to set the current directory to %hs, or select CANCEL to exit.
+
+0x40000008
+
+STATUS_SERIAL_MORE_WRITES
+
+
+{Serial IOCTL Complete} A serial I/O operation was completed by another write to a serial port. (The IOCTL_SERIAL_XOFF_COUNTER reached zero.)
+
+0x40000009
+
+STATUS_REGISTRY_RECOVERED
+
+
+{Registry Recovery} One of the files that contains the system registry data had to be recovered by using a log or alternate copy. The recovery was successful.
+
+0x4000000A
+
+STATUS_FT_READ_RECOVERY_FROM_BACKUP
+
+
+{Redundant Read} To satisfy a read request, the Windows NT operating system fault-tolerant file system successfully read the requested data from a redundant copy. This was done because the file system encountered a failure on a member of the fault-tolerant volume but was unable to reassign the failing area of the device.
+
+0x4000000B
+
+STATUS_FT_WRITE_RECOVERY
+
+
+{Redundant Write} To satisfy a write request, the Windows NT fault-tolerant file system successfully wrote a redundant copy of the information. This was done because the file system encountered a failure on a member of the fault-tolerant volume but was unable to reassign the failing area of the device.
+
+0x4000000C
+
+STATUS_SERIAL_COUNTER_TIMEOUT
+
+
+{Serial IOCTL Timeout} A serial I/O operation completed because the time-out period expired. (The IOCTL_SERIAL_XOFF_COUNTER had not reached zero.)
+
+0x4000000D
+
+STATUS_NULL_LM_PASSWORD
+
+
+{Password Too Complex} The Windows password is too complex to be converted to a LAN Manager password. The LAN Manager password that returned is a NULL string.
+
+0x4000000E
+
+STATUS_IMAGE_MACHINE_TYPE_MISMATCH
+
+
+{Machine Type Mismatch} The image file %hs is valid but is for a machine type other than the current machine. Select OK to continue, or CANCEL to fail the DLL load.
+
+0x4000000F
+
+STATUS_RECEIVE_PARTIAL
+
+
+{Partial Data Received} The network transport returned partial data to its client. The remaining data will be sent later.
+
+0x40000010
+
+STATUS_RECEIVE_EXPEDITED
+
+
+{Expedited Data Received} The network transport returned data to its client that was marked as expedited by the remote system.
+
+0x40000011
+
+STATUS_RECEIVE_PARTIAL_EXPEDITED
+
+
+{Partial Expedited Data Received} The network transport returned partial data to its client and this data was marked as expedited by the remote system. The remaining data will be sent later.
+
+0x40000012
+
+STATUS_EVENT_DONE
+
+
+{TDI Event Done} The TDI indication has completed successfully.
+
+0x40000013
+
+STATUS_EVENT_PENDING
+
+
+{TDI Event Pending} The TDI indication has entered the pending state.
+
+0x40000014
+
+STATUS_CHECKING_FILE_SYSTEM
+
+
+Checking file system on %wZ.
+
+0x40000015
+
+STATUS_FATAL_APP_EXIT
+
+
+{Fatal Application Exit} %hs
+
+0x40000016
+
+STATUS_PREDEFINED_HANDLE
+
+
+The specified registry key is referenced by a predefined handle.
+
+0x40000017
+
+STATUS_WAS_UNLOCKED
+
+
+{Page Unlocked} The page protection of a locked page was changed to 'No Access' and the page was unlocked from memory and from the process.
+
+0x40000018
+
+STATUS_SERVICE_NOTIFICATION
+
+
+%hs
+
+0x40000019
+
+STATUS_WAS_LOCKED
+
+
+{Page Locked} One of the pages to lock was already locked.
+
+0x4000001A
+
+STATUS_LOG_HARD_ERROR
+
+
+Application popup: %1 : %2
+
+0x4000001B
+
+STATUS_ALREADY_WIN32
+
+
+A Win32 process already exists.
+
+0x4000001C
+
+STATUS_WX86_UNSIMULATE
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x4000001D
+
+STATUS_WX86_CONTINUE
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x4000001E
+
+STATUS_WX86_SINGLE_STEP
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x4000001F
+
+STATUS_WX86_BREAKPOINT
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000020
+
+STATUS_WX86_EXCEPTION_CONTINUE
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000021
+
+STATUS_WX86_EXCEPTION_LASTCHANCE
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000022
+
+STATUS_WX86_EXCEPTION_CHAIN
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000023
+
+STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
+
+
+{Machine Type Mismatch} The image file %hs is valid but is for a machine type other than the current machine.
+
+0x40000024
+
+STATUS_NO_YIELD_PERFORMED
+
+
+A yield execution was performed and no thread was available to run.
+
+0x40000025
+
+STATUS_TIMER_RESUME_IGNORED
+
+
+The resume flag to a timer API was ignored.
+
+0x40000026
+
+STATUS_ARBITRATION_UNHANDLED
+
+
+The arbiter has deferred arbitration of these resources to its parent.
+
+0x40000027
+
+STATUS_CARDBUS_NOT_SUPPORTED
+
+
+The device has detected a CardBus card in its slot.
+
+0x40000028
+
+STATUS_WX86_CREATEWX86TIB
+
+
+An exception status code that is used by the Win32 x86 emulation subsystem.
+
+0x40000029
+
+STATUS_MP_PROCESSOR_MISMATCH
+
+
+The CPUs in this multiprocessor system are not all the same revision level. To use all processors, the operating system restricts itself to the features of the least capable processor in the system. If problems occur with this system, contact the CPU manufacturer to see if this mix of processors is supported.
+
+0x4000002A
+
+STATUS_HIBERNATED
+
+
+The system was put into hibernation.
+
+0x4000002B
+
+STATUS_RESUME_HIBERNATION
+
+
+The system was resumed from hibernation.
+
+0x4000002C
+
+STATUS_FIRMWARE_UPDATED
+
+
+Windows has detected that the system firmware (BIOS) was updated [previous firmware date = %2, current firmware date %3].
+
+0x4000002D
+
+STATUS_DRIVERS_LEAKING_LOCKED_PAGES
+
+
+A device driver is leaking locked I/O pages and is causing system degradation. The system has automatically enabled the tracking code to try and catch the culprit.
+
+0x4000002E
+
+STATUS_MESSAGE_RETRIEVED
+
+
+The ALPC message being canceled has already been retrieved from the queue on the other side.
+
+0x4000002F
+
+STATUS_SYSTEM_POWERSTATE_TRANSITION
+
+
+The system power state is transitioning from %2 to %3.
+
+0x40000030
+
+STATUS_ALPC_CHECK_COMPLETION_LIST
+
+
+The receive operation was successful. Check the ALPC completion list for the received message.
+
+0x40000031
+
+STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION
+
+
+The system power state is transitioning from %2 to %3 but could enter %4.
+
+0x40000032
+
+STATUS_ACCESS_AUDIT_BY_POLICY
+
+
+Access to %1 is monitored by policy rule %2.
+
+0x40000033
+
+STATUS_ABANDON_HIBERFILE
+
+
+A valid hibernation file has been invalidated and should be abandoned.
+
+0x40000034
+
+STATUS_BIZRULES_NOT_ENABLED
+
+
+Business rule scripts are disabled for the calling application.
+
+0x40000294
+
+STATUS_WAKE_SYSTEM
+
+
+The system has awoken.
+
+0x40000370
+
+STATUS_DS_SHUTTING_DOWN
+
+
+The directory service is shutting down.
+
+0x40010001
+
+DBG_REPLY_LATER
+
+
+Debugger will reply later.
+
+0x40010002
+
+DBG_UNABLE_TO_PROVIDE_HANDLE
+
+
+Debugger cannot provide a handle.
+
+0x40010003
+
+DBG_TERMINATE_THREAD
+
+
+Debugger terminated the thread.
+
+0x40010004
+
+DBG_TERMINATE_PROCESS
+
+
+Debugger terminated the process.
+
+0x40010005
+
+DBG_CONTROL_C
+
+
+Debugger obtained control of C.
+
+0x40010006
+
+DBG_PRINTEXCEPTION_C
+
+
+Debugger printed an exception on control C.
+
+0x40010007
+
+DBG_RIPEXCEPTION
+
+
+Debugger received a RIP exception.
+
+0x40010008
+
+DBG_CONTROL_BREAK
+
+
+Debugger received a control break.
+
+0x40010009
+
+DBG_COMMAND_EXCEPTION
+
+
+Debugger command communication exception.
+
+0x40020056
+
+RPC_NT_UUID_LOCAL_ONLY
+
+
+A UUID that is valid only on this computer has been allocated.
+
+0x400200AF
+
+RPC_NT_SEND_INCOMPLETE
+
+
+Some data remains to be sent in the request buffer.
+
+0x400A0004
+
+STATUS_CTX_CDM_CONNECT
+
+
+The Client Drive Mapping Service has connected on Terminal Connection.
+
+0x400A0005
+
+STATUS_CTX_CDM_DISCONNECT
+
+
+The Client Drive Mapping Service has disconnected on Terminal Connection.
+
+0x4015000D
+
+STATUS_SXS_RELEASE_ACTIVATION_CONTEXT
+
+
+A kernel mode component is releasing a reference on an activation context.
+
+0x40190034
+
+STATUS_RECOVERY_NOT_NEEDED
+
+
+The transactional resource manager is already consistent. Recovery is not needed.
+
+0x40190035
+
+STATUS_RM_ALREADY_STARTED
+
+
+The transactional resource manager has already been started.
+
+0x401A000C
+
+STATUS_LOG_NO_RESTART
+
+
+The log service encountered a log stream with no restart area.
+
+0x401B00EC
+
+STATUS_VIDEO_DRIVER_DEBUG_REPORT_REQUEST
+
+
+{Display Driver Recovered From Failure} The %hs display driver has detected a failure and recovered from it. Some graphical operations might have failed. The next time you restart the machine, a dialog box appears, giving you an opportunity to upload data about this failure to Microsoft.
+
+0x401E000A
+
+STATUS_GRAPHICS_PARTIAL_DATA_POPULATED
+
+
+The specified buffer is not big enough to contain the entire requested dataset. Partial data is populated up to the size of the buffer.
+
+The caller needs to provide a buffer of the size as specified in the partially populated buffer's content (interface specific).
+
+0x401E0117
+
+STATUS_GRAPHICS_DRIVER_MISMATCH
+
+
+The kernel driver detected a version mismatch between it and the user mode driver.
+
+0x401E0307
+
+STATUS_GRAPHICS_MODE_NOT_PINNED
+
+
+No mode is pinned on the specified VidPN source/target.
+
+0x401E031E
+
+STATUS_GRAPHICS_NO_PREFERRED_MODE
+
+
+The specified mode set does not specify a preference for one of its modes.
+
+0x401E034B
+
+STATUS_GRAPHICS_DATASET_IS_EMPTY
+
+
+The specified dataset (for example, mode set, frequency range set, descriptor set, or topology) is empty.
+
+0x401E034C
+
+STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET
+
+
+The specified dataset (for example, mode set, frequency range set, descriptor set, or topology) does not contain any more elements.
+
+0x401E0351
+
+STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED
+
+
+The specified content transformation is not pinned on the specified VidPN present path.
+
+0x401E042F
+
+STATUS_GRAPHICS_UNKNOWN_CHILD_STATUS
+
+
+The child device presence was not reliably detected.
+
+0x401E0437
+
+STATUS_GRAPHICS_LEADLINK_START_DEFERRED
+
+
+Starting the lead adapter in a linked configuration has been temporarily deferred.
+
+0x401E0439
+
+STATUS_GRAPHICS_POLLING_TOO_FREQUENTLY
+
+
+The display adapter is being polled for children too frequently at the same polling level.
+
+0x401E043A
+
+STATUS_GRAPHICS_START_DEFERRED
+
+
+Starting the adapter has been temporarily deferred.
+
+0x40230001
+
+STATUS_NDIS_INDICATION_REQUIRED
+
+
+The request will be completed later by an NDIS status indication.
+
+0x80000001
+
+STATUS_GUARD_PAGE_VIOLATION
+
+
+{EXCEPTION} Guard Page Exception A page of memory that marks the end of a data structure, such as a stack or an array, has been accessed.
+
+0x80000002
+
+STATUS_DATATYPE_MISALIGNMENT
+
+
+{EXCEPTION} Alignment Fault A data type misalignment was detected in a load or store instruction.
+
+0x80000003
+
+STATUS_BREAKPOINT
+
+
+{EXCEPTION} Breakpoint A breakpoint has been reached.
+
+0x80000004
+
+STATUS_SINGLE_STEP
+
+
+{EXCEPTION} Single Step A single step or trace operation has just been completed.
+
+0x80000005
+
+STATUS_BUFFER_OVERFLOW
+
+
+{Buffer Overflow} The data was too large to fit into the specified buffer.
+
+0x80000006
+
+STATUS_NO_MORE_FILES
+
+
+{No More Files} No more files were found which match the file specification.
+
+0x80000007
+
+STATUS_WAKE_SYSTEM_DEBUGGER
+
+
+{Kernel Debugger Awakened} The system debugger was awakened by an interrupt.
+
+0x8000000A
+
+STATUS_HANDLES_CLOSED
+
+
+{Handles Closed} Handles to objects have been automatically closed because of the requested operation.
+
+0x8000000B
+
+STATUS_NO_INHERITANCE
+
+
+{Non-Inheritable ACL} An access control list (ACL) contains no components that can be inherited.
+
+0x8000000C
+
+STATUS_GUID_SUBSTITUTION_MADE
+
+
+{GUID Substitution} During the translation of a globally unique identifier (GUID) to a Windows security ID (SID), no administratively defined GUID prefix was found. A substitute prefix was used, which will not compromise system security. However, this might provide a more restrictive access than intended.
+
+0x8000000D
+
+STATUS_PARTIAL_COPY
+
+
+Because of protection conflicts, not all the requested bytes could be copied.
+
+0x8000000E
+
+STATUS_DEVICE_PAPER_EMPTY
+
+
+{Out of Paper} The printer is out of paper.
+
+0x8000000F
+
+STATUS_DEVICE_POWERED_OFF
+
+
+{Device Power Is Off} The printer power has been turned off.
+
+0x80000010
+
+STATUS_DEVICE_OFF_LINE
+
+
+{Device Offline} The printer has been taken offline.
+
+0x80000011
+
+STATUS_DEVICE_BUSY
+
+
+{Device Busy} The device is currently busy.
+
+0x80000012
+
+STATUS_NO_MORE_EAS
+
+
+{No More EAs} No more extended attributes (EAs) were found for the file.
+
+0x80000013
+
+STATUS_INVALID_EA_NAME
+
+
+{Illegal EA} The specified extended attribute (EA) name contains at least one illegal character.
+
+0x80000014
+
+STATUS_EA_LIST_INCONSISTENT
+
+
+{Inconsistent EA List} The extended attribute (EA) list is inconsistent.
+
+0x80000015
+
+STATUS_INVALID_EA_FLAG
+
+
+{Invalid EA Flag} An invalid extended attribute (EA) flag was set.
+
+0x80000016
+
+STATUS_VERIFY_REQUIRED
+
+
+{Verifying Disk} The media has changed and a verify operation is in progress; therefore, no reads or writes can be performed to the device, except those that are used in the verify operation.
+
+0x80000017
+
+STATUS_EXTRANEOUS_INFORMATION
+
+
+{Too Much Information} The specified access control list (ACL) contained more information than was expected.
+
+0x80000018
+
+STATUS_RXACT_COMMIT_NECESSARY
+
+
+This warning level status indicates that the transaction state already exists for the registry subtree, but that a transaction commit was previously aborted. The commit has NOT been completed but has not been rolled back either; therefore, it can still be committed, if needed.
+
+0x8000001A
+
+STATUS_NO_MORE_ENTRIES
+
+
+{No More Entries} No more entries are available from an enumeration operation.
+
+0x8000001B
+
+STATUS_FILEMARK_DETECTED
+
+
+{Filemark Found} A filemark was detected.
+
+0x8000001C
+
+STATUS_MEDIA_CHANGED
+
+
+{Media Changed} The media has changed.
+
+0x8000001D
+
+STATUS_BUS_RESET
+
+
+{I/O Bus Reset} An I/O bus reset was detected.
+
+0x8000001E
+
+STATUS_END_OF_MEDIA
+
+
+{End of Media} The end of the media was encountered.
+
+0x8000001F
+
+STATUS_BEGINNING_OF_MEDIA
+
+
+The beginning of a tape or partition has been detected.
+
+0x80000020
+
+STATUS_MEDIA_CHECK
+
+
+{Media Changed} The media might have changed.
+
+0x80000021
+
+STATUS_SETMARK_DETECTED
+
+
+A tape access reached a set mark.
+
+0x80000022
+
+STATUS_NO_DATA_DETECTED
+
+
+During a tape access, the end of the data written is reached.
+
+0x80000023
+
+STATUS_REDIRECTOR_HAS_OPEN_HANDLES
+
+
+The redirector is in use and cannot be unloaded.
+
+0x80000024
+
+STATUS_SERVER_HAS_OPEN_HANDLES
+
+
+The server is in use and cannot be unloaded.
+
+0x80000025
+
+STATUS_ALREADY_DISCONNECTED
+
+
+The specified connection has already been disconnected.
+
+0x80000026
+
+STATUS_LONGJUMP
+
+
+A long jump has been executed.
+
+0x80000027
+
+STATUS_CLEANER_CARTRIDGE_INSTALLED
+
+
+A cleaner cartridge is present in the tape library.
+
+0x80000028
+
+STATUS_PLUGPLAY_QUERY_VETOED
+
+
+The Plug and Play query operation was not successful.
+
+0x80000029
+
+STATUS_UNWIND_CONSOLIDATE
+
+
+A frame consolidation has been executed.
+
+0x8000002A
+
+STATUS_REGISTRY_HIVE_RECOVERED
+
+
+{Registry Hive Recovered} The registry hive (file): %hs was corrupted and it has been recovered. Some data might have been lost.
+
+0x8000002B
+
+STATUS_DLL_MIGHT_BE_INSECURE
+
+
+The application is attempting to run executable code from the module %hs. This might be insecure. An alternative, %hs, is available. Should the application use the secure module %hs?
+
+0x8000002C
+
+STATUS_DLL_MIGHT_BE_INCOMPATIBLE
+
+
+The application is loading executable code from the module %hs. This is secure but might be incompatible with previous releases of the operating system. An alternative, %hs, is available. Should the application use the secure module %hs?
+
+0x8000002D
+
+STATUS_STOPPED_ON_SYMLINK
+
+
+The create operation stopped after reaching a symbolic link.
+
+0x80000288
+
+STATUS_DEVICE_REQUIRES_CLEANING
+
+
+The device has indicated that cleaning is necessary.
+
+0x80000289
+
+STATUS_DEVICE_DOOR_OPEN
+
+
+The device has indicated that its door is open. Further operations require it closed and secured.
+
+0x80000803
+
+STATUS_DATA_LOST_REPAIR
+
+
+Windows discovered a corruption in the file %hs. This file has now been repaired. Check if any data in the file was lost because of the corruption.
+
+0x80010001
+
+DBG_EXCEPTION_NOT_HANDLED
+
+
+Debugger did not handle the exception.
+
+0x80130001
+
+STATUS_CLUSTER_NODE_ALREADY_UP
+
+
+The cluster node is already up.
+
+0x80130002
+
+STATUS_CLUSTER_NODE_ALREADY_DOWN
+
+
+The cluster node is already down.
+
+0x80130003
+
+STATUS_CLUSTER_NETWORK_ALREADY_ONLINE
+
+
+The cluster network is already online.
+
+0x80130004
+
+STATUS_CLUSTER_NETWORK_ALREADY_OFFLINE
+
+
+The cluster network is already offline.
+
+0x80130005
+
+STATUS_CLUSTER_NODE_ALREADY_MEMBER
+
+
+The cluster node is already a member of the cluster.
+
+0x80190009
+
+STATUS_COULD_NOT_RESIZE_LOG
+
+
+The log could not be set to the requested size.
+
+0x80190029
+
+STATUS_NO_TXF_METADATA
+
+
+There is no transaction metadata on the file.
+
+0x80190031
+
+STATUS_CANT_RECOVER_WITH_HANDLE_OPEN
+
+
+The file cannot be recovered because there is a handle still open on it.
+
+0x80190041
+
+STATUS_TXF_METADATA_ALREADY_PRESENT
+
+
+Transaction metadata is already present on this file and cannot be superseded.
+
+0x80190042
+
+STATUS_TRANSACTION_SCOPE_CALLBACKS_NOT_SET
+
+
+A transaction scope could not be entered because the scope handler has not been initialized.
+
+0x801B00EB
+
+STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD_RECOVERED
+
+
+{Display Driver Stopped Responding and recovered} The %hs display driver has stopped working normally. The recovery had been performed.
+
+0x801C0001
+
+STATUS_FLT_BUFFER_TOO_SMALL
+
+
+{Buffer too small} The buffer is too small to contain the entry. No information has been written to the buffer.
+
+0x80210001
+
+STATUS_FVE_PARTIAL_METADATA
+
+
+Volume metadata read or write is incomplete.
+
+0x80210002
+
+STATUS_FVE_TRANSIENT_STATE
+
+
+BitLocker encryption keys were ignored because the volume was in a transient state.
+
+0xC0000001
+
+STATUS_UNSUCCESSFUL
+
+
+{Operation Failed} The requested operation was unsuccessful.
+
+0xC0000002
+
+STATUS_NOT_IMPLEMENTED
+
+
+{Not Implemented} The requested operation is not implemented.
+
+0xC0000003
+
+STATUS_INVALID_INFO_CLASS
+
+
+{Invalid Parameter} The specified information class is not a valid information class for the specified object.
+
+0xC0000004
+
+STATUS_INFO_LENGTH_MISMATCH
+
+
+The specified information record length does not match the length that is required for the specified information class.
+
+0xC0000005
+
+STATUS_ACCESS_VIOLATION
+
+
+The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.
+
+0xC0000006
+
+STATUS_IN_PAGE_ERROR
+
+
+The instruction at 0x%08lx referenced memory at 0x%08lx. The required data was not placed into memory because of an I/O error status of 0x%08lx.
+
+0xC0000007
+
+STATUS_PAGEFILE_QUOTA
+
+
+The page file quota for the process has been exhausted.
+
+0xC0000008
+
+STATUS_INVALID_HANDLE
+
+
+An invalid HANDLE was specified.
+
+0xC0000009
+
+STATUS_BAD_INITIAL_STACK
+
+
+An invalid initial stack was specified in a call to NtCreateThread.
+
+0xC000000A
+
+STATUS_BAD_INITIAL_PC
+
+
+An invalid initial start address was specified in a call to NtCreateThread.
+
+0xC000000B
+
+STATUS_INVALID_CID
+
+
+An invalid client ID was specified.
+
+0xC000000C
+
+STATUS_TIMER_NOT_CANCELED
+
+
+An attempt was made to cancel or set a timer that has an associated APC and the specified thread is not the thread that originally set the timer with an associated APC routine.
+
+0xC000000D
+
+STATUS_INVALID_PARAMETER
+
+
+An invalid parameter was passed to a service or function.
+
+0xC000000E
+
+STATUS_NO_SUCH_DEVICE
+
+
+A device that does not exist was specified.
+
+0xC000000F
+
+STATUS_NO_SUCH_FILE
+
+
+{File Not Found} The file %hs does not exist.
+
+0xC0000010
+
+STATUS_INVALID_DEVICE_REQUEST
+
+
+The specified request is not a valid operation for the target device.
+
+0xC0000011
+
+STATUS_END_OF_FILE
+
+
+The end-of-file marker has been reached. There is no valid data in the file beyond this marker.
+
+0xC0000012
+
+STATUS_WRONG_VOLUME
+
+
+{Wrong Volume} The wrong volume is in the drive. Insert volume %hs into drive %hs.
+
+0xC0000013
+
+STATUS_NO_MEDIA_IN_DEVICE
+
+
+{No Disk} There is no disk in the drive. Insert a disk into drive %hs.
+
+0xC0000014
+
+STATUS_UNRECOGNIZED_MEDIA
+
+
+{Unknown Disk Format} The disk in drive %hs is not formatted properly. Check the disk, and reformat it, if needed.
+
+0xC0000015
+
+STATUS_NONEXISTENT_SECTOR
+
+
+{Sector Not Found} The specified sector does not exist.
+
+0xC0000016
+
+STATUS_MORE_PROCESSING_REQUIRED
+
+
+{Still Busy} The specified I/O request packet (IRP) cannot be disposed of because the I/O operation is not complete.
+
+0xC0000017
+
+STATUS_NO_MEMORY
+
+
+{Not Enough Quota} Not enough virtual memory or paging file quota is available to complete the specified operation.
+
+0xC0000018
+
+STATUS_CONFLICTING_ADDRESSES
+
+
+{Conflicting Address Range} The specified address range conflicts with the address space.
+
+0xC0000019
+
+STATUS_NOT_MAPPED_VIEW
+
+
+The address range to unmap is not a mapped view.
+
+0xC000001A
+
+STATUS_UNABLE_TO_FREE_VM
+
+
+The virtual memory cannot be freed.
+
+0xC000001B
+
+STATUS_UNABLE_TO_DELETE_SECTION
+
+
+The specified section cannot be deleted.
+
+0xC000001C
+
+STATUS_INVALID_SYSTEM_SERVICE
+
+
+An invalid system service was specified in a system service call.
+
+0xC000001D
+
+STATUS_ILLEGAL_INSTRUCTION
+
+
+{EXCEPTION} Illegal Instruction An attempt was made to execute an illegal instruction.
+
+0xC000001E
+
+STATUS_INVALID_LOCK_SEQUENCE
+
+
+{Invalid Lock Sequence} An attempt was made to execute an invalid lock sequence.
+
+0xC000001F
+
+STATUS_INVALID_VIEW_SIZE
+
+
+{Invalid Mapping} An attempt was made to create a view for a section that is bigger than the section.
+
+0xC0000020
+
+STATUS_INVALID_FILE_FOR_SECTION
+
+
+{Bad File} The attributes of the specified mapping file for a section of memory cannot be read.
+
+0xC0000021
+
+STATUS_ALREADY_COMMITTED
+
+
+{Already Committed} The specified address range is already committed.
+
+0xC0000022
+
+STATUS_ACCESS_DENIED
+
+
+{Access Denied} A process has requested access to an object but has not been granted those access rights.
+
+0xC0000023
+
+STATUS_BUFFER_TOO_SMALL
+
+
+{Buffer Too Small} The buffer is too small to contain the entry. No information has been written to the buffer.
+
+0xC0000024
+
+STATUS_OBJECT_TYPE_MISMATCH
+
+
+{Wrong Type} There is a mismatch between the type of object that is required by the requested operation and the type of object that is specified in the request.
+
+0xC0000025
+
+STATUS_NONCONTINUABLE_EXCEPTION
+
+
+{EXCEPTION} Cannot Continue Windows cannot continue from this exception.
+
+0xC0000026
+
+STATUS_INVALID_DISPOSITION
+
+
+An invalid exception disposition was returned by an exception handler.
+
+0xC0000027
+
+STATUS_UNWIND
+
+
+Unwind exception code.
+
+0xC0000028
+
+STATUS_BAD_STACK
+
+
+An invalid or unaligned stack was encountered during an unwind operation.
+
+0xC0000029
+
+STATUS_INVALID_UNWIND_TARGET
+
+
+An invalid unwind target was encountered during an unwind operation.
+
+0xC000002A
+
+STATUS_NOT_LOCKED
+
+
+An attempt was made to unlock a page of memory that was not locked.
+
+0xC000002B
+
+STATUS_PARITY_ERROR
+
+
+A device parity error on an I/O operation.
+
+0xC000002C
+
+STATUS_UNABLE_TO_DECOMMIT_VM
+
+
+An attempt was made to decommit uncommitted virtual memory.
+
+0xC000002D
+
+STATUS_NOT_COMMITTED
+
+
+An attempt was made to change the attributes on memory that has not been committed.
+
+0xC000002E
+
+STATUS_INVALID_PORT_ATTRIBUTES
+
+
+Invalid object attributes specified to NtCreatePort or invalid port attributes specified to NtConnectPort.
+
+0xC000002F
+
+STATUS_PORT_MESSAGE_TOO_LONG
+
+
+The length of the message that was passed to NtRequestPort or NtRequestWaitReplyPort is longer than the maximum message that is allowed by the port.
+
+0xC0000030
+
+STATUS_INVALID_PARAMETER_MIX
+
+
+An invalid combination of parameters was specified.
+
+0xC0000031
+
+STATUS_INVALID_QUOTA_LOWER
+
+
+An attempt was made to lower a quota limit below the current usage.
+
+0xC0000032
+
+STATUS_DISK_CORRUPT_ERROR
+
+
+{Corrupt Disk} The file system structure on the disk is corrupt and unusable. Run the Chkdsk utility on the volume %hs.
+
+0xC0000033
+
+STATUS_OBJECT_NAME_INVALID
+
+
+The object name is invalid.
+
+0xC0000034
+
+STATUS_OBJECT_NAME_NOT_FOUND
+
+
+The object name is not found.
+
+0xC0000035
+
+STATUS_OBJECT_NAME_COLLISION
+
+
+The object name already exists.
+
+0xC0000037
+
+STATUS_PORT_DISCONNECTED
+
+
+An attempt was made to send a message to a disconnected communication port.
+
+0xC0000038
+
+STATUS_DEVICE_ALREADY_ATTACHED
+
+
+An attempt was made to attach to a device that was already attached to another device.
+
+0xC0000039
+
+STATUS_OBJECT_PATH_INVALID
+
+
+The object path component was not a directory object.
+
+0xC000003A
+
+STATUS_OBJECT_PATH_NOT_FOUND
+
+
+{Path Not Found} The path %hs does not exist.
+
+0xC000003B
+
+STATUS_OBJECT_PATH_SYNTAX_BAD
+
+
+The object path component was not a directory object.
+
+0xC000003C
+
+STATUS_DATA_OVERRUN
+
+
+{Data Overrun} A data overrun error occurred.
+
+0xC000003D
+
+STATUS_DATA_LATE_ERROR
+
+
+{Data Late} A data late error occurred.
+
+0xC000003E
+
+STATUS_DATA_ERROR
+
+
+{Data Error} An error occurred in reading or writing data.
+
+0xC000003F
+
+STATUS_CRC_ERROR
+
+
+{Bad CRC} A cyclic redundancy check (CRC) checksum error occurred.
+
+0xC0000040
+
+STATUS_SECTION_TOO_BIG
+
+
+{Section Too Large} The specified section is too big to map the file.
+
+0xC0000041
+
+STATUS_PORT_CONNECTION_REFUSED
+
+
+The NtConnectPort request is refused.
+
+0xC0000042
+
+STATUS_INVALID_PORT_HANDLE
+
+
+The type of port handle is invalid for the operation that is requested.
+
+0xC0000043
+
+STATUS_SHARING_VIOLATION
+
+
+A file cannot be opened because the share access flags are incompatible.
+
+0xC0000044
+
+STATUS_QUOTA_EXCEEDED
+
+
+Insufficient quota exists to complete the operation.
+
+0xC0000045
+
+STATUS_INVALID_PAGE_PROTECTION
+
+
+The specified page protection was not valid.
+
+0xC0000046
+
+STATUS_MUTANT_NOT_OWNED
+
+
+An attempt to release a mutant object was made by a thread that was not the owner of the mutant object.
+
+0xC0000047
+
+STATUS_SEMAPHORE_LIMIT_EXCEEDED
+
+
+An attempt was made to release a semaphore such that its maximum count would have been exceeded.
+
+0xC0000048
+
+STATUS_PORT_ALREADY_SET
+
+
+An attempt was made to set the DebugPort or ExceptionPort of a process, but a port already exists in the process, or an attempt was made to set the CompletionPort of a file but a port was already set in the file, or an attempt was made to set the associated completion port of an ALPC port but it is already set.
+
+0xC0000049
+
+STATUS_SECTION_NOT_IMAGE
+
+
+An attempt was made to query image information on a section that does not map an image.
+
+0xC000004A
+
+STATUS_SUSPEND_COUNT_EXCEEDED
+
+
+An attempt was made to suspend a thread whose suspend count was at its maximum.
+
+0xC000004B
+
+STATUS_THREAD_IS_TERMINATING
+
+
+An attempt was made to suspend a thread that has begun termination.
+
+0xC000004C
+
+STATUS_BAD_WORKING_SET_LIMIT
+
+
+An attempt was made to set the working set limit to an invalid value (for example, the minimum greater than maximum).
+
+0xC000004D
+
+STATUS_INCOMPATIBLE_FILE_MAP
+
+
+A section was created to map a file that is not compatible with an already existing section that maps the same file.
+
+0xC000004E
+
+STATUS_SECTION_PROTECTION
+
+
+A view to a section specifies a protection that is incompatible with the protection of the initial view.
+
+0xC000004F
+
+STATUS_EAS_NOT_SUPPORTED
+
+
+An operation involving EAs failed because the file system does not support EAs.
+
+0xC0000050
+
+STATUS_EA_TOO_LARGE
+
+
+An EA operation failed because the EA set is too large.
+
+0xC0000051
+
+STATUS_NONEXISTENT_EA_ENTRY
+
+
+An EA operation failed because the name or EA index is invalid.
+
+0xC0000052
+
+STATUS_NO_EAS_ON_FILE
+
+
+The file for which EAs were requested has no EAs.
+
+0xC0000053
+
+STATUS_EA_CORRUPT_ERROR
+
+
+The EA is corrupt and cannot be read.
+
+0xC0000054
+
+STATUS_FILE_LOCK_CONFLICT
+
+
+A requested read/write cannot be granted due to a conflicting file lock.
+
+0xC0000055
+
+STATUS_LOCK_NOT_GRANTED
+
+
+A requested file lock cannot be granted due to other existing locks.
+
+0xC0000056
+
+STATUS_DELETE_PENDING
+
+
+A non-close operation has been requested of a file object that has a delete pending.
+
+0xC0000057
+
+STATUS_CTL_FILE_NOT_SUPPORTED
+
+
+An attempt was made to set the control attribute on a file. This attribute is not supported in the destination file system.
+
+0xC0000058
+
+STATUS_UNKNOWN_REVISION
+
+
+Indicates a revision number that was encountered or specified is not one that is known by the service. It might be a more recent revision than the service is aware of.
+
+0xC0000059
+
+STATUS_REVISION_MISMATCH
+
+
+Indicates that two revision levels are incompatible.
+
+0xC000005A
+
+STATUS_INVALID_OWNER
+
+
+Indicates a particular security ID cannot be assigned as the owner of an object.
+
+0xC000005B
+
+STATUS_INVALID_PRIMARY_GROUP
+
+
+Indicates a particular security ID cannot be assigned as the primary group of an object.
+
+0xC000005C
+
+STATUS_NO_IMPERSONATION_TOKEN
+
+
+An attempt has been made to operate on an impersonation token by a thread that is not currently impersonating a client.
+
+0xC000005D
+
+STATUS_CANT_DISABLE_MANDATORY
+
+
+A mandatory group cannot be disabled.
+
+0xC000005E
+
+STATUS_NO_LOGON_SERVERS
+
+
+No logon servers are currently available to service the logon request.
+
+0xC000005F
+
+STATUS_NO_SUCH_LOGON_SESSION
+
+
+A specified logon session does not exist. It might already have been terminated.
+
+0xC0000060
+
+STATUS_NO_SUCH_PRIVILEGE
+
+
+A specified privilege does not exist.
+
+0xC0000061
+
+STATUS_PRIVILEGE_NOT_HELD
+
+
+A required privilege is not held by the client.
+
+0xC0000062
+
+STATUS_INVALID_ACCOUNT_NAME
+
+
+The name provided is not a properly formed account name.
+
+0xC0000063
+
+STATUS_USER_EXISTS
+
+
+The specified account already exists.
+
+0xC0000064
+
+STATUS_NO_SUCH_USER
+
+
+The specified account does not exist.
+
+0xC0000065
+
+STATUS_GROUP_EXISTS
+
+
+The specified group already exists.
+
+0xC0000066
+
+STATUS_NO_SUCH_GROUP
+
+
+The specified group does not exist.
+
+0xC0000067
+
+STATUS_MEMBER_IN_GROUP
+
+
+The specified user account is already in the specified group account. Also used to indicate a group cannot be deleted because it contains a member.
+
+0xC0000068
+
+STATUS_MEMBER_NOT_IN_GROUP
+
+
+The specified user account is not a member of the specified group account.
+
+0xC0000069
+
+STATUS_LAST_ADMIN
+
+
+Indicates the requested operation would disable or delete the last remaining administration account. This is not allowed to prevent creating a situation in which the system cannot be administrated.
+
+0xC000006A
+
+STATUS_WRONG_PASSWORD
+
+
+When trying to update a password, this return status indicates that the value provided as the current password is not correct.
+
+0xC000006B
+
+STATUS_ILL_FORMED_PASSWORD
+
+
+When trying to update a password, this return status indicates that the value provided for the new password contains values that are not allowed in passwords.
+
+0xC000006C
+
+STATUS_PASSWORD_RESTRICTION
+
+
+When trying to update a password, this status indicates that some password update rule has been violated. For example, the password might not meet length criteria.
+
+0xC000006D
+
+STATUS_LOGON_FAILURE
+
+
+The attempted logon is invalid. This is either due to a bad username or authentication information.
+
+0xC000006E
+
+STATUS_ACCOUNT_RESTRICTION
+
+
+Indicates a referenced user name and authentication information are valid, but some user account restriction has prevented successful authentication (such as time-of-day restrictions).
+
+0xC000006F
+
+STATUS_INVALID_LOGON_HOURS
+
+
+The user account has time restrictions and cannot be logged onto at this time.
+
+0xC0000070
+
+STATUS_INVALID_WORKSTATION
+
+
+The user account is restricted so that it cannot be used to log on from the source workstation.
+
+0xC0000071
+
+STATUS_PASSWORD_EXPIRED
+
+
+The user account password has expired.
+
+0xC0000072
+
+STATUS_ACCOUNT_DISABLED
+
+
+The referenced account is currently disabled and cannot be logged on to.
+
+0xC0000073
+
+STATUS_NONE_MAPPED
+
+
+None of the information to be translated has been translated.
+
+0xC0000074
+
+STATUS_TOO_MANY_LUIDS_REQUESTED
+
+
+The number of LUIDs requested cannot be allocated with a single allocation.
+
+0xC0000075
+
+STATUS_LUIDS_EXHAUSTED
+
+
+Indicates there are no more LUIDs to allocate.
+
+0xC0000076
+
+STATUS_INVALID_SUB_AUTHORITY
+
+
+Indicates the sub-authority value is invalid for the particular use.
+
+0xC0000077
+
+STATUS_INVALID_ACL
+
+
+Indicates the ACL structure is not valid.
+
+0xC0000078
+
+STATUS_INVALID_SID
+
+
+Indicates the SID structure is not valid.
+
+0xC0000079
+
+STATUS_INVALID_SECURITY_DESCR
+
+
+Indicates the SECURITY_DESCRIPTOR structure is not valid.
+
+0xC000007A
+
+STATUS_PROCEDURE_NOT_FOUND
+
+
+Indicates the specified procedure address cannot be found in the DLL.
+
+0xC000007B
+
+STATUS_INVALID_IMAGE_FORMAT
+
+
+{Bad Image} %hs is either not designed to run on Windows or it contains an error. Try installing the program again using the original installation media or contact your system administrator or the software vendor for support.
+
+0xC000007C
+
+STATUS_NO_TOKEN
+
+
+An attempt was made to reference a token that does not exist. This is typically done by referencing the token that is associated with a thread when the thread is not impersonating a client.
+
+0xC000007D
+
+STATUS_BAD_INHERITANCE_ACL
+
+
+Indicates that an attempt to build either an inherited ACL or ACE was not successful. This can be caused by a number of things. One of the more probable causes is the replacement of a CreatorId with a SID that did not fit into the ACE or ACL.
+
+0xC000007E
+
+STATUS_RANGE_NOT_LOCKED
+
+
+The range specified in NtUnlockFile was not locked.
+
+0xC000007F
+
+STATUS_DISK_FULL
+
+
+An operation failed because the disk was full.
+
+0xC0000080
+
+STATUS_SERVER_DISABLED
+
+
+The GUID allocation server is disabled at the moment.
+
+0xC0000081
+
+STATUS_SERVER_NOT_DISABLED
+
+
+The GUID allocation server is enabled at the moment.
+
+0xC0000082
+
+STATUS_TOO_MANY_GUIDS_REQUESTED
+
+
+Too many GUIDs were requested from the allocation server at once.
+
+0xC0000083
+
+STATUS_GUIDS_EXHAUSTED
+
+
+The GUIDs could not be allocated because the Authority Agent was exhausted.
+
+0xC0000084
+
+STATUS_INVALID_ID_AUTHORITY
+
+
+The value provided was an invalid value for an identifier authority.
+
+0xC0000085
+
+STATUS_AGENTS_EXHAUSTED
+
+
+No more authority agent values are available for the particular identifier authority value.
+
+0xC0000086
+
+STATUS_INVALID_VOLUME_LABEL
+
+
+An invalid volume label has been specified.
+
+0xC0000087
+
+STATUS_SECTION_NOT_EXTENDED
+
+
+A mapped section could not be extended.
+
+0xC0000088
+
+STATUS_NOT_MAPPED_DATA
+
+
+Specified section to flush does not map a data file.
+
+0xC0000089
+
+STATUS_RESOURCE_DATA_NOT_FOUND
+
+
+Indicates the specified image file did not contain a resource section.
+
+0xC000008A
+
+STATUS_RESOURCE_TYPE_NOT_FOUND
+
+
+Indicates the specified resource type cannot be found in the image file.
+
+0xC000008B
+
+STATUS_RESOURCE_NAME_NOT_FOUND
+
+
+Indicates the specified resource name cannot be found in the image file.
+
+0xC000008C
+
+STATUS_ARRAY_BOUNDS_EXCEEDED
+
+
+{EXCEPTION} Array bounds exceeded.
+
+0xC000008D
+
+STATUS_FLOAT_DENORMAL_OPERAND
+
+
+{EXCEPTION} Floating-point denormal operand.
+
+0xC000008E
+
+STATUS_FLOAT_DIVIDE_BY_ZERO
+
+
+{EXCEPTION} Floating-point division by zero.
+
+0xC000008F
+
+STATUS_FLOAT_INEXACT_RESULT
+
+
+{EXCEPTION} Floating-point inexact result.
+
+0xC0000090
+
+STATUS_FLOAT_INVALID_OPERATION
+
+
+{EXCEPTION} Floating-point invalid operation.
+
+0xC0000091
+
+STATUS_FLOAT_OVERFLOW
+
+
+{EXCEPTION} Floating-point overflow.
+
+0xC0000092
+
+STATUS_FLOAT_STACK_CHECK
+
+
+{EXCEPTION} Floating-point stack check.
+
+0xC0000093
+
+STATUS_FLOAT_UNDERFLOW
+
+
+{EXCEPTION} Floating-point underflow.
+
+0xC0000094
+
+STATUS_INTEGER_DIVIDE_BY_ZERO
+
+
+{EXCEPTION} Integer division by zero.
+
+0xC0000095
+
+STATUS_INTEGER_OVERFLOW
+
+
+{EXCEPTION} Integer overflow.
+
+0xC0000096
+
+STATUS_PRIVILEGED_INSTRUCTION
+
+
+{EXCEPTION} Privileged instruction.
+
+0xC0000097
+
+STATUS_TOO_MANY_PAGING_FILES
+
+
+An attempt was made to install more paging files than the system supports.
+
+0xC0000098
+
+STATUS_FILE_INVALID
+
+
+The volume for a file has been externally altered such that the opened file is no longer valid.
+
+0xC0000099
+
+STATUS_ALLOTTED_SPACE_EXCEEDED
+
+
+When a block of memory is allotted for future updates, such as the memory allocated to hold discretionary access control and primary group information, successive updates might exceed the amount of memory originally allotted. Because a quota might already have been charged to several processes that have handles to the object, it is not reasonable to alter the size of the allocated memory. Instead, a request that requires more memory than has been allotted must fail and the STATUS_ALLOTTED_SPACE_EXCEEDED error returned.
+
+0xC000009A
+
+STATUS_INSUFFICIENT_RESOURCES
+
+
+Insufficient system resources exist to complete the API.
+
+0xC000009B
+
+STATUS_DFS_EXIT_PATH_FOUND
+
+
+An attempt has been made to open a DFS exit path control file.
+
+0xC000009C
+
+STATUS_DEVICE_DATA_ERROR
+
+
+There are bad blocks (sectors) on the hard disk.
+
+0xC000009D
+
+STATUS_DEVICE_NOT_CONNECTED
+
+
+There is bad cabling, non-termination, or the controller is not able to obtain access to the hard disk.
+
+0xC000009F
+
+STATUS_FREE_VM_NOT_AT_BASE
+
+
+Virtual memory cannot be freed because the base address is not the base of the region and a region size of zero was specified.
+
+0xC00000A0
+
+STATUS_MEMORY_NOT_ALLOCATED
+
+
+An attempt was made to free virtual memory that is not allocated.
+
+0xC00000A1
+
+STATUS_WORKING_SET_QUOTA
+
+
+The working set is not big enough to allow the requested pages to be locked.
+
+0xC00000A2
+
+STATUS_MEDIA_WRITE_PROTECTED
+
+
+{Write Protect Error} The disk cannot be written to because it is write-protected. Remove the write protection from the volume %hs in drive %hs.
+
+0xC00000A3
+
+STATUS_DEVICE_NOT_READY
+
+
+{Drive Not Ready} The drive is not ready for use; its door might be open. Check drive %hs and make sure that a disk is inserted and that the drive door is closed.
+
+0xC00000A4
+
+STATUS_INVALID_GROUP_ATTRIBUTES
+
+
+The specified attributes are invalid or are incompatible with the attributes for the group as a whole.
+
+0xC00000A5
+
+STATUS_BAD_IMPERSONATION_LEVEL
+
+
+A specified impersonation level is invalid. Also used to indicate that a required impersonation level was not provided.
+
+0xC00000A6
+
+STATUS_CANT_OPEN_ANONYMOUS
+
+
+An attempt was made to open an anonymous-level token. Anonymous tokens cannot be opened.
+
+0xC00000A7
+
+STATUS_BAD_VALIDATION_CLASS
+
+
+The validation information class requested was invalid.
+
+0xC00000A8
+
+STATUS_BAD_TOKEN_TYPE
+
+
+The type of a token object is inappropriate for its attempted use.
+
+0xC00000A9
+
+STATUS_BAD_MASTER_BOOT_RECORD
+
+
+The type of a token object is inappropriate for its attempted use.
+
+0xC00000AA
+
+STATUS_INSTRUCTION_MISALIGNMENT
+
+
+An attempt was made to execute an instruction at an unaligned address and the host system does not support unaligned instruction references.
+
+0xC00000AB
+
+STATUS_INSTANCE_NOT_AVAILABLE
+
+
+The maximum named pipe instance count has been reached.
+
+0xC00000AC
+
+STATUS_PIPE_NOT_AVAILABLE
+
+
+An instance of a named pipe cannot be found in the listening state.
+
+0xC00000AD
+
+STATUS_INVALID_PIPE_STATE
+
+
+The named pipe is not in the connected or closing state.
+
+0xC00000AE
+
+STATUS_PIPE_BUSY
+
+
+The specified pipe is set to complete operations and there are current I/O operations queued so that it cannot be changed to queue operations.
+
+0xC00000AF
+
+STATUS_ILLEGAL_FUNCTION
+
+
+The specified handle is not open to the server end of the named pipe.
+
+0xC00000B0
+
+STATUS_PIPE_DISCONNECTED
+
+
+The specified named pipe is in the disconnected state.
+
+0xC00000B1
+
+STATUS_PIPE_CLOSING
+
+
+The specified named pipe is in the closing state.
+
+0xC00000B2
+
+STATUS_PIPE_CONNECTED
+
+
+The specified named pipe is in the connected state.
+
+0xC00000B3
+
+STATUS_PIPE_LISTENING
+
+
+The specified named pipe is in the listening state.
+
+0xC00000B4
+
+STATUS_INVALID_READ_MODE
+
+
+The specified named pipe is not in message mode.
+
+0xC00000B5
+
+STATUS_IO_TIMEOUT
+
+
+{Device Timeout} The specified I/O operation on %hs was not completed before the time-out period expired.
+
+0xC00000B6
+
+STATUS_FILE_FORCED_CLOSED
+
+
+The specified file has been closed by another process.
+
+0xC00000B7
+
+STATUS_PROFILING_NOT_STARTED
+
+
+Profiling is not started.
+
+0xC00000B8
+
+STATUS_PROFILING_NOT_STOPPED
+
+
+Profiling is not stopped.
+
+0xC00000B9
+
+STATUS_COULD_NOT_INTERPRET
+
+
+The passed ACL did not contain the minimum required information.
+
+0xC00000BA
+
+STATUS_FILE_IS_A_DIRECTORY
+
+
+The file that was specified as a target is a directory, and the caller specified that it could be anything but a directory.
+
+0xC00000BB
+
+STATUS_NOT_SUPPORTED
+
+
+The request is not supported.
+
+0xC00000BC
+
+STATUS_REMOTE_NOT_LISTENING
+
+
+This remote computer is not listening.
+
+0xC00000BD
+
+STATUS_DUPLICATE_NAME
+
+
+A duplicate name exists on the network.
+
+0xC00000BE
+
+STATUS_BAD_NETWORK_PATH
+
+
+The network path cannot be located.
+
+0xC00000BF
+
+STATUS_NETWORK_BUSY
+
+
+The network is busy.
+
+0xC00000C0
+
+STATUS_DEVICE_DOES_NOT_EXIST
+
+
+This device does not exist.
+
+0xC00000C1
+
+STATUS_TOO_MANY_COMMANDS
+
+
+The network BIOS command limit has been reached.
+
+0xC00000C2
+
+STATUS_ADAPTER_HARDWARE_ERROR
+
+
+An I/O adapter hardware error has occurred.
+
+0xC00000C3
+
+STATUS_INVALID_NETWORK_RESPONSE
+
+
+The network responded incorrectly.
+
+0xC00000C4
+
+STATUS_UNEXPECTED_NETWORK_ERROR
+
+
+An unexpected network error occurred.
+
+0xC00000C5
+
+STATUS_BAD_REMOTE_ADAPTER
+
+
+The remote adapter is not compatible.
+
+0xC00000C6
+
+STATUS_PRINT_QUEUE_FULL
+
+
+The print queue is full.
+
+0xC00000C7
+
+STATUS_NO_SPOOL_SPACE
+
+
+Space to store the file that is waiting to be printed is not available on the server.
+
+0xC00000C8
+
+STATUS_PRINT_CANCELLED
+
+
+The requested print file has been canceled.
+
+0xC00000C9
+
+STATUS_NETWORK_NAME_DELETED
+
+
+The network name was deleted.
+
+0xC00000CA
+
+STATUS_NETWORK_ACCESS_DENIED
+
+
+Network access is denied.
+
+0xC00000CB
+
+STATUS_BAD_DEVICE_TYPE
+
+
+{Incorrect Network Resource Type} The specified device type (LPT, for example) conflicts with the actual device type on the remote resource.
+
+0xC00000CC
+
+STATUS_BAD_NETWORK_NAME
+
+
+{Network Name Not Found} The specified share name cannot be found on the remote server.
+
+0xC00000CD
+
+STATUS_TOO_MANY_NAMES
+
+
+The name limit for the network adapter card of the local computer was exceeded.
+
+0xC00000CE
+
+STATUS_TOO_MANY_SESSIONS
+
+
+The network BIOS session limit was exceeded.
+
+0xC00000CF
+
+STATUS_SHARING_PAUSED
+
+
+File sharing has been temporarily paused.
+
+0xC00000D0
+
+STATUS_REQUEST_NOT_ACCEPTED
+
+
+No more connections can be made to this remote computer at this time because the computer has already accepted the maximum number of connections.
+
+0xC00000D1
+
+STATUS_REDIRECTOR_PAUSED
+
+
+Print or disk redirection is temporarily paused.
+
+0xC00000D2
+
+STATUS_NET_WRITE_FAULT
+
+
+A network data fault occurred.
+
+0xC00000D3
+
+STATUS_PROFILING_AT_LIMIT
+
+
+The number of active profiling objects is at the maximum and no more can be started.
+
+0xC00000D4
+
+STATUS_NOT_SAME_DEVICE
+
+
+{Incorrect Volume} The destination file of a rename request is located on a different device than the source of the rename request.
+
+0xC00000D5
+
+STATUS_FILE_RENAMED
+
+
+The specified file has been renamed and thus cannot be modified.
+
+0xC00000D6
+
+STATUS_VIRTUAL_CIRCUIT_CLOSED
+
+
+{Network Request Timeout} The session with a remote server has been disconnected because the time-out interval for a request has expired.
+
+0xC00000D7
+
+STATUS_NO_SECURITY_ON_OBJECT
+
+
+Indicates an attempt was made to operate on the security of an object that does not have security associated with it.
+
+0xC00000D8
+
+STATUS_CANT_WAIT
+
+
+Used to indicate that an operation cannot continue without blocking for I/O.
+
+0xC00000D9
+
+STATUS_PIPE_EMPTY
+
+
+Used to indicate that a read operation was done on an empty pipe.
+
+0xC00000DA
+
+STATUS_CANT_ACCESS_DOMAIN_INFO
+
+
+Configuration information could not be read from the domain controller, either because the machine is unavailable or access has been denied.
+
+0xC00000DB
+
+STATUS_CANT_TERMINATE_SELF
+
+
+Indicates that a thread attempted to terminate itself by default (called NtTerminateThread with NULL) and it was the last thread in the current process.
+
+0xC00000DC
+
+STATUS_INVALID_SERVER_STATE
+
+
+Indicates the Sam Server was in the wrong state to perform the desired operation.
+
+0xC00000DD
+
+STATUS_INVALID_DOMAIN_STATE
+
+
+Indicates the domain was in the wrong state to perform the desired operation.
+
+0xC00000DE
+
+STATUS_INVALID_DOMAIN_ROLE
+
+
+This operation is only allowed for the primary domain controller of the domain.
+
+0xC00000DF
+
+STATUS_NO_SUCH_DOMAIN
+
+
+The specified domain did not exist.
+
+0xC00000E0
+
+STATUS_DOMAIN_EXISTS
+
+
+The specified domain already exists.
+
+0xC00000E1
+
+STATUS_DOMAIN_LIMIT_EXCEEDED
+
+
+An attempt was made to exceed the limit on the number of domains per server for this release.
+
+0xC00000E2
+
+STATUS_OPLOCK_NOT_GRANTED
+
+
+An error status returned when the opportunistic lock (oplock) request is denied.
+
+0xC00000E3
+
+STATUS_INVALID_OPLOCK_PROTOCOL
+
+
+An error status returned when an invalid opportunistic lock (oplock) acknowledgment is received by a file system.
+
+0xC00000E4
+
+STATUS_INTERNAL_DB_CORRUPTION
+
+
+This error indicates that the requested operation cannot be completed due to a catastrophic media failure or an on-disk data structure corruption.
+
+0xC00000E5
+
+STATUS_INTERNAL_ERROR
+
+
+An internal error occurred.
+
+0xC00000E6
+
+STATUS_GENERIC_NOT_MAPPED
+
+
+Indicates generic access types were contained in an access mask which should already be mapped to non-generic access types.
+
+0xC00000E7
+
+STATUS_BAD_DESCRIPTOR_FORMAT
+
+
+Indicates a security descriptor is not in the necessary format (absolute or self-relative).
+
+0xC00000E8
+
+STATUS_INVALID_USER_BUFFER
+
+
+An access to a user buffer failed at an expected point in time. This code is defined because the caller does not want to accept STATUS_ACCESS_VIOLATION in its filter.
+
+0xC00000E9
+
+STATUS_UNEXPECTED_IO_ERROR
+
+
+If an I/O error that is not defined in the standard FsRtl filter is returned, it is converted to the following error, which is guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0xC00000EA
+
+STATUS_UNEXPECTED_MM_CREATE_ERR
+
+
+If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0xC00000EB
+
+STATUS_UNEXPECTED_MM_MAP_ERROR
+
+
+If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0xC00000EC
+
+STATUS_UNEXPECTED_MM_EXTEND_ERR
+
+
+If an MM error that is not defined in the standard FsRtl filter is returned, it is converted to one of the following errors, which are guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0xC00000ED
+
+STATUS_NOT_LOGON_PROCESS
+
+
+The requested action is restricted for use by logon processes only. The calling process has not registered as a logon process.
+
+0xC00000EE
+
+STATUS_LOGON_SESSION_EXISTS
+
+
+An attempt has been made to start a new session manager or LSA logon session by using an ID that is already in use.
+
+0xC00000EF
+
+STATUS_INVALID_PARAMETER_1
+
+
+An invalid parameter was passed to a service or function as the first argument.
+
+0xC00000F0
+
+STATUS_INVALID_PARAMETER_2
+
+
+An invalid parameter was passed to a service or function as the second argument.
+
+0xC00000F1
+
+STATUS_INVALID_PARAMETER_3
+
+
+An invalid parameter was passed to a service or function as the third argument.
+
+0xC00000F2
+
+STATUS_INVALID_PARAMETER_4
+
+
+An invalid parameter was passed to a service or function as the fourth argument.
+
+0xC00000F3
+
+STATUS_INVALID_PARAMETER_5
+
+
+An invalid parameter was passed to a service or function as the fifth argument.
+
+0xC00000F4
+
+STATUS_INVALID_PARAMETER_6
+
+
+An invalid parameter was passed to a service or function as the sixth argument.
+
+0xC00000F5
+
+STATUS_INVALID_PARAMETER_7
+
+
+An invalid parameter was passed to a service or function as the seventh argument.
+
+0xC00000F6
+
+STATUS_INVALID_PARAMETER_8
+
+
+An invalid parameter was passed to a service or function as the eighth argument.
+
+0xC00000F7
+
+STATUS_INVALID_PARAMETER_9
+
+
+An invalid parameter was passed to a service or function as the ninth argument.
+
+0xC00000F8
+
+STATUS_INVALID_PARAMETER_10
+
+
+An invalid parameter was passed to a service or function as the tenth argument.
+
+0xC00000F9
+
+STATUS_INVALID_PARAMETER_11
+
+
+An invalid parameter was passed to a service or function as the eleventh argument.
+
+0xC00000FA
+
+STATUS_INVALID_PARAMETER_12
+
+
+An invalid parameter was passed to a service or function as the twelfth argument.
+
+0xC00000FB
+
+STATUS_REDIRECTOR_NOT_STARTED
+
+
+An attempt was made to access a network file, but the network software was not yet started.
+
+0xC00000FC
+
+STATUS_REDIRECTOR_STARTED
+
+
+An attempt was made to start the redirector, but the redirector has already been started.
+
+0xC00000FD
+
+STATUS_STACK_OVERFLOW
+
+
+A new guard page for the stack cannot be created.
+
+0xC00000FE
+
+STATUS_NO_SUCH_PACKAGE
+
+
+A specified authentication package is unknown.
+
+0xC00000FF
+
+STATUS_BAD_FUNCTION_TABLE
+
+
+A malformed function table was encountered during an unwind operation.
+
+0xC0000100
+
+STATUS_VARIABLE_NOT_FOUND
+
+
+Indicates the specified environment variable name was not found in the specified environment block.
+
+0xC0000101
+
+STATUS_DIRECTORY_NOT_EMPTY
+
+
+Indicates that the directory trying to be deleted is not empty.
+
+0xC0000102
+
+STATUS_FILE_CORRUPT_ERROR
+
+
+{Corrupt File} The file or directory %hs is corrupt and unreadable. Run the Chkdsk utility.
+
+0xC0000103
+
+STATUS_NOT_A_DIRECTORY
+
+
+A requested opened file is not a directory.
+
+0xC0000104
+
+STATUS_BAD_LOGON_SESSION_STATE
+
+
+The logon session is not in a state that is consistent with the requested operation.
+
+0xC0000105
+
+STATUS_LOGON_SESSION_COLLISION
+
+
+An internal LSA error has occurred. An authentication package has requested the creation of a logon session but the ID of an already existing logon session has been specified.
+
+0xC0000106
+
+STATUS_NAME_TOO_LONG
+
+
+A specified name string is too long for its intended use.
+
+0xC0000107
+
+STATUS_FILES_OPEN
+
+
+The user attempted to force close the files on a redirected drive, but there were opened files on the drive, and the user did not specify a sufficient level of force.
+
+0xC0000108
+
+STATUS_CONNECTION_IN_USE
+
+
+The user attempted to force close the files on a redirected drive, but there were opened directories on the drive, and the user did not specify a sufficient level of force.
+
+0xC0000109
+
+STATUS_MESSAGE_NOT_FOUND
+
+
+RtlFindMessage could not locate the requested message ID in the message table resource.
+
+0xC000010A
+
+STATUS_PROCESS_IS_TERMINATING
+
+
+An attempt was made to duplicate an object handle into or out of an exiting process.
+
+0xC000010B
+
+STATUS_INVALID_LOGON_TYPE
+
+
+Indicates an invalid value has been provided for the LogonType requested.
+
+0xC000010C
+
+STATUS_NO_GUID_TRANSLATION
+
+
+Indicates that an attempt was made to assign protection to a file system file or directory and one of the SIDs in the security descriptor could not be translated into a GUID that could be stored by the file system. This causes the protection attempt to fail, which might cause a file creation attempt to fail.
+
+0xC000010D
+
+STATUS_CANNOT_IMPERSONATE
+
+
+Indicates that an attempt has been made to impersonate via a named pipe that has not yet been read from.
+
+0xC000010E
+
+STATUS_IMAGE_ALREADY_LOADED
+
+
+Indicates that the specified image is already loaded.
+
+0xC0000117
+
+STATUS_NO_LDT
+
+
+Indicates that an attempt was made to change the size of the LDT for a process that has no LDT.
+
+0xC0000118
+
+STATUS_INVALID_LDT_SIZE
+
+
+Indicates that an attempt was made to grow an LDT by setting its size, or that the size was not an even number of selectors.
+
+0xC0000119
+
+STATUS_INVALID_LDT_OFFSET
+
+
+Indicates that the starting value for the LDT information was not an integral multiple of the selector size.
+
+0xC000011A
+
+STATUS_INVALID_LDT_DESCRIPTOR
+
+
+Indicates that the user supplied an invalid descriptor when trying to set up LDT descriptors.
+
+0xC000011B
+
+STATUS_INVALID_IMAGE_NE_FORMAT
+
+
+The specified image file did not have the correct format. It appears to be NE format.
+
+0xC000011C
+
+STATUS_RXACT_INVALID_STATE
+
+
+Indicates that the transaction state of a registry subtree is incompatible with the requested operation. For example, a request has been made to start a new transaction with one already in progress, or a request has been made to apply a transaction when one is not currently in progress.
+
+0xC000011D
+
+STATUS_RXACT_COMMIT_FAILURE
+
+
+Indicates an error has occurred during a registry transaction commit. The database has been left in an unknown, but probably inconsistent, state. The state of the registry transaction is left as COMMITTING.
+
+0xC000011E
+
+STATUS_MAPPED_FILE_SIZE_ZERO
+
+
+An attempt was made to map a file of size zero with the maximum size specified as zero.
+
+0xC000011F
+
+STATUS_TOO_MANY_OPENED_FILES
+
+
+Too many files are opened on a remote server. This error should only be returned by the Windows redirector on a remote drive.
+
+0xC0000120
+
+STATUS_CANCELLED
+
+
+The I/O request was canceled.
+
+0xC0000121
+
+STATUS_CANNOT_DELETE
+
+
+An attempt has been made to remove a file or directory that cannot be deleted.
+
+0xC0000122
+
+STATUS_INVALID_COMPUTER_NAME
+
+
+Indicates a name that was specified as a remote computer name is syntactically invalid.
+
+0xC0000123
+
+STATUS_FILE_DELETED
+
+
+An I/O request other than close was performed on a file after it was deleted, which can only happen to a request that did not complete before the last handle was closed via NtClose.
+
+0xC0000124
+
+STATUS_SPECIAL_ACCOUNT
+
+
+Indicates an operation that is incompatible with built-in accounts has been attempted on a built-in (special) SAM account. For example, built-in accounts cannot be deleted.
+
+0xC0000125
+
+STATUS_SPECIAL_GROUP
+
+
+The operation requested cannot be performed on the specified group because it is a built-in special group.
+
+0xC0000126
+
+STATUS_SPECIAL_USER
+
+
+The operation requested cannot be performed on the specified user because it is a built-in special user.
+
+0xC0000127
+
+STATUS_MEMBERS_PRIMARY_GROUP
+
+
+Indicates a member cannot be removed from a group because the group is currently the member's primary group.
+
+0xC0000128
+
+STATUS_FILE_CLOSED
+
+
+An I/O request other than close and several other special case operations was attempted using a file object that had already been closed.
+
+0xC0000129
+
+STATUS_TOO_MANY_THREADS
+
+
+Indicates a process has too many threads to perform the requested action. For example, assignment of a primary token can be performed only when a process has zero or one threads.
+
+0xC000012A
+
+STATUS_THREAD_NOT_IN_PROCESS
+
+
+An attempt was made to operate on a thread within a specific process, but the specified thread is not in the specified process.
+
+0xC000012B
+
+STATUS_TOKEN_ALREADY_IN_USE
+
+
+An attempt was made to establish a token for use as a primary token but the token is already in use. A token can only be the primary token of one process at a time.
+
+0xC000012C
+
+STATUS_PAGEFILE_QUOTA_EXCEEDED
+
+
+The page file quota was exceeded.
+
+0xC000012D
+
+STATUS_COMMITMENT_LIMIT
+
+
+{Out of Virtual Memory} Your system is low on virtual memory. To ensure that Windows runs correctly, increase the size of your virtual memory paging file. For more information, see Help.
+
+0xC000012E
+
+STATUS_INVALID_IMAGE_LE_FORMAT
+
+
+The specified image file did not have the correct format: it appears to be LE format.
+
+0xC000012F
+
+STATUS_INVALID_IMAGE_NOT_MZ
+
+
+The specified image file did not have the correct format: it did not have an initial MZ.
+
+0xC0000130
+
+STATUS_INVALID_IMAGE_PROTECT
+
+
+The specified image file did not have the correct format: it did not have a proper e_lfarlc in the MZ header.
+
+0xC0000131
+
+STATUS_INVALID_IMAGE_WIN_16
+
+
+The specified image file did not have the correct format: it appears to be a 16-bit Windows image.
+
+0xC0000132
+
+STATUS_LOGON_SERVER_CONFLICT
+
+
+The Netlogon service cannot start because another Netlogon service running in the domain conflicts with the specified role.
+
+0xC0000133
+
+STATUS_TIME_DIFFERENCE_AT_DC
+
+
+The time at the primary domain controller is different from the time at the backup domain controller or member server by too large an amount.
+
+0xC0000134
+
+STATUS_SYNCHRONIZATION_REQUIRED
+
+
+On applicable Windows Server releases, the SAM database is significantly out of synchronization with the copy on the domain controller. A complete synchronization is required.
+
+0xC0000135
+
+STATUS_DLL_NOT_FOUND
+
+
+{Unable To Locate Component} This application has failed to start because %hs was not found. Reinstalling the application might fix this problem.
+
+0xC0000136
+
+STATUS_OPEN_FAILED
+
+
+The NtCreateFile API failed. This error should never be returned to an application; it is a place holder for the Windows LAN Manager Redirector to use in its internal error-mapping routines.
+
+0xC0000137
+
+STATUS_IO_PRIVILEGE_FAILED
+
+
+{Privilege Failed} The I/O permissions for the process could not be changed.
+
+0xC0000138
+
+STATUS_ORDINAL_NOT_FOUND
+
+
+{Ordinal Not Found} The ordinal %ld could not be located in the dynamic link library %hs.
+
+0xC0000139
+
+STATUS_ENTRYPOINT_NOT_FOUND
+
+
+{Entry Point Not Found} The procedure entry point %hs could not be located in the dynamic link library %hs.
+
+0xC000013A
+
+STATUS_CONTROL_C_EXIT
+
+
+{Application Exit by CTRL+C} The application terminated as a result of a CTRL+C.
+
+0xC000013B
+
+STATUS_LOCAL_DISCONNECT
+
+
+{Virtual Circuit Closed} The network transport on your computer has closed a network connection. There might or might not be I/O requests outstanding.
+
+0xC000013C
+
+STATUS_REMOTE_DISCONNECT
+
+
+{Virtual Circuit Closed} The network transport on a remote computer has closed a network connection. There might or might not be I/O requests outstanding.
+
+0xC000013D
+
+STATUS_REMOTE_RESOURCES
+
+
+{Insufficient Resources on Remote Computer} The remote computer has insufficient resources to complete the network request. For example, the remote computer might not have enough available memory to carry out the request at this time.
+
+0xC000013E
+
+STATUS_LINK_FAILED
+
+
+{Virtual Circuit Closed} An existing connection (virtual circuit) has been broken at the remote computer. There is probably something wrong with the network software protocol or the network hardware on the remote computer.
+
+0xC000013F
+
+STATUS_LINK_TIMEOUT
+
+
+{Virtual Circuit Closed} The network transport on your computer has closed a network connection because it had to wait too long for a response from the remote computer.
+
+0xC0000140
+
+STATUS_INVALID_CONNECTION
+
+
+The connection handle that was given to the transport was invalid.
+
+0xC0000141
+
+STATUS_INVALID_ADDRESS
+
+
+The address handle that was given to the transport was invalid.
+
+0xC0000142
+
+STATUS_DLL_INIT_FAILED
+
+
+{DLL Initialization Failed} Initialization of the dynamic link library %hs failed. The process is terminating abnormally.
+
+0xC0000143
+
+STATUS_MISSING_SYSTEMFILE
+
+
+{Missing System File} The required system file %hs is bad or missing.
+
+0xC0000144
+
+STATUS_UNHANDLED_EXCEPTION
+
+
+{Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx.
+
+0xC0000145
+
+STATUS_APP_INIT_FAILURE
+
+
+{Application Error} The application failed to initialize properly (0x%lx). Click OK to terminate the application.
+
+0xC0000146
+
+STATUS_PAGEFILE_CREATE_FAILED
+
+
+{Unable to Create Paging File} The creation of the paging file %hs failed (%lx). The requested size was %ld.
+
+0xC0000147
+
+STATUS_NO_PAGEFILE
+
+
+{No Paging File Specified} No paging file was specified in the system configuration.
+
+0xC0000148
+
+STATUS_INVALID_LEVEL
+
+
+{Incorrect System Call Level} An invalid level was passed into the specified system call.
+
+0xC0000149
+
+STATUS_WRONG_PASSWORD_CORE
+
+
+{Incorrect Password to LAN Manager Server} You specified an incorrect password to a LAN Manager 2.x or MS-NET server.
+
+0xC000014A
+
+STATUS_ILLEGAL_FLOAT_CONTEXT
+
+
+{EXCEPTION} A real-mode application issued a floating-point instruction and floating-point hardware is not present.
+
+0xC000014B
+
+STATUS_PIPE_BROKEN
+
+
+The pipe operation has failed because the other end of the pipe has been closed.
+
+0xC000014C
+
+STATUS_REGISTRY_CORRUPT
+
+
+{The Registry Is Corrupt} The structure of one of the files that contains registry data is corrupt; the image of the file in memory is corrupt; or the file could not be recovered because the alternate copy or log was absent or corrupt.
+
+0xC000014D
+
+STATUS_REGISTRY_IO_FAILED
+
+
+An I/O operation initiated by the Registry failed and cannot be recovered. The registry could not read in, write out, or flush one of the files that contain the system's image of the registry.
+
+0xC000014E
+
+STATUS_NO_EVENT_PAIR
+
+
+An event pair synchronization operation was performed using the thread-specific client/server event pair object, but no event pair object was associated with the thread.
+
+0xC000014F
+
+STATUS_UNRECOGNIZED_VOLUME
+
+
+The volume does not contain a recognized file system. Be sure that all required file system drivers are loaded and that the volume is not corrupt.
+
+0xC0000150
+
+STATUS_SERIAL_NO_DEVICE_INITED
+
+
+No serial device was successfully initialized. The serial driver will unload.
+
+0xC0000151
+
+STATUS_NO_SUCH_ALIAS
+
+
+The specified local group does not exist.
+
+0xC0000152
+
+STATUS_MEMBER_NOT_IN_ALIAS
+
+
+The specified account name is not a member of the group.
+
+0xC0000153
+
+STATUS_MEMBER_IN_ALIAS
+
+
+The specified account name is already a member of the group.
+
+0xC0000154
+
+STATUS_ALIAS_EXISTS
+
+
+The specified local group already exists.
+
+0xC0000155
+
+STATUS_LOGON_NOT_GRANTED
+
+
+A requested type of logon (for example, interactive, network, and service) is not granted by the local security policy of the target system. Ask the system administrator to grant the necessary form of logon.
+
+0xC0000156
+
+STATUS_TOO_MANY_SECRETS
+
+
+The maximum number of secrets that can be stored in a single system was exceeded. The length and number of secrets is limited to satisfy U.S. State Department export restrictions.
+
+0xC0000157
+
+STATUS_SECRET_TOO_LONG
+
+
+The length of a secret exceeds the maximum allowable length. The length and number of secrets is limited to satisfy U.S. State Department export restrictions.
+
+0xC0000158
+
+STATUS_INTERNAL_DB_ERROR
+
+
+The local security authority (LSA) database contains an internal inconsistency.
+
+0xC0000159
+
+STATUS_FULLSCREEN_MODE
+
+
+The requested operation cannot be performed in full-screen mode.
+
+0xC000015A
+
+STATUS_TOO_MANY_CONTEXT_IDS
+
+
+During a logon attempt, the user's security context accumulated too many security IDs. This is a very unusual situation. Remove the user from some global or local groups to reduce the number of security IDs to incorporate into the security context.
+
+0xC000015B
+
+STATUS_LOGON_TYPE_NOT_GRANTED
+
+
+A user has requested a type of logon (for example, interactive or network) that has not been granted. An administrator has control over who can logon interactively and through the network.
+
+0xC000015C
+
+STATUS_NOT_REGISTRY_FILE
+
+
+The system has attempted to load or restore a file into the registry, and the specified file is not in the format of a registry file.
+
+0xC000015D
+
+STATUS_NT_CROSS_ENCRYPTION_REQUIRED
+
+
+An attempt was made to change a user password in the security account manager without providing the necessary Windows cross-encrypted password.
+
+0xC000015E
+
+STATUS_DOMAIN_CTRLR_CONFIG_ERROR
+
+
+A domain server has an incorrect configuration.
+
+0xC000015F
+
+STATUS_FT_MISSING_MEMBER
+
+
+An attempt was made to explicitly access the secondary copy of information via a device control to the fault tolerance driver and the secondary copy is not present in the system.
+
+0xC0000160
+
+STATUS_ILL_FORMED_SERVICE_ENTRY
+
+
+A configuration registry node that represents a driver service entry was ill-formed and did not contain the required value entries.
+
+0xC0000161
+
+STATUS_ILLEGAL_CHARACTER
+
+
+An illegal character was encountered. For a multibyte character set, this includes a lead byte without a succeeding trail byte. For the Unicode character set this includes the characters 0xFFFF and 0xFFFE.
+
+0xC0000162
+
+STATUS_UNMAPPABLE_CHARACTER
+
+
+No mapping for the Unicode character exists in the target multibyte code page.
+
+0xC0000163
+
+STATUS_UNDEFINED_CHARACTER
+
+
+The Unicode character is not defined in the Unicode character set that is installed on the system.
+
+0xC0000164
+
+STATUS_FLOPPY_VOLUME
+
+
+The paging file cannot be created on a floppy disk.
+
+0xC0000165
+
+STATUS_FLOPPY_ID_MARK_NOT_FOUND
+
+
+{Floppy Disk Error} While accessing a floppy disk, an ID address mark was not found.
+
+0xC0000166
+
+STATUS_FLOPPY_WRONG_CYLINDER
+
+
+{Floppy Disk Error} While accessing a floppy disk, the track address from the sector ID field was found to be different from the track address that is maintained by the controller.
+
+0xC0000167
+
+STATUS_FLOPPY_UNKNOWN_ERROR
+
+
+{Floppy Disk Error} The floppy disk controller reported an error that is not recognized by the floppy disk driver.
+
+0xC0000168
+
+STATUS_FLOPPY_BAD_REGISTERS
+
+
+{Floppy Disk Error} While accessing a floppy-disk, the controller returned inconsistent results via its registers.
+
+0xC0000169
+
+STATUS_DISK_RECALIBRATE_FAILED
+
+
+{Hard Disk Error} While accessing the hard disk, a recalibrate operation failed, even after retries.
+
+0xC000016A
+
+STATUS_DISK_OPERATION_FAILED
+
+
+{Hard Disk Error} While accessing the hard disk, a disk operation failed even after retries.
+
+0xC000016B
+
+STATUS_DISK_RESET_FAILED
+
+
+{Hard Disk Error} While accessing the hard disk, a disk controller reset was needed, but even that failed.
+
+0xC000016C
+
+STATUS_SHARED_IRQ_BUSY
+
+
+An attempt was made to open a device that was sharing an interrupt request (IRQ) with other devices. At least one other device that uses that IRQ was already opened. Two concurrent opens of devices that share an IRQ and only work via interrupts is not supported for the particular bus type that the devices use.
+
+0xC000016D
+
+STATUS_FT_ORPHANING
+
+
+{FT Orphaning} A disk that is part of a fault-tolerant volume can no longer be accessed.
+
+0xC000016E
+
+STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT
+
+
+The basic input/output system (BIOS) failed to connect a system interrupt to the device or bus for which the device is connected.
+
+0xC0000172
+
+STATUS_PARTITION_FAILURE
+
+
+The tape could not be partitioned.
+
+0xC0000173
+
+STATUS_INVALID_BLOCK_LENGTH
+
+
+When accessing a new tape of a multi-volume partition, the current blocksize is incorrect.
+
+0xC0000174
+
+STATUS_DEVICE_NOT_PARTITIONED
+
+
+The tape partition information could not be found when loading a tape.
+
+0xC0000175
+
+STATUS_UNABLE_TO_LOCK_MEDIA
+
+
+An attempt to lock the eject media mechanism failed.
+
+0xC0000176
+
+STATUS_UNABLE_TO_UNLOAD_MEDIA
+
+
+An attempt to unload media failed.
+
+0xC0000177
+
+STATUS_EOM_OVERFLOW
+
+
+The physical end of tape was detected.
+
+0xC0000178
+
+STATUS_NO_MEDIA
+
+
+{No Media} There is no media in the drive. Insert media into drive %hs.
+
+0xC000017A
+
+STATUS_NO_SUCH_MEMBER
+
+
+A member could not be added to or removed from the local group because the member does not exist.
+
+0xC000017B
+
+STATUS_INVALID_MEMBER
+
+
+A new member could not be added to a local group because the member has the wrong account type.
+
+0xC000017C
+
+STATUS_KEY_DELETED
+
+
+An illegal operation was attempted on a registry key that has been marked for deletion.
+
+0xC000017D
+
+STATUS_NO_LOG_SPACE
+
+
+The system could not allocate the required space in a registry log.
+
+0xC000017E
+
+STATUS_TOO_MANY_SIDS
+
+
+Too many SIDs have been specified.
+
+0xC000017F
+
+STATUS_LM_CROSS_ENCRYPTION_REQUIRED
+
+
+An attempt was made to change a user password in the security account manager without providing the necessary LM cross-encrypted password.
+
+0xC0000180
+
+STATUS_KEY_HAS_CHILDREN
+
+
+An attempt was made to create a symbolic link in a registry key that already has subkeys or values.
+
+0xC0000181
+
+STATUS_CHILD_MUST_BE_VOLATILE
+
+
+An attempt was made to create a stable subkey under a volatile parent key.
+
+0xC0000182
+
+STATUS_DEVICE_CONFIGURATION_ERROR
+
+
+The I/O device is configured incorrectly or the configuration parameters to the driver are incorrect.
+
+0xC0000183
+
+STATUS_DRIVER_INTERNAL_ERROR
+
+
+An error was detected between two drivers or within an I/O driver.
+
+0xC0000184
+
+STATUS_INVALID_DEVICE_STATE
+
+
+The device is not in a valid state to perform this request.
+
+0xC0000185
+
+STATUS_IO_DEVICE_ERROR
+
+
+The I/O device reported an I/O error.
+
+0xC0000186
+
+STATUS_DEVICE_PROTOCOL_ERROR
+
+
+A protocol error was detected between the driver and the device.
+
+0xC0000187
+
+STATUS_BACKUP_CONTROLLER
+
+
+This operation is only allowed for the primary domain controller of the domain.
+
+0xC0000188
+
+STATUS_LOG_FILE_FULL
+
+
+The log file space is insufficient to support this operation.
+
+0xC0000189
+
+STATUS_TOO_LATE
+
+
+A write operation was attempted to a volume after it was dismounted.
+
+0xC000018A
+
+STATUS_NO_TRUST_LSA_SECRET
+
+
+The workstation does not have a trust secret for the primary domain in the local LSA database.
+
+0xC000018B
+
+STATUS_NO_TRUST_SAM_ACCOUNT
+
+
+On applicable Windows Server releases, the SAM database does not have a computer account for this workstation trust relationship.
+
+0xC000018C
+
+STATUS_TRUSTED_DOMAIN_FAILURE
+
+
+The logon request failed because the trust relationship between the primary domain and the trusted domain failed.
+
+0xC000018D
+
+STATUS_TRUSTED_RELATIONSHIP_FAILURE
+
+
+The logon request failed because the trust relationship between this workstation and the primary domain failed.
+
+0xC000018E
+
+STATUS_EVENTLOG_FILE_CORRUPT
+
+
+The Eventlog log file is corrupt.
+
+0xC000018F
+
+STATUS_EVENTLOG_CANT_START
+
+
+No Eventlog log file could be opened. The Eventlog service did not start.
+
+0xC0000190
+
+STATUS_TRUST_FAILURE
+
+
+The network logon failed. This might be because the validation authority cannot be reached.
+
+0xC0000191
+
+STATUS_MUTANT_LIMIT_EXCEEDED
+
+
+An attempt was made to acquire a mutant such that its maximum count would have been exceeded.
+
+0xC0000192
+
+STATUS_NETLOGON_NOT_STARTED
+
+
+An attempt was made to logon, but the NetLogon service was not started.
+
+0xC0000193
+
+STATUS_ACCOUNT_EXPIRED
+
+
+The user account has expired.
+
+0xC0000194
+
+STATUS_POSSIBLE_DEADLOCK
+
+
+{EXCEPTION} Possible deadlock condition.
+
+0xC0000195
+
+STATUS_NETWORK_CREDENTIAL_CONFLICT
+
+
+Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.
+
+0xC0000196
+
+STATUS_REMOTE_SESSION_LIMIT
+
+
+An attempt was made to establish a session to a network server, but there are already too many sessions established to that server.
+
+0xC0000197
+
+STATUS_EVENTLOG_FILE_CHANGED
+
+
+The log file has changed between reads.
+
+0xC0000198
+
+STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
+
+
+The account used is an interdomain trust account. Use your global user account or local user account to access this server.
+
+0xC0000199
+
+STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+
+
+The account used is a computer account. Use your global user account or local user account to access this server.
+
+0xC000019A
+
+STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
+
+
+The account used is a server trust account. Use your global user account or local user account to access this server.
+
+0xC000019B
+
+STATUS_DOMAIN_TRUST_INCONSISTENT
+
+
+The name or SID of the specified domain is inconsistent with the trust information for that domain.
+
+0xC000019C
+
+STATUS_FS_DRIVER_REQUIRED
+
+
+A volume has been accessed for which a file system driver is required that has not yet been loaded.
+
+0xC000019D
+
+STATUS_IMAGE_ALREADY_LOADED_AS_DLL
+
+
+Indicates that the specified image is already loaded as a DLL.
+
+0xC000019E
+
+STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING
+
+
+Short name settings cannot be changed on this volume due to the global registry setting.
+
+0xC000019F
+
+STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME
+
+
+Short names are not enabled on this volume.
+
+0xC00001A0
+
+STATUS_SECURITY_STREAM_IS_INCONSISTENT
+
+
+The security stream for the given volume is in an inconsistent state. Please run CHKDSK on the volume.
+
+0xC00001A1
+
+STATUS_INVALID_LOCK_RANGE
+
+
+A requested file lock operation cannot be processed due to an invalid byte range.
+
+0xC00001A2
+
+STATUS_INVALID_ACE_CONDITION
+
+
+The specified access control entry (ACE) contains an invalid condition.
+
+0xC00001A3
+
+STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT
+
+
+The subsystem needed to support the image type is not present.
+
+0xC00001A4
+
+STATUS_NOTIFICATION_GUID_ALREADY_DEFINED
+
+
+The specified file already has a notification GUID associated with it.
+
+0xC0000201
+
+STATUS_NETWORK_OPEN_RESTRICTION
+
+
+A remote open failed because the network open restrictions were not satisfied.
+
+0xC0000202
+
+STATUS_NO_USER_SESSION_KEY
+
+
+There is no user session key for the specified logon session.
+
+0xC0000203
+
+STATUS_USER_SESSION_DELETED
+
+
+The remote user session has been deleted.
+
+0xC0000204
+
+STATUS_RESOURCE_LANG_NOT_FOUND
+
+
+Indicates the specified resource language ID cannot be found in the image file.
+
+0xC0000205
+
+STATUS_INSUFF_SERVER_RESOURCES
+
+
+Insufficient server resources exist to complete the request.
+
+0xC0000206
+
+STATUS_INVALID_BUFFER_SIZE
+
+
+The size of the buffer is invalid for the specified operation.
+
+0xC0000207
+
+STATUS_INVALID_ADDRESS_COMPONENT
+
+
+The transport rejected the specified network address as invalid.
+
+0xC0000208
+
+STATUS_INVALID_ADDRESS_WILDCARD
+
+
+The transport rejected the specified network address due to invalid use of a wildcard.
+
+0xC0000209
+
+STATUS_TOO_MANY_ADDRESSES
+
+
+The transport address could not be opened because all the available addresses are in use.
+
+0xC000020A
+
+STATUS_ADDRESS_ALREADY_EXISTS
+
+
+The transport address could not be opened because it already exists.
+
+0xC000020B
+
+STATUS_ADDRESS_CLOSED
+
+
+The transport address is now closed.
+
+0xC000020C
+
+STATUS_CONNECTION_DISCONNECTED
+
+
+The transport connection is now disconnected.
+
+0xC000020D
+
+STATUS_CONNECTION_RESET
+
+
+The transport connection has been reset.
+
+0xC000020E
+
+STATUS_TOO_MANY_NODES
+
+
+The transport cannot dynamically acquire any more nodes.
+
+0xC000020F
+
+STATUS_TRANSACTION_ABORTED
+
+
+The transport aborted a pending transaction.
+
+0xC0000210
+
+STATUS_TRANSACTION_TIMED_OUT
+
+
+The transport timed out a request that is waiting for a response.
+
+0xC0000211
+
+STATUS_TRANSACTION_NO_RELEASE
+
+
+The transport did not receive a release for a pending response.
+
+0xC0000212
+
+STATUS_TRANSACTION_NO_MATCH
+
+
+The transport did not find a transaction that matches the specific token.
+
+0xC0000213
+
+STATUS_TRANSACTION_RESPONDED
+
+
+The transport had previously responded to a transaction request.
+
+0xC0000214
+
+STATUS_TRANSACTION_INVALID_ID
+
+
+The transport does not recognize the specified transaction request ID.
+
+0xC0000215
+
+STATUS_TRANSACTION_INVALID_TYPE
+
+
+The transport does not recognize the specified transaction request type.
+
+0xC0000216
+
+STATUS_NOT_SERVER_SESSION
+
+
+The transport can only process the specified request on the server side of a session.
+
+0xC0000217
+
+STATUS_NOT_CLIENT_SESSION
+
+
+The transport can only process the specified request on the client side of a session.
+
+0xC0000218
+
+STATUS_CANNOT_LOAD_REGISTRY_FILE
+
+
+{Registry File Failure} The registry cannot load the hive (file): %hs or its log or alternate. It is corrupt, absent, or not writable.
+
+0xC0000219
+
+STATUS_DEBUG_ATTACH_FAILED
+
+
+{Unexpected Failure in DebugActiveProcess} An unexpected failure occurred while processing a DebugActiveProcess API request. Choosing OK will terminate the process, and choosing Cancel will ignore the error.
+
+0xC000021A
+
+STATUS_SYSTEM_PROCESS_TERMINATED
+
+
+{Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down.
+
+0xC000021B
+
+STATUS_DATA_NOT_ACCEPTED
+
+
+{Data Not Accepted} The TDI client could not handle the data received during an indication.
+
+0xC000021C
+
+STATUS_NO_BROWSER_SERVERS_FOUND
+
+
+{Unable to Retrieve Browser Server List} The list of servers for this workgroup is not currently available.
+
+0xC000021D
+
+STATUS_VDM_HARD_ERROR
+
+
+NTVDM encountered a hard error.
+
+0xC000021E
+
+STATUS_DRIVER_CANCEL_TIMEOUT
+
+
+{Cancel Timeout} The driver %hs failed to complete a canceled I/O request in the allotted time.
+
+0xC000021F
+
+STATUS_REPLY_MESSAGE_MISMATCH
+
+
+{Reply Message Mismatch} An attempt was made to reply to an LPC message, but the thread specified by the client ID in the message was not waiting on that message.
+
+0xC0000220
+
+STATUS_MAPPED_ALIGNMENT
+
+
+{Mapped View Alignment Incorrect} An attempt was made to map a view of a file, but either the specified base address or the offset into the file were not aligned on the proper allocation granularity.
+
+0xC0000221
+
+STATUS_IMAGE_CHECKSUM_MISMATCH
+
+
+{Bad Image Checksum} The image %hs is possibly corrupt. The header checksum does not match the computed checksum.
+
+0xC0000222
+
+STATUS_LOST_WRITEBEHIND_DATA
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs. The data has been lost. This error might be caused by a failure of your computer hardware or network connection. Try to save this file elsewhere.
+
+0xC0000223
+
+STATUS_CLIENT_SERVER_PARAMETERS_INVALID
+
+
+The parameters passed to the server in the client/server shared memory window were invalid. Too much data might have been put in the shared memory window.
+
+0xC0000224
+
+STATUS_PASSWORD_MUST_CHANGE
+
+
+The user password must be changed before logging on the first time.
+
+0xC0000225
+
+STATUS_NOT_FOUND
+
+
+The object was not found.
+
+0xC0000226
+
+STATUS_NOT_TINY_STREAM
+
+
+The stream is not a tiny stream.
+
+0xC0000227
+
+STATUS_RECOVERY_FAILURE
+
+
+A transaction recovery failed.
+
+0xC0000228
+
+STATUS_STACK_OVERFLOW_READ
+
+
+The request must be handled by the stack overflow code.
+
+0xC0000229
+
+STATUS_FAIL_CHECK
+
+
+A consistency check failed.
+
+0xC000022A
+
+STATUS_DUPLICATE_OBJECTID
+
+
+The attempt to insert the ID in the index failed because the ID is already in the index.
+
+0xC000022B
+
+STATUS_OBJECTID_EXISTS
+
+
+The attempt to set the object ID failed because the object already has an ID.
+
+0xC000022C
+
+STATUS_CONVERT_TO_LARGE
+
+
+Internal OFS status codes indicating how an allocation operation is handled. Either it is retried after the containing oNode is moved or the extent stream is converted to a large stream.
+
+0xC000022D
+
+STATUS_RETRY
+
+
+The request needs to be retried.
+
+0xC000022E
+
+STATUS_FOUND_OUT_OF_SCOPE
+
+
+The attempt to find the object found an object on the volume that matches by ID; however, it is out of the scope of the handle that is used for the operation.
+
+0xC000022F
+
+STATUS_ALLOCATE_BUCKET
+
+
+The bucket array must be grown. Retry the transaction after doing so.
+
+0xC0000230
+
+STATUS_PROPSET_NOT_FOUND
+
+
+The specified property set does not exist on the object.
+
+0xC0000231
+
+STATUS_MARSHALL_OVERFLOW
+
+
+The user/kernel marshaling buffer has overflowed.
+
+0xC0000232
+
+STATUS_INVALID_VARIANT
+
+
+The supplied variant structure contains invalid data.
+
+0xC0000233
+
+STATUS_DOMAIN_CONTROLLER_NOT_FOUND
+
+
+A domain controller for this domain was not found.
+
+0xC0000234
+
+STATUS_ACCOUNT_LOCKED_OUT
+
+
+The user account has been automatically locked because too many invalid logon attempts or password change attempts have been requested.
+
+0xC0000235
+
+STATUS_HANDLE_NOT_CLOSABLE
+
+
+NtClose was called on a handle that was protected from close via NtSetInformationObject.
+
+0xC0000236
+
+STATUS_CONNECTION_REFUSED
+
+
+The transport-connection attempt was refused by the remote system.
+
+0xC0000237
+
+STATUS_GRACEFUL_DISCONNECT
+
+
+The transport connection was gracefully closed.
+
+0xC0000238
+
+STATUS_ADDRESS_ALREADY_ASSOCIATED
+
+
+The transport endpoint already has an address associated with it.
+
+0xC0000239
+
+STATUS_ADDRESS_NOT_ASSOCIATED
+
+
+An address has not yet been associated with the transport endpoint.
+
+0xC000023A
+
+STATUS_CONNECTION_INVALID
+
+
+An operation was attempted on a nonexistent transport connection.
+
+0xC000023B
+
+STATUS_CONNECTION_ACTIVE
+
+
+An invalid operation was attempted on an active transport connection.
+
+0xC000023C
+
+STATUS_NETWORK_UNREACHABLE
+
+
+The remote network is not reachable by the transport.
+
+0xC000023D
+
+STATUS_HOST_UNREACHABLE
+
+
+The remote system is not reachable by the transport.
+
+0xC000023E
+
+STATUS_PROTOCOL_UNREACHABLE
+
+
+The remote system does not support the transport protocol.
+
+0xC000023F
+
+STATUS_PORT_UNREACHABLE
+
+
+No service is operating at the destination port of the transport on the remote system.
+
+0xC0000240
+
+STATUS_REQUEST_ABORTED
+
+
+The request was aborted.
+
+0xC0000241
+
+STATUS_CONNECTION_ABORTED
+
+
+The transport connection was aborted by the local system.
+
+0xC0000242
+
+STATUS_BAD_COMPRESSION_BUFFER
+
+
+The specified buffer contains ill-formed data.
+
+0xC0000243
+
+STATUS_USER_MAPPED_FILE
+
+
+The requested operation cannot be performed on a file with a user mapped section open.
+
+0xC0000244
+
+STATUS_AUDIT_FAILED
+
+
+{Audit Failed} An attempt to generate a security audit failed.
+
+0xC0000245
+
+STATUS_TIMER_RESOLUTION_NOT_SET
+
+
+The timer resolution was not previously set by the current process.
+
+0xC0000246
+
+STATUS_CONNECTION_COUNT_LIMIT
+
+
+A connection to the server could not be made because the limit on the number of concurrent connections for this account has been reached.
+
+0xC0000247
+
+STATUS_LOGIN_TIME_RESTRICTION
+
+
+Attempting to log on during an unauthorized time of day for this account.
+
+0xC0000248
+
+STATUS_LOGIN_WKSTA_RESTRICTION
+
+
+The account is not authorized to log on from this station.
+
+0xC0000249
+
+STATUS_IMAGE_MP_UP_MISMATCH
+
+
+{UP/MP Image Mismatch} The image %hs has been modified for use on a uniprocessor system, but you are running it on a multiprocessor machine. Reinstall the image file.
+
+0xC0000250
+
+STATUS_INSUFFICIENT_LOGON_INFO
+
+
+There is insufficient account information to log you on.
+
+0xC0000251
+
+STATUS_BAD_DLL_ENTRYPOINT
+
+
+{Invalid DLL Entrypoint} The dynamic link library %hs is not written correctly. The stack pointer has been left in an inconsistent state. The entry point should be declared as WINAPI or STDCALL. Select YES to fail the DLL load. Select NO to continue execution. Selecting NO might cause the application to operate incorrectly.
+
+0xC0000252
+
+STATUS_BAD_SERVICE_ENTRYPOINT
+
+
+{Invalid Service Callback Entrypoint} The %hs service is not written correctly. The stack pointer has been left in an inconsistent state. The callback entry point should be declared as WINAPI or STDCALL. Selecting OK will cause the service to continue operation. However, the service process might operate incorrectly.
+
+0xC0000253
+
+STATUS_LPC_REPLY_LOST
+
+
+The server received the messages but did not send a reply.
+
+0xC0000254
+
+STATUS_IP_ADDRESS_CONFLICT1
+
+
+There is an IP address conflict with another system on the network.
+
+0xC0000255
+
+STATUS_IP_ADDRESS_CONFLICT2
+
+
+There is an IP address conflict with another system on the network.
+
+0xC0000256
+
+STATUS_REGISTRY_QUOTA_LIMIT
+
+
+{Low On Registry Space} The system has reached the maximum size that is allowed for the system part of the registry. Additional storage requests will be ignored.
+
+0xC0000257
+
+STATUS_PATH_NOT_COVERED
+
+
+The contacted server does not support the indicated part of the DFS namespace.
+
+0xC0000258
+
+STATUS_NO_CALLBACK_ACTIVE
+
+
+A callback return system service cannot be executed when no callback is active.
+
+0xC0000259
+
+STATUS_LICENSE_QUOTA_EXCEEDED
+
+
+The service being accessed is licensed for a particular number of connections. No more connections can be made to the service at this time because the service has already accepted the maximum number of connections.
+
+0xC000025A
+
+STATUS_PWD_TOO_SHORT
+
+
+The password provided is too short to meet the policy of your user account. Choose a longer password.
+
+0xC000025B
+
+STATUS_PWD_TOO_RECENT
+
+
+The policy of your user account does not allow you to change passwords too frequently. This is done to prevent users from changing back to a familiar, but potentially discovered, password. If you feel your password has been compromised, contact your administrator immediately to have a new one assigned.
+
+0xC000025C
+
+STATUS_PWD_HISTORY_CONFLICT
+
+
+You have attempted to change your password to one that you have used in the past. The policy of your user account does not allow this. Select a password that you have not previously used.
+
+0xC000025E
+
+STATUS_PLUGPLAY_NO_DEVICE
+
+
+You have attempted to load a legacy device driver while its device instance had been disabled.
+
+0xC000025F
+
+STATUS_UNSUPPORTED_COMPRESSION
+
+
+The specified compression format is unsupported.
+
+0xC0000260
+
+STATUS_INVALID_HW_PROFILE
+
+
+The specified hardware profile configuration is invalid.
+
+0xC0000261
+
+STATUS_INVALID_PLUGPLAY_DEVICE_PATH
+
+
+The specified Plug and Play registry device path is invalid.
+
+0xC0000262
+
+STATUS_DRIVER_ORDINAL_NOT_FOUND
+
+
+{Driver Entry Point Not Found} The %hs device driver could not locate the ordinal %ld in driver %hs.
+
+0xC0000263
+
+STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
+
+
+{Driver Entry Point Not Found} The %hs device driver could not locate the entry point %hs in driver %hs.
+
+0xC0000264
+
+STATUS_RESOURCE_NOT_OWNED
+
+
+{Application Error} The application attempted to release a resource it did not own. Click OK to terminate the application.
+
+0xC0000265
+
+STATUS_TOO_MANY_LINKS
+
+
+An attempt was made to create more links on a file than the file system supports.
+
+0xC0000266
+
+STATUS_QUOTA_LIST_INCONSISTENT
+
+
+The specified quota list is internally inconsistent with its descriptor.
+
+0xC0000267
+
+STATUS_FILE_IS_OFFLINE
+
+
+The specified file has been relocated to offline storage.
+
+0xC0000268
+
+STATUS_EVALUATION_EXPIRATION
+
+
+{Windows Evaluation Notification} The evaluation period for this installation of Windows has expired. This system will shutdown in 1 hour. To restore access to this installation of Windows, upgrade this installation by using a licensed distribution of this product.
+
+0xC0000269
+
+STATUS_ILLEGAL_DLL_RELOCATION
+
+
+{Illegal System DLL Relocation} The system DLL %hs was relocated in memory. The application will not run properly. The relocation occurred because the DLL %hs occupied an address range that is reserved for Windows system DLLs. The vendor supplying the DLL should be contacted for a new DLL.
+
+0xC000026A
+
+STATUS_LICENSE_VIOLATION
+
+
+{License Violation} The system has detected tampering with your registered product type. This is a violation of your software license. Tampering with the product type is not permitted.
+
+0xC000026B
+
+STATUS_DLL_INIT_FAILED_LOGOFF
+
+
+{DLL Initialization Failed} The application failed to initialize because the window station is shutting down.
+
+0xC000026C
+
+STATUS_DRIVER_UNABLE_TO_LOAD
+
+
+{Unable to Load Device Driver} %hs device driver could not be loaded. Error Status was 0x%x.
+
+0xC000026D
+
+STATUS_DFS_UNAVAILABLE
+
+
+DFS is unavailable on the contacted server.
+
+0xC000026E
+
+STATUS_VOLUME_DISMOUNTED
+
+
+An operation was attempted to a volume after it was dismounted.
+
+0xC000026F
+
+STATUS_WX86_INTERNAL_ERROR
+
+
+An internal error occurred in the Win32 x86 emulation subsystem.
+
+0xC0000270
+
+STATUS_WX86_FLOAT_STACK_CHECK
+
+
+Win32 x86 emulation subsystem floating-point stack check.
+
+0xC0000271
+
+STATUS_VALIDATE_CONTINUE
+
+
+The validation process needs to continue on to the next step.
+
+0xC0000272
+
+STATUS_NO_MATCH
+
+
+There was no match for the specified key in the index.
+
+0xC0000273
+
+STATUS_NO_MORE_MATCHES
+
+
+There are no more matches for the current index enumeration.
+
+0xC0000275
+
+STATUS_NOT_A_REPARSE_POINT
+
+
+The NTFS file or directory is not a reparse point.
+
+0xC0000276
+
+STATUS_IO_REPARSE_TAG_INVALID
+
+
+The Windows I/O reparse tag passed for the NTFS reparse point is invalid.
+
+0xC0000277
+
+STATUS_IO_REPARSE_TAG_MISMATCH
+
+
+The Windows I/O reparse tag does not match the one that is in the NTFS reparse point.
+
+0xC0000278
+
+STATUS_IO_REPARSE_DATA_INVALID
+
+
+The user data passed for the NTFS reparse point is invalid.
+
+0xC0000279
+
+STATUS_IO_REPARSE_TAG_NOT_HANDLED
+
+
+The layered file system driver for this I/O tag did not handle it when needed.
+
+0xC0000280
+
+STATUS_REPARSE_POINT_NOT_RESOLVED
+
+
+The NTFS symbolic link could not be resolved even though the initial file name is valid.
+
+0xC0000281
+
+STATUS_DIRECTORY_IS_A_REPARSE_POINT
+
+
+The NTFS directory is a reparse point.
+
+0xC0000282
+
+STATUS_RANGE_LIST_CONFLICT
+
+
+The range could not be added to the range list because of a conflict.
+
+0xC0000283
+
+STATUS_SOURCE_ELEMENT_EMPTY
+
+
+The specified medium changer source element contains no media.
+
+0xC0000284
+
+STATUS_DESTINATION_ELEMENT_FULL
+
+
+The specified medium changer destination element already contains media.
+
+0xC0000285
+
+STATUS_ILLEGAL_ELEMENT_ADDRESS
+
+
+The specified medium changer element does not exist.
+
+0xC0000286
+
+STATUS_MAGAZINE_NOT_PRESENT
+
+
+The specified element is contained in a magazine that is no longer present.
+
+0xC0000287
+
+STATUS_REINITIALIZATION_NEEDED
+
+
+The device requires re-initialization due to hardware errors.
+
+0xC000028A
+
+STATUS_ENCRYPTION_FAILED
+
+
+The file encryption attempt failed.
+
+0xC000028B
+
+STATUS_DECRYPTION_FAILED
+
+
+The file decryption attempt failed.
+
+0xC000028C
+
+STATUS_RANGE_NOT_FOUND
+
+
+The specified range could not be found in the range list.
+
+0xC000028D
+
+STATUS_NO_RECOVERY_POLICY
+
+
+There is no encryption recovery policy configured for this system.
+
+0xC000028E
+
+STATUS_NO_EFS
+
+
+The required encryption driver is not loaded for this system.
+
+0xC000028F
+
+STATUS_WRONG_EFS
+
+
+The file was encrypted with a different encryption driver than is currently loaded.
+
+0xC0000290
+
+STATUS_NO_USER_KEYS
+
+
+There are no EFS keys defined for the user.
+
+0xC0000291
+
+STATUS_FILE_NOT_ENCRYPTED
+
+
+The specified file is not encrypted.
+
+0xC0000292
+
+STATUS_NOT_EXPORT_FORMAT
+
+
+The specified file is not in the defined EFS export format.
+
+0xC0000293
+
+STATUS_FILE_ENCRYPTED
+
+
+The specified file is encrypted and the user does not have the ability to decrypt it.
+
+0xC0000295
+
+STATUS_WMI_GUID_NOT_FOUND
+
+
+The GUID passed was not recognized as valid by a WMI data provider.
+
+0xC0000296
+
+STATUS_WMI_INSTANCE_NOT_FOUND
+
+
+The instance name passed was not recognized as valid by a WMI data provider.
+
+0xC0000297
+
+STATUS_WMI_ITEMID_NOT_FOUND
+
+
+The data item ID passed was not recognized as valid by a WMI data provider.
+
+0xC0000298
+
+STATUS_WMI_TRY_AGAIN
+
+
+The WMI request could not be completed and should be retried.
+
+0xC0000299
+
+STATUS_SHARED_POLICY
+
+
+The policy object is shared and can only be modified at the root.
+
+0xC000029A
+
+STATUS_POLICY_OBJECT_NOT_FOUND
+
+
+The policy object does not exist when it should.
+
+0xC000029B
+
+STATUS_POLICY_ONLY_IN_DS
+
+
+The requested policy information only lives in the Ds.
+
+0xC000029C
+
+STATUS_VOLUME_NOT_UPGRADED
+
+
+The volume must be upgraded to enable this feature.
+
+0xC000029D
+
+STATUS_REMOTE_STORAGE_NOT_ACTIVE
+
+
+The remote storage service is not operational at this time.
+
+0xC000029E
+
+STATUS_REMOTE_STORAGE_MEDIA_ERROR
+
+
+The remote storage service encountered a media error.
+
+0xC000029F
+
+STATUS_NO_TRACKING_SERVICE
+
+
+The tracking (workstation) service is not running.
+
+0xC00002A0
+
+STATUS_SERVER_SID_MISMATCH
+
+
+The server process is running under a SID that is different from the SID that is required by client.
+
+0xC00002A1
+
+STATUS_DS_NO_ATTRIBUTE_OR_VALUE
+
+
+The specified directory service attribute or value does not exist.
+
+0xC00002A2
+
+STATUS_DS_INVALID_ATTRIBUTE_SYNTAX
+
+
+The attribute syntax specified to the directory service is invalid.
+
+0xC00002A3
+
+STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED
+
+
+The attribute type specified to the directory service is not defined.
+
+0xC00002A4
+
+STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS
+
+
+The specified directory service attribute or value already exists.
+
+0xC00002A5
+
+STATUS_DS_BUSY
+
+
+The directory service is busy.
+
+0xC00002A6
+
+STATUS_DS_UNAVAILABLE
+
+
+The directory service is unavailable.
+
+0xC00002A7
+
+STATUS_DS_NO_RIDS_ALLOCATED
+
+
+The directory service was unable to allocate a relative identifier.
+
+0xC00002A8
+
+STATUS_DS_NO_MORE_RIDS
+
+
+The directory service has exhausted the pool of relative identifiers.
+
+0xC00002A9
+
+STATUS_DS_INCORRECT_ROLE_OWNER
+
+
+The requested operation could not be performed because the directory service is not the master for that type of operation.
+
+0xC00002AA
+
+STATUS_DS_RIDMGR_INIT_ERROR
+
+
+The directory service was unable to initialize the subsystem that allocates relative identifiers.
+
+0xC00002AB
+
+STATUS_DS_OBJ_CLASS_VIOLATION
+
+
+The requested operation did not satisfy one or more constraints that are associated with the class of the object.
+
+0xC00002AC
+
+STATUS_DS_CANT_ON_NON_LEAF
+
+
+The directory service can perform the requested operation only on a leaf object.
+
+0xC00002AD
+
+STATUS_DS_CANT_ON_RDN
+
+
+The directory service cannot perform the requested operation on the Relatively Defined Name (RDN) attribute of an object.
+
+0xC00002AE
+
+STATUS_DS_CANT_MOD_OBJ_CLASS
+
+
+The directory service detected an attempt to modify the object class of an object.
+
+0xC00002AF
+
+STATUS_DS_CROSS_DOM_MOVE_FAILED
+
+
+An error occurred while performing a cross domain move operation.
+
+0xC00002B0
+
+STATUS_DS_GC_NOT_AVAILABLE
+
+
+Unable to contact the global catalog server.
+
+0xC00002B1
+
+STATUS_DIRECTORY_SERVICE_REQUIRED
+
+
+The requested operation requires a directory service, and none was available.
+
+0xC00002B2
+
+STATUS_REPARSE_ATTRIBUTE_CONFLICT
+
+
+The reparse attribute cannot be set because it is incompatible with an existing attribute.
+
+0xC00002B3
+
+STATUS_CANT_ENABLE_DENY_ONLY
+
+
+A group marked "use for deny only" cannot be enabled.
+
+0xC00002B4
+
+STATUS_FLOAT_MULTIPLE_FAULTS
+
+
+{EXCEPTION} Multiple floating-point faults.
+
+0xC00002B5
+
+STATUS_FLOAT_MULTIPLE_TRAPS
+
+
+{EXCEPTION} Multiple floating-point traps.
+
+0xC00002B6
+
+STATUS_DEVICE_REMOVED
+
+
+The device has been removed.
+
+0xC00002B7
+
+STATUS_JOURNAL_DELETE_IN_PROGRESS
+
+
+The volume change journal is being deleted.
+
+0xC00002B8
+
+STATUS_JOURNAL_NOT_ACTIVE
+
+
+The volume change journal is not active.
+
+0xC00002B9
+
+STATUS_NOINTERFACE
+
+
+The requested interface is not supported.
+
+0xC00002C1
+
+STATUS_DS_ADMIN_LIMIT_EXCEEDED
+
+
+A directory service resource limit has been exceeded.
+
+0xC00002C2
+
+STATUS_DRIVER_FAILED_SLEEP
+
+
+{System Standby Failed} The driver %hs does not support standby mode. Updating this driver allows the system to go to standby mode.
+
+0xC00002C3
+
+STATUS_MUTUAL_AUTHENTICATION_FAILED
+
+
+Mutual Authentication failed. The server password is out of date at the domain controller.
+
+0xC00002C4
+
+STATUS_CORRUPT_SYSTEM_FILE
+
+
+The system file %1 has become corrupt and has been replaced.
+
+0xC00002C5
+
+STATUS_DATATYPE_MISALIGNMENT_ERROR
+
+
+{EXCEPTION} Alignment Error A data type misalignment error was detected in a load or store instruction.
+
+0xC00002C6
+
+STATUS_WMI_READ_ONLY
+
+
+The WMI data item or data block is read-only.
+
+0xC00002C7
+
+STATUS_WMI_SET_FAILURE
+
+
+The WMI data item or data block could not be changed.
+
+0xC00002C8
+
+STATUS_COMMITMENT_MINIMUM
+
+
+{Virtual Memory Minimum Too Low} Your system is low on virtual memory. Windows is increasing the size of your virtual memory paging file. During this process, memory requests for some applications might be denied. For more information, see Help.
+
+0xC00002C9
+
+STATUS_REG_NAT_CONSUMPTION
+
+
+{EXCEPTION} Register NaT consumption faults. A NaT value is consumed on a non-speculative instruction.
+
+0xC00002CA
+
+STATUS_TRANSPORT_FULL
+
+
+The transport element of the medium changer contains media, which is causing the operation to fail.
+
+0xC00002CB
+
+STATUS_DS_SAM_INIT_FAILURE
+
+
+Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. Click OK to shut down this system and restart in Directory Services Restore Mode. Check the event log for more detailed information.
+
+0xC00002CC
+
+STATUS_ONLY_IF_CONNECTED
+
+
+This operation is supported only when you are connected to the server.
+
+0xC00002CD
+
+STATUS_DS_SENSITIVE_GROUP_VIOLATION
+
+
+Only an administrator can modify the membership list of an administrative group.
+
+0xC00002CE
+
+STATUS_PNP_RESTART_ENUMERATION
+
+
+A device was removed so enumeration must be restarted.
+
+0xC00002CF
+
+STATUS_JOURNAL_ENTRY_DELETED
+
+
+The journal entry has been deleted from the journal.
+
+0xC00002D0
+
+STATUS_DS_CANT_MOD_PRIMARYGROUPID
+
+
+Cannot change the primary group ID of a domain controller account.
+
+0xC00002D1
+
+STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
+
+
+{Fatal System Error} The system image %s is not properly signed. The file has been replaced with the signed file. The system has been shut down.
+
+0xC00002D2
+
+STATUS_PNP_REBOOT_REQUIRED
+
+
+The device will not start without a reboot.
+
+0xC00002D3
+
+STATUS_POWER_STATE_INVALID
+
+
+The power state of the current device cannot support this request.
+
+0xC00002D4
+
+STATUS_DS_INVALID_GROUP_TYPE
+
+
+The specified group type is invalid.
+
+0xC00002D5
+
+STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN
+
+
+In a mixed domain, no nesting of a global group if the group is security enabled.
+
+0xC00002D6
+
+STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN
+
+
+In a mixed domain, cannot nest local groups with other local groups, if the group is security enabled.
+
+0xC00002D7
+
+STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER
+
+
+A global group cannot have a local group as a member.
+
+0xC00002D8
+
+STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER
+
+
+A global group cannot have a universal group as a member.
+
+0xC00002D9
+
+STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER
+
+
+A universal group cannot have a local group as a member.
+
+0xC00002DA
+
+STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER
+
+
+A global group cannot have a cross-domain member.
+
+0xC00002DB
+
+STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER
+
+
+A local group cannot have another cross-domain local group as a member.
+
+0xC00002DC
+
+STATUS_DS_HAVE_PRIMARY_MEMBERS
+
+
+Cannot change to a security-disabled group because primary members are in this group.
+
+0xC00002DD
+
+STATUS_WMI_NOT_SUPPORTED
+
+
+The WMI operation is not supported by the data block or method.
+
+0xC00002DE
+
+STATUS_INSUFFICIENT_POWER
+
+
+There is not enough power to complete the requested operation.
+
+0xC00002DF
+
+STATUS_SAM_NEED_BOOTKEY_PASSWORD
+
+
+The Security Accounts Manager needs to get the boot password.
+
+0xC00002E0
+
+STATUS_SAM_NEED_BOOTKEY_FLOPPY
+
+
+The Security Accounts Manager needs to get the boot key from the floppy disk.
+
+0xC00002E1
+
+STATUS_DS_CANT_START
+
+
+The directory service cannot start.
+
+0xC00002E2
+
+STATUS_DS_INIT_FAILURE
+
+
+The directory service could not start because of the following error: %hs Error Status: 0x%x. Click OK to shut down this system and restart in Directory Services Restore Mode. Check the event log for more detailed information.
+
+0xC00002E3
+
+STATUS_SAM_INIT_FAILURE
+
+
+The Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. Click OK to shut down this system and restart in Safe Mode. Check the event log for more detailed information.
+
+0xC00002E4
+
+STATUS_DS_GC_REQUIRED
+
+
+The requested operation can be performed only on a global catalog server.
+
+0xC00002E5
+
+STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY
+
+
+A local group can only be a member of other local groups in the same domain.
+
+0xC00002E6
+
+STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS
+
+
+Foreign security principals cannot be members of universal groups.
+
+0xC00002E7
+
+STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED
+
+
+Your computer could not be joined to the domain. You have exceeded the maximum number of computer accounts you are allowed to create in this domain. Contact your system administrator to have this limit reset or increased.
+
+0xC00002E9
+
+STATUS_CURRENT_DOMAIN_NOT_ALLOWED
+
+
+This operation cannot be performed on the current domain.
+
+0xC00002EA
+
+STATUS_CANNOT_MAKE
+
+
+The directory or file cannot be created.
+
+0xC00002EB
+
+STATUS_SYSTEM_SHUTDOWN
+
+
+The system is in the process of shutting down.
+
+0xC00002EC
+
+STATUS_DS_INIT_FAILURE_CONSOLE
+
+
+Directory Services could not start because of the following error: %hs Error Status: 0x%x. Click OK to shut down the system. You can use the recovery console to diagnose the system further.
+
+0xC00002ED
+
+STATUS_DS_SAM_INIT_FAILURE_CONSOLE
+
+
+Security Accounts Manager initialization failed because of the following error: %hs Error Status: 0x%x. Click OK to shut down the system. You can use the recovery console to diagnose the system further.
+
+0xC00002EE
+
+STATUS_UNFINISHED_CONTEXT_DELETED
+
+
+A security context was deleted before the context was completed. This is considered a logon failure.
+
+0xC00002EF
+
+STATUS_NO_TGT_REPLY
+
+
+The client is trying to negotiate a context and the server requires user-to-user but did not send a TGT reply.
+
+0xC00002F0
+
+STATUS_OBJECTID_NOT_FOUND
+
+
+An object ID was not found in the file.
+
+0xC00002F1
+
+STATUS_NO_IP_ADDRESSES
+
+
+Unable to accomplish the requested task because the local machine does not have any IP addresses.
+
+0xC00002F2
+
+STATUS_WRONG_CREDENTIAL_HANDLE
+
+
+The supplied credential handle does not match the credential that is associated with the security context.
+
+0xC00002F3
+
+STATUS_CRYPTO_SYSTEM_INVALID
+
+
+The crypto system or checksum function is invalid because a required function is unavailable.
+
+0xC00002F4
+
+STATUS_MAX_REFERRALS_EXCEEDED
+
+
+The number of maximum ticket referrals has been exceeded.
+
+0xC00002F5
+
+STATUS_MUST_BE_KDC
+
+
+The local machine must be a Kerberos KDC (domain controller) and it is not.
+
+0xC00002F6
+
+STATUS_STRONG_CRYPTO_NOT_SUPPORTED
+
+
+The other end of the security negotiation requires strong crypto but it is not supported on the local machine.
+
+0xC00002F7
+
+STATUS_TOO_MANY_PRINCIPALS
+
+
+The KDC reply contained more than one principal name.
+
+0xC00002F8
+
+STATUS_NO_PA_DATA
+
+
+Expected to find PA data for a hint of what etype to use, but it was not found.
+
+0xC00002F9
+
+STATUS_PKINIT_NAME_MISMATCH
+
+
+The client certificate does not contain a valid UPN, or does not match the client name in the logon request. Contact your administrator.
+
+0xC00002FA
+
+STATUS_SMARTCARD_LOGON_REQUIRED
+
+
+Smart card logon is required and was not used.
+
+0xC00002FB
+
+STATUS_KDC_INVALID_REQUEST
+
+
+An invalid request was sent to the KDC.
+
+0xC00002FC
+
+STATUS_KDC_UNABLE_TO_REFER
+
+
+The KDC was unable to generate a referral for the service requested.
+
+0xC00002FD
+
+STATUS_KDC_UNKNOWN_ETYPE
+
+
+The encryption type requested is not supported by the KDC.
+
+0xC00002FE
+
+STATUS_SHUTDOWN_IN_PROGRESS
+
+
+A system shutdown is in progress.
+
+0xC00002FF
+
+STATUS_SERVER_SHUTDOWN_IN_PROGRESS
+
+
+The server machine is shutting down.
+
+0xC0000300
+
+STATUS_NOT_SUPPORTED_ON_SBS
+
+
+This operation is not supported on a computer running Windows Server 2003 operating system for Small Business Server.
+
+0xC0000301
+
+STATUS_WMI_GUID_DISCONNECTED
+
+
+The WMI GUID is no longer available.
+
+0xC0000302
+
+STATUS_WMI_ALREADY_DISABLED
+
+
+Collection or events for the WMI GUID is already disabled.
+
+0xC0000303
+
+STATUS_WMI_ALREADY_ENABLED
+
+
+Collection or events for the WMI GUID is already enabled.
+
+0xC0000304
+
+STATUS_MFT_TOO_FRAGMENTED
+
+
+The master file table on the volume is too fragmented to complete this operation.
+
+0xC0000305
+
+STATUS_COPY_PROTECTION_FAILURE
+
+
+Copy protection failure.
+
+0xC0000306
+
+STATUS_CSS_AUTHENTICATION_FAILURE
+
+
+Copy protection error—DVD CSS Authentication failed.
+
+0xC0000307
+
+STATUS_CSS_KEY_NOT_PRESENT
+
+
+Copy protection error—The specified sector does not contain a valid key.
+
+0xC0000308
+
+STATUS_CSS_KEY_NOT_ESTABLISHED
+
+
+Copy protection error—DVD session key not established.
+
+0xC0000309
+
+STATUS_CSS_SCRAMBLED_SECTOR
+
+
+Copy protection error—The read failed because the sector is encrypted.
+
+0xC000030A
+
+STATUS_CSS_REGION_MISMATCH
+
+
+Copy protection error—The region of the specified DVD does not correspond to the region setting of the drive.
+
+0xC000030B
+
+STATUS_CSS_RESETS_EXHAUSTED
+
+
+Copy protection error—The region setting of the drive might be permanent.
+
+0xC0000320
+
+STATUS_PKINIT_FAILURE
+
+
+The Kerberos protocol encountered an error while validating the KDC certificate during smart card logon. There is more information in the system event log.
+
+0xC0000321
+
+STATUS_SMARTCARD_SUBSYSTEM_FAILURE
+
+
+The Kerberos protocol encountered an error while attempting to use the smart card subsystem.
+
+0xC0000322
+
+STATUS_NO_KERB_KEY
+
+
+The target server does not have acceptable Kerberos credentials.
+
+0xC0000350
+
+STATUS_HOST_DOWN
+
+
+The transport determined that the remote system is down.
+
+0xC0000351
+
+STATUS_UNSUPPORTED_PREAUTH
+
+
+An unsupported pre-authentication mechanism was presented to the Kerberos package.
+
+0xC0000352
+
+STATUS_EFS_ALG_BLOB_TOO_BIG
+
+
+The encryption algorithm that is used on the source file needs a bigger key buffer than the one that is used on the destination file.
+
+0xC0000353
+
+STATUS_PORT_NOT_SET
+
+
+An attempt to remove a processes DebugPort was made, but a port was not already associated with the process.
+
+0xC0000354
+
+STATUS_DEBUGGER_INACTIVE
+
+
+An attempt to do an operation on a debug port failed because the port is in the process of being deleted.
+
+0xC0000355
+
+STATUS_DS_VERSION_CHECK_FAILURE
+
+
+This version of Windows is not compatible with the behavior version of the directory forest, domain, or domain controller.
+
+0xC0000356
+
+STATUS_AUDITING_DISABLED
+
+
+The specified event is currently not being audited.
+
+0xC0000357
+
+STATUS_PRENT4_MACHINE_ACCOUNT
+
+
+The machine account was created prior to Windows NT 4.0 operating system. The account needs to be recreated.
+
+0xC0000358
+
+STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER
+
+
+An account group cannot have a universal group as a member.
+
+0xC0000359
+
+STATUS_INVALID_IMAGE_WIN_32
+
+
+The specified image file did not have the correct format; it appears to be a 32-bit Windows image.
+
+0xC000035A
+
+STATUS_INVALID_IMAGE_WIN_64
+
+
+The specified image file did not have the correct format; it appears to be a 64-bit Windows image.
+
+0xC000035B
+
+STATUS_BAD_BINDINGS
+
+
+The client's supplied SSPI channel bindings were incorrect.
+
+0xC000035C
+
+STATUS_NETWORK_SESSION_EXPIRED
+
+
+The client session has expired; so the client must re-authenticate to continue accessing the remote resources.
+
+0xC000035D
+
+STATUS_APPHELP_BLOCK
+
+
+The AppHelp dialog box canceled; thus preventing the application from starting.
+
+0xC000035E
+
+STATUS_ALL_SIDS_FILTERED
+
+
+The SID filtering operation removed all SIDs.
+
+0xC000035F
+
+STATUS_NOT_SAFE_MODE_DRIVER
+
+
+The driver was not loaded because the system is starting in safe mode.
+
+0xC0000361
+
+STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT
+
+
+Access to %1 has been restricted by your Administrator by the default software restriction policy level.
+
+0xC0000362
+
+STATUS_ACCESS_DISABLED_BY_POLICY_PATH
+
+
+Access to %1 has been restricted by your Administrator by location with policy rule %2 placed on path %3.
+
+0xC0000363
+
+STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER
+
+
+Access to %1 has been restricted by your Administrator by software publisher policy.
+
+0xC0000364
+
+STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
+
+
+Access to %1 has been restricted by your Administrator by policy rule %2.
+
+0xC0000365
+
+STATUS_FAILED_DRIVER_ENTRY
+
+
+The driver was not loaded because it failed its initialization call.
+
+0xC0000366
+
+STATUS_DEVICE_ENUMERATION_ERROR
+
+
+The device encountered an error while applying power or reading the device configuration. This might be caused by a failure of your hardware or by a poor connection.
+
+0xC0000368
+
+STATUS_MOUNT_POINT_NOT_RESOLVED
+
+
+The create operation failed because the name contained at least one mount point that resolves to a volume to which the specified device object is not attached.
+
+0xC0000369
+
+STATUS_INVALID_DEVICE_OBJECT_PARAMETER
+
+
+The device object parameter is either not a valid device object or is not attached to the volume that is specified by the file name.
+
+0xC000036A
+
+STATUS_MCA_OCCURED
+
+
+A machine check error has occurred. Check the system event log for additional information.
+
+0xC000036B
+
+STATUS_DRIVER_BLOCKED_CRITICAL
+
+
+Driver %2 has been blocked from loading.
+
+0xC000036C
+
+STATUS_DRIVER_BLOCKED
+
+
+Driver %2 has been blocked from loading.
+
+0xC000036D
+
+STATUS_DRIVER_DATABASE_ERROR
+
+
+There was error [%2] processing the driver database.
+
+0xC000036E
+
+STATUS_SYSTEM_HIVE_TOO_LARGE
+
+
+System hive size has exceeded its limit.
+
+0xC000036F
+
+STATUS_INVALID_IMPORT_OF_NON_DLL
+
+
+A dynamic link library (DLL) referenced a module that was neither a DLL nor the process's executable image.
+
+0xC0000371
+
+STATUS_NO_SECRETS
+
+
+The local account store does not contain secret material for the specified account.
+
+0xC0000372
+
+STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY
+
+
+Access to %1 has been restricted by your Administrator by policy rule %2.
+
+0xC0000373
+
+STATUS_FAILED_STACK_SWITCH
+
+
+The system was not able to allocate enough memory to perform a stack switch.
+
+0xC0000374
+
+STATUS_HEAP_CORRUPTION
+
+
+A heap has been corrupted.
+
+0xC0000380
+
+STATUS_SMARTCARD_WRONG_PIN
+
+
+An incorrect PIN was presented to the smart card.
+
+0xC0000381
+
+STATUS_SMARTCARD_CARD_BLOCKED
+
+
+The smart card is blocked.
+
+0xC0000382
+
+STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED
+
+
+No PIN was presented to the smart card.
+
+0xC0000383
+
+STATUS_SMARTCARD_NO_CARD
+
+
+No smart card is available.
+
+0xC0000384
+
+STATUS_SMARTCARD_NO_KEY_CONTAINER
+
+
+The requested key container does not exist on the smart card.
+
+0xC0000385
+
+STATUS_SMARTCARD_NO_CERTIFICATE
+
+
+The requested certificate does not exist on the smart card.
+
+0xC0000386
+
+STATUS_SMARTCARD_NO_KEYSET
+
+
+The requested keyset does not exist.
+
+0xC0000387
+
+STATUS_SMARTCARD_IO_ERROR
+
+
+A communication error with the smart card has been detected.
+
+0xC0000388
+
+STATUS_DOWNGRADE_DETECTED
+
+
+The system detected a possible attempt to compromise security. Ensure that you can contact the server that authenticated you.
+
+0xC0000389
+
+STATUS_SMARTCARD_CERT_REVOKED
+
+
+The smart card certificate used for authentication has been revoked. Contact your system administrator. There might be additional information in the event log.
+
+0xC000038A
+
+STATUS_ISSUING_CA_UNTRUSTED
+
+
+An untrusted certificate authority was detected while processing the smart card certificate that is used for authentication. Contact your system administrator.
+
+0xC000038B
+
+STATUS_REVOCATION_OFFLINE_C
+
+
+The revocation status of the smart card certificate that is used for authentication could not be determined. Contact your system administrator.
+
+0xC000038C
+
+STATUS_PKINIT_CLIENT_FAILURE
+
+
+The smart card certificate used for authentication was not trusted. Contact your system administrator.
+
+0xC000038D
+
+STATUS_SMARTCARD_CERT_EXPIRED
+
+
+The smart card certificate used for authentication has expired. Contact your system administrator.
+
+0xC000038E
+
+STATUS_DRIVER_FAILED_PRIOR_UNLOAD
+
+
+The driver could not be loaded because a previous version of the driver is still in memory.
+
+0xC000038F
+
+STATUS_SMARTCARD_SILENT_CONTEXT
+
+
+The smart card provider could not perform the action because the context was acquired as silent.
+
+0xC0000401
+
+STATUS_PER_USER_TRUST_QUOTA_EXCEEDED
+
+
+The delegated trust creation quota of the current user has been exceeded.
+
+0xC0000402
+
+STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED
+
+
+The total delegated trust creation quota has been exceeded.
+
+0xC0000403
+
+STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED
+
+
+The delegated trust deletion quota of the current user has been exceeded.
+
+0xC0000404
+
+STATUS_DS_NAME_NOT_UNIQUE
+
+
+The requested name already exists as a unique identifier.
+
+0xC0000405
+
+STATUS_DS_DUPLICATE_ID_FOUND
+
+
+The requested object has a non-unique identifier and cannot be retrieved.
+
+0xC0000406
+
+STATUS_DS_GROUP_CONVERSION_ERROR
+
+
+The group cannot be converted due to attribute restrictions on the requested group type.
+
+0xC0000407
+
+STATUS_VOLSNAP_PREPARE_HIBERNATE
+
+
+{Volume Shadow Copy Service} Wait while the Volume Shadow Copy Service prepares volume %hs for hibernation.
+
+0xC0000408
+
+STATUS_USER2USER_REQUIRED
+
+
+Kerberos sub-protocol User2User is required.
+
+0xC0000409
+
+STATUS_STACK_BUFFER_OVERRUN
+
+
+The system detected an overrun of a stack-based buffer in this application. This overrun could potentially allow a malicious user to gain control of this application.
+
+0xC000040A
+
+STATUS_NO_S4U_PROT_SUPPORT
+
+
+The Kerberos subsystem encountered an error. A service for user protocol request was made against a domain controller which does not support service for user.
+
+0xC000040B
+
+STATUS_CROSSREALM_DELEGATION_FAILURE
+
+
+An attempt was made by this server to make a Kerberos constrained delegation request for a target that is outside the server realm. This action is not supported and the resulting error indicates a misconfiguration on the allowed-to-delegate-to list for this server. Contact your administrator.
+
+0xC000040C
+
+STATUS_REVOCATION_OFFLINE_KDC
+
+
+The revocation status of the domain controller certificate used for smart card authentication could not be determined. There is additional information in the system event log. Contact your system administrator.
+
+0xC000040D
+
+STATUS_ISSUING_CA_UNTRUSTED_KDC
+
+
+An untrusted certificate authority was detected while processing the domain controller certificate used for authentication. There is additional information in the system event log. Contact your system administrator.
+
+0xC000040E
+
+STATUS_KDC_CERT_EXPIRED
+
+
+The domain controller certificate used for smart card logon has expired. Contact your system administrator with the contents of your system event log.
+
+0xC000040F
+
+STATUS_KDC_CERT_REVOKED
+
+
+The domain controller certificate used for smart card logon has been revoked. Contact your system administrator with the contents of your system event log.
+
+0xC0000410
+
+STATUS_PARAMETER_QUOTA_EXCEEDED
+
+
+Data present in one of the parameters is more than the function can operate on.
+
+0xC0000411
+
+STATUS_HIBERNATION_FAILURE
+
+
+The system has failed to hibernate (The error code is %hs). Hibernation will be disabled until the system is restarted.
+
+0xC0000412
+
+STATUS_DELAY_LOAD_FAILED
+
+
+An attempt to delay-load a .dll or get a function address in a delay-loaded .dll failed.
+
+0xC0000413
+
+STATUS_AUTHENTICATION_FIREWALL_FAILED
+
+
+Logon Failure: The machine you are logging onto is protected by an authentication firewall. The specified account is not allowed to authenticate to the machine.
+
+0xC0000414
+
+STATUS_VDM_DISALLOWED
+
+
+%hs is a 16-bit application. You do not have permissions to execute 16-bit applications. Check your permissions with your system administrator.
+
+0xC0000415
+
+STATUS_HUNG_DISPLAY_DRIVER_THREAD
+
+
+{Display Driver Stopped Responding} The %hs display driver has stopped working normally. Save your work and reboot the system to restore full display functionality. The next time you reboot the machine a dialog will be displayed giving you a chance to report this failure to Microsoft.
+
+0xC0000416
+
+STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE
+
+
+The Desktop heap encountered an error while allocating session memory. There is more information in the system event log.
+
+0xC0000417
+
+STATUS_INVALID_CRUNTIME_PARAMETER
+
+
+An invalid parameter was passed to a C runtime function.
+
+0xC0000418
+
+STATUS_NTLM_BLOCKED
+
+
+The authentication failed because NTLM was blocked.
+
+0xC0000419
+
+STATUS_DS_SRC_SID_EXISTS_IN_FOREST
+
+
+The source object's SID already exists in destination forest.
+
+0xC000041A
+
+STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST
+
+
+The domain name of the trusted domain already exists in the forest.
+
+0xC000041B
+
+STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST
+
+
+The flat name of the trusted domain already exists in the forest.
+
+0xC000041C
+
+STATUS_INVALID_USER_PRINCIPAL_NAME
+
+
+The User Principal Name (UPN) is invalid.
+
+0xC0000420
+
+STATUS_ASSERTION_FAILURE
+
+
+There has been an assertion failure.
+
+0xC0000421
+
+STATUS_VERIFIER_STOP
+
+
+Application verifier has found an error in the current process.
+
+0xC0000423
+
+STATUS_CALLBACK_POP_STACK
+
+
+A user mode unwind is in progress.
+
+0xC0000424
+
+STATUS_INCOMPATIBLE_DRIVER_BLOCKED
+
+
+%2 has been blocked from loading due to incompatibility with this system. Contact your software vendor for a compatible version of the driver.
+
+0xC0000425
+
+STATUS_HIVE_UNLOADED
+
+
+Illegal operation attempted on a registry key which has already been unloaded.
+
+0xC0000426
+
+STATUS_COMPRESSION_DISABLED
+
+
+Compression is disabled for this volume.
+
+0xC0000427
+
+STATUS_FILE_SYSTEM_LIMITATION
+
+
+The requested operation could not be completed due to a file system limitation.
+
+0xC0000428
+
+STATUS_INVALID_IMAGE_HASH
+
+
+The hash for image %hs cannot be found in the system catalogs. The image is likely corrupt or the victim of tampering.
+
+0xC0000429
+
+STATUS_NOT_CAPABLE
+
+
+The implementation is not capable of performing the request.
+
+0xC000042A
+
+STATUS_REQUEST_OUT_OF_SEQUENCE
+
+
+The requested operation is out of order with respect to other operations.
+
+0xC000042B
+
+STATUS_IMPLEMENTATION_LIMIT
+
+
+An operation attempted to exceed an implementation-defined limit.
+
+0xC000042C
+
+STATUS_ELEVATION_REQUIRED
+
+
+The requested operation requires elevation.
+
+0xC000042D
+
+STATUS_NO_SECURITY_CONTEXT
+
+
+The required security context does not exist.
+
+0xC000042E
+
+STATUS_PKU2U_CERT_FAILURE
+
+
+The PKU2U protocol encountered an error while attempting to utilize the associated certificates.
+
+0xC0000432
+
+STATUS_BEYOND_VDL
+
+
+The operation was attempted beyond the valid data length of the file.
+
+0xC0000433
+
+STATUS_ENCOUNTERED_WRITE_IN_PROGRESS
+
+
+The attempted write operation encountered a write already in progress for some portion of the range.
+
+0xC0000434
+
+STATUS_PTE_CHANGED
+
+
+The page fault mappings changed in the middle of processing a fault so the operation must be retried.
+
+0xC0000435
+
+STATUS_PURGE_FAILED
+
+
+The attempt to purge this file from memory failed to purge some or all the data from memory.
+
+0xC0000440
+
+STATUS_CRED_REQUIRES_CONFIRMATION
+
+
+The requested credential requires confirmation.
+
+0xC0000441
+
+STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE
+
+
+The remote server sent an invalid response for a file being opened with Client Side Encryption.
+
+0xC0000442
+
+STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER
+
+
+Client Side Encryption is not supported by the remote server even though it claims to support it.
+
+0xC0000443
+
+STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE
+
+
+File is encrypted and should be opened in Client Side Encryption mode.
+
+0xC0000444
+
+STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE
+
+
+A new encrypted file is being created and a $EFS needs to be provided.
+
+0xC0000445
+
+STATUS_CS_ENCRYPTION_FILE_NOT_CSE
+
+
+The SMB client requested a CSE FSCTL on a non-CSE file.
+
+0xC0000446
+
+STATUS_INVALID_LABEL
+
+
+Indicates a particular Security ID cannot be assigned as the label of an object.
+
+0xC0000450
+
+STATUS_DRIVER_PROCESS_TERMINATED
+
+
+The process hosting the driver for this device has terminated.
+
+0xC0000451
+
+STATUS_AMBIGUOUS_SYSTEM_DEVICE
+
+
+The requested system device cannot be identified due to multiple indistinguishable devices potentially matching the identification criteria.
+
+0xC0000452
+
+STATUS_SYSTEM_DEVICE_NOT_FOUND
+
+
+The requested system device cannot be found.
+
+0xC0000453
+
+STATUS_RESTART_BOOT_APPLICATION
+
+
+This boot application must be restarted.
+
+0xC0000454
+
+STATUS_INSUFFICIENT_NVRAM_RESOURCES
+
+
+Insufficient NVRAM resources exist to complete the API. A reboot might be required.
+
+0xC0000460
+
+STATUS_NO_RANGES_PROCESSED
+
+
+No ranges for the specified operation were able to be processed.
+
+0xC0000463
+
+STATUS_DEVICE_FEATURE_NOT_SUPPORTED
+
+
+The storage device does not support Offload Write.
+
+0xC0000464
+
+STATUS_DEVICE_UNREACHABLE
+
+
+Data cannot be moved because the source device cannot communicate with the destination device.
+
+0xC0000465
+
+STATUS_INVALID_TOKEN
+
+
+The token representing the data is invalid or expired.
+
+0xC0000466
+
+STATUS_SERVER_UNAVAILABLE
+
+
+The file server is temporarily unavailable.
+
+0xC0000500
+
+STATUS_INVALID_TASK_NAME
+
+
+The specified task name is invalid.
+
+0xC0000501
+
+STATUS_INVALID_TASK_INDEX
+
+
+The specified task index is invalid.
+
+0xC0000502
+
+STATUS_THREAD_ALREADY_IN_TASK
+
+
+The specified thread is already joining a task.
+
+0xC0000503
+
+STATUS_CALLBACK_BYPASS
+
+
+A callback has requested to bypass native code.
+
+0xC0000602
+
+STATUS_FAIL_FAST_EXCEPTION
+
+
+A fail fast exception occurred. Exception handlers will not be invoked and the process will be terminated immediately.
+
+0xC0000603
+
+STATUS_IMAGE_CERT_REVOKED
+
+
+Windows cannot verify the digital signature for this file. The signing certificate for this file has been revoked.
+
+0xC0000700
+
+STATUS_PORT_CLOSED
+
+
+The ALPC port is closed.
+
+0xC0000701
+
+STATUS_MESSAGE_LOST
+
+
+The ALPC message requested is no longer available.
+
+0xC0000702
+
+STATUS_INVALID_MESSAGE
+
+
+The ALPC message supplied is invalid.
+
+0xC0000703
+
+STATUS_REQUEST_CANCELED
+
+
+The ALPC message has been canceled.
+
+0xC0000704
+
+STATUS_RECURSIVE_DISPATCH
+
+
+Invalid recursive dispatch attempt.
+
+0xC0000705
+
+STATUS_LPC_RECEIVE_BUFFER_EXPECTED
+
+
+No receive buffer has been supplied in a synchronous request.
+
+0xC0000706
+
+STATUS_LPC_INVALID_CONNECTION_USAGE
+
+
+The connection port is used in an invalid context.
+
+0xC0000707
+
+STATUS_LPC_REQUESTS_NOT_ALLOWED
+
+
+The ALPC port does not accept new request messages.
+
+0xC0000708
+
+STATUS_RESOURCE_IN_USE
+
+
+The resource requested is already in use.
+
+0xC0000709
+
+STATUS_HARDWARE_MEMORY_ERROR
+
+
+The hardware has reported an uncorrectable memory error.
+
+0xC000070A
+
+STATUS_THREADPOOL_HANDLE_EXCEPTION
+
+
+Status 0x%08x was returned, waiting on handle 0x%x for wait 0x%p, in waiter 0x%p.
+
+0xC000070B
+
+STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED
+
+
+After a callback to 0x%p(0x%p), a completion call to Set event(0x%p) failed with status 0x%08x.
+
+0xC000070C
+
+STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED
+
+
+After a callback to 0x%p(0x%p), a completion call to ReleaseSemaphore(0x%p, %d) failed with status 0x%08x.
+
+0xC000070D
+
+STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED
+
+
+After a callback to 0x%p(0x%p), a completion call to ReleaseMutex(%p) failed with status 0x%08x.
+
+0xC000070E
+
+STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED
+
+
+After a callback to 0x%p(0x%p), a completion call to FreeLibrary(%p) failed with status 0x%08x.
+
+0xC000070F
+
+STATUS_THREADPOOL_RELEASED_DURING_OPERATION
+
+
+The thread pool 0x%p was released while a thread was posting a callback to 0x%p(0x%p) to it.
+
+0xC0000710
+
+STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING
+
+
+A thread pool worker thread is impersonating a client, after a callback to 0x%p(0x%p). This is unexpected, indicating that the callback is missing a call to revert the impersonation.
+
+0xC0000711
+
+STATUS_APC_RETURNED_WHILE_IMPERSONATING
+
+
+A thread pool worker thread is impersonating a client, after executing an APC. This is unexpected, indicating that the APC is missing a call to revert the impersonation.
+
+0xC0000712
+
+STATUS_PROCESS_IS_PROTECTED
+
+
+Either the target process, or the target thread's containing process, is a protected process.
+
+0xC0000713
+
+STATUS_MCA_EXCEPTION
+
+
+A thread is getting dispatched with MCA EXCEPTION because of MCA.
+
+0xC0000714
+
+STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE
+
+
+The client certificate account mapping is not unique.
+
+0xC0000715
+
+STATUS_SYMLINK_CLASS_DISABLED
+
+
+The symbolic link cannot be followed because its type is disabled.
+
+0xC0000716
+
+STATUS_INVALID_IDN_NORMALIZATION
+
+
+Indicates that the specified string is not valid for IDN normalization.
+
+0xC0000717
+
+STATUS_NO_UNICODE_TRANSLATION
+
+
+No mapping for the Unicode character exists in the target multi-byte code page.
+
+0xC0000718
+
+STATUS_ALREADY_REGISTERED
+
+
+The provided callback is already registered.
+
+0xC0000719
+
+STATUS_CONTEXT_MISMATCH
+
+
+The provided context did not match the target.
+
+0xC000071A
+
+STATUS_PORT_ALREADY_HAS_COMPLETION_LIST
+
+
+The specified port already has a completion list.
+
+0xC000071B
+
+STATUS_CALLBACK_RETURNED_THREAD_PRIORITY
+
+
+A threadpool worker thread entered a callback at thread base priority 0x%x and exited at priority 0x%x.
+
+This is unexpected, indicating that the callback missed restoring the priority.
+
+0xC000071C
+
+STATUS_INVALID_THREAD
+
+
+An invalid thread, handle %p, is specified for this operation. Possibly, a threadpool worker thread was specified.
+
+0xC000071D
+
+STATUS_CALLBACK_RETURNED_TRANSACTION
+
+
+A threadpool worker thread entered a callback, which left transaction state.
+
+This is unexpected, indicating that the callback missed clearing the transaction.
+
+0xC000071E
+
+STATUS_CALLBACK_RETURNED_LDR_LOCK
+
+
+A threadpool worker thread entered a callback, which left the loader lock held.
+
+This is unexpected, indicating that the callback missed releasing the lock.
+
+0xC000071F
+
+STATUS_CALLBACK_RETURNED_LANG
+
+
+A threadpool worker thread entered a callback, which left with preferred languages set.
+
+This is unexpected, indicating that the callback missed clearing them.
+
+0xC0000720
+
+STATUS_CALLBACK_RETURNED_PRI_BACK
+
+
+A threadpool worker thread entered a callback, which left with background priorities set.
+
+This is unexpected, indicating that the callback missed restoring the original priorities.
+
+0xC0000800
+
+STATUS_DISK_REPAIR_DISABLED
+
+
+The attempted operation required self healing to be enabled.
+
+0xC0000801
+
+STATUS_DS_DOMAIN_RENAME_IN_PROGRESS
+
+
+The directory service cannot perform the requested operation because a domain rename operation is in progress.
+
+0xC0000802
+
+STATUS_DISK_QUOTA_EXCEEDED
+
+
+An operation failed because the storage quota was exceeded.
+
+0xC0000804
+
+STATUS_CONTENT_BLOCKED
+
+
+An operation failed because the content was blocked.
+
+0xC0000805
+
+STATUS_BAD_CLUSTERS
+
+
+The operation could not be completed due to bad clusters on disk.
+
+0xC0000806
+
+STATUS_VOLUME_DIRTY
+
+
+The operation could not be completed because the volume is dirty. Please run the Chkdsk utility and try again.
+
+0xC0000901
+
+STATUS_FILE_CHECKED_OUT
+
+
+This file is checked out or locked for editing by another user.
+
+0xC0000902
+
+STATUS_CHECKOUT_REQUIRED
+
+
+The file must be checked out before saving changes.
+
+0xC0000903
+
+STATUS_BAD_FILE_TYPE
+
+
+The file type being saved or retrieved has been blocked.
+
+0xC0000904
+
+STATUS_FILE_TOO_LARGE
+
+
+The file size exceeds the limit allowed and cannot be saved.
+
+0xC0000905
+
+STATUS_FORMS_AUTH_REQUIRED
+
+
+Access Denied. Before opening files in this location, you must first browse to the e.g. site and select the option to log on automatically.
+
+0xC0000906
+
+STATUS_VIRUS_INFECTED
+
+
+The operation did not complete successfully because the file contains a virus.
+
+0xC0000907
+
+STATUS_VIRUS_DELETED
+
+
+This file contains a virus and cannot be opened. Due to the nature of this virus, the file has been removed from this location.
+
+0xC0000908
+
+STATUS_BAD_MCFG_TABLE
+
+
+The resources required for this device conflict with the MCFG table.
+
+0xC0000909
+
+STATUS_CANNOT_BREAK_OPLOCK
+
+
+The operation did not complete successfully because it would cause an oplock to be broken. The caller has requested that existing oplocks not be broken.
+
+0xC0009898
+
+STATUS_WOW_ASSERTION
+
+
+WOW Assertion Error.
+
+0xC000A000
+
+STATUS_INVALID_SIGNATURE
+
+
+The cryptographic signature is invalid.
+
+0xC000A001
+
+STATUS_HMAC_NOT_SUPPORTED
+
+
+The cryptographic provider does not support HMAC.
+
+0xC000A010
+
+STATUS_IPSEC_QUEUE_OVERFLOW
+
+
+The IPsec queue overflowed.
+
+0xC000A011
+
+STATUS_ND_QUEUE_OVERFLOW
+
+
+The neighbor discovery queue overflowed.
+
+0xC000A012
+
+STATUS_HOPLIMIT_EXCEEDED
+
+
+An Internet Control Message Protocol (ICMP) hop limit exceeded error was received.
+
+0xC000A013
+
+STATUS_PROTOCOL_NOT_SUPPORTED
+
+
+The protocol is not installed on the local machine.
+
+0xC000A080
+
+STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error might be caused by network connectivity issues. Try to save this file elsewhere.
+
+0xC000A081
+
+STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error was returned by the server on which the file exists. Try to save this file elsewhere.
+
+0xC000A082
+
+STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error might be caused if the device has been removed or the media is write-protected.
+
+0xC000A083
+
+STATUS_XML_PARSE_ERROR
+
+
+Windows was unable to parse the requested XML data.
+
+0xC000A084
+
+STATUS_XMLDSIG_ERROR
+
+
+An error was encountered while processing an XML digital signature.
+
+0xC000A085
+
+STATUS_WRONG_COMPARTMENT
+
+
+This indicates that the caller made the connection request in the wrong routing compartment.
+
+0xC000A086
+
+STATUS_AUTHIP_FAILURE
+
+
+This indicates that there was an AuthIP failure when attempting to connect to the remote host.
+
+0xC000A087
+
+STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS
+
+
+OID mapped groups cannot have members.
+
+0xC000A088
+
+STATUS_DS_OID_NOT_FOUND
+
+
+The specified OID cannot be found.
+
+0xC000A100
+
+STATUS_HASH_NOT_SUPPORTED
+
+
+Hash generation for the specified version and hash type is not enabled on server.
+
+0xC000A101
+
+STATUS_HASH_NOT_PRESENT
+
+
+The hash requests is not present or not up to date with the current file contents.
+
+0xC000A2A1
+
+STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED
+
+
+A file system filter on the server has not opted in for Offload Read support.
+
+0xC000A2A2
+
+STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED
+
+
+A file system filter on the server has not opted in for Offload Write support.
+
+0xC000A2A3
+
+STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED
+
+
+Offload read operations cannot be performed on:
+
+ Compressed files
+
+ Sparse files
+
+ Encrypted files
+
+ File system metadata files
+
+0xC000A2A4
+
+STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED
+
+
+Offload write operations cannot be performed on:
+
+ Compressed files
+
+ Sparse files
+
+ Encrypted files
+
+ File system metadata files
+
+0xC0010001
+
+DBG_NO_STATE_CHANGE
+
+
+The debugger did not perform a state change.
+
+0xC0010002
+
+DBG_APP_NOT_IDLE
+
+
+The debugger found that the application is not idle.
+
+0xC0020001
+
+RPC_NT_INVALID_STRING_BINDING
+
+
+The string binding is invalid.
+
+0xC0020002
+
+RPC_NT_WRONG_KIND_OF_BINDING
+
+
+The binding handle is not the correct type.
+
+0xC0020003
+
+RPC_NT_INVALID_BINDING
+
+
+The binding handle is invalid.
+
+0xC0020004
+
+RPC_NT_PROTSEQ_NOT_SUPPORTED
+
+
+The RPC protocol sequence is not supported.
+
+0xC0020005
+
+RPC_NT_INVALID_RPC_PROTSEQ
+
+
+The RPC protocol sequence is invalid.
+
+0xC0020006
+
+RPC_NT_INVALID_STRING_UUID
+
+
+The string UUID is invalid.
+
+0xC0020007
+
+RPC_NT_INVALID_ENDPOINT_FORMAT
+
+
+The endpoint format is invalid.
+
+0xC0020008
+
+RPC_NT_INVALID_NET_ADDR
+
+
+The network address is invalid.
+
+0xC0020009
+
+RPC_NT_NO_ENDPOINT_FOUND
+
+
+No endpoint was found.
+
+0xC002000A
+
+RPC_NT_INVALID_TIMEOUT
+
+
+The time-out value is invalid.
+
+0xC002000B
+
+RPC_NT_OBJECT_NOT_FOUND
+
+
+The object UUID was not found.
+
+0xC002000C
+
+RPC_NT_ALREADY_REGISTERED
+
+
+The object UUID has already been registered.
+
+0xC002000D
+
+RPC_NT_TYPE_ALREADY_REGISTERED
+
+
+The type UUID has already been registered.
+
+0xC002000E
+
+RPC_NT_ALREADY_LISTENING
+
+
+The RPC server is already listening.
+
+0xC002000F
+
+RPC_NT_NO_PROTSEQS_REGISTERED
+
+
+No protocol sequences have been registered.
+
+0xC0020010
+
+RPC_NT_NOT_LISTENING
+
+
+The RPC server is not listening.
+
+0xC0020011
+
+RPC_NT_UNKNOWN_MGR_TYPE
+
+
+The manager type is unknown.
+
+0xC0020012
+
+RPC_NT_UNKNOWN_IF
+
+
+The interface is unknown.
+
+0xC0020013
+
+RPC_NT_NO_BINDINGS
+
+
+There are no bindings.
+
+0xC0020014
+
+RPC_NT_NO_PROTSEQS
+
+
+There are no protocol sequences.
+
+0xC0020015
+
+RPC_NT_CANT_CREATE_ENDPOINT
+
+
+The endpoint cannot be created.
+
+0xC0020016
+
+RPC_NT_OUT_OF_RESOURCES
+
+
+Insufficient resources are available to complete this operation.
+
+0xC0020017
+
+RPC_NT_SERVER_UNAVAILABLE
+
+
+The RPC server is unavailable.
+
+0xC0020018
+
+RPC_NT_SERVER_TOO_BUSY
+
+
+The RPC server is too busy to complete this operation.
+
+0xC0020019
+
+RPC_NT_INVALID_NETWORK_OPTIONS
+
+
+The network options are invalid.
+
+0xC002001A
+
+RPC_NT_NO_CALL_ACTIVE
+
+
+No RPCs are active on this thread.
+
+0xC002001B
+
+RPC_NT_CALL_FAILED
+
+
+The RPC failed.
+
+0xC002001C
+
+RPC_NT_CALL_FAILED_DNE
+
+
+The RPC failed and did not execute.
+
+0xC002001D
+
+RPC_NT_PROTOCOL_ERROR
+
+
+An RPC protocol error occurred.
+
+0xC002001F
+
+RPC_NT_UNSUPPORTED_TRANS_SYN
+
+
+The RPC server does not support the transfer syntax.
+
+0xC0020021
+
+RPC_NT_UNSUPPORTED_TYPE
+
+
+The type UUID is not supported.
+
+0xC0020022
+
+RPC_NT_INVALID_TAG
+
+
+The tag is invalid.
+
+0xC0020023
+
+RPC_NT_INVALID_BOUND
+
+
+The array bounds are invalid.
+
+0xC0020024
+
+RPC_NT_NO_ENTRY_NAME
+
+
+The binding does not contain an entry name.
+
+0xC0020025
+
+RPC_NT_INVALID_NAME_SYNTAX
+
+
+The name syntax is invalid.
+
+0xC0020026
+
+RPC_NT_UNSUPPORTED_NAME_SYNTAX
+
+
+The name syntax is not supported.
+
+0xC0020028
+
+RPC_NT_UUID_NO_ADDRESS
+
+
+No network address is available to construct a UUID.
+
+0xC0020029
+
+RPC_NT_DUPLICATE_ENDPOINT
+
+
+The endpoint is a duplicate.
+
+0xC002002A
+
+RPC_NT_UNKNOWN_AUTHN_TYPE
+
+
+The authentication type is unknown.
+
+0xC002002B
+
+RPC_NT_MAX_CALLS_TOO_SMALL
+
+
+The maximum number of calls is too small.
+
+0xC002002C
+
+RPC_NT_STRING_TOO_LONG
+
+
+The string is too long.
+
+0xC002002D
+
+RPC_NT_PROTSEQ_NOT_FOUND
+
+
+The RPC protocol sequence was not found.
+
+0xC002002E
+
+RPC_NT_PROCNUM_OUT_OF_RANGE
+
+
+The procedure number is out of range.
+
+0xC002002F
+
+RPC_NT_BINDING_HAS_NO_AUTH
+
+
+The binding does not contain any authentication information.
+
+0xC0020030
+
+RPC_NT_UNKNOWN_AUTHN_SERVICE
+
+
+The authentication service is unknown.
+
+0xC0020031
+
+RPC_NT_UNKNOWN_AUTHN_LEVEL
+
+
+The authentication level is unknown.
+
+0xC0020032
+
+RPC_NT_INVALID_AUTH_IDENTITY
+
+
+The security context is invalid.
+
+0xC0020033
+
+RPC_NT_UNKNOWN_AUTHZ_SERVICE
+
+
+The authorization service is unknown.
+
+0xC0020034
+
+EPT_NT_INVALID_ENTRY
+
+
+The entry is invalid.
+
+0xC0020035
+
+EPT_NT_CANT_PERFORM_OP
+
+
+The operation cannot be performed.
+
+0xC0020036
+
+EPT_NT_NOT_REGISTERED
+
+
+No more endpoints are available from the endpoint mapper.
+
+0xC0020037
+
+RPC_NT_NOTHING_TO_EXPORT
+
+
+No interfaces have been exported.
+
+0xC0020038
+
+RPC_NT_INCOMPLETE_NAME
+
+
+The entry name is incomplete.
+
+0xC0020039
+
+RPC_NT_INVALID_VERS_OPTION
+
+
+The version option is invalid.
+
+0xC002003A
+
+RPC_NT_NO_MORE_MEMBERS
+
+
+There are no more members.
+
+0xC002003B
+
+RPC_NT_NOT_ALL_OBJS_UNEXPORTED
+
+
+There is nothing to unexport.
+
+0xC002003C
+
+RPC_NT_INTERFACE_NOT_FOUND
+
+
+The interface was not found.
+
+0xC002003D
+
+RPC_NT_ENTRY_ALREADY_EXISTS
+
+
+The entry already exists.
+
+0xC002003E
+
+RPC_NT_ENTRY_NOT_FOUND
+
+
+The entry was not found.
+
+0xC002003F
+
+RPC_NT_NAME_SERVICE_UNAVAILABLE
+
+
+The name service is unavailable.
+
+0xC0020040
+
+RPC_NT_INVALID_NAF_ID
+
+
+The network address family is invalid.
+
+0xC0020041
+
+RPC_NT_CANNOT_SUPPORT
+
+
+The requested operation is not supported.
+
+0xC0020042
+
+RPC_NT_NO_CONTEXT_AVAILABLE
+
+
+No security context is available to allow impersonation.
+
+0xC0020043
+
+RPC_NT_INTERNAL_ERROR
+
+
+An internal error occurred in the RPC.
+
+0xC0020044
+
+RPC_NT_ZERO_DIVIDE
+
+
+The RPC server attempted to divide an integer by zero.
+
+0xC0020045
+
+RPC_NT_ADDRESS_ERROR
+
+
+An addressing error occurred in the RPC server.
+
+0xC0020046
+
+RPC_NT_FP_DIV_ZERO
+
+
+A floating point operation at the RPC server caused a divide by zero.
+
+0xC0020047
+
+RPC_NT_FP_UNDERFLOW
+
+
+A floating point underflow occurred at the RPC server.
+
+0xC0020048
+
+RPC_NT_FP_OVERFLOW
+
+
+A floating point overflow occurred at the RPC server.
+
+0xC0020049
+
+RPC_NT_CALL_IN_PROGRESS
+
+
+An RPC is already in progress for this thread.
+
+0xC002004A
+
+RPC_NT_NO_MORE_BINDINGS
+
+
+There are no more bindings.
+
+0xC002004B
+
+RPC_NT_GROUP_MEMBER_NOT_FOUND
+
+
+The group member was not found.
+
+0xC002004C
+
+EPT_NT_CANT_CREATE
+
+
+The endpoint mapper database entry could not be created.
+
+0xC002004D
+
+RPC_NT_INVALID_OBJECT
+
+
+The object UUID is the nil UUID.
+
+0xC002004F
+
+RPC_NT_NO_INTERFACES
+
+
+No interfaces have been registered.
+
+0xC0020050
+
+RPC_NT_CALL_CANCELLED
+
+
+The RPC was canceled.
+
+0xC0020051
+
+RPC_NT_BINDING_INCOMPLETE
+
+
+The binding handle does not contain all the required information.
+
+0xC0020052
+
+RPC_NT_COMM_FAILURE
+
+
+A communications failure occurred during an RPC.
+
+0xC0020053
+
+RPC_NT_UNSUPPORTED_AUTHN_LEVEL
+
+
+The requested authentication level is not supported.
+
+0xC0020054
+
+RPC_NT_NO_PRINC_NAME
+
+
+No principal name was registered.
+
+0xC0020055
+
+RPC_NT_NOT_RPC_ERROR
+
+
+The error specified is not a valid Windows RPC error code.
+
+0xC0020057
+
+RPC_NT_SEC_PKG_ERROR
+
+
+A security package-specific error occurred.
+
+0xC0020058
+
+RPC_NT_NOT_CANCELLED
+
+
+The thread was not canceled.
+
+0xC0020062
+
+RPC_NT_INVALID_ASYNC_HANDLE
+
+
+Invalid asynchronous RPC handle.
+
+0xC0020063
+
+RPC_NT_INVALID_ASYNC_CALL
+
+
+Invalid asynchronous RPC call handle for this operation.
+
+0xC0020064
+
+RPC_NT_PROXY_ACCESS_DENIED
+
+
+Access to the HTTP proxy is denied.
+
+0xC0030001
+
+RPC_NT_NO_MORE_ENTRIES
+
+
+The list of RPC servers available for auto-handle binding has been exhausted.
+
+0xC0030002
+
+RPC_NT_SS_CHAR_TRANS_OPEN_FAIL
+
+
+The file designated by DCERPCCHARTRANS cannot be opened.
+
+0xC0030003
+
+RPC_NT_SS_CHAR_TRANS_SHORT_FILE
+
+
+The file containing the character translation table has fewer than 512 bytes.
+
+0xC0030004
+
+RPC_NT_SS_IN_NULL_CONTEXT
+
+
+A null context handle is passed as an [in] parameter.
+
+0xC0030005
+
+RPC_NT_SS_CONTEXT_MISMATCH
+
+
+The context handle does not match any known context handles.
+
+0xC0030006
+
+RPC_NT_SS_CONTEXT_DAMAGED
+
+
+The context handle changed during a call.
+
+0xC0030007
+
+RPC_NT_SS_HANDLES_MISMATCH
+
+
+The binding handles passed to an RPC do not match.
+
+0xC0030008
+
+RPC_NT_SS_CANNOT_GET_CALL_HANDLE
+
+
+The stub is unable to get the call handle.
+
+0xC0030009
+
+RPC_NT_NULL_REF_POINTER
+
+
+A null reference pointer was passed to the stub.
+
+0xC003000A
+
+RPC_NT_ENUM_VALUE_OUT_OF_RANGE
+
+
+The enumeration value is out of range.
+
+0xC003000B
+
+RPC_NT_BYTE_COUNT_TOO_SMALL
+
+
+The byte count is too small.
+
+0xC003000C
+
+RPC_NT_BAD_STUB_DATA
+
+
+The stub received bad data.
+
+0xC0030059
+
+RPC_NT_INVALID_ES_ACTION
+
+
+Invalid operation on the encoding/decoding handle.
+
+0xC003005A
+
+RPC_NT_WRONG_ES_VERSION
+
+
+Incompatible version of the serializing package.
+
+0xC003005B
+
+RPC_NT_WRONG_STUB_VERSION
+
+
+Incompatible version of the RPC stub.
+
+0xC003005C
+
+RPC_NT_INVALID_PIPE_OBJECT
+
+
+The RPC pipe object is invalid or corrupt.
+
+0xC003005D
+
+RPC_NT_INVALID_PIPE_OPERATION
+
+
+An invalid operation was attempted on an RPC pipe object.
+
+0xC003005E
+
+RPC_NT_WRONG_PIPE_VERSION
+
+
+Unsupported RPC pipe version.
+
+0xC003005F
+
+RPC_NT_PIPE_CLOSED
+
+
+The RPC pipe object has already been closed.
+
+0xC0030060
+
+RPC_NT_PIPE_DISCIPLINE_ERROR
+
+
+The RPC call completed before all pipes were processed.
+
+0xC0030061
+
+RPC_NT_PIPE_EMPTY
+
+
+No more data is available from the RPC pipe.
+
+0xC0040035
+
+STATUS_PNP_BAD_MPS_TABLE
+
+
+A device is missing in the system BIOS MPS table. This device will not be used. Contact your system vendor for a system BIOS update.
+
+0xC0040036
+
+STATUS_PNP_TRANSLATION_FAILED
+
+
+A translator failed to translate resources.
+
+0xC0040037
+
+STATUS_PNP_IRQ_TRANSLATION_FAILED
+
+
+An IRQ translator failed to translate resources.
+
+0xC0040038
+
+STATUS_PNP_INVALID_ID
+
+
+Driver %2 returned an invalid ID for a child device (%3).
+
+0xC0040039
+
+STATUS_IO_REISSUE_AS_CACHED
+
+
+Reissue the given operation as a cached I/O operation
+
+0xC00A0001
+
+STATUS_CTX_WINSTATION_NAME_INVALID
+
+
+Session name %1 is invalid.
+
+0xC00A0002
+
+STATUS_CTX_INVALID_PD
+
+
+The protocol driver %1 is invalid.
+
+0xC00A0003
+
+STATUS_CTX_PD_NOT_FOUND
+
+
+The protocol driver %1 was not found in the system path.
+
+0xC00A0006
+
+STATUS_CTX_CLOSE_PENDING
+
+
+A close operation is pending on the terminal connection.
+
+0xC00A0007
+
+STATUS_CTX_NO_OUTBUF
+
+
+No free output buffers are available.
+
+0xC00A0008
+
+STATUS_CTX_MODEM_INF_NOT_FOUND
+
+
+The MODEM.INF file was not found.
+
+0xC00A0009
+
+STATUS_CTX_INVALID_MODEMNAME
+
+
+The modem (%1) was not found in the MODEM.INF file.
+
+0xC00A000A
+
+STATUS_CTX_RESPONSE_ERROR
+
+
+The modem did not accept the command sent to it. Verify that the configured modem name matches the attached modem.
+
+0xC00A000B
+
+STATUS_CTX_MODEM_RESPONSE_TIMEOUT
+
+
+The modem did not respond to the command sent to it. Verify that the modem cable is properly attached and the modem is turned on.
+
+0xC00A000C
+
+STATUS_CTX_MODEM_RESPONSE_NO_CARRIER
+
+
+Carrier detection has failed or the carrier has been dropped due to disconnection.
+
+0xC00A000D
+
+STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE
+
+
+A dial tone was not detected within the required time. Verify that the phone cable is properly attached and functional.
+
+0xC00A000E
+
+STATUS_CTX_MODEM_RESPONSE_BUSY
+
+
+A busy signal was detected at a remote site on callback.
+
+0xC00A000F
+
+STATUS_CTX_MODEM_RESPONSE_VOICE
+
+
+A voice was detected at a remote site on callback.
+
+0xC00A0010
+
+STATUS_CTX_TD_ERROR
+
+
+Transport driver error.
+
+0xC00A0012
+
+STATUS_CTX_LICENSE_CLIENT_INVALID
+
+
+The client you are using is not licensed to use this system. Your logon request is denied.
+
+0xC00A0013
+
+STATUS_CTX_LICENSE_NOT_AVAILABLE
+
+
+The system has reached its licensed logon limit. Try again later.
+
+0xC00A0014
+
+STATUS_CTX_LICENSE_EXPIRED
+
+
+The system license has expired. Your logon request is denied.
+
+0xC00A0015
+
+STATUS_CTX_WINSTATION_NOT_FOUND
+
+
+The specified session cannot be found.
+
+0xC00A0016
+
+STATUS_CTX_WINSTATION_NAME_COLLISION
+
+
+The specified session name is already in use.
+
+0xC00A0017
+
+STATUS_CTX_WINSTATION_BUSY
+
+
+The requested operation cannot be completed because the terminal connection is currently processing a connect, disconnect, reset, or delete operation.
+
+0xC00A0018
+
+STATUS_CTX_BAD_VIDEO_MODE
+
+
+An attempt has been made to connect to a session whose video mode is not supported by the current client.
+
+0xC00A0022
+
+STATUS_CTX_GRAPHICS_INVALID
+
+
+The application attempted to enable DOS graphics mode. DOS graphics mode is not supported.
+
+0xC00A0024
+
+STATUS_CTX_NOT_CONSOLE
+
+
+The requested operation can be performed only on the system console. This is most often the result of a driver or system DLL requiring direct console access.
+
+0xC00A0026
+
+STATUS_CTX_CLIENT_QUERY_TIMEOUT
+
+
+The client failed to respond to the server connect message.
+
+0xC00A0027
+
+STATUS_CTX_CONSOLE_DISCONNECT
+
+
+Disconnecting the console session is not supported.
+
+0xC00A0028
+
+STATUS_CTX_CONSOLE_CONNECT
+
+
+Reconnecting a disconnected session to the console is not supported.
+
+0xC00A002A
+
+STATUS_CTX_SHADOW_DENIED
+
+
+The request to control another session remotely was denied.
+
+0xC00A002B
+
+STATUS_CTX_WINSTATION_ACCESS_DENIED
+
+
+A process has requested access to a session, but has not been granted those access rights.
+
+0xC00A002E
+
+STATUS_CTX_INVALID_WD
+
+
+The terminal connection driver %1 is invalid.
+
+0xC00A002F
+
+STATUS_CTX_WD_NOT_FOUND
+
+
+The terminal connection driver %1 was not found in the system path.
+
+0xC00A0030
+
+STATUS_CTX_SHADOW_INVALID
+
+
+The requested session cannot be controlled remotely. You cannot control your own session, a session that is trying to control your session, a session that has no user logged on, or other sessions from the console.
+
+0xC00A0031
+
+STATUS_CTX_SHADOW_DISABLED
+
+
+The requested session is not configured to allow remote control.
+
+0xC00A0032
+
+STATUS_RDP_PROTOCOL_ERROR
+
+
+The RDP protocol component %2 detected an error in the protocol stream and has disconnected the client.
+
+0xC00A0033
+
+STATUS_CTX_CLIENT_LICENSE_NOT_SET
+
+
+Your request to connect to this terminal server has been rejected. Your terminal server client license number has not been entered for this copy of the terminal client. Contact your system administrator for help in entering a valid, unique license number for this terminal server client. Click OK to continue.
+
+0xC00A0034
+
+STATUS_CTX_CLIENT_LICENSE_IN_USE
+
+
+Your request to connect to this terminal server has been rejected. Your terminal server client license number is currently being used by another user. Contact your system administrator to obtain a new copy of the terminal server client with a valid, unique license number. Click OK to continue.
+
+0xC00A0035
+
+STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE
+
+
+The remote control of the console was terminated because the display mode was changed. Changing the display mode in a remote control session is not supported.
+
+0xC00A0036
+
+STATUS_CTX_SHADOW_NOT_RUNNING
+
+
+Remote control could not be terminated because the specified session is not currently being remotely controlled.
+
+0xC00A0037
+
+STATUS_CTX_LOGON_DISABLED
+
+
+Your interactive logon privilege has been disabled. Contact your system administrator.
+
+0xC00A0038
+
+STATUS_CTX_SECURITY_LAYER_ERROR
+
+
+The terminal server security layer detected an error in the protocol stream and has disconnected the client.
+
+0xC00A0039
+
+STATUS_TS_INCOMPATIBLE_SESSIONS
+
+
+The target session is incompatible with the current session.
+
+0xC00B0001
+
+STATUS_MUI_FILE_NOT_FOUND
+
+
+The resource loader failed to find an MUI file.
+
+0xC00B0002
+
+STATUS_MUI_INVALID_FILE
+
+
+The resource loader failed to load an MUI file because the file failed to pass validation.
+
+0xC00B0003
+
+STATUS_MUI_INVALID_RC_CONFIG
+
+
+The RC manifest is corrupted with garbage data, is an unsupported version, or is missing a required item.
+
+0xC00B0004
+
+STATUS_MUI_INVALID_LOCALE_NAME
+
+
+The RC manifest has an invalid culture name.
+
+0xC00B0005
+
+STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME
+
+
+The RC manifest has and invalid ultimate fallback name.
+
+0xC00B0006
+
+STATUS_MUI_FILE_NOT_LOADED
+
+
+The resource loader cache does not have a loaded MUI entry.
+
+0xC00B0007
+
+STATUS_RESOURCE_ENUM_USER_STOP
+
+
+The user stopped resource enumeration.
+
+0xC0130001
+
+STATUS_CLUSTER_INVALID_NODE
+
+
+The cluster node is not valid.
+
+0xC0130002
+
+STATUS_CLUSTER_NODE_EXISTS
+
+
+The cluster node already exists.
+
+0xC0130003
+
+STATUS_CLUSTER_JOIN_IN_PROGRESS
+
+
+A node is in the process of joining the cluster.
+
+0xC0130004
+
+STATUS_CLUSTER_NODE_NOT_FOUND
+
+
+The cluster node was not found.
+
+0xC0130005
+
+STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND
+
+
+The cluster local node information was not found.
+
+0xC0130006
+
+STATUS_CLUSTER_NETWORK_EXISTS
+
+
+The cluster network already exists.
+
+0xC0130007
+
+STATUS_CLUSTER_NETWORK_NOT_FOUND
+
+
+The cluster network was not found.
+
+0xC0130008
+
+STATUS_CLUSTER_NETINTERFACE_EXISTS
+
+
+The cluster network interface already exists.
+
+0xC0130009
+
+STATUS_CLUSTER_NETINTERFACE_NOT_FOUND
+
+
+The cluster network interface was not found.
+
+0xC013000A
+
+STATUS_CLUSTER_INVALID_REQUEST
+
+
+The cluster request is not valid for this object.
+
+0xC013000B
+
+STATUS_CLUSTER_INVALID_NETWORK_PROVIDER
+
+
+The cluster network provider is not valid.
+
+0xC013000C
+
+STATUS_CLUSTER_NODE_DOWN
+
+
+The cluster node is down.
+
+0xC013000D
+
+STATUS_CLUSTER_NODE_UNREACHABLE
+
+
+The cluster node is not reachable.
+
+0xC013000E
+
+STATUS_CLUSTER_NODE_NOT_MEMBER
+
+
+The cluster node is not a member of the cluster.
+
+0xC013000F
+
+STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS
+
+
+A cluster join operation is not in progress.
+
+0xC0130010
+
+STATUS_CLUSTER_INVALID_NETWORK
+
+
+The cluster network is not valid.
+
+0xC0130011
+
+STATUS_CLUSTER_NO_NET_ADAPTERS
+
+
+No network adapters are available.
+
+0xC0130012
+
+STATUS_CLUSTER_NODE_UP
+
+
+The cluster node is up.
+
+0xC0130013
+
+STATUS_CLUSTER_NODE_PAUSED
+
+
+The cluster node is paused.
+
+0xC0130014
+
+STATUS_CLUSTER_NODE_NOT_PAUSED
+
+
+The cluster node is not paused.
+
+0xC0130015
+
+STATUS_CLUSTER_NO_SECURITY_CONTEXT
+
+
+No cluster security context is available.
+
+0xC0130016
+
+STATUS_CLUSTER_NETWORK_NOT_INTERNAL
+
+
+The cluster network is not configured for internal cluster communication.
+
+0xC0130017
+
+STATUS_CLUSTER_POISONED
+
+
+The cluster node has been poisoned.
+
+0xC0140001
+
+STATUS_ACPI_INVALID_OPCODE
+
+
+An attempt was made to run an invalid AML opcode.
+
+0xC0140002
+
+STATUS_ACPI_STACK_OVERFLOW
+
+
+The AML interpreter stack has overflowed.
+
+0xC0140003
+
+STATUS_ACPI_ASSERT_FAILED
+
+
+An inconsistent state has occurred.
+
+0xC0140004
+
+STATUS_ACPI_INVALID_INDEX
+
+
+An attempt was made to access an array outside its bounds.
+
+0xC0140005
+
+STATUS_ACPI_INVALID_ARGUMENT
+
+
+A required argument was not specified.
+
+0xC0140006
+
+STATUS_ACPI_FATAL
+
+
+A fatal error has occurred.
+
+0xC0140007
+
+STATUS_ACPI_INVALID_SUPERNAME
+
+
+An invalid SuperName was specified.
+
+0xC0140008
+
+STATUS_ACPI_INVALID_ARGTYPE
+
+
+An argument with an incorrect type was specified.
+
+0xC0140009
+
+STATUS_ACPI_INVALID_OBJTYPE
+
+
+An object with an incorrect type was specified.
+
+0xC014000A
+
+STATUS_ACPI_INVALID_TARGETTYPE
+
+
+A target with an incorrect type was specified.
+
+0xC014000B
+
+STATUS_ACPI_INCORRECT_ARGUMENT_COUNT
+
+
+An incorrect number of arguments was specified.
+
+0xC014000C
+
+STATUS_ACPI_ADDRESS_NOT_MAPPED
+
+
+An address failed to translate.
+
+0xC014000D
+
+STATUS_ACPI_INVALID_EVENTTYPE
+
+
+An incorrect event type was specified.
+
+0xC014000E
+
+STATUS_ACPI_HANDLER_COLLISION
+
+
+A handler for the target already exists.
+
+0xC014000F
+
+STATUS_ACPI_INVALID_DATA
+
+
+Invalid data for the target was specified.
+
+0xC0140010
+
+STATUS_ACPI_INVALID_REGION
+
+
+An invalid region for the target was specified.
+
+0xC0140011
+
+STATUS_ACPI_INVALID_ACCESS_SIZE
+
+
+An attempt was made to access a field outside the defined range.
+
+0xC0140012
+
+STATUS_ACPI_ACQUIRE_GLOBAL_LOCK
+
+
+The global system lock could not be acquired.
+
+0xC0140013
+
+STATUS_ACPI_ALREADY_INITIALIZED
+
+
+An attempt was made to reinitialize the ACPI subsystem.
+
+0xC0140014
+
+STATUS_ACPI_NOT_INITIALIZED
+
+
+The ACPI subsystem has not been initialized.
+
+0xC0140015
+
+STATUS_ACPI_INVALID_MUTEX_LEVEL
+
+
+An incorrect mutex was specified.
+
+0xC0140016
+
+STATUS_ACPI_MUTEX_NOT_OWNED
+
+
+The mutex is not currently owned.
+
+0xC0140017
+
+STATUS_ACPI_MUTEX_NOT_OWNER
+
+
+An attempt was made to access the mutex by a process that was not the owner.
+
+0xC0140018
+
+STATUS_ACPI_RS_ACCESS
+
+
+An error occurred during an access to region space.
+
+0xC0140019
+
+STATUS_ACPI_INVALID_TABLE
+
+
+An attempt was made to use an incorrect table.
+
+0xC0140020
+
+STATUS_ACPI_REG_HANDLER_FAILED
+
+
+The registration of an ACPI event failed.
+
+0xC0140021
+
+STATUS_ACPI_POWER_REQUEST_FAILED
+
+
+An ACPI power object failed to transition state.
+
+0xC0150001
+
+STATUS_SXS_SECTION_NOT_FOUND
+
+
+The requested section is not present in the activation context.
+
+0xC0150002
+
+STATUS_SXS_CANT_GEN_ACTCTX
+
+
+Windows was unble to process the application binding information. Refer to the system event log for further information.
+
+0xC0150003
+
+STATUS_SXS_INVALID_ACTCTXDATA_FORMAT
+
+
+The application binding data format is invalid.
+
+0xC0150004
+
+STATUS_SXS_ASSEMBLY_NOT_FOUND
+
+
+The referenced assembly is not installed on the system.
+
+0xC0150005
+
+STATUS_SXS_MANIFEST_FORMAT_ERROR
+
+
+The manifest file does not begin with the required tag and format information.
+
+0xC0150006
+
+STATUS_SXS_MANIFEST_PARSE_ERROR
+
+
+The manifest file contains one or more syntax errors.
+
+0xC0150007
+
+STATUS_SXS_ACTIVATION_CONTEXT_DISABLED
+
+
+The application attempted to activate a disabled activation context.
+
+0xC0150008
+
+STATUS_SXS_KEY_NOT_FOUND
+
+
+The requested lookup key was not found in any active activation context.
+
+0xC0150009
+
+STATUS_SXS_VERSION_CONFLICT
+
+
+A component version required by the application conflicts with another component version that is already active.
+
+0xC015000A
+
+STATUS_SXS_WRONG_SECTION_TYPE
+
+
+The type requested activation context section does not match the query API used.
+
+0xC015000B
+
+STATUS_SXS_THREAD_QUERIES_DISABLED
+
+
+Lack of system resources has required isolated activation to be disabled for the current thread of execution.
+
+0xC015000C
+
+STATUS_SXS_ASSEMBLY_MISSING
+
+
+The referenced assembly could not be found.
+
+0xC015000E
+
+STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET
+
+
+An attempt to set the process default activation context failed because the process default activation context was already set.
+
+0xC015000F
+
+STATUS_SXS_EARLY_DEACTIVATION
+
+
+The activation context being deactivated is not the most recently activated one.
+
+0xC0150010
+
+STATUS_SXS_INVALID_DEACTIVATION
+
+
+The activation context being deactivated is not active for the current thread of execution.
+
+0xC0150011
+
+STATUS_SXS_MULTIPLE_DEACTIVATION
+
+
+The activation context being deactivated has already been deactivated.
+
+0xC0150012
+
+STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY
+
+
+The activation context of the system default assembly could not be generated.
+
+0xC0150013
+
+STATUS_SXS_PROCESS_TERMINATION_REQUESTED
+
+
+A component used by the isolation facility has requested that the process be terminated.
+
+0xC0150014
+
+STATUS_SXS_CORRUPT_ACTIVATION_STACK
+
+
+The activation context activation stack for the running thread of execution is corrupt.
+
+0xC0150015
+
+STATUS_SXS_CORRUPTION
+
+
+The application isolation metadata for this process or thread has become corrupt.
+
+0xC0150016
+
+STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE
+
+
+The value of an attribute in an identity is not within the legal range.
+
+0xC0150017
+
+STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME
+
+
+The name of an attribute in an identity is not within the legal range.
+
+0xC0150018
+
+STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE
+
+
+An identity contains two definitions for the same attribute.
+
+0xC0150019
+
+STATUS_SXS_IDENTITY_PARSE_ERROR
+
+
+The identity string is malformed. This might be due to a trailing comma, more than two unnamed attributes, a missing attribute name, or a missing attribute value.
+
+0xC015001A
+
+STATUS_SXS_COMPONENT_STORE_CORRUPT
+
+
+The component store has become corrupted.
+
+0xC015001B
+
+STATUS_SXS_FILE_HASH_MISMATCH
+
+
+A component's file does not match the verification information present in the component manifest.
+
+0xC015001C
+
+STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT
+
+
+The identities of the manifests are identical, but their contents are different.
+
+0xC015001D
+
+STATUS_SXS_IDENTITIES_DIFFERENT
+
+
+The component identities are different.
+
+0xC015001E
+
+STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT
+
+
+The assembly is not a deployment.
+
+0xC015001F
+
+STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY
+
+
+The file is not a part of the assembly.
+
+0xC0150020
+
+STATUS_ADVANCED_INSTALLER_FAILED
+
+
+An advanced installer failed during setup or servicing.
+
+0xC0150021
+
+STATUS_XML_ENCODING_MISMATCH
+
+
+The character encoding in the XML declaration did not match the encoding used in the document.
+
+0xC0150022
+
+STATUS_SXS_MANIFEST_TOO_BIG
+
+
+The size of the manifest exceeds the maximum allowed.
+
+0xC0150023
+
+STATUS_SXS_SETTING_NOT_REGISTERED
+
+
+The setting is not registered.
+
+0xC0150024
+
+STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE
+
+
+One or more required transaction members are not present.
+
+0xC0150025
+
+STATUS_SMI_PRIMITIVE_INSTALLER_FAILED
+
+
+The SMI primitive installer failed during setup or servicing.
+
+0xC0150026
+
+STATUS_GENERIC_COMMAND_FAILED
+
+
+A generic command executable returned a result that indicates failure.
+
+0xC0150027
+
+STATUS_SXS_FILE_HASH_MISSING
+
+
+A component is missing file verification information in its manifest.
+
+0xC0190001
+
+STATUS_TRANSACTIONAL_CONFLICT
+
+
+The function attempted to use a name that is reserved for use by another transaction.
+
+0xC0190002
+
+STATUS_INVALID_TRANSACTION
+
+
+The transaction handle associated with this operation is invalid.
+
+0xC0190003
+
+STATUS_TRANSACTION_NOT_ACTIVE
+
+
+The requested operation was made in the context of a transaction that is no longer active.
+
+0xC0190004
+
+STATUS_TM_INITIALIZATION_FAILED
+
+
+The transaction manager was unable to be successfully initialized. Transacted operations are not supported.
+
+0xC0190005
+
+STATUS_RM_NOT_ACTIVE
+
+
+Transaction support within the specified file system resource manager was not started or was shut down due to an error.
+
+0xC0190006
+
+STATUS_RM_METADATA_CORRUPT
+
+
+The metadata of the resource manager has been corrupted. The resource manager will not function.
+
+0xC0190007
+
+STATUS_TRANSACTION_NOT_JOINED
+
+
+The resource manager attempted to prepare a transaction that it has not successfully joined.
+
+0xC0190008
+
+STATUS_DIRECTORY_NOT_RM
+
+
+The specified directory does not contain a file system resource manager.
+
+0xC019000A
+
+STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE
+
+
+The remote server or share does not support transacted file operations.
+
+0xC019000B
+
+STATUS_LOG_RESIZE_INVALID_SIZE
+
+
+The requested log size for the file system resource manager is invalid.
+
+0xC019000C
+
+STATUS_REMOTE_FILE_VERSION_MISMATCH
+
+
+The remote server sent mismatching version number or Fid for a file opened with transactions.
+
+0xC019000F
+
+STATUS_CRM_PROTOCOL_ALREADY_EXISTS
+
+
+The resource manager tried to register a protocol that already exists.
+
+0xC0190010
+
+STATUS_TRANSACTION_PROPAGATION_FAILED
+
+
+The attempt to propagate the transaction failed.
+
+0xC0190011
+
+STATUS_CRM_PROTOCOL_NOT_FOUND
+
+
+The requested propagation protocol was not registered as a CRM.
+
+0xC0190012
+
+STATUS_TRANSACTION_SUPERIOR_EXISTS
+
+
+The transaction object already has a superior enlistment, and the caller attempted an operation that would have created a new superior. Only a single superior enlistment is allowed.
+
+0xC0190013
+
+STATUS_TRANSACTION_REQUEST_NOT_VALID
+
+
+The requested operation is not valid on the transaction object in its current state.
+
+0xC0190014
+
+STATUS_TRANSACTION_NOT_REQUESTED
+
+
+The caller has called a response API, but the response is not expected because the transaction manager did not issue the corresponding request to the caller.
+
+0xC0190015
+
+STATUS_TRANSACTION_ALREADY_ABORTED
+
+
+It is too late to perform the requested operation, because the transaction has already been aborted.
+
+0xC0190016
+
+STATUS_TRANSACTION_ALREADY_COMMITTED
+
+
+It is too late to perform the requested operation, because the transaction has already been committed.
+
+0xC0190017
+
+STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER
+
+
+The buffer passed in to NtPushTransaction or NtPullTransaction is not in a valid format.
+
+0xC0190018
+
+STATUS_CURRENT_TRANSACTION_NOT_VALID
+
+
+The current transaction context associated with the thread is not a valid handle to a transaction object.
+
+0xC0190019
+
+STATUS_LOG_GROWTH_FAILED
+
+
+An attempt to create space in the transactional resource manager's log failed. The failure status has been recorded in the event log.
+
+0xC0190021
+
+STATUS_OBJECT_NO_LONGER_EXISTS
+
+
+The object (file, stream, or link) that corresponds to the handle has been deleted by a transaction savepoint rollback.
+
+0xC0190022
+
+STATUS_STREAM_MINIVERSION_NOT_FOUND
+
+
+The specified file miniversion was not found for this transacted file open.
+
+0xC0190023
+
+STATUS_STREAM_MINIVERSION_NOT_VALID
+
+
+The specified file miniversion was found but has been invalidated. The most likely cause is a transaction savepoint rollback.
+
+0xC0190024
+
+STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION
+
+
+A miniversion can be opened only in the context of the transaction that created it.
+
+0xC0190025
+
+STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT
+
+
+It is not possible to open a miniversion with modify access.
+
+0xC0190026
+
+STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS
+
+
+It is not possible to create any more miniversions for this stream.
+
+0xC0190028
+
+STATUS_HANDLE_NO_LONGER_VALID
+
+
+The handle has been invalidated by a transaction. The most likely cause is the presence of memory mapping on a file or an open handle when the transaction ended or rolled back to savepoint.
+
+0xC0190030
+
+STATUS_LOG_CORRUPTION_DETECTED
+
+
+The log data is corrupt.
+
+0xC0190032
+
+STATUS_RM_DISCONNECTED
+
+
+The transaction outcome is unavailable because the resource manager responsible for it is disconnected.
+
+0xC0190033
+
+STATUS_ENLISTMENT_NOT_SUPERIOR
+
+
+The request was rejected because the enlistment in question is not a superior enlistment.
+
+0xC0190036
+
+STATUS_FILE_IDENTITY_NOT_PERSISTENT
+
+
+The file cannot be opened in a transaction because its identity depends on the outcome of an unresolved transaction.
+
+0xC0190037
+
+STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY
+
+
+The operation cannot be performed because another transaction is depending on this property not changing.
+
+0xC0190038
+
+STATUS_CANT_CROSS_RM_BOUNDARY
+
+
+The operation would involve a single file with two transactional resource managers and is, therefore, not allowed.
+
+0xC0190039
+
+STATUS_TXF_DIR_NOT_EMPTY
+
+
+The $Txf directory must be empty for this operation to succeed.
+
+0xC019003A
+
+STATUS_INDOUBT_TRANSACTIONS_EXIST
+
+
+The operation would leave a transactional resource manager in an inconsistent state and is therefore not allowed.
+
+0xC019003B
+
+STATUS_TM_VOLATILE
+
+
+The operation could not be completed because the transaction manager does not have a log.
+
+0xC019003C
+
+STATUS_ROLLBACK_TIMER_EXPIRED
+
+
+A rollback could not be scheduled because a previously scheduled rollback has already executed or been queued for execution.
+
+0xC019003D
+
+STATUS_TXF_ATTRIBUTE_CORRUPT
+
+
+The transactional metadata attribute on the file or directory %hs is corrupt and unreadable.
+
+0xC019003E
+
+STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION
+
+
+The encryption operation could not be completed because a transaction is active.
+
+0xC019003F
+
+STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED
+
+
+This object is not allowed to be opened in a transaction.
+
+0xC0190040
+
+STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE
+
+
+Memory mapping (creating a mapped section) a remote file under a transaction is not supported.
+
+0xC0190043
+
+STATUS_TRANSACTION_REQUIRED_PROMOTION
+
+
+Promotion was required to allow the resource manager to enlist, but the transaction was set to disallow it.
+
+0xC0190044
+
+STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION
+
+
+This file is open for modification in an unresolved transaction and can be opened for execute only by a transacted reader.
+
+0xC0190045
+
+STATUS_TRANSACTIONS_NOT_FROZEN
+
+
+The request to thaw frozen transactions was ignored because transactions were not previously frozen.
+
+0xC0190046
+
+STATUS_TRANSACTION_FREEZE_IN_PROGRESS
+
+
+Transactions cannot be frozen because a freeze is already in progress.
+
+0xC0190047
+
+STATUS_NOT_SNAPSHOT_VOLUME
+
+
+The target volume is not a snapshot volume. This operation is valid only on a volume mounted as a snapshot.
+
+0xC0190048
+
+STATUS_NO_SAVEPOINT_WITH_OPEN_FILES
+
+
+The savepoint operation failed because files are open on the transaction, which is not permitted.
+
+0xC0190049
+
+STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION
+
+
+The sparse operation could not be completed because a transaction is active on the file.
+
+0xC019004A
+
+STATUS_TM_IDENTITY_MISMATCH
+
+
+The call to create a transaction manager object failed because the Tm Identity that is stored in the log file does not match the Tm Identity that was passed in as an argument.
+
+0xC019004B
+
+STATUS_FLOATED_SECTION
+
+
+I/O was attempted on a section object that has been floated as a result of a transaction ending. There is no valid data.
+
+0xC019004C
+
+STATUS_CANNOT_ACCEPT_TRANSACTED_WORK
+
+
+The transactional resource manager cannot currently accept transacted work due to a transient condition, such as low resources.
+
+0xC019004D
+
+STATUS_CANNOT_ABORT_TRANSACTIONS
+
+
+The transactional resource manager had too many transactions outstanding that could not be aborted. The transactional resource manager has been shut down.
+
+0xC019004E
+
+STATUS_TRANSACTION_NOT_FOUND
+
+
+The specified transaction was unable to be opened because it was not found.
+
+0xC019004F
+
+STATUS_RESOURCEMANAGER_NOT_FOUND
+
+
+The specified resource manager was unable to be opened because it was not found.
+
+0xC0190050
+
+STATUS_ENLISTMENT_NOT_FOUND
+
+
+The specified enlistment was unable to be opened because it was not found.
+
+0xC0190051
+
+STATUS_TRANSACTIONMANAGER_NOT_FOUND
+
+
+The specified transaction manager was unable to be opened because it was not found.
+
+0xC0190052
+
+STATUS_TRANSACTIONMANAGER_NOT_ONLINE
+
+
+The specified resource manager was unable to create an enlistment because its associated transaction manager is not online.
+
+0xC0190053
+
+STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION
+
+
+The specified transaction manager was unable to create the objects contained in its log file in the Ob namespace. Therefore, the transaction manager was unable to recover.
+
+0xC0190054
+
+STATUS_TRANSACTION_NOT_ROOT
+
+
+The call to create a superior enlistment on this transaction object could not be completed because the transaction object specified for the enlistment is a subordinate branch of the transaction. Only the root of the transaction can be enlisted as a superior.
+
+0xC0190055
+
+STATUS_TRANSACTION_OBJECT_EXPIRED
+
+
+Because the associated transaction manager or resource manager has been closed, the handle is no longer valid.
+
+0xC0190056
+
+STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION
+
+
+The compression operation could not be completed because a transaction is active on the file.
+
+0xC0190057
+
+STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED
+
+
+The specified operation could not be performed on this superior enlistment because the enlistment was not created with the corresponding completion response in the NotificationMask.
+
+0xC0190058
+
+STATUS_TRANSACTION_RECORD_TOO_LONG
+
+
+The specified operation could not be performed because the record to be logged was too long. This can occur because either there are too many enlistments on this transaction or the combined RecoveryInformation being logged on behalf of those enlistments is too long.
+
+0xC0190059
+
+STATUS_NO_LINK_TRACKING_IN_TRANSACTION
+
+
+The link-tracking operation could not be completed because a transaction is active.
+
+0xC019005A
+
+STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION
+
+
+This operation cannot be performed in a transaction.
+
+0xC019005B
+
+STATUS_TRANSACTION_INTEGRITY_VIOLATED
+
+
+The kernel transaction manager had to abort or forget the transaction because it blocked forward progress.
+
+0xC0190060
+
+STATUS_EXPIRED_HANDLE
+
+
+The handle is no longer properly associated with its transaction. It might have been opened in a transactional resource manager that was subsequently forced to restart. Please close the handle and open a new one.
+
+0xC0190061
+
+STATUS_TRANSACTION_NOT_ENLISTED
+
+
+The specified operation could not be performed because the resource manager is not enlisted in the transaction.
+
+0xC01A0001
+
+STATUS_LOG_SECTOR_INVALID
+
+
+The log service found an invalid log sector.
+
+0xC01A0002
+
+STATUS_LOG_SECTOR_PARITY_INVALID
+
+
+The log service encountered a log sector with invalid block parity.
+
+0xC01A0003
+
+STATUS_LOG_SECTOR_REMAPPED
+
+
+The log service encountered a remapped log sector.
+
+0xC01A0004
+
+STATUS_LOG_BLOCK_INCOMPLETE
+
+
+The log service encountered a partial or incomplete log block.
+
+0xC01A0005
+
+STATUS_LOG_INVALID_RANGE
+
+
+The log service encountered an attempt to access data outside the active log range.
+
+0xC01A0006
+
+STATUS_LOG_BLOCKS_EXHAUSTED
+
+
+The log service user-log marshaling buffers are exhausted.
+
+0xC01A0007
+
+STATUS_LOG_READ_CONTEXT_INVALID
+
+
+The log service encountered an attempt to read from a marshaling area with an invalid read context.
+
+0xC01A0008
+
+STATUS_LOG_RESTART_INVALID
+
+
+The log service encountered an invalid log restart area.
+
+0xC01A0009
+
+STATUS_LOG_BLOCK_VERSION
+
+
+The log service encountered an invalid log block version.
+
+0xC01A000A
+
+STATUS_LOG_BLOCK_INVALID
+
+
+The log service encountered an invalid log block.
+
+0xC01A000B
+
+STATUS_LOG_READ_MODE_INVALID
+
+
+The log service encountered an attempt to read the log with an invalid read mode.
+
+0xC01A000D
+
+STATUS_LOG_METADATA_CORRUPT
+
+
+The log service encountered a corrupted metadata file.
+
+0xC01A000E
+
+STATUS_LOG_METADATA_INVALID
+
+
+The log service encountered a metadata file that could not be created by the log file system.
+
+0xC01A000F
+
+STATUS_LOG_METADATA_INCONSISTENT
+
+
+The log service encountered a metadata file with inconsistent data.
+
+0xC01A0010
+
+STATUS_LOG_RESERVATION_INVALID
+
+
+The log service encountered an attempt to erroneously allocate or dispose reservation space.
+
+0xC01A0011
+
+STATUS_LOG_CANT_DELETE
+
+
+The log service cannot delete the log file or the file system container.
+
+0xC01A0012
+
+STATUS_LOG_CONTAINER_LIMIT_EXCEEDED
+
+
+The log service has reached the maximum allowable containers allocated to a log file.
+
+0xC01A0013
+
+STATUS_LOG_START_OF_LOG
+
+
+The log service has attempted to read or write backward past the start of the log.
+
+0xC01A0014
+
+STATUS_LOG_POLICY_ALREADY_INSTALLED
+
+
+The log policy could not be installed because a policy of the same type is already present.
+
+0xC01A0015
+
+STATUS_LOG_POLICY_NOT_INSTALLED
+
+
+The log policy in question was not installed at the time of the request.
+
+0xC01A0016
+
+STATUS_LOG_POLICY_INVALID
+
+
+The installed set of policies on the log is invalid.
+
+0xC01A0017
+
+STATUS_LOG_POLICY_CONFLICT
+
+
+A policy on the log in question prevented the operation from completing.
+
+0xC01A0018
+
+STATUS_LOG_PINNED_ARCHIVE_TAIL
+
+
+The log space cannot be reclaimed because the log is pinned by the archive tail.
+
+0xC01A0019
+
+STATUS_LOG_RECORD_NONEXISTENT
+
+
+The log record is not a record in the log file.
+
+0xC01A001A
+
+STATUS_LOG_RECORDS_RESERVED_INVALID
+
+
+The number of reserved log records or the adjustment of the number of reserved log records is invalid.
+
+0xC01A001B
+
+STATUS_LOG_SPACE_RESERVED_INVALID
+
+
+The reserved log space or the adjustment of the log space is invalid.
+
+0xC01A001C
+
+STATUS_LOG_TAIL_INVALID
+
+
+A new or existing archive tail or the base of the active log is invalid.
+
+0xC01A001D
+
+STATUS_LOG_FULL
+
+
+The log space is exhausted.
+
+0xC01A001E
+
+STATUS_LOG_MULTIPLEXED
+
+
+The log is multiplexed; no direct writes to the physical log are allowed.
+
+0xC01A001F
+
+STATUS_LOG_DEDICATED
+
+
+The operation failed because the log is dedicated.
+
+0xC01A0020
+
+STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS
+
+
+The operation requires an archive context.
+
+0xC01A0021
+
+STATUS_LOG_ARCHIVE_IN_PROGRESS
+
+
+Log archival is in progress.
+
+0xC01A0022
+
+STATUS_LOG_EPHEMERAL
+
+
+The operation requires a nonephemeral log, but the log is ephemeral.
+
+0xC01A0023
+
+STATUS_LOG_NOT_ENOUGH_CONTAINERS
+
+
+The log must have at least two containers before it can be read from or written to.
+
+0xC01A0024
+
+STATUS_LOG_CLIENT_ALREADY_REGISTERED
+
+
+A log client has already registered on the stream.
+
+0xC01A0025
+
+STATUS_LOG_CLIENT_NOT_REGISTERED
+
+
+A log client has not been registered on the stream.
+
+0xC01A0026
+
+STATUS_LOG_FULL_HANDLER_IN_PROGRESS
+
+
+A request has already been made to handle the log full condition.
+
+0xC01A0027
+
+STATUS_LOG_CONTAINER_READ_FAILED
+
+
+The log service encountered an error when attempting to read from a log container.
+
+0xC01A0028
+
+STATUS_LOG_CONTAINER_WRITE_FAILED
+
+
+The log service encountered an error when attempting to write to a log container.
+
+0xC01A0029
+
+STATUS_LOG_CONTAINER_OPEN_FAILED
+
+
+The log service encountered an error when attempting to open a log container.
+
+0xC01A002A
+
+STATUS_LOG_CONTAINER_STATE_INVALID
+
+
+The log service encountered an invalid container state when attempting a requested action.
+
+0xC01A002B
+
+STATUS_LOG_STATE_INVALID
+
+
+The log service is not in the correct state to perform a requested action.
+
+0xC01A002C
+
+STATUS_LOG_PINNED
+
+
+The log space cannot be reclaimed because the log is pinned.
+
+0xC01A002D
+
+STATUS_LOG_METADATA_FLUSH_FAILED
+
+
+The log metadata flush failed.
+
+0xC01A002E
+
+STATUS_LOG_INCONSISTENT_SECURITY
+
+
+Security on the log and its containers is inconsistent.
+
+0xC01A002F
+
+STATUS_LOG_APPENDED_FLUSH_FAILED
+
+
+Records were appended to the log or reservation changes were made, but the log could not be flushed.
+
+0xC01A0030
+
+STATUS_LOG_PINNED_RESERVATION
+
+
+The log is pinned due to reservation consuming most of the log space. Free some reserved records to make space available.
+
+0xC01B00EA
+
+STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD
+
+
+{Display Driver Stopped Responding} The %hs display driver has stopped working normally. Save your work and reboot the system to restore full display functionality. The next time you reboot the computer, a dialog box will allow you to upload data about this failure to Microsoft.
+
+0xC01C0001
+
+STATUS_FLT_NO_HANDLER_DEFINED
+
+
+A handler was not defined by the filter for this operation.
+
+0xC01C0002
+
+STATUS_FLT_CONTEXT_ALREADY_DEFINED
+
+
+A context is already defined for this object.
+
+0xC01C0003
+
+STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST
+
+
+Asynchronous requests are not valid for this operation.
+
+0xC01C0004
+
+STATUS_FLT_DISALLOW_FAST_IO
+
+
+This is an internal error code used by the filter manager to determine if a fast I/O operation should be forced down the input/output request packet (IRP) path. Minifilters should never return this value.
+
+0xC01C0005
+
+STATUS_FLT_INVALID_NAME_REQUEST
+
+
+An invalid name request was made. The name requested cannot be retrieved at this time.
+
+0xC01C0006
+
+STATUS_FLT_NOT_SAFE_TO_POST_OPERATION
+
+
+Posting this operation to a worker thread for further processing is not safe at this time because it could lead to a system deadlock.
+
+0xC01C0007
+
+STATUS_FLT_NOT_INITIALIZED
+
+
+The Filter Manager was not initialized when a filter tried to register. Make sure that the Filter Manager is loaded as a driver.
+
+0xC01C0008
+
+STATUS_FLT_FILTER_NOT_READY
+
+
+The filter is not ready for attachment to volumes because it has not finished initializing (FltStartFiltering has not been called).
+
+0xC01C0009
+
+STATUS_FLT_POST_OPERATION_CLEANUP
+
+
+The filter must clean up any operation-specific context at this time because it is being removed from the system before the operation is completed by the lower drivers.
+
+0xC01C000A
+
+STATUS_FLT_INTERNAL_ERROR
+
+
+The Filter Manager had an internal error from which it cannot recover; therefore, the operation has failed. This is usually the result of a filter returning an invalid value from a pre-operation callback.
+
+0xC01C000B
+
+STATUS_FLT_DELETING_OBJECT
+
+
+The object specified for this action is in the process of being deleted; therefore, the action requested cannot be completed at this time.
+
+0xC01C000C
+
+STATUS_FLT_MUST_BE_NONPAGED_POOL
+
+
+A nonpaged pool must be used for this type of context.
+
+0xC01C000D
+
+STATUS_FLT_DUPLICATE_ENTRY
+
+
+A duplicate handler definition has been provided for an operation.
+
+0xC01C000E
+
+STATUS_FLT_CBDQ_DISABLED
+
+
+The callback data queue has been disabled.
+
+0xC01C000F
+
+STATUS_FLT_DO_NOT_ATTACH
+
+
+Do not attach the filter to the volume at this time.
+
+0xC01C0010
+
+STATUS_FLT_DO_NOT_DETACH
+
+
+Do not detach the filter from the volume at this time.
+
+0xC01C0011
+
+STATUS_FLT_INSTANCE_ALTITUDE_COLLISION
+
+
+An instance already exists at this altitude on the volume specified.
+
+0xC01C0012
+
+STATUS_FLT_INSTANCE_NAME_COLLISION
+
+
+An instance already exists with this name on the volume specified.
+
+0xC01C0013
+
+STATUS_FLT_FILTER_NOT_FOUND
+
+
+The system could not find the filter specified.
+
+0xC01C0014
+
+STATUS_FLT_VOLUME_NOT_FOUND
+
+
+The system could not find the volume specified.
+
+0xC01C0015
+
+STATUS_FLT_INSTANCE_NOT_FOUND
+
+
+The system could not find the instance specified.
+
+0xC01C0016
+
+STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND
+
+
+No registered context allocation definition was found for the given request.
+
+0xC01C0017
+
+STATUS_FLT_INVALID_CONTEXT_REGISTRATION
+
+
+An invalid parameter was specified during context registration.
+
+0xC01C0018
+
+STATUS_FLT_NAME_CACHE_MISS
+
+
+The name requested was not found in the Filter Manager name cache and could not be retrieved from the file system.
+
+0xC01C0019
+
+STATUS_FLT_NO_DEVICE_OBJECT
+
+
+The requested device object does not exist for the given volume.
+
+0xC01C001A
+
+STATUS_FLT_VOLUME_ALREADY_MOUNTED
+
+
+The specified volume is already mounted.
+
+0xC01C001B
+
+STATUS_FLT_ALREADY_ENLISTED
+
+
+The specified transaction context is already enlisted in a transaction.
+
+0xC01C001C
+
+STATUS_FLT_CONTEXT_ALREADY_LINKED
+
+
+The specified context is already attached to another object.
+
+0xC01C0020
+
+STATUS_FLT_NO_WAITER_FOR_REPLY
+
+
+No waiter is present for the filter's reply to this message.
+
+0xC01D0001
+
+STATUS_MONITOR_NO_DESCRIPTOR
+
+
+A monitor descriptor could not be obtained.
+
+0xC01D0002
+
+STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT
+
+
+This release does not support the format of the obtained monitor descriptor.
+
+0xC01D0003
+
+STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM
+
+
+The checksum of the obtained monitor descriptor is invalid.
+
+0xC01D0004
+
+STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK
+
+
+The monitor descriptor contains an invalid standard timing block.
+
+0xC01D0005
+
+STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED
+
+
+WMI data-block registration failed for one of the MSMonitorClass WMI subclasses.
+
+0xC01D0006
+
+STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK
+
+
+The provided monitor descriptor block is either corrupted or does not contain the monitor's detailed serial number.
+
+0xC01D0007
+
+STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK
+
+
+The provided monitor descriptor block is either corrupted or does not contain the monitor's user-friendly name.
+
+0xC01D0008
+
+STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA
+
+
+There is no monitor descriptor data at the specified (offset or size) region.
+
+0xC01D0009
+
+STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK
+
+
+The monitor descriptor contains an invalid detailed timing block.
+
+0xC01D000A
+
+STATUS_MONITOR_INVALID_MANUFACTURE_DATE
+
+
+Monitor descriptor contains invalid manufacture date.
+
+0xC01E0000
+
+STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER
+
+
+Exclusive mode ownership is needed to create an unmanaged primary allocation.
+
+0xC01E0001
+
+STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER
+
+
+The driver needs more DMA buffer space to complete the requested operation.
+
+0xC01E0002
+
+STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER
+
+
+The specified display adapter handle is invalid.
+
+0xC01E0003
+
+STATUS_GRAPHICS_ADAPTER_WAS_RESET
+
+
+The specified display adapter and all of its state have been reset.
+
+0xC01E0004
+
+STATUS_GRAPHICS_INVALID_DRIVER_MODEL
+
+
+The driver stack does not match the expected driver model.
+
+0xC01E0005
+
+STATUS_GRAPHICS_PRESENT_MODE_CHANGED
+
+
+Present happened but ended up into the changed desktop mode.
+
+0xC01E0006
+
+STATUS_GRAPHICS_PRESENT_OCCLUDED
+
+
+Nothing to present due to desktop occlusion.
+
+0xC01E0007
+
+STATUS_GRAPHICS_PRESENT_DENIED
+
+
+Not able to present due to denial of desktop access.
+
+0xC01E0008
+
+STATUS_GRAPHICS_CANNOTCOLORCONVERT
+
+
+Not able to present with color conversion.
+
+0xC01E000B
+
+STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED
+
+
+Present redirection is disabled (desktop windowing management subsystem is off).
+
+0xC01E000C
+
+STATUS_GRAPHICS_PRESENT_UNOCCLUDED
+
+
+Previous exclusive VidPn source owner has released its ownership
+
+0xC01E0100
+
+STATUS_GRAPHICS_NO_VIDEO_MEMORY
+
+
+Not enough video memory is available to complete the operation.
+
+0xC01E0101
+
+STATUS_GRAPHICS_CANT_LOCK_MEMORY
+
+
+Could not probe and lock the underlying memory of an allocation.
+
+0xC01E0102
+
+STATUS_GRAPHICS_ALLOCATION_BUSY
+
+
+The allocation is currently busy.
+
+0xC01E0103
+
+STATUS_GRAPHICS_TOO_MANY_REFERENCES
+
+
+An object being referenced has already reached the maximum reference count and cannot be referenced further.
+
+0xC01E0104
+
+STATUS_GRAPHICS_TRY_AGAIN_LATER
+
+
+A problem could not be solved due to an existing condition. Try again later.
+
+0xC01E0105
+
+STATUS_GRAPHICS_TRY_AGAIN_NOW
+
+
+A problem could not be solved due to an existing condition. Try again now.
+
+0xC01E0106
+
+STATUS_GRAPHICS_ALLOCATION_INVALID
+
+
+The allocation is invalid.
+
+0xC01E0107
+
+STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE
+
+
+No more unswizzling apertures are currently available.
+
+0xC01E0108
+
+STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED
+
+
+The current allocation cannot be unswizzled by an aperture.
+
+0xC01E0109
+
+STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION
+
+
+The request failed because a pinned allocation cannot be evicted.
+
+0xC01E0110
+
+STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE
+
+
+The allocation cannot be used from its current segment location for the specified operation.
+
+0xC01E0111
+
+STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION
+
+
+A locked allocation cannot be used in the current command buffer.
+
+0xC01E0112
+
+STATUS_GRAPHICS_ALLOCATION_CLOSED
+
+
+The allocation being referenced has been closed permanently.
+
+0xC01E0113
+
+STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE
+
+
+An invalid allocation instance is being referenced.
+
+0xC01E0114
+
+STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE
+
+
+An invalid allocation handle is being referenced.
+
+0xC01E0115
+
+STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE
+
+
+The allocation being referenced does not belong to the current device.
+
+0xC01E0116
+
+STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST
+
+
+The specified allocation lost its content.
+
+0xC01E0200
+
+STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE
+
+
+A GPU exception was detected on the given device. The device cannot be scheduled.
+
+0xC01E0300
+
+STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY
+
+
+The specified VidPN topology is invalid.
+
+0xC01E0301
+
+STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED
+
+
+The specified VidPN topology is valid but is not supported by this model of the display adapter.
+
+0xC01E0302
+
+STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED
+
+
+The specified VidPN topology is valid but is not currently supported by the display adapter due to allocation of its resources.
+
+0xC01E0303
+
+STATUS_GRAPHICS_INVALID_VIDPN
+
+
+The specified VidPN handle is invalid.
+
+0xC01E0304
+
+STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE
+
+
+The specified video present source is invalid.
+
+0xC01E0305
+
+STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET
+
+
+The specified video present target is invalid.
+
+0xC01E0306
+
+STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED
+
+
+The specified VidPN modality is not supported (for example, at least two of the pinned modes are not co-functional).
+
+0xC01E0308
+
+STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET
+
+
+The specified VidPN source mode set is invalid.
+
+0xC01E0309
+
+STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET
+
+
+The specified VidPN target mode set is invalid.
+
+0xC01E030A
+
+STATUS_GRAPHICS_INVALID_FREQUENCY
+
+
+The specified video signal frequency is invalid.
+
+0xC01E030B
+
+STATUS_GRAPHICS_INVALID_ACTIVE_REGION
+
+
+The specified video signal active region is invalid.
+
+0xC01E030C
+
+STATUS_GRAPHICS_INVALID_TOTAL_REGION
+
+
+The specified video signal total region is invalid.
+
+0xC01E0310
+
+STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE
+
+
+The specified video present source mode is invalid.
+
+0xC01E0311
+
+STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE
+
+
+The specified video present target mode is invalid.
+
+0xC01E0312
+
+STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET
+
+
+The pinned mode must remain in the set on the VidPN's co-functional modality enumeration.
+
+0xC01E0313
+
+STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY
+
+
+The specified video present path is already in the VidPN's topology.
+
+0xC01E0314
+
+STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET
+
+
+The specified mode is already in the mode set.
+
+0xC01E0315
+
+STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET
+
+
+The specified video present source set is invalid.
+
+0xC01E0316
+
+STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET
+
+
+The specified video present target set is invalid.
+
+0xC01E0317
+
+STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET
+
+
+The specified video present source is already in the video present source set.
+
+0xC01E0318
+
+STATUS_GRAPHICS_TARGET_ALREADY_IN_SET
+
+
+The specified video present target is already in the video present target set.
+
+0xC01E0319
+
+STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH
+
+
+The specified VidPN present path is invalid.
+
+0xC01E031A
+
+STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY
+
+
+The miniport has no recommendation for augmenting the specified VidPN's topology.
+
+0xC01E031B
+
+STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET
+
+
+The specified monitor frequency range set is invalid.
+
+0xC01E031C
+
+STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE
+
+
+The specified monitor frequency range is invalid.
+
+0xC01E031D
+
+STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET
+
+
+The specified frequency range is not in the specified monitor frequency range set.
+
+0xC01E031F
+
+STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET
+
+
+The specified frequency range is already in the specified monitor frequency range set.
+
+0xC01E0320
+
+STATUS_GRAPHICS_STALE_MODESET
+
+
+The specified mode set is stale. Reacquire the new mode set.
+
+0xC01E0321
+
+STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET
+
+
+The specified monitor source mode set is invalid.
+
+0xC01E0322
+
+STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE
+
+
+The specified monitor source mode is invalid.
+
+0xC01E0323
+
+STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN
+
+
+The miniport does not have a recommendation regarding the request to provide a functional VidPN given the current display adapter configuration.
+
+0xC01E0324
+
+STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE
+
+
+The ID of the specified mode is being used by another mode in the set.
+
+0xC01E0325
+
+STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION
+
+
+The system failed to determine a mode that is supported by both the display adapter and the monitor connected to it.
+
+0xC01E0326
+
+STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES
+
+
+The number of video present targets must be greater than or equal to the number of video present sources.
+
+0xC01E0327
+
+STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY
+
+
+The specified present path is not in the VidPN's topology.
+
+0xC01E0328
+
+STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE
+
+
+The display adapter must have at least one video present source.
+
+0xC01E0329
+
+STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET
+
+
+The display adapter must have at least one video present target.
+
+0xC01E032A
+
+STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET
+
+
+The specified monitor descriptor set is invalid.
+
+0xC01E032B
+
+STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR
+
+
+The specified monitor descriptor is invalid.
+
+0xC01E032C
+
+STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET
+
+
+The specified descriptor is not in the specified monitor descriptor set.
+
+0xC01E032D
+
+STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET
+
+
+The specified descriptor is already in the specified monitor descriptor set.
+
+0xC01E032E
+
+STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE
+
+
+The ID of the specified monitor descriptor is being used by another descriptor in the set.
+
+0xC01E032F
+
+STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE
+
+
+The specified video present target subset type is invalid.
+
+0xC01E0330
+
+STATUS_GRAPHICS_RESOURCES_NOT_RELATED
+
+
+Two or more of the specified resources are not related to each other, as defined by the interface semantics.
+
+0xC01E0331
+
+STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE
+
+
+The ID of the specified video present source is being used by another source in the set.
+
+0xC01E0332
+
+STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE
+
+
+The ID of the specified video present target is being used by another target in the set.
+
+0xC01E0333
+
+STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET
+
+
+The specified VidPN source cannot be used because there is no available VidPN target to connect it to.
+
+0xC01E0334
+
+STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER
+
+
+The newly arrived monitor could not be associated with a display adapter.
+
+0xC01E0335
+
+STATUS_GRAPHICS_NO_VIDPNMGR
+
+
+The particular display adapter does not have an associated VidPN manager.
+
+0xC01E0336
+
+STATUS_GRAPHICS_NO_ACTIVE_VIDPN
+
+
+The VidPN manager of the particular display adapter does not have an active VidPN.
+
+0xC01E0337
+
+STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY
+
+
+The specified VidPN topology is stale; obtain the new topology.
+
+0xC01E0338
+
+STATUS_GRAPHICS_MONITOR_NOT_CONNECTED
+
+
+No monitor is connected on the specified video present target.
+
+0xC01E0339
+
+STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY
+
+
+The specified source is not part of the specified VidPN's topology.
+
+0xC01E033A
+
+STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE
+
+
+The specified primary surface size is invalid.
+
+0xC01E033B
+
+STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE
+
+
+The specified visible region size is invalid.
+
+0xC01E033C
+
+STATUS_GRAPHICS_INVALID_STRIDE
+
+
+The specified stride is invalid.
+
+0xC01E033D
+
+STATUS_GRAPHICS_INVALID_PIXELFORMAT
+
+
+The specified pixel format is invalid.
+
+0xC01E033E
+
+STATUS_GRAPHICS_INVALID_COLORBASIS
+
+
+The specified color basis is invalid.
+
+0xC01E033F
+
+STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE
+
+
+The specified pixel value access mode is invalid.
+
+0xC01E0340
+
+STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY
+
+
+The specified target is not part of the specified VidPN's topology.
+
+0xC01E0341
+
+STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT
+
+
+Failed to acquire the display mode management interface.
+
+0xC01E0342
+
+STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE
+
+
+The specified VidPN source is already owned by a DMM client and cannot be used until that client releases it.
+
+0xC01E0343
+
+STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN
+
+
+The specified VidPN is active and cannot be accessed.
+
+0xC01E0344
+
+STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL
+
+
+The specified VidPN's present path importance ordinal is invalid.
+
+0xC01E0345
+
+STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION
+
+
+The specified VidPN's present path content geometry transformation is invalid.
+
+0xC01E0346
+
+STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED
+
+
+The specified content geometry transformation is not supported on the respective VidPN present path.
+
+0xC01E0347
+
+STATUS_GRAPHICS_INVALID_GAMMA_RAMP
+
+
+The specified gamma ramp is invalid.
+
+0xC01E0348
+
+STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED
+
+
+The specified gamma ramp is not supported on the respective VidPN present path.
+
+0xC01E0349
+
+STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED
+
+
+Multisampling is not supported on the respective VidPN present path.
+
+0xC01E034A
+
+STATUS_GRAPHICS_MODE_NOT_IN_MODESET
+
+
+The specified mode is not in the specified mode set.
+
+0xC01E034D
+
+STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON
+
+
+The specified VidPN topology recommendation reason is invalid.
+
+0xC01E034E
+
+STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE
+
+
+The specified VidPN present path content type is invalid.
+
+0xC01E034F
+
+STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE
+
+
+The specified VidPN present path copy protection type is invalid.
+
+0xC01E0350
+
+STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS
+
+
+Only one unassigned mode set can exist at any one time for a particular VidPN source or target.
+
+0xC01E0352
+
+STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING
+
+
+The specified scan line ordering type is invalid.
+
+0xC01E0353
+
+STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED
+
+
+The topology changes are not allowed for the specified VidPN.
+
+0xC01E0354
+
+STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS
+
+
+All available importance ordinals are being used in the specified topology.
+
+0xC01E0355
+
+STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT
+
+
+The specified primary surface has a different private-format attribute than the current primary surface.
+
+0xC01E0356
+
+STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM
+
+
+The specified mode-pruning algorithm is invalid.
+
+0xC01E0357
+
+STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN
+
+
+The specified monitor-capability origin is invalid.
+
+0xC01E0358
+
+STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT
+
+
+The specified monitor-frequency range constraint is invalid.
+
+0xC01E0359
+
+STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED
+
+
+The maximum supported number of present paths has been reached.
+
+0xC01E035A
+
+STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION
+
+
+The miniport requested that augmentation be canceled for the specified source of the specified VidPN's topology.
+
+0xC01E035B
+
+STATUS_GRAPHICS_INVALID_CLIENT_TYPE
+
+
+The specified client type was not recognized.
+
+0xC01E035C
+
+STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET
+
+
+The client VidPN is not set on this adapter (for example, no user mode-initiated mode changes have taken place on this adapter).
+
+0xC01E0400
+
+STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED
+
+
+The specified display adapter child device already has an external device connected to it.
+
+0xC01E0401
+
+STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED
+
+
+The display adapter child device does not support reporting a descriptor.
+
+0xC01E0430
+
+STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER
+
+
+The display adapter is not linked to any other adapters.
+
+0xC01E0431
+
+STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED
+
+
+The lead adapter in a linked configuration was not enumerated yet.
+
+0xC01E0432
+
+STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED
+
+
+Some chain adapters in a linked configuration have not yet been enumerated.
+
+0xC01E0433
+
+STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY
+
+
+The chain of linked adapters is not ready to start because of an unknown failure.
+
+0xC01E0434
+
+STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED
+
+
+An attempt was made to start a lead link display adapter when the chain links had not yet started.
+
+0xC01E0435
+
+STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON
+
+
+An attempt was made to turn on a lead link display adapter when the chain links were turned off.
+
+0xC01E0436
+
+STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE
+
+
+The adapter link was found in an inconsistent state. Not all adapters are in an expected PNP/power state.
+
+0xC01E0438
+
+STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER
+
+
+The driver trying to start is not the same as the driver for the posted display adapter.
+
+0xC01E043B
+
+STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED
+
+
+An operation is being attempted that requires the display adapter to be in a quiescent state.
+
+0xC01E0500
+
+STATUS_GRAPHICS_OPM_NOT_SUPPORTED
+
+
+The driver does not support OPM.
+
+0xC01E0501
+
+STATUS_GRAPHICS_COPP_NOT_SUPPORTED
+
+
+The driver does not support COPP.
+
+0xC01E0502
+
+STATUS_GRAPHICS_UAB_NOT_SUPPORTED
+
+
+The driver does not support UAB.
+
+0xC01E0503
+
+STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS
+
+
+The specified encrypted parameters are invalid.
+
+0xC01E0504
+
+STATUS_GRAPHICS_OPM_PARAMETER_ARRAY_TOO_SMALL
+
+
+An array passed to a function cannot hold all of the data that the function wants to put in it.
+
+0xC01E0505
+
+STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST
+
+
+The GDI display device passed to this function does not have any active protected outputs.
+
+0xC01E0506
+
+STATUS_GRAPHICS_PVP_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME
+
+
+The PVP cannot find an actual GDI display device that corresponds to the passed-in GDI display device name.
+
+0xC01E0507
+
+STATUS_GRAPHICS_PVP_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP
+
+
+This function failed because the GDI display device passed to it was not attached to the Windows desktop.
+
+0xC01E0508
+
+STATUS_GRAPHICS_PVP_MIRRORING_DEVICES_NOT_SUPPORTED
+
+
+The PVP does not support mirroring display devices because they do not have any protected outputs.
+
+0xC01E050A
+
+STATUS_GRAPHICS_OPM_INVALID_POINTER
+
+
+The function failed because an invalid pointer parameter was passed to it. A pointer parameter is invalid if it is null, is not correctly aligned, or it points to an invalid address or a kernel mode address.
+
+0xC01E050B
+
+STATUS_GRAPHICS_OPM_INTERNAL_ERROR
+
+
+An internal error caused an operation to fail.
+
+0xC01E050C
+
+STATUS_GRAPHICS_OPM_INVALID_HANDLE
+
+
+The function failed because the caller passed in an invalid OPM user-mode handle.
+
+0xC01E050D
+
+STATUS_GRAPHICS_PVP_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE
+
+
+This function failed because the GDI device passed to it did not have any monitors associated with it.
+
+0xC01E050E
+
+STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH
+
+
+A certificate could not be returned because the certificate buffer passed to the function was too small.
+
+0xC01E050F
+
+STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED
+
+
+DxgkDdiOpmCreateProtectedOutput() could not create a protected output because the video present yarget is in spanning mode.
+
+0xC01E0510
+
+STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED
+
+
+DxgkDdiOpmCreateProtectedOutput() could not create a protected output because the video present target is in theater mode.
+
+0xC01E0511
+
+STATUS_GRAPHICS_PVP_HFS_FAILED
+
+
+The function call failed because the display adapter's hardware functionality scan (HFS) failed to validate the graphics hardware.
+
+0xC01E0512
+
+STATUS_GRAPHICS_OPM_INVALID_SRM
+
+
+The HDCP SRM passed to this function did not comply with section 5 of the HDCP 1.1 specification.
+
+0xC01E0513
+
+STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP
+
+
+The protected output cannot enable the HDCP system because it does not support it.
+
+0xC01E0514
+
+STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP
+
+
+The protected output cannot enable analog copy protection because it does not support it.
+
+0xC01E0515
+
+STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA
+
+
+The protected output cannot enable the CGMS-A protection technology because it does not support it.
+
+0xC01E0516
+
+STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET
+
+
+DxgkDdiOPMGetInformation() cannot return the version of the SRM being used because the application never successfully passed an SRM to the protected output.
+
+0xC01E0517
+
+STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH
+
+
+DxgkDdiOPMConfigureProtectedOutput() cannot enable the specified output protection technology because the output's screen resolution is too high.
+
+0xC01E0518
+
+STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE
+
+
+DxgkDdiOPMConfigureProtectedOutput() cannot enable HDCP because other physical outputs are using the display adapter's HDCP hardware.
+
+0xC01E051A
+
+STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS
+
+
+The operating system asynchronously destroyed this OPM-protected output because the operating system state changed. This error typically occurs because the monitor PDO associated with this protected output was removed or stopped, the protected output's session became a nonconsole session, or the protected output's desktop became inactive.
+
+0xC01E051B
+
+STATUS_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS
+
+
+OPM functions cannot be called when a session is changing its type. Three types of sessions currently exist: console, disconnected, and remote (RDP or ICA).
+
+0xC01E051C
+
+STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS
+
+
+The DxgkDdiOPMGetCOPPCompatibleInformation, DxgkDdiOPMGetInformation, or DxgkDdiOPMConfigureProtectedOutput function failed. This error is returned only if a protected output has OPM semantics.
+
+DxgkDdiOPMGetCOPPCompatibleInformation always returns this error if a protected output has OPM semantics.
+
+DxgkDdiOPMGetInformation returns this error code if the caller requested COPP-specific information.
+
+DxgkDdiOPMConfigureProtectedOutput returns this error when the caller tries to use a COPP-specific command.
+
+0xC01E051D
+
+STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST
+
+
+The DxgkDdiOPMGetInformation and DxgkDdiOPMGetCOPPCompatibleInformation functions return this error code if the passed-in sequence number is not the expected sequence number or the passed-in OMAC value is invalid.
+
+0xC01E051E
+
+STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR
+
+
+The function failed because an unexpected error occurred inside a display driver.
+
+0xC01E051F
+
+STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS
+
+
+The DxgkDdiOPMGetCOPPCompatibleInformation, DxgkDdiOPMGetInformation, or DxgkDdiOPMConfigureProtectedOutput function failed. This error is returned only if a protected output has COPP semantics.
+
+DxgkDdiOPMGetCOPPCompatibleInformation returns this error code if the caller requested OPM-specific information.
+
+DxgkDdiOPMGetInformation always returns this error if a protected output has COPP semantics.
+
+DxgkDdiOPMConfigureProtectedOutput returns this error when the caller tries to use an OPM-specific command.
+
+0xC01E0520
+
+STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED
+
+
+The DxgkDdiOPMGetCOPPCompatibleInformation and DxgkDdiOPMConfigureProtectedOutput functions return this error if the display driver does not support the DXGKMDT_OPM_GET_ACP_AND_CGMSA_SIGNALING and DXGKMDT_OPM_SET_ACP_AND_CGMSA_SIGNALING GUIDs.
+
+0xC01E0521
+
+STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST
+
+
+The DxgkDdiOPMConfigureProtectedOutput function returns this error code if the passed-in sequence number is not the expected sequence number or the passed-in OMAC value is invalid.
+
+0xC01E0580
+
+STATUS_GRAPHICS_I2C_NOT_SUPPORTED
+
+
+The monitor connected to the specified video output does not have an I2C bus.
+
+0xC01E0581
+
+STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST
+
+
+No device on the I2C bus has the specified address.
+
+0xC01E0582
+
+STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA
+
+
+An error occurred while transmitting data to the device on the I2C bus.
+
+0xC01E0583
+
+STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA
+
+
+An error occurred while receiving data from the device on the I2C bus.
+
+0xC01E0584
+
+STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED
+
+
+The monitor does not support the specified VCP code.
+
+0xC01E0585
+
+STATUS_GRAPHICS_DDCCI_INVALID_DATA
+
+
+The data received from the monitor is invalid.
+
+0xC01E0586
+
+STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE
+
+
+A function call failed because a monitor returned an invalid timing status byte when the operating system used the DDC/CI get timing report and timing message command to get a timing report from a monitor.
+
+0xC01E0587
+
+STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING
+
+
+A monitor returned a DDC/CI capabilities string that did not comply with the ACCESS.bus 3.0, DDC/CI 1.1, or MCCS 2 Revision 1 specification.
+
+0xC01E0588
+
+STATUS_GRAPHICS_MCA_INTERNAL_ERROR
+
+
+An internal error caused an operation to fail.
+
+0xC01E0589
+
+STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND
+
+
+An operation failed because a DDC/CI message had an invalid value in its command field.
+
+0xC01E058A
+
+STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH
+
+
+This error occurred because a DDC/CI message had an invalid value in its length field.
+
+0xC01E058B
+
+STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM
+
+
+This error occurred because the value in a DDC/CI message's checksum field did not match the message's computed checksum value. This error implies that the data was corrupted while it was being transmitted from a monitor to a computer.
+
+0xC01E058C
+
+STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE
+
+
+This function failed because an invalid monitor handle was passed to it.
+
+0xC01E058D
+
+STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS
+
+
+The operating system asynchronously destroyed the monitor that corresponds to this handle because the operating system's state changed. This error typically occurs because the monitor PDO associated with this handle was removed or stopped, or a display mode change occurred. A display mode change occurs when Windows sends a WM_DISPLAYCHANGE message to applications.
+
+0xC01E05E0
+
+STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED
+
+
+This function can be used only if a program is running in the local console session. It cannot be used if a program is running on a remote desktop session or on a terminal server session.
+
+0xC01E05E1
+
+STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME
+
+
+This function cannot find an actual GDI display device that corresponds to the specified GDI display device name.
+
+0xC01E05E2
+
+STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP
+
+
+The function failed because the specified GDI display device was not attached to the Windows desktop.
+
+0xC01E05E3
+
+STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED
+
+
+This function does not support GDI mirroring display devices because GDI mirroring display devices do not have any physical monitors associated with them.
+
+0xC01E05E4
+
+STATUS_GRAPHICS_INVALID_POINTER
+
+
+The function failed because an invalid pointer parameter was passed to it. A pointer parameter is invalid if it is null, is not correctly aligned, or points to an invalid address or to a kernel mode address.
+
+0xC01E05E5
+
+STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE
+
+
+This function failed because the GDI device passed to it did not have a monitor associated with it.
+
+0xC01E05E6
+
+STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL
+
+
+An array passed to the function cannot hold all of the data that the function must copy into the array.
+
+0xC01E05E7
+
+STATUS_GRAPHICS_INTERNAL_ERROR
+
+
+An internal error caused an operation to fail.
+
+0xC01E05E8
+
+STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS
+
+
+The function failed because the current session is changing its type. This function cannot be called when the current session is changing its type. Three types of sessions currently exist: console, disconnected, and remote (RDP or ICA).
+
+0xC0210000
+
+STATUS_FVE_LOCKED_VOLUME
+
+
+The volume must be unlocked before it can be used.
+
+0xC0210001
+
+STATUS_FVE_NOT_ENCRYPTED
+
+
+The volume is fully decrypted and no key is available.
+
+0xC0210002
+
+STATUS_FVE_BAD_INFORMATION
+
+
+The control block for the encrypted volume is not valid.
+
+0xC0210003
+
+STATUS_FVE_TOO_SMALL
+
+
+Not enough free space remains on the volume to allow encryption.
+
+0xC0210004
+
+STATUS_FVE_FAILED_WRONG_FS
+
+
+The partition cannot be encrypted because the file system is not supported.
+
+0xC0210005
+
+STATUS_FVE_FAILED_BAD_FS
+
+
+The file system is inconsistent. Run the Check Disk utility.
+
+0xC0210006
+
+STATUS_FVE_FS_NOT_EXTENDED
+
+
+The file system does not extend to the end of the volume.
+
+0xC0210007
+
+STATUS_FVE_FS_MOUNTED
+
+
+This operation cannot be performed while a file system is mounted on the volume.
+
+0xC0210008
+
+STATUS_FVE_NO_LICENSE
+
+
+BitLocker Drive Encryption is not included with this version of Windows.
+
+0xC0210009
+
+STATUS_FVE_ACTION_NOT_ALLOWED
+
+
+The requested action was denied by the FVE control engine.
+
+0xC021000A
+
+STATUS_FVE_BAD_DATA
+
+
+The data supplied is malformed.
+
+0xC021000B
+
+STATUS_FVE_VOLUME_NOT_BOUND
+
+
+The volume is not bound to the system.
+
+0xC021000C
+
+STATUS_FVE_NOT_DATA_VOLUME
+
+
+The volume specified is not a data volume.
+
+0xC021000D
+
+STATUS_FVE_CONV_READ_ERROR
+
+
+A read operation failed while converting the volume.
+
+0xC021000E
+
+STATUS_FVE_CONV_WRITE_ERROR
+
+
+A write operation failed while converting the volume.
+
+0xC021000F
+
+STATUS_FVE_OVERLAPPED_UPDATE
+
+
+The control block for the encrypted volume was updated by another thread. Try again.
+
+0xC0210010
+
+STATUS_FVE_FAILED_SECTOR_SIZE
+
+
+The volume encryption algorithm cannot be used on this sector size.
+
+0xC0210011
+
+STATUS_FVE_FAILED_AUTHENTICATION
+
+
+BitLocker recovery authentication failed.
+
+0xC0210012
+
+STATUS_FVE_NOT_OS_VOLUME
+
+
+The volume specified is not the boot operating system volume.
+
+0xC0210013
+
+STATUS_FVE_KEYFILE_NOT_FOUND
+
+
+The BitLocker startup key or recovery password could not be read from external media.
+
+0xC0210014
+
+STATUS_FVE_KEYFILE_INVALID
+
+
+The BitLocker startup key or recovery password file is corrupt or invalid.
+
+0xC0210015
+
+STATUS_FVE_KEYFILE_NO_VMK
+
+
+The BitLocker encryption key could not be obtained from the startup key or the recovery password.
+
+0xC0210016
+
+STATUS_FVE_TPM_DISABLED
+
+
+The TPM is disabled.
+
+0xC0210017
+
+STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO
+
+
+The authorization data for the SRK of the TPM is not zero.
+
+0xC0210018
+
+STATUS_FVE_TPM_INVALID_PCR
+
+
+The system boot information changed or the TPM locked out access to BitLocker encryption keys until the computer is restarted.
+
+0xC0210019
+
+STATUS_FVE_TPM_NO_VMK
+
+
+The BitLocker encryption key could not be obtained from the TPM.
+
+0xC021001A
+
+STATUS_FVE_PIN_INVALID
+
+
+The BitLocker encryption key could not be obtained from the TPM and PIN.
+
+0xC021001B
+
+STATUS_FVE_AUTH_INVALID_APPLICATION
+
+
+A boot application hash does not match the hash computed when BitLocker was turned on.
+
+0xC021001C
+
+STATUS_FVE_AUTH_INVALID_CONFIG
+
+
+The Boot Configuration Data (BCD) settings are not supported or have changed because BitLocker was enabled.
+
+0xC021001D
+
+STATUS_FVE_DEBUGGER_ENABLED
+
+
+Boot debugging is enabled. Run Windows Boot Configuration Data Store Editor (bcdedit.exe) to turn it off.
+
+0xC021001E
+
+STATUS_FVE_DRY_RUN_FAILED
+
+
+The BitLocker encryption key could not be obtained.
+
+0xC021001F
+
+STATUS_FVE_BAD_METADATA_POINTER
+
+
+The metadata disk region pointer is incorrect.
+
+0xC0210020
+
+STATUS_FVE_OLD_METADATA_COPY
+
+
+The backup copy of the metadata is out of date.
+
+0xC0210021
+
+STATUS_FVE_REBOOT_REQUIRED
+
+
+No action was taken because a system restart is required.
+
+0xC0210022
+
+STATUS_FVE_RAW_ACCESS
+
+
+No action was taken because BitLocker Drive Encryption is in RAW access mode.
+
+0xC0210023
+
+STATUS_FVE_RAW_BLOCKED
+
+
+BitLocker Drive Encryption cannot enter RAW access mode for this volume.
+
+0xC0210026
+
+STATUS_FVE_NO_FEATURE_LICENSE
+
+
+This feature of BitLocker Drive Encryption is not included with this version of Windows.
+
+0xC0210027
+
+STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED
+
+
+Group policy does not permit turning off BitLocker Drive Encryption on roaming data volumes.
+
+0xC0210028
+
+STATUS_FVE_CONV_RECOVERY_FAILED
+
+
+Bitlocker Drive Encryption failed to recover from aborted conversion. This could be due to either all conversion logs being corrupted or the media being write-protected.
+
+0xC0210029
+
+STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG
+
+
+The requested virtualization size is too big.
+
+0xC0210030
+
+STATUS_FVE_VOLUME_TOO_SMALL
+
+
+The drive is too small to be protected using BitLocker Drive Encryption.
+
+0xC0220001
+
+STATUS_FWP_CALLOUT_NOT_FOUND
+
+
+The callout does not exist.
+
+0xC0220002
+
+STATUS_FWP_CONDITION_NOT_FOUND
+
+
+The filter condition does not exist.
+
+0xC0220003
+
+STATUS_FWP_FILTER_NOT_FOUND
+
+
+The filter does not exist.
+
+0xC0220004
+
+STATUS_FWP_LAYER_NOT_FOUND
+
+
+The layer does not exist.
+
+0xC0220005
+
+STATUS_FWP_PROVIDER_NOT_FOUND
+
+
+The provider does not exist.
+
+0xC0220006
+
+STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND
+
+
+The provider context does not exist.
+
+0xC0220007
+
+STATUS_FWP_SUBLAYER_NOT_FOUND
+
+
+The sublayer does not exist.
+
+0xC0220008
+
+STATUS_FWP_NOT_FOUND
+
+
+The object does not exist.
+
+0xC0220009
+
+STATUS_FWP_ALREADY_EXISTS
+
+
+An object with that GUID or LUID already exists.
+
+0xC022000A
+
+STATUS_FWP_IN_USE
+
+
+The object is referenced by other objects and cannot be deleted.
+
+0xC022000B
+
+STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS
+
+
+The call is not allowed from within a dynamic session.
+
+0xC022000C
+
+STATUS_FWP_WRONG_SESSION
+
+
+The call was made from the wrong session and cannot be completed.
+
+0xC022000D
+
+STATUS_FWP_NO_TXN_IN_PROGRESS
+
+
+The call must be made from within an explicit transaction.
+
+0xC022000E
+
+STATUS_FWP_TXN_IN_PROGRESS
+
+
+The call is not allowed from within an explicit transaction.
+
+0xC022000F
+
+STATUS_FWP_TXN_ABORTED
+
+
+The explicit transaction has been forcibly canceled.
+
+0xC0220010
+
+STATUS_FWP_SESSION_ABORTED
+
+
+The session has been canceled.
+
+0xC0220011
+
+STATUS_FWP_INCOMPATIBLE_TXN
+
+
+The call is not allowed from within a read-only transaction.
+
+0xC0220012
+
+STATUS_FWP_TIMEOUT
+
+
+The call timed out while waiting to acquire the transaction lock.
+
+0xC0220013
+
+STATUS_FWP_NET_EVENTS_DISABLED
+
+
+The collection of network diagnostic events is disabled.
+
+0xC0220014
+
+STATUS_FWP_INCOMPATIBLE_LAYER
+
+
+The operation is not supported by the specified layer.
+
+0xC0220015
+
+STATUS_FWP_KM_CLIENTS_ONLY
+
+
+The call is allowed for kernel-mode callers only.
+
+0xC0220016
+
+STATUS_FWP_LIFETIME_MISMATCH
+
+
+The call tried to associate two objects with incompatible lifetimes.
+
+0xC0220017
+
+STATUS_FWP_BUILTIN_OBJECT
+
+
+The object is built-in and cannot be deleted.
+
+0xC0220018
+
+STATUS_FWP_TOO_MANY_BOOTTIME_FILTERS
+
+
+The maximum number of boot-time filters has been reached.
+
+0xC0220018
+
+STATUS_FWP_TOO_MANY_CALLOUTS
+
+
+The maximum number of callouts has been reached.
+
+0xC0220019
+
+STATUS_FWP_NOTIFICATION_DROPPED
+
+
+A notification could not be delivered because a message queue has reached maximum capacity.
+
+0xC022001A
+
+STATUS_FWP_TRAFFIC_MISMATCH
+
+
+The traffic parameters do not match those for the security association context.
+
+0xC022001B
+
+STATUS_FWP_INCOMPATIBLE_SA_STATE
+
+
+The call is not allowed for the current security association state.
+
+0xC022001C
+
+STATUS_FWP_NULL_POINTER
+
+
+A required pointer is null.
+
+0xC022001D
+
+STATUS_FWP_INVALID_ENUMERATOR
+
+
+An enumerator is not valid.
+
+0xC022001E
+
+STATUS_FWP_INVALID_FLAGS
+
+
+The flags field contains an invalid value.
+
+0xC022001F
+
+STATUS_FWP_INVALID_NET_MASK
+
+
+A network mask is not valid.
+
+0xC0220020
+
+STATUS_FWP_INVALID_RANGE
+
+
+An FWP_RANGE is not valid.
+
+0xC0220021
+
+STATUS_FWP_INVALID_INTERVAL
+
+
+The time interval is not valid.
+
+0xC0220022
+
+STATUS_FWP_ZERO_LENGTH_ARRAY
+
+
+An array that must contain at least one element has a zero length.
+
+0xC0220023
+
+STATUS_FWP_NULL_DISPLAY_NAME
+
+
+The displayData.name field cannot be null.
+
+0xC0220024
+
+STATUS_FWP_INVALID_ACTION_TYPE
+
+
+The action type is not one of the allowed action types for a filter.
+
+0xC0220025
+
+STATUS_FWP_INVALID_WEIGHT
+
+
+The filter weight is not valid.
+
+0xC0220026
+
+STATUS_FWP_MATCH_TYPE_MISMATCH
+
+
+A filter condition contains a match type that is not compatible with the operands.
+
+0xC0220027
+
+STATUS_FWP_TYPE_MISMATCH
+
+
+An FWP_VALUE or FWPM_CONDITION_VALUE is of the wrong type.
+
+0xC0220028
+
+STATUS_FWP_OUT_OF_BOUNDS
+
+
+An integer value is outside the allowed range.
+
+0xC0220029
+
+STATUS_FWP_RESERVED
+
+
+A reserved field is nonzero.
+
+0xC022002A
+
+STATUS_FWP_DUPLICATE_CONDITION
+
+
+A filter cannot contain multiple conditions operating on a single field.
+
+0xC022002B
+
+STATUS_FWP_DUPLICATE_KEYMOD
+
+
+A policy cannot contain the same keying module more than once.
+
+0xC022002C
+
+STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER
+
+
+The action type is not compatible with the layer.
+
+0xC022002D
+
+STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER
+
+
+The action type is not compatible with the sublayer.
+
+0xC022002E
+
+STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER
+
+
+The raw context or the provider context is not compatible with the layer.
+
+0xC022002F
+
+STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT
+
+
+The raw context or the provider context is not compatible with the callout.
+
+0xC0220030
+
+STATUS_FWP_INCOMPATIBLE_AUTH_METHOD
+
+
+The authentication method is not compatible with the policy type.
+
+0xC0220031
+
+STATUS_FWP_INCOMPATIBLE_DH_GROUP
+
+
+The Diffie-Hellman group is not compatible with the policy type.
+
+0xC0220032
+
+STATUS_FWP_EM_NOT_SUPPORTED
+
+
+An IKE policy cannot contain an Extended Mode policy.
+
+0xC0220033
+
+STATUS_FWP_NEVER_MATCH
+
+
+The enumeration template or subscription will never match any objects.
+
+0xC0220034
+
+STATUS_FWP_PROVIDER_CONTEXT_MISMATCH
+
+
+The provider context is of the wrong type.
+
+0xC0220035
+
+STATUS_FWP_INVALID_PARAMETER
+
+
+The parameter is incorrect.
+
+0xC0220036
+
+STATUS_FWP_TOO_MANY_SUBLAYERS
+
+
+The maximum number of sublayers has been reached.
+
+0xC0220037
+
+STATUS_FWP_CALLOUT_NOTIFICATION_FAILED
+
+
+The notification function for a callout returned an error.
+
+0xC0220038
+
+STATUS_FWP_INCOMPATIBLE_AUTH_CONFIG
+
+
+The IPsec authentication configuration is not compatible with the authentication type.
+
+0xC0220039
+
+STATUS_FWP_INCOMPATIBLE_CIPHER_CONFIG
+
+
+The IPsec cipher configuration is not compatible with the cipher type.
+
+0xC022003C
+
+STATUS_FWP_DUPLICATE_AUTH_METHOD
+
+
+A policy cannot contain the same auth method more than once.
+
+0xC0220100
+
+STATUS_FWP_TCPIP_NOT_READY
+
+
+The TCP/IP stack is not ready.
+
+0xC0220101
+
+STATUS_FWP_INJECT_HANDLE_CLOSING
+
+
+The injection handle is being closed by another thread.
+
+0xC0220102
+
+STATUS_FWP_INJECT_HANDLE_STALE
+
+
+The injection handle is stale.
+
+0xC0220103
+
+STATUS_FWP_CANNOT_PEND
+
+
+The classify cannot be pended.
+
+0xC0230002
+
+STATUS_NDIS_CLOSING
+
+
+The binding to the network interface is being closed.
+
+0xC0230004
+
+STATUS_NDIS_BAD_VERSION
+
+
+An invalid version was specified.
+
+0xC0230005
+
+STATUS_NDIS_BAD_CHARACTERISTICS
+
+
+An invalid characteristics table was used.
+
+0xC0230006
+
+STATUS_NDIS_ADAPTER_NOT_FOUND
+
+
+Failed to find the network interface or the network interface is not ready.
+
+0xC0230007
+
+STATUS_NDIS_OPEN_FAILED
+
+
+Failed to open the network interface.
+
+0xC0230008
+
+STATUS_NDIS_DEVICE_FAILED
+
+
+The network interface has encountered an internal unrecoverable failure.
+
+0xC0230009
+
+STATUS_NDIS_MULTICAST_FULL
+
+
+The multicast list on the network interface is full.
+
+0xC023000A
+
+STATUS_NDIS_MULTICAST_EXISTS
+
+
+An attempt was made to add a duplicate multicast address to the list.
+
+0xC023000B
+
+STATUS_NDIS_MULTICAST_NOT_FOUND
+
+
+At attempt was made to remove a multicast address that was never added.
+
+0xC023000C
+
+STATUS_NDIS_REQUEST_ABORTED
+
+
+The network interface aborted the request.
+
+0xC023000D
+
+STATUS_NDIS_RESET_IN_PROGRESS
+
+
+The network interface cannot process the request because it is being reset.
+
+0xC023000F
+
+STATUS_NDIS_INVALID_PACKET
+
+
+An attempt was made to send an invalid packet on a network interface.
+
+0xC0230010
+
+STATUS_NDIS_INVALID_DEVICE_REQUEST
+
+
+The specified request is not a valid operation for the target device.
+
+0xC0230011
+
+STATUS_NDIS_ADAPTER_NOT_READY
+
+
+The network interface is not ready to complete this operation.
+
+0xC0230014
+
+STATUS_NDIS_INVALID_LENGTH
+
+
+The length of the buffer submitted for this operation is not valid.
+
+0xC0230015
+
+STATUS_NDIS_INVALID_DATA
+
+
+The data used for this operation is not valid.
+
+0xC0230016
+
+STATUS_NDIS_BUFFER_TOO_SHORT
+
+
+The length of the submitted buffer for this operation is too small.
+
+0xC0230017
+
+STATUS_NDIS_INVALID_OID
+
+
+The network interface does not support this object identifier.
+
+0xC0230018
+
+STATUS_NDIS_ADAPTER_REMOVED
+
+
+The network interface has been removed.
+
+0xC0230019
+
+STATUS_NDIS_UNSUPPORTED_MEDIA
+
+
+The network interface does not support this media type.
+
+0xC023001A
+
+STATUS_NDIS_GROUP_ADDRESS_IN_USE
+
+
+An attempt was made to remove a token ring group address that is in use by other components.
+
+0xC023001B
+
+STATUS_NDIS_FILE_NOT_FOUND
+
+
+An attempt was made to map a file that cannot be found.
+
+0xC023001C
+
+STATUS_NDIS_ERROR_READING_FILE
+
+
+An error occurred while NDIS tried to map the file.
+
+0xC023001D
+
+STATUS_NDIS_ALREADY_MAPPED
+
+
+An attempt was made to map a file that is already mapped.
+
+0xC023001E
+
+STATUS_NDIS_RESOURCE_CONFLICT
+
+
+An attempt to allocate a hardware resource failed because the resource is used by another component.
+
+0xC023001F
+
+STATUS_NDIS_MEDIA_DISCONNECTED
+
+
+The I/O operation failed because the network media is disconnected or the wireless access point is out of range.
+
+0xC0230022
+
+STATUS_NDIS_INVALID_ADDRESS
+
+
+The network address used in the request is invalid.
+
+0xC023002A
+
+STATUS_NDIS_PAUSED
+
+
+The offload operation on the network interface has been paused.
+
+0xC023002B
+
+STATUS_NDIS_INTERFACE_NOT_FOUND
+
+
+The network interface was not found.
+
+0xC023002C
+
+STATUS_NDIS_UNSUPPORTED_REVISION
+
+
+The revision number specified in the structure is not supported.
+
+0xC023002D
+
+STATUS_NDIS_INVALID_PORT
+
+
+The specified port does not exist on this network interface.
+
+0xC023002E
+
+STATUS_NDIS_INVALID_PORT_STATE
+
+
+The current state of the specified port on this network interface does not support the requested operation.
+
+0xC023002F
+
+STATUS_NDIS_LOW_POWER_STATE
+
+
+The miniport adapter is in a lower power state.
+
+0xC02300BB
+
+STATUS_NDIS_NOT_SUPPORTED
+
+
+The network interface does not support this request.
+
+0xC023100F
+
+STATUS_NDIS_OFFLOAD_POLICY
+
+
+The TCP connection is not offloadable because of a local policy setting.
+
+0xC0231012
+
+STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED
+
+
+The TCP connection is not offloadable by the Chimney offload target.
+
+0xC0231013
+
+STATUS_NDIS_OFFLOAD_PATH_REJECTED
+
+
+The IP Path object is not in an offloadable state.
+
+0xC0232000
+
+STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED
+
+
+The wireless LAN interface is in auto-configuration mode and does not support the requested parameter change operation.
+
+0xC0232001
+
+STATUS_NDIS_DOT11_MEDIA_IN_USE
+
+
+The wireless LAN interface is busy and cannot perform the requested operation.
+
+0xC0232002
+
+STATUS_NDIS_DOT11_POWER_STATE_INVALID
+
+
+The wireless LAN interface is power down and does not support the requested operation.
+
+0xC0232003
+
+STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL
+
+
+The list of wake on LAN patterns is full.
+
+0xC0232004
+
+STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL
+
+
+The list of low power protocol offloads is full.
+
+0xC0360001
+
+STATUS_IPSEC_BAD_SPI
+
+
+The SPI in the packet does not match a valid IPsec SA.
+
+0xC0360002
+
+STATUS_IPSEC_SA_LIFETIME_EXPIRED
+
+
+The packet was received on an IPsec SA whose lifetime has expired.
+
+0xC0360003
+
+STATUS_IPSEC_WRONG_SA
+
+
+The packet was received on an IPsec SA that does not match the packet characteristics.
+
+0xC0360004
+
+STATUS_IPSEC_REPLAY_CHECK_FAILED
+
+
+The packet sequence number replay check failed.
+
+0xC0360005
+
+STATUS_IPSEC_INVALID_PACKET
+
+
+The IPsec header and/or trailer in the packet is invalid.
+
+0xC0360006
+
+STATUS_IPSEC_INTEGRITY_CHECK_FAILED
+
+
+The IPsec integrity check failed.
+
+0xC0360007
+
+STATUS_IPSEC_CLEAR_TEXT_DROP
+
+
+IPsec dropped a clear text packet.
+
+0xC0360008
+
+STATUS_IPSEC_AUTH_FIREWALL_DROP
+
+
+IPsec dropped an incoming ESP packet in authenticated firewall mode. This drop is benign.
+
+0xC0360009
+
+STATUS_IPSEC_THROTTLE_DROP
+
+
+IPsec dropped a packet due to DOS throttle.
+
+0xC0368000
+
+STATUS_IPSEC_DOSP_BLOCK
+
+
+IPsec Dos Protection matched an explicit block rule.
+
+0xC0368001
+
+STATUS_IPSEC_DOSP_RECEIVED_MULTICAST
+
+
+IPsec Dos Protection received an IPsec specific multicast packet which is not allowed.
+
+0xC0368002
+
+STATUS_IPSEC_DOSP_INVALID_PACKET
+
+
+IPsec Dos Protection received an incorrectly formatted packet.
+
+0xC0368003
+
+STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED
+
+
+IPsec Dos Protection failed to lookup state.
+
+0xC0368004
+
+STATUS_IPSEC_DOSP_MAX_ENTRIES
+
+
+IPsec Dos Protection failed to create state because there are already maximum number of entries allowed by policy.
+
+0xC0368005
+
+STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED
+
+
+IPsec Dos Protection received an IPsec negotiation packet for a keying module which is not allowed by policy.
+
+0xC0368006
+
+STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES
+
+
+IPsec Dos Protection failed to create per internal IP ratelimit queue because there is already maximum number of queues allowed by policy.
+
+0xC038005B
+
+STATUS_VOLMGR_MIRROR_NOT_SUPPORTED
+
+
+The system does not support mirrored volumes.
+
+0xC038005C
+
+STATUS_VOLMGR_RAID5_NOT_SUPPORTED
+
+
+The system does not support RAID-5 volumes.
+
+0xC03A0014
+
+STATUS_VIRTDISK_PROVIDER_NOT_FOUND
+
+
+A virtual disk support provider for the specified file was not found.
+
+0xC03A0015
+
+STATUS_VIRTDISK_NOT_VIRTUAL_DISK
+
+
+The specified disk is not a virtual disk.
+
+0xC03A0016
+
+STATUS_VHD_PARENT_VHD_ACCESS_DENIED
+
+
+The chain of virtual hard disks is inaccessible. The process has not been granted access rights to the parent virtual hard disk for the differencing disk.
+
+0xC03A0017
+
+STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH
+
+
+The chain of virtual hard disks is corrupted. There is a mismatch in the virtual sizes of the parent virtual hard disk and differencing disk.
+
+0xC03A0018
+
+STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED
+
+
+The chain of virtual hard disks is corrupted. A differencing disk is indicated in its own parent chain.
+
+0xC03A0019
+
+STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT
+
+
+The chain of virtual hard disks is inaccessible. There was an error opening a virtual hard disk further up the chain.
diff --git a/libcli/util/tstream.c b/libcli/util/tstream.c
new file mode 100644
index 0000000..95e31ca
--- /dev/null
+++ b/libcli/util/tstream.c
@@ -0,0 +1,205 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Stefan Metzmacher 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 <tevent.h>
+#include "system/filesys.h"
+#include "system/network.h"
+#include "../lib/tsocket/tsocket.h"
+#include "../libcli/util/tstream.h"
+#include "../lib/util/tevent_ntstatus.h"
+
+struct tstream_read_pdu_blob_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tevent_context *ev;
+ struct tstream_context *stream;
+ tstream_read_pdu_blob_full_fn_t *full_fn;
+ void *full_private;
+ } caller;
+
+ DATA_BLOB pdu_blob;
+ struct iovec tmp_vector;
+};
+
+static void tstream_read_pdu_blob_done(struct tevent_req *subreq);
+
+struct tevent_req *tstream_read_pdu_blob_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ size_t initial_read_size,
+ tstream_read_pdu_blob_full_fn_t *full_fn,
+ void *full_private)
+{
+ struct tevent_req *req;
+ struct tstream_read_pdu_blob_state *state;
+ struct tevent_req *subreq;
+ uint8_t *buf;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_read_pdu_blob_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.ev = ev;
+ state->caller.stream = stream;
+ state->caller.full_fn = full_fn;
+ state->caller.full_private = full_private;
+
+ if (initial_read_size == 0) {
+ tevent_req_error(req, EINVAL);
+ return tevent_req_post(req, ev);
+ }
+
+ buf = talloc_array(state, uint8_t, initial_read_size);
+ if (tevent_req_nomem(buf, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->pdu_blob.data = buf;
+ state->pdu_blob.length = initial_read_size;
+
+ state->tmp_vector.iov_base = (char *) buf;
+ state->tmp_vector.iov_len = initial_read_size;
+
+ subreq = tstream_readv_send(state, ev, stream, &state->tmp_vector, 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
+
+ return req;
+}
+
+static void tstream_read_pdu_blob_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tstream_read_pdu_blob_state *state =
+ tevent_req_data(req,
+ struct tstream_read_pdu_blob_state);
+ ssize_t ret;
+ int sys_errno;
+ size_t old_buf_size = state->pdu_blob.length;
+ size_t new_buf_size = 0;
+ size_t pdu_size = 0;
+ NTSTATUS status;
+ uint8_t *buf;
+
+ ret = tstream_readv_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix_common(sys_errno);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ status = state->caller.full_fn(state->caller.stream,
+ state->caller.full_private,
+ state->pdu_blob, &pdu_size);
+ if (NT_STATUS_IS_OK(status)) {
+ tevent_req_done(req);
+ return;
+ } else if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ /* more to get */
+ if (pdu_size > 0) {
+ new_buf_size = pdu_size;
+ } else {
+ /* we don't know the size yet, so get one more byte */
+ new_buf_size = old_buf_size + 1;
+ }
+ } else if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ if (new_buf_size <= old_buf_size) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_BUFFER_SIZE);
+ return;
+ }
+
+ buf = talloc_realloc(state, state->pdu_blob.data, uint8_t, new_buf_size);
+ if (tevent_req_nomem(buf, req)) {
+ return;
+ }
+ state->pdu_blob.data = buf;
+ state->pdu_blob.length = new_buf_size;
+
+ state->tmp_vector.iov_base = (char *) (buf + old_buf_size);
+ state->tmp_vector.iov_len = new_buf_size - old_buf_size;
+
+ subreq = tstream_readv_send(state,
+ state->caller.ev,
+ state->caller.stream,
+ &state->tmp_vector,
+ 1);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tstream_read_pdu_blob_done, req);
+}
+
+NTSTATUS tstream_read_pdu_blob_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pdu_blob)
+{
+ struct tstream_read_pdu_blob_state *state = tevent_req_data(req,
+ struct tstream_read_pdu_blob_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *pdu_blob = state->pdu_blob;
+ talloc_steal(mem_ctx, pdu_blob->data);
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tstream_full_request_u32(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob, size_t *size)
+{
+ if (blob.length < 4) {
+ return STATUS_MORE_ENTRIES;
+ }
+ *size = 4 + RIVAL(blob.data, 0);
+ if (*size > blob.length) {
+ return STATUS_MORE_ENTRIES;
+ }
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tstream_full_request_u16(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob, size_t *size)
+{
+ if (blob.length < 2) {
+ return STATUS_MORE_ENTRIES;
+ }
+ *size = 2 + RSVAL(blob.data, 0);
+ if (*size > blob.length) {
+ return STATUS_MORE_ENTRIES;
+ }
+ return NT_STATUS_OK;
+}
diff --git a/libcli/util/tstream.h b/libcli/util/tstream.h
new file mode 100644
index 0000000..cf66abe
--- /dev/null
+++ b/libcli/util/tstream.h
@@ -0,0 +1,123 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Copyright (C) Stefan Metzmacher 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 _LIBCLI_UTIL_TSTREAM_H_
+#define _LIBCLI_UTIL_TSTREAM_H_
+
+/**
+ * @brief The function which will report the size of the full pdu.
+ *
+ * @param[in] stream The tstream_context to operate on
+ *
+ * @param[in] private_data Some private data which could be used.
+ *
+ * @param[in] blob The received blob to get the size from.
+ *
+ * @param[out] packet_size The pointer to store the size of the full pdu.
+ *
+ * @return NT_STATUS_OK on success, STATUS_MORE_ENTRIES if there
+ * are more entries.
+ */
+typedef NTSTATUS tstream_read_pdu_blob_full_fn_t(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob,
+ size_t *packet_size);
+
+/**
+ * @brief A helper function to read a full PDU from a stream
+ *
+ * This function is designed for simple PDUs and as compat layer
+ * for the Samba4 packet interface.
+ *
+ * tstream_readv_pdu_send() is a more powerful interface,
+ * which is part of the main (non samba specific) tsocket code.
+ *
+ * @param[in] mem_ctx The memory context for the result.
+ *
+ * @param[in] ev The event context the operation should work on.
+ *
+ * @param[in] stream The stream to read data from.
+ *
+ * @param[in] initial_read_size The initial byte count that is needed to workout
+ * the full pdu size.
+ *
+ * @param[in] full_fn The callback function that will report the size
+ * of the full pdu.
+ *
+ * @param[in] full_private The private data for the callback function.
+ *
+ * @return The async request handle. NULL on fatal error.
+ *
+ * @see tstream_read_pdu_blob_recv()
+ * @see tstream_readv_pdu_send()
+ * @see tstream_readv_pdu_queue_send()
+ *
+ */
+struct tevent_req *tstream_read_pdu_blob_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream,
+ size_t initial_read_size,
+ tstream_read_pdu_blob_full_fn_t *full_fn,
+ void *full_private);
+/**
+ * @brief Receive the result of the tstream_read_pdu_blob_send() call.
+ *
+ * @param[in] req The tevent request from tstream_read_pdu_blob_send().
+ *
+ * @param[in] mem_ctx The memory context for returned pdu DATA_BLOB.
+ *
+ * @param[in] pdu_blob The DATA_BLOB with the full pdu.
+ *
+ * @return The NTSTATUS result, NT_STATUS_OK on success
+ * and others on failure.
+ *
+ * @see tstream_read_pdu_blob_send()
+ */
+NTSTATUS tstream_read_pdu_blob_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *pdu_blob);
+
+/**
+ * @brief Get a PDU size with a 32 bit size header field
+ *
+ * Work out if a packet is complete for protocols that use a 32 bit
+ * network byte order length.
+ *
+ * @see tstream_read_pdu_blob_send()
+ * @see tstream_read_pdu_blob_recv()
+ */
+NTSTATUS tstream_full_request_u32(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob, size_t *size);
+
+/**
+ * @brief Get a PDU size with a 16 bit size header field
+ *
+ * Work out if a packet is complete for protocols that use a 16 bit
+ * network byte order length.
+ *
+ * @see tstream_read_pdu_blob_send()
+ * @see tstream_read_pdu_blob_recv()
+ */
+NTSTATUS tstream_full_request_u16(struct tstream_context *stream,
+ void *private_data,
+ DATA_BLOB blob, size_t *size);
+
+
+#endif /* _LIBCLI_UTIL_TSTREAM_H_ */
diff --git a/libcli/util/werror.h b/libcli/util/werror.h
new file mode 100644
index 0000000..365e6d9
--- /dev/null
+++ b/libcli/util/werror.h
@@ -0,0 +1,171 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB parameters and setup, plus a whole lot more.
+
+ 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 _WERROR_H_
+#define _WERROR_H_
+
+#include <stdint.h>
+
+/* the following rather strange looking definitions of NTSTATUS and WERROR
+ and there in order to catch common coding errors where different error types
+ are mixed up. This is especially important as we slowly convert Samba
+ from using bool for internal functions
+*/
+
+#if defined(HAVE_IMMEDIATE_STRUCTURES)
+typedef struct {uint32_t w;} WERROR;
+#define W_ERROR(x) ((WERROR) { x })
+#define W_ERROR_V(x) ((x).w)
+#else
+typedef uint32_t WERROR;
+#define W_ERROR(x) (x)
+#define W_ERROR_V(x) (x)
+#endif
+
+#include "libcli/util/werror_gen.h"
+
+#define W_ERROR_IS_OK(x) (W_ERROR_V(x) == 0)
+#define W_ERROR_EQUAL(x,y) (W_ERROR_V(x) == W_ERROR_V(y))
+
+#define W_ERROR_HAVE_NO_MEMORY(x) do { \
+ if (!(x)) {\
+ return WERR_NOT_ENOUGH_MEMORY;\
+ }\
+} while (0)
+
+#define W_ERROR_HAVE_NO_MEMORY_AND_FREE(x, ctx) do { \
+ if (!(x)) {\
+ talloc_free(ctx); \
+ return WERR_NOT_ENOUGH_MEMORY;\
+ }\
+} while (0)
+
+#define W_ERROR_IS_OK_RETURN(x) do { \
+ if (W_ERROR_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define W_ERROR_NOT_OK_RETURN(x) do { \
+ if (!W_ERROR_IS_OK(x)) {\
+ return x;\
+ }\
+} while (0)
+
+#define W_ERROR_NOT_OK_GOTO_DONE(x) do { \
+ if (!W_ERROR_IS_OK(x)) {\
+ goto done;\
+ }\
+} while (0)
+
+#define W_ERROR_NOT_OK_GOTO(x, y) do {\
+ if (!W_ERROR_IS_OK(x)) {\
+ goto y;\
+ }\
+} while(0)
+
+/* these are win32 error codes. There are only a few places where
+ these matter for Samba, primarily in the NT printing code */
+#define WERR_OK W_ERROR(0x00000000)
+#define WERR_STATUS_MORE_ENTRIES W_ERROR(0x00000105)
+
+#define WERR_MULTIPLE_FAULT_VIOLATION W_ERROR(0x00000280)
+#define WERR_SERVICE_NOTIFICATION W_ERROR(0x000002CC)
+#define WERR_LOG_HARD_ERROR W_ERROR(0x000002CE)
+#define WERR_WAIT_1 W_ERROR(0x000002DB)
+#define WERR_WAIT_2 W_ERROR(0x000002DC)
+#define WERR_WAIT_3 W_ERROR(0x000002DD)
+#define WERR_WAIT_63 W_ERROR(0x000002DE)
+#define WERR_ABANDONED_WAIT_63 W_ERROR(0x000002E0)
+#define WERR_USER_APC W_ERROR(0x000002E1)
+#define WERR_KERNEL_APC W_ERROR(0x000002E2)
+#define WERR_ALERTED W_ERROR(0x000002E3)
+#define WERR_INVALID_PRIMARY_GROUP W_ERROR(0x0000051C)
+
+#define WERR_DS_DRA_SECRETS_DENIED W_ERROR(0x000021B6)
+
+#define WERR_DNS_ERROR_KEYMASTER_REQUIRED W_ERROR(0x0000238D)
+#define WERR_DNS_ERROR_NOT_ALLOWED_ON_SIGNED_ZONE W_ERROR(0x0000238E)
+#define WERR_DNS_ERROR_INVALID_NSEC3_PARAMETERS W_ERROR(0x0000238F)
+#define WERR_DNS_ERROR_NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS W_ERROR(0x00002390)
+#define WERR_DNS_ERROR_UNSUPPORTED_ALGORITHM W_ERROR(0x00002391)
+#define WERR_DNS_ERROR_INVALID_KEY_SIZE W_ERROR(0x00002392)
+#define WERR_DNS_ERROR_SIGNING_KEY_NOT_ACCESSIBLE W_ERROR(0x00002393)
+#define WERR_DNS_ERROR_KSP_DOES_NOT_SUPPORT_PROTECTION W_ERROR(0x00002394)
+#define WERR_DNS_ERROR_UNEXPECTED_DATA_PROTECTION_ERROR W_ERROR(0x00002395)
+#define WERR_DNS_ERROR_UNEXPECTED_CNG_ERROR W_ERROR(0x00002396)
+#define WERR_DNS_ERROR_UNKNOWN_SIGNING_PARAMETER_VERSION W_ERROR(0x00002397)
+#define WERR_DNS_ERROR_KSP_NOT_ACCESSIBLE W_ERROR(0x00002398)
+#define WERR_DNS_ERROR_TOO_MANY_SKDS W_ERROR(0x00002399)
+#define WERR_DNS_ERROR_INVALID_ROLLOVER_PERIOD W_ERROR(0x0000239A)
+#define WERR_DNS_ERROR_INVALID_INITIAL_ROLLOVER_OFFSET W_ERROR(0x0000239B)
+#define WERR_DNS_ERROR_ROLLOVER_IN_PROGRESS W_ERROR(0x0000239C)
+#define WERR_DNS_ERROR_STANDBY_KEY_NOT_PRESENT W_ERROR(0x0000239D)
+#define WERR_DNS_ERROR_NOT_ALLOWED_ON_ZSK W_ERROR(0x0000239E)
+#define WERR_DNS_ERROR_NOT_ALLOWED_ON_ACTIVE_SKD W_ERROR(0x0000239F)
+#define WERR_DNS_ERROR_ROLLOVER_ALREADY_QUEUED W_ERROR(0x000023A0)
+#define WERR_DNS_ERROR_NOT_ALLOWED_ON_UNSIGNED_ZONE W_ERROR(0x000023A1)
+#define WERR_DNS_ERROR_BAD_KEYMASTER W_ERROR(0x000023A2)
+#define WERR_DNS_ERROR_INVALID_SIGNATURE_VALIDITY_PERIOD W_ERROR(0x000023A3)
+#define WERR_DNS_ERROR_INVALID_NSEC3_ITERATION_COUNT W_ERROR(0x000023A4)
+#define WERR_DNS_ERROR_DNSSEC_IS_DISABLED W_ERROR(0x000023A5)
+#define WERR_DNS_ERROR_INVALID_XML W_ERROR(0x000023A6)
+#define WERR_DNS_ERROR_NO_VALID_TRUST_ANCHORS W_ERROR(0x000023A7)
+#define WERR_DNS_ERROR_ROLLOVER_NOT_POKEABLE W_ERROR(0x000023A8)
+#define WERR_DNS_ERROR_NSEC3_NAME_COLLISION W_ERROR(0x000023A9)
+
+#define WERR_DNS_REQUEST_PENDING W_ERROR(0x00002522)
+#define WERR_DNS_ERROR_NOT_ALLOWED_UNDER_DNAME W_ERROR(0x00002562)
+#define WERR_DNS_ERROR_DELEGATION_REQUIRED W_ERROR(0x00002563)
+#define WERR_DNS_ERROR_INVALID_POLICY_TABLE W_ERROR(0x00002564)
+#define WERR_DNS_ERROR_NODE_IS_DNMAE WERR_DNS_ERROR_NODE_IS_DNAME
+#define WERR_DNS_ERROR_NODE_IS_DNAME W_ERROR(0x000025F8) /* Used to be: "WERR_DNS_ERROR_NODE_IS_DNMAE" */
+#define WERR_DNS_ERROR_DNAME_COLLISION W_ERROR(0x000025F9)
+#define WERR_DNS_ERROR_ALIAS_LOOP W_ERROR(0x000025FA)
+
+/* Configuration Manager Errors */
+/* Basically Win32 errors meanings are specific to the \ntsvcs pipe */
+#define WERR_CM_INVALID_POINTER W_ERROR(3)
+#define WERR_CM_BUFFER_SMALL W_ERROR(26)
+#define WERR_CM_NO_MORE_HW_PROFILES W_ERROR(35)
+#define WERR_CM_NO_SUCH_VALUE W_ERROR(37)
+
+/* DFS errors */
+
+#ifndef NERR_BASE
+#define NERR_BASE (2100)
+#endif
+
+#ifndef MAX_NERR
+#define MAX_NERR (NERR_BASE+899)
+#endif
+
+/* Generic error code aliases */
+#define WERR_FOOBAR WERR_GEN_FAILURE
+
+/*****************************************************************************
+ returns a windows error message. not amazingly helpful, but better than a number.
+ *****************************************************************************/
+const char *win_errstr(WERROR werror);
+
+const char *get_friendly_werror_msg(WERROR werror);
+
+
+#endif
diff --git a/libcli/util/werror_err_table.txt b/libcli/util/werror_err_table.txt
new file mode 100644
index 0000000..5796afc
--- /dev/null
+++ b/libcli/util/werror_err_table.txt
@@ -0,0 +1,18949 @@
+Errors retrieved from https://msdn.microsoft.com/en-us/library/cc231199.aspx.
+License retrieved from https://msdn.microsoft.com/en-us/library/cc231196.aspx:
+
+Intellectual Property Rights Notice for Open Specifications Documentation
+
+ - Technical Documentation. Microsoft publishes Open Specifications documentation (“this documentation”) for protocols, file formats, data portability, computer languages, and standards support. Additionally, overview documents cover inter-protocol relationships and interactions.
+
+ - Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other terms that are contained in the terms of use for the Microsoft website that hosts this documentation, you can make copies of it in order to develop implementations of the technologies that are described in this documentation and can distribute portions of it in your implementations that use these technologies or in your documentation as necessary to properly document the implementation. You can also distribute in your implementation, with or without modification, any schemas, IDLs, or code samples that are included in the documentation. This permission also applies to any documents that are referenced in the Open Specifications documentation.
+
+ - No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation.
+
+ - Patents. Microsoft has patents that might cover your implementations of the technologies described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of this documentation grants any licenses under those patents or any other Microsoft patents. However, a given Open Specifications document might be covered by the Microsoft Open Specifications Promise or the Microsoft Community Promise. If you would prefer a written license, or if the technologies described in this documentation are not covered by the Open Specifications Promise or Community Promise, as applicable, patent licenses are available by contacting iplg@microsoft.com.
+
+ - Trademarks. The names of companies and products contained in this documentation might be covered by trademarks or similar intellectual property rights. This notice does not grant any licenses under those rights. For a list of Microsoft trademarks, visit www.microsoft.com/trademarks.
+
+ - Fictitious Names. The example companies, organizations, products, domain names, email addresses, logos, people, places, and events that are depicted in this documentation are fictitious. No association with any real company, organization, product, domain name, email address, logo, person, place, or event is intended or should be inferred.
+
+Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other than as specifically described above, whether by implication, estoppel, or otherwise.
+
+Tools. The Open Specifications documentation does not require the use of Microsoft programming tools or programming environments in order for you to develop an implementation. If you have access to Microsoft programming tools and environments, you are free to take advantage of them. Certain Open Specifications documents are intended for use in conjunction with publicly available standards specifications and network programming art and, as such, assume that the reader either is familiar with the aforementioned material or has immediate access to it.
+
+===========
+
+0x00000000
+
+ERROR_SUCCESS
+
+
+The operation completed successfully.
+
+0x00000000
+
+NERR_Success
+
+
+The operation completed successfully.
+
+0x00000001
+
+ERROR_INVALID_FUNCTION
+
+
+Incorrect function.
+
+0x00000002
+
+ERROR_FILE_NOT_FOUND
+
+
+The system cannot find the file specified.
+
+0x00000003
+
+ERROR_PATH_NOT_FOUND
+
+
+The system cannot find the path specified.
+
+0x00000004
+
+ERROR_TOO_MANY_OPEN_FILES
+
+
+The system cannot open the file.
+
+0x00000005
+
+ERROR_ACCESS_DENIED
+
+
+Access is denied.
+
+0x00000006
+
+ERROR_INVALID_HANDLE
+
+
+The handle is invalid.
+
+0x00000007
+
+ERROR_ARENA_TRASHED
+
+
+The storage control blocks were destroyed.
+
+0x00000008
+
+ERROR_NOT_ENOUGH_MEMORY
+
+
+Not enough storage is available to process this command.
+
+0x00000009
+
+ERROR_INVALID_BLOCK
+
+
+The storage control block address is invalid.
+
+0x0000000A
+
+ERROR_BAD_ENVIRONMENT
+
+
+The environment is incorrect.
+
+0x0000000B
+
+ERROR_BAD_FORMAT
+
+
+An attempt was made to load a program with an incorrect format.
+
+0x0000000C
+
+ERROR_INVALID_ACCESS
+
+
+The access code is invalid.
+
+0x0000000D
+
+ERROR_INVALID_DATA
+
+
+The data is invalid.
+
+0x0000000E
+
+ERROR_OUTOFMEMORY
+
+
+Not enough storage is available to complete this operation.
+
+0x0000000F
+
+ERROR_INVALID_DRIVE
+
+
+The system cannot find the drive specified.
+
+0x00000010
+
+ERROR_CURRENT_DIRECTORY
+
+
+The directory cannot be removed.
+
+0x00000011
+
+ERROR_NOT_SAME_DEVICE
+
+
+The system cannot move the file to a different disk drive.
+
+0x00000012
+
+ERROR_NO_MORE_FILES
+
+
+There are no more files.
+
+0x00000013
+
+ERROR_WRITE_PROTECT
+
+
+The media is write-protected.
+
+0x00000014
+
+ERROR_BAD_UNIT
+
+
+The system cannot find the device specified.
+
+0x00000015
+
+ERROR_NOT_READY
+
+
+The device is not ready.
+
+0x00000016
+
+ERROR_BAD_COMMAND
+
+
+The device does not recognize the command.
+
+0x00000017
+
+ERROR_CRC
+
+
+Data error (cyclic redundancy check).
+
+0x00000018
+
+ERROR_BAD_LENGTH
+
+
+The program issued a command but the command length is incorrect.
+
+0x00000019
+
+ERROR_SEEK
+
+
+The drive cannot locate a specific area or track on the disk.
+
+0x0000001A
+
+ERROR_NOT_DOS_DISK
+
+
+The specified disk cannot be accessed.
+
+0x0000001B
+
+ERROR_SECTOR_NOT_FOUND
+
+
+The drive cannot find the sector requested.
+
+0x0000001C
+
+ERROR_OUT_OF_PAPER
+
+
+The printer is out of paper.
+
+0x0000001D
+
+ERROR_WRITE_FAULT
+
+
+The system cannot write to the specified device.
+
+0x0000001E
+
+ERROR_READ_FAULT
+
+
+The system cannot read from the specified device.
+
+0x0000001F
+
+ERROR_GEN_FAILURE
+
+
+A device attached to the system is not functioning.
+
+0x00000020
+
+ERROR_SHARING_VIOLATION
+
+
+The process cannot access the file because it is being used by another process.
+
+0x00000021
+
+ERROR_LOCK_VIOLATION
+
+
+The process cannot access the file because another process has locked a portion of the file.
+
+0x00000022
+
+ERROR_WRONG_DISK
+
+
+The wrong disk is in the drive. Insert %2 (Volume Serial Number: %3) into drive %1.
+
+0x00000024
+
+ERROR_SHARING_BUFFER_EXCEEDED
+
+
+Too many files opened for sharing.
+
+0x00000026
+
+ERROR_HANDLE_EOF
+
+
+Reached the end of the file.
+
+0x00000027
+
+ERROR_HANDLE_DISK_FULL
+
+
+The disk is full.
+
+0x00000032
+
+ERROR_NOT_SUPPORTED
+
+
+The request is not supported.
+
+0x00000033
+
+ERROR_REM_NOT_LIST
+
+
+Windows cannot find the network path. Verify that the network path is correct and the destination computer is not busy or turned off. If Windows still cannot find the network path, contact your network administrator.
+
+0x00000034
+
+ERROR_DUP_NAME
+
+
+You were not connected because a duplicate name exists on the network. Go to System in Control Panel to change the computer name, and then try again.
+
+0x00000035
+
+ERROR_BAD_NETPATH
+
+
+The network path was not found.
+
+0x00000036
+
+ERROR_NETWORK_BUSY
+
+
+The network is busy.
+
+0x00000037
+
+ERROR_DEV_NOT_EXIST
+
+
+The specified network resource or device is no longer available.
+
+0x00000038
+
+ERROR_TOO_MANY_CMDS
+
+
+The network BIOS command limit has been reached.
+
+0x00000039
+
+ERROR_ADAP_HDW_ERR
+
+
+A network adapter hardware error occurred.
+
+0x0000003A
+
+ERROR_BAD_NET_RESP
+
+
+The specified server cannot perform the requested operation.
+
+0x0000003B
+
+ERROR_UNEXP_NET_ERR
+
+
+An unexpected network error occurred.
+
+0x0000003C
+
+ERROR_BAD_REM_ADAP
+
+
+The remote adapter is not compatible.
+
+0x0000003D
+
+ERROR_PRINTQ_FULL
+
+
+The print queue is full.
+
+0x0000003E
+
+ERROR_NO_SPOOL_SPACE
+
+
+Space to store the file waiting to be printed is not available on the server.
+
+0x0000003F
+
+ERROR_PRINT_CANCELLED
+
+
+Your file waiting to be printed was deleted.
+
+0x00000040
+
+ERROR_NETNAME_DELETED
+
+
+The specified network name is no longer available.
+
+0x00000041
+
+ERROR_NETWORK_ACCESS_DENIED
+
+
+Network access is denied.
+
+0x00000042
+
+ERROR_BAD_DEV_TYPE
+
+
+The network resource type is not correct.
+
+0x00000043
+
+ERROR_BAD_NET_NAME
+
+
+The network name cannot be found.
+
+0x00000044
+
+ERROR_TOO_MANY_NAMES
+
+
+The name limit for the local computer network adapter card was exceeded.
+
+0x00000045
+
+ERROR_TOO_MANY_SESS
+
+
+The network BIOS session limit was exceeded.
+
+0x00000046
+
+ERROR_SHARING_PAUSED
+
+
+The remote server has been paused or is in the process of being started.
+
+0x00000047
+
+ERROR_REQ_NOT_ACCEP
+
+
+No more connections can be made to this remote computer at this time because the computer has accepted the maximum number of connections.
+
+0x00000048
+
+ERROR_REDIR_PAUSED
+
+
+The specified printer or disk device has been paused.
+
+0x00000050
+
+ERROR_FILE_EXISTS
+
+
+The file exists.
+
+0x00000052
+
+ERROR_CANNOT_MAKE
+
+
+The directory or file cannot be created.
+
+0x00000053
+
+ERROR_FAIL_I24
+
+
+Fail on INT 24.
+
+0x00000054
+
+ERROR_OUT_OF_STRUCTURES
+
+
+Storage to process this request is not available.
+
+0x00000055
+
+ERROR_ALREADY_ASSIGNED
+
+
+The local device name is already in use.
+
+0x00000056
+
+ERROR_INVALID_PASSWORD
+
+
+The specified network password is not correct.
+
+0x00000057
+
+ERROR_INVALID_PARAMETER
+
+
+The parameter is incorrect.
+
+0x00000058
+
+ERROR_NET_WRITE_FAULT
+
+
+A write fault occurred on the network.
+
+0x00000059
+
+ERROR_NO_PROC_SLOTS
+
+
+The system cannot start another process at this time.
+
+0x00000064
+
+ERROR_TOO_MANY_SEMAPHORES
+
+
+Cannot create another system semaphore.
+
+0x00000065
+
+ERROR_EXCL_SEM_ALREADY_OWNED
+
+
+The exclusive semaphore is owned by another process.
+
+0x00000066
+
+ERROR_SEM_IS_SET
+
+
+The semaphore is set and cannot be closed.
+
+0x00000067
+
+ERROR_TOO_MANY_SEM_REQUESTS
+
+
+The semaphore cannot be set again.
+
+0x00000068
+
+ERROR_INVALID_AT_INTERRUPT_TIME
+
+
+Cannot request exclusive semaphores at interrupt time.
+
+0x00000069
+
+ERROR_SEM_OWNER_DIED
+
+
+The previous ownership of this semaphore has ended.
+
+0x0000006A
+
+ERROR_SEM_USER_LIMIT
+
+
+Insert the disk for drive %1.
+
+0x0000006B
+
+ERROR_DISK_CHANGE
+
+
+The program stopped because an alternate disk was not inserted.
+
+0x0000006C
+
+ERROR_DRIVE_LOCKED
+
+
+The disk is in use or locked by another process.
+
+0x0000006D
+
+ERROR_BROKEN_PIPE
+
+
+The pipe has been ended.
+
+0x0000006E
+
+ERROR_OPEN_FAILED
+
+
+The system cannot open the device or file specified.
+
+0x0000006F
+
+ERROR_BUFFER_OVERFLOW
+
+
+The file name is too long.
+
+0x00000070
+
+ERROR_DISK_FULL
+
+
+There is not enough space on the disk.
+
+0x00000071
+
+ERROR_NO_MORE_SEARCH_HANDLES
+
+
+No more internal file identifiers are available.
+
+0x00000072
+
+ERROR_INVALID_TARGET_HANDLE
+
+
+The target internal file identifier is incorrect.
+
+0x00000075
+
+ERROR_INVALID_CATEGORY
+
+
+The Input Output Control (IOCTL) call made by the application program is not correct.
+
+0x00000076
+
+ERROR_INVALID_VERIFY_SWITCH
+
+
+The verify-on-write switch parameter value is not correct.
+
+0x00000077
+
+ERROR_BAD_DRIVER_LEVEL
+
+
+The system does not support the command requested.
+
+0x00000078
+
+ERROR_CALL_NOT_IMPLEMENTED
+
+
+This function is not supported on this system.
+
+0x00000079
+
+ERROR_SEM_TIMEOUT
+
+
+The semaphore time-out period has expired.
+
+0x0000007A
+
+ERROR_INSUFFICIENT_BUFFER
+
+
+The data area passed to a system call is too small.
+
+0x0000007B
+
+ERROR_INVALID_NAME
+
+
+The file name, directory name, or volume label syntax is incorrect.
+
+0x0000007C
+
+ERROR_INVALID_LEVEL
+
+
+The system call level is not correct.
+
+0x0000007D
+
+ERROR_NO_VOLUME_LABEL
+
+
+The disk has no volume label.
+
+0x0000007E
+
+ERROR_MOD_NOT_FOUND
+
+
+The specified module could not be found.
+
+0x0000007F
+
+ERROR_PROC_NOT_FOUND
+
+
+The specified procedure could not be found.
+
+0x00000080
+
+ERROR_WAIT_NO_CHILDREN
+
+
+There are no child processes to wait for.
+
+0x00000081
+
+ERROR_CHILD_NOT_COMPLETE
+
+
+The %1 application cannot be run in Win32 mode.
+
+0x00000082
+
+ERROR_DIRECT_ACCESS_HANDLE
+
+
+Attempt to use a file handle to an open disk partition for an operation other than raw disk I/O.
+
+0x00000083
+
+ERROR_NEGATIVE_SEEK
+
+
+An attempt was made to move the file pointer before the beginning of the file.
+
+0x00000084
+
+ERROR_SEEK_ON_DEVICE
+
+
+The file pointer cannot be set on the specified device or file.
+
+0x00000085
+
+ERROR_IS_JOIN_TARGET
+
+
+A JOIN or SUBST command cannot be used for a drive that contains previously joined drives.
+
+0x00000086
+
+ERROR_IS_JOINED
+
+
+An attempt was made to use a JOIN or SUBST command on a drive that has already been joined.
+
+0x00000087
+
+ERROR_IS_SUBSTED
+
+
+An attempt was made to use a JOIN or SUBST command on a drive that has already been substituted.
+
+0x00000088
+
+ERROR_NOT_JOINED
+
+
+The system tried to delete the JOIN of a drive that is not joined.
+
+0x00000089
+
+ERROR_NOT_SUBSTED
+
+
+The system tried to delete the substitution of a drive that is not substituted.
+
+0x0000008A
+
+ERROR_JOIN_TO_JOIN
+
+
+The system tried to join a drive to a directory on a joined drive.
+
+0x0000008B
+
+ERROR_SUBST_TO_SUBST
+
+
+The system tried to substitute a drive to a directory on a substituted drive.
+
+0x0000008C
+
+ERROR_JOIN_TO_SUBST
+
+
+The system tried to join a drive to a directory on a substituted drive.
+
+0x0000008D
+
+ERROR_SUBST_TO_JOIN
+
+
+The system tried to SUBST a drive to a directory on a joined drive.
+
+0x0000008E
+
+ERROR_BUSY_DRIVE
+
+
+The system cannot perform a JOIN or SUBST at this time.
+
+0x0000008F
+
+ERROR_SAME_DRIVE
+
+
+The system cannot join or substitute a drive to or for a directory on the same drive.
+
+0x00000090
+
+ERROR_DIR_NOT_ROOT
+
+
+The directory is not a subdirectory of the root directory.
+
+0x00000091
+
+ERROR_DIR_NOT_EMPTY
+
+
+The directory is not empty.
+
+0x00000092
+
+ERROR_IS_SUBST_PATH
+
+
+The path specified is being used in a substitute.
+
+0x00000093
+
+ERROR_IS_JOIN_PATH
+
+
+Not enough resources are available to process this command.
+
+0x00000094
+
+ERROR_PATH_BUSY
+
+
+The path specified cannot be used at this time.
+
+0x00000095
+
+ERROR_IS_SUBST_TARGET
+
+
+An attempt was made to join or substitute a drive for which a directory on the drive is the target of a previous substitute.
+
+0x00000096
+
+ERROR_SYSTEM_TRACE
+
+
+System trace information was not specified in your CONFIG.SYS file, or tracing is disallowed.
+
+0x00000097
+
+ERROR_INVALID_EVENT_COUNT
+
+
+The number of specified semaphore events for DosMuxSemWait is not correct.
+
+0x00000098
+
+ERROR_TOO_MANY_MUXWAITERS
+
+
+DosMuxSemWait did not execute; too many semaphores are already set.
+
+0x00000099
+
+ERROR_INVALID_LIST_FORMAT
+
+
+The DosMuxSemWait list is not correct.
+
+0x0000009A
+
+ERROR_LABEL_TOO_LONG
+
+
+The volume label you entered exceeds the label character limit of the destination file system.
+
+0x0000009B
+
+ERROR_TOO_MANY_TCBS
+
+
+Cannot create another thread.
+
+0x0000009C
+
+ERROR_SIGNAL_REFUSED
+
+
+The recipient process has refused the signal.
+
+0x0000009D
+
+ERROR_DISCARDED
+
+
+The segment is already discarded and cannot be locked.
+
+0x0000009E
+
+ERROR_NOT_LOCKED
+
+
+The segment is already unlocked.
+
+0x0000009F
+
+ERROR_BAD_THREADID_ADDR
+
+
+The address for the thread ID is not correct.
+
+0x000000A0
+
+ERROR_BAD_ARGUMENTS
+
+
+One or more arguments are not correct.
+
+0x000000A1
+
+ERROR_BAD_PATHNAME
+
+
+The specified path is invalid.
+
+0x000000A2
+
+ERROR_SIGNAL_PENDING
+
+
+A signal is already pending.
+
+0x000000A4
+
+ERROR_MAX_THRDS_REACHED
+
+
+No more threads can be created in the system.
+
+0x000000A7
+
+ERROR_LOCK_FAILED
+
+
+Unable to lock a region of a file.
+
+0x000000AA
+
+ERROR_BUSY
+
+
+The requested resource is in use.
+
+0x000000AD
+
+ERROR_CANCEL_VIOLATION
+
+
+A lock request was not outstanding for the supplied cancel region.
+
+0x000000AE
+
+ERROR_ATOMIC_LOCKS_NOT_SUPPORTED
+
+
+The file system does not support atomic changes to the lock type.
+
+0x000000B4
+
+ERROR_INVALID_SEGMENT_NUMBER
+
+
+The system detected a segment number that was not correct.
+
+0x000000B6
+
+ERROR_INVALID_ORDINAL
+
+
+The operating system cannot run %1.
+
+0x000000B7
+
+ERROR_ALREADY_EXISTS
+
+
+Cannot create a file when that file already exists.
+
+0x000000BA
+
+ERROR_INVALID_FLAG_NUMBER
+
+
+The flag passed is not correct.
+
+0x000000BB
+
+ERROR_SEM_NOT_FOUND
+
+
+The specified system semaphore name was not found.
+
+0x000000BC
+
+ERROR_INVALID_STARTING_CODESEG
+
+
+The operating system cannot run %1.
+
+0x000000BD
+
+ERROR_INVALID_STACKSEG
+
+
+The operating system cannot run %1.
+
+0x000000BE
+
+ERROR_INVALID_MODULETYPE
+
+
+The operating system cannot run %1.
+
+0x000000BF
+
+ERROR_INVALID_EXE_SIGNATURE
+
+
+Cannot run %1 in Win32 mode.
+
+0x000000C0
+
+ERROR_EXE_MARKED_INVALID
+
+
+The operating system cannot run %1.
+
+0x000000C1
+
+ERROR_BAD_EXE_FORMAT
+
+
+%1 is not a valid Win32 application.
+
+0x000000C2
+
+ERROR_ITERATED_DATA_EXCEEDS_64k
+
+
+The operating system cannot run %1.
+
+0x000000C3
+
+ERROR_INVALID_MINALLOCSIZE
+
+
+The operating system cannot run %1.
+
+0x000000C4
+
+ERROR_DYNLINK_FROM_INVALID_RING
+
+
+The operating system cannot run this application program.
+
+0x000000C5
+
+ERROR_IOPL_NOT_ENABLED
+
+
+The operating system is not presently configured to run this application.
+
+0x000000C6
+
+ERROR_INVALID_SEGDPL
+
+
+The operating system cannot run %1.
+
+0x000000C7
+
+ERROR_AUTODATASEG_EXCEEDS_64k
+
+
+The operating system cannot run this application program.
+
+0x000000C8
+
+ERROR_RING2SEG_MUST_BE_MOVABLE
+
+
+The code segment cannot be greater than or equal to 64 KB.
+
+0x000000C9
+
+ERROR_RELOC_CHAIN_XEEDS_SEGLIM
+
+
+The operating system cannot run %1.
+
+0x000000CA
+
+ERROR_INFLOOP_IN_RELOC_CHAIN
+
+
+The operating system cannot run %1.
+
+0x000000CB
+
+ERROR_ENVVAR_NOT_FOUND
+
+
+The system could not find the environment option that was entered.
+
+0x000000CD
+
+ERROR_NO_SIGNAL_SENT
+
+
+No process in the command subtree has a signal handler.
+
+0x000000CE
+
+ERROR_FILENAME_EXCED_RANGE
+
+
+The file name or extension is too long.
+
+0x000000CF
+
+ERROR_RING2_STACK_IN_USE
+
+
+The ring 2 stack is in use.
+
+0x000000D0
+
+ERROR_META_EXPANSION_TOO_LONG
+
+
+The asterisk (*) or question mark (?) global file name characters are entered incorrectly, or too many global file name characters are specified.
+
+0x000000D1
+
+ERROR_INVALID_SIGNAL_NUMBER
+
+
+The signal being posted is not correct.
+
+0x000000D2
+
+ERROR_THREAD_1_INACTIVE
+
+
+The signal handler cannot be set.
+
+0x000000D4
+
+ERROR_LOCKED
+
+
+The segment is locked and cannot be reallocated.
+
+0x000000D6
+
+ERROR_TOO_MANY_MODULES
+
+
+Too many dynamic-link modules are attached to this program or dynamic-link module.
+
+0x000000D7
+
+ERROR_NESTING_NOT_ALLOWED
+
+
+Cannot nest calls to LoadModule.
+
+0x000000D8
+
+ERROR_EXE_MACHINE_TYPE_MISMATCH
+
+
+This version of %1 is not compatible with the version of Windows you're running. Check your computer's system information to see whether you need an x86 (32-bit) or x64 (64-bit) version of the program, and then contact the software publisher.
+
+0x000000D9
+
+ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY
+
+
+The image file %1 is signed, unable to modify.
+
+0x000000DA
+
+ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY
+
+
+The image file %1 is strong signed, unable to modify.
+
+0x000000DC
+
+ERROR_FILE_CHECKED_OUT
+
+
+This file is checked out or locked for editing by another user.
+
+0x000000DD
+
+ERROR_CHECKOUT_REQUIRED
+
+
+The file must be checked out before saving changes.
+
+0x000000DE
+
+ERROR_BAD_FILE_TYPE
+
+
+The file type being saved or retrieved has been blocked.
+
+0x000000DF
+
+ERROR_FILE_TOO_LARGE
+
+
+The file size exceeds the limit allowed and cannot be saved.
+
+0x000000E0
+
+ERROR_FORMS_AUTH_REQUIRED
+
+
+Access denied. Before opening files in this location, you must first browse to the website and select the option to sign in automatically.
+
+0x000000E1
+
+ERROR_VIRUS_INFECTED
+
+
+Operation did not complete successfully because the file contains a virus.
+
+0x000000E2
+
+ERROR_VIRUS_DELETED
+
+
+This file contains a virus and cannot be opened. Due to the nature of this virus, the file has been removed from this location.
+
+0x000000E5
+
+ERROR_PIPE_LOCAL
+
+
+The pipe is local.
+
+0x000000E6
+
+ERROR_BAD_PIPE
+
+
+The pipe state is invalid.
+
+0x000000E7
+
+ERROR_PIPE_BUSY
+
+
+All pipe instances are busy.
+
+0x000000E8
+
+ERROR_NO_DATA
+
+
+The pipe is being closed.
+
+0x000000E9
+
+ERROR_PIPE_NOT_CONNECTED
+
+
+No process is on the other end of the pipe.
+
+0x000000EA
+
+ERROR_MORE_DATA
+
+
+More data is available.
+
+0x000000F0
+
+ERROR_VC_DISCONNECTED
+
+
+The session was canceled.
+
+0x000000FE
+
+ERROR_INVALID_EA_NAME
+
+
+The specified extended attribute name was invalid.
+
+0x000000FF
+
+ERROR_EA_LIST_INCONSISTENT
+
+
+The extended attributes are inconsistent.
+
+0x00000102
+
+WAIT_TIMEOUT
+
+
+The wait operation timed out.
+
+0x00000103
+
+ERROR_NO_MORE_ITEMS
+
+
+No more data is available.
+
+0x0000010A
+
+ERROR_CANNOT_COPY
+
+
+The copy functions cannot be used.
+
+0x0000010B
+
+ERROR_DIRECTORY
+
+
+The directory name is invalid.
+
+0x00000113
+
+ERROR_EAS_DIDNT_FIT
+
+
+The extended attributes did not fit in the buffer.
+
+0x00000114
+
+ERROR_EA_FILE_CORRUPT
+
+
+The extended attribute file on the mounted file system is corrupt.
+
+0x00000115
+
+ERROR_EA_TABLE_FULL
+
+
+The extended attribute table file is full.
+
+0x00000116
+
+ERROR_INVALID_EA_HANDLE
+
+
+The specified extended attribute handle is invalid.
+
+0x0000011A
+
+ERROR_EAS_NOT_SUPPORTED
+
+
+The mounted file system does not support extended attributes.
+
+0x00000120
+
+ERROR_NOT_OWNER
+
+
+Attempt to release mutex not owned by caller.
+
+0x0000012A
+
+ERROR_TOO_MANY_POSTS
+
+
+Too many posts were made to a semaphore.
+
+0x0000012B
+
+ERROR_PARTIAL_COPY
+
+
+Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
+
+0x0000012C
+
+ERROR_OPLOCK_NOT_GRANTED
+
+
+The oplock request is denied.
+
+0x0000012D
+
+ERROR_INVALID_OPLOCK_PROTOCOL
+
+
+An invalid oplock acknowledgment was received by the system.
+
+0x0000012E
+
+ERROR_DISK_TOO_FRAGMENTED
+
+
+The volume is too fragmented to complete this operation.
+
+0x0000012F
+
+ERROR_DELETE_PENDING
+
+
+The file cannot be opened because it is in the process of being deleted.
+
+0x0000013D
+
+ERROR_MR_MID_NOT_FOUND
+
+
+The system cannot find message text for message number 0x%1 in the message file for %2.
+
+0x0000013E
+
+ERROR_SCOPE_NOT_FOUND
+
+
+The scope specified was not found.
+
+0x0000015E
+
+ERROR_FAIL_NOACTION_REBOOT
+
+
+No action was taken because a system reboot is required.
+
+0x0000015F
+
+ERROR_FAIL_SHUTDOWN
+
+
+The shutdown operation failed.
+
+0x00000160
+
+ERROR_FAIL_RESTART
+
+
+The restart operation failed.
+
+0x00000161
+
+ERROR_MAX_SESSIONS_REACHED
+
+
+The maximum number of sessions has been reached.
+
+0x00000190
+
+ERROR_THREAD_MODE_ALREADY_BACKGROUND
+
+
+The thread is already in background processing mode.
+
+0x00000191
+
+ERROR_THREAD_MODE_NOT_BACKGROUND
+
+
+The thread is not in background processing mode.
+
+0x00000192
+
+ERROR_PROCESS_MODE_ALREADY_BACKGROUND
+
+
+The process is already in background processing mode.
+
+0x00000193
+
+ERROR_PROCESS_MODE_NOT_BACKGROUND
+
+
+The process is not in background processing mode.
+
+0x000001E7
+
+ERROR_INVALID_ADDRESS
+
+
+Attempt to access invalid address.
+
+0x000001F4
+
+ERROR_USER_PROFILE_LOAD
+
+
+User profile cannot be loaded.
+
+0x00000216
+
+ERROR_ARITHMETIC_OVERFLOW
+
+
+Arithmetic result exceeded 32 bits.
+
+0x00000217
+
+ERROR_PIPE_CONNECTED
+
+
+There is a process on the other end of the pipe.
+
+0x00000218
+
+ERROR_PIPE_LISTENING
+
+
+Waiting for a process to open the other end of the pipe.
+
+0x00000219
+
+ERROR_VERIFIER_STOP
+
+
+Application verifier has found an error in the current process.
+
+0x0000021A
+
+ERROR_ABIOS_ERROR
+
+
+An error occurred in the ABIOS subsystem.
+
+0x0000021B
+
+ERROR_WX86_WARNING
+
+
+A warning occurred in the WX86 subsystem.
+
+0x0000021C
+
+ERROR_WX86_ERROR
+
+
+An error occurred in the WX86 subsystem.
+
+0x0000021D
+
+ERROR_TIMER_NOT_CANCELED
+
+
+An attempt was made to cancel or set a timer that has an associated asynchronous procedure call (APC) and the subject thread is not the thread that originally set the timer with an associated APC routine.
+
+0x0000021E
+
+ERROR_UNWIND
+
+
+Unwind exception code.
+
+0x0000021F
+
+ERROR_BAD_STACK
+
+
+An invalid or unaligned stack was encountered during an unwind operation.
+
+0x00000220
+
+ERROR_INVALID_UNWIND_TARGET
+
+
+An invalid unwind target was encountered during an unwind operation.
+
+0x00000221
+
+ERROR_INVALID_PORT_ATTRIBUTES
+
+
+Invalid object attributes specified to NtCreatePort or invalid port attributes specified to NtConnectPort.
+
+0x00000222
+
+ERROR_PORT_MESSAGE_TOO_LONG
+
+
+Length of message passed to NtRequestPort or NtRequestWaitReplyPort was longer than the maximum message allowed by the port.
+
+0x00000223
+
+ERROR_INVALID_QUOTA_LOWER
+
+
+An attempt was made to lower a quota limit below the current usage.
+
+0x00000224
+
+ERROR_DEVICE_ALREADY_ATTACHED
+
+
+An attempt was made to attach to a device that was already attached to another device.
+
+0x00000225
+
+ERROR_INSTRUCTION_MISALIGNMENT
+
+
+An attempt was made to execute an instruction at an unaligned address, and the host system does not support unaligned instruction references.
+
+0x00000226
+
+ERROR_PROFILING_NOT_STARTED
+
+
+Profiling not started.
+
+0x00000227
+
+ERROR_PROFILING_NOT_STOPPED
+
+
+Profiling not stopped.
+
+0x00000228
+
+ERROR_COULD_NOT_INTERPRET
+
+
+The passed ACL did not contain the minimum required information.
+
+0x00000229
+
+ERROR_PROFILING_AT_LIMIT
+
+
+The number of active profiling objects is at the maximum and no more can be started.
+
+0x0000022A
+
+ERROR_CANT_WAIT
+
+
+Used to indicate that an operation cannot continue without blocking for I/O.
+
+0x0000022B
+
+ERROR_CANT_TERMINATE_SELF
+
+
+Indicates that a thread attempted to terminate itself by default (called NtTerminateThread with NULL) and it was the last thread in the current process.
+
+0x0000022C
+
+ERROR_UNEXPECTED_MM_CREATE_ERR
+
+
+If an MM error is returned that is not defined in the standard FsRtl filter, it is converted to one of the following errors that is guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0x0000022D
+
+ERROR_UNEXPECTED_MM_MAP_ERROR
+
+
+If an MM error is returned that is not defined in the standard FsRtl filter, it is converted to one of the following errors that is guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0x0000022E
+
+ERROR_UNEXPECTED_MM_EXTEND_ERR
+
+
+If an MM error is returned that is not defined in the standard FsRtl filter, it is converted to one of the following errors that is guaranteed to be in the filter. In this case, information is lost; however, the filter correctly handles the exception.
+
+0x0000022F
+
+ERROR_BAD_FUNCTION_TABLE
+
+
+A malformed function table was encountered during an unwind operation.
+
+0x00000230
+
+ERROR_NO_GUID_TRANSLATION
+
+
+Indicates that an attempt was made to assign protection to a file system file or directory and one of the SIDs in the security descriptor could not be translated into a GUID that could be stored by the file system. This causes the protection attempt to fail, which might cause a file creation attempt to fail.
+
+0x00000231
+
+ERROR_INVALID_LDT_SIZE
+
+
+Indicates that an attempt was made to grow a local domain table (LDT) by setting its size, or that the size was not an even number of selectors.
+
+0x00000233
+
+ERROR_INVALID_LDT_OFFSET
+
+
+Indicates that the starting value for the LDT information was not an integral multiple of the selector size.
+
+0x00000234
+
+ERROR_INVALID_LDT_DESCRIPTOR
+
+
+Indicates that the user supplied an invalid descriptor when trying to set up LDT descriptors.
+
+0x00000235
+
+ERROR_TOO_MANY_THREADS
+
+
+Indicates a process has too many threads to perform the requested action. For example, assignment of a primary token can be performed only when a process has zero or one threads.
+
+0x00000236
+
+ERROR_THREAD_NOT_IN_PROCESS
+
+
+An attempt was made to operate on a thread within a specific process, but the thread specified is not in the process specified.
+
+0x00000237
+
+ERROR_PAGEFILE_QUOTA_EXCEEDED
+
+
+Page file quota was exceeded.
+
+0x00000238
+
+ERROR_LOGON_SERVER_CONFLICT
+
+
+The Netlogon service cannot start because another Netlogon service running in the domain conflicts with the specified role.
+
+0x00000239
+
+ERROR_SYNCHRONIZATION_REQUIRED
+
+
+On applicable Windows Server releases, the Security Accounts Manager (SAM) database is significantly out of synchronization with the copy on the domain controller. A complete synchronization is required.
+
+0x0000023A
+
+ERROR_NET_OPEN_FAILED
+
+
+The NtCreateFile API failed. This error should never be returned to an application, it is a place holder for the Windows LAN Manager Redirector to use in its internal error mapping routines.
+
+0x0000023B
+
+ERROR_IO_PRIVILEGE_FAILED
+
+
+{Privilege Failed} The I/O permissions for the process could not be changed.
+
+0x0000023C
+
+ERROR_CONTROL_C_EXIT
+
+
+{Application Exit by CTRL+C} The application terminated as a result of a CTRL+C.
+
+0x0000023D
+
+ERROR_MISSING_SYSTEMFILE
+
+
+{Missing System File} The required system file %hs is bad or missing.
+
+0x0000023E
+
+ERROR_UNHANDLED_EXCEPTION
+
+
+{Application Error} The exception %s (0x%08lx) occurred in the application at location 0x%08lx.
+
+0x0000023F
+
+ERROR_APP_INIT_FAILURE
+
+
+{Application Error} The application failed to initialize properly (0x%lx). Click OK to terminate the application.
+
+0x00000240
+
+ERROR_PAGEFILE_CREATE_FAILED
+
+
+{Unable to Create Paging File} The creation of the paging file %hs failed (%lx). The requested size was %ld.
+
+0x00000241
+
+ERROR_INVALID_IMAGE_HASH
+
+
+The hash for the image cannot be found in the system catalogs. The image is likely corrupt or the victim of tampering.
+
+0x00000242
+
+ERROR_NO_PAGEFILE
+
+
+{No Paging File Specified} No paging file was specified in the system configuration.
+
+0x00000243
+
+ERROR_ILLEGAL_FLOAT_CONTEXT
+
+
+{EXCEPTION} A real-mode application issued a floating-point instruction, and floating-point hardware is not present.
+
+0x00000244
+
+ERROR_NO_EVENT_PAIR
+
+
+An event pair synchronization operation was performed using the thread-specific client/server event pair object, but no event pair object was associated with the thread.
+
+0x00000245
+
+ERROR_DOMAIN_CTRLR_CONFIG_ERROR
+
+
+A domain server has an incorrect configuration.
+
+0x00000246
+
+ERROR_ILLEGAL_CHARACTER
+
+
+An illegal character was encountered. For a multibyte character set, this includes a lead byte without a succeeding trail byte. For the Unicode character set, this includes the characters 0xFFFF and 0xFFFE.
+
+0x00000247
+
+ERROR_UNDEFINED_CHARACTER
+
+
+The Unicode character is not defined in the Unicode character set installed on the system.
+
+0x00000248
+
+ERROR_FLOPPY_VOLUME
+
+
+The paging file cannot be created on a floppy disk.
+
+0x00000249
+
+ERROR_BIOS_FAILED_TO_CONNECT_INTERRUPT
+
+
+The system bios failed to connect a system interrupt to the device or bus for which the device is connected.
+
+0x0000024A
+
+ERROR_BACKUP_CONTROLLER
+
+
+This operation is only allowed for the primary domain controller (PDC) of the domain.
+
+0x0000024B
+
+ERROR_MUTANT_LIMIT_EXCEEDED
+
+
+An attempt was made to acquire a mutant such that its maximum count would have been exceeded.
+
+0x0000024C
+
+ERROR_FS_DRIVER_REQUIRED
+
+
+A volume has been accessed for which a file system driver is required that has not yet been loaded.
+
+0x0000024D
+
+ERROR_CANNOT_LOAD_REGISTRY_FILE
+
+
+{Registry File Failure} The registry cannot load the hive (file): %hs or its log or alternate. It is corrupt, absent, or not writable.
+
+0x0000024E
+
+ERROR_DEBUG_ATTACH_FAILED
+
+
+{Unexpected Failure in DebugActiveProcess} An unexpected failure occurred while processing a DebugActiveProcess API request. Choosing OK will terminate the process, and choosing Cancel will ignore the error.
+
+0x0000024F
+
+ERROR_SYSTEM_PROCESS_TERMINATED
+
+
+{Fatal System Error} The %hs system process terminated unexpectedly with a status of 0x%08x (0x%08x 0x%08x). The system has been shut down.
+
+0x00000250
+
+ERROR_DATA_NOT_ACCEPTED
+
+
+{Data Not Accepted} The transport driver interface (TDI) client could not handle the data received during an indication.
+
+0x00000251
+
+ERROR_VDM_HARD_ERROR
+
+
+The NT Virtual DOS Machine (NTVDM) encountered a hard error.
+
+0x00000252
+
+ERROR_DRIVER_CANCEL_TIMEOUT
+
+
+{Cancel Timeout} The driver %hs failed to complete a canceled I/O request in the allotted time.
+
+0x00000253
+
+ERROR_REPLY_MESSAGE_MISMATCH
+
+
+{Reply Message Mismatch} An attempt was made to reply to a local procedure call (LPC) message, but the thread specified by the client ID in the message was not waiting on that message.
+
+0x00000254
+
+ERROR_LOST_WRITEBEHIND_DATA
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs. The data has been lost. This error might be caused by a failure of your computer hardware or network connection. Try to save this file elsewhere.
+
+0x00000255
+
+ERROR_CLIENT_SERVER_PARAMETERS_INVALID
+
+
+The parameters passed to the server in the client/server shared memory window were invalid. Too much data might have been put in the shared memory window.
+
+0x00000256
+
+ERROR_NOT_TINY_STREAM
+
+
+The stream is not a tiny stream.
+
+0x00000257
+
+ERROR_STACK_OVERFLOW_READ
+
+
+The request must be handled by the stack overflow code.
+
+0x00000258
+
+ERROR_CONVERT_TO_LARGE
+
+
+Internal OFS status codes indicating how an allocation operation is handled. Either it is retried after the containing onode is moved or the extent stream is converted to a large stream.
+
+0x00000259
+
+ERROR_FOUND_OUT_OF_SCOPE
+
+
+The attempt to find the object found an object matching by ID on the volume but it is out of the scope of the handle used for the operation.
+
+0x0000025A
+
+ERROR_ALLOCATE_BUCKET
+
+
+The bucket array must be grown. Retry transaction after doing so.
+
+0x0000025B
+
+ERROR_MARSHALL_OVERFLOW
+
+
+The user/kernel marshaling buffer has overflowed.
+
+0x0000025C
+
+ERROR_INVALID_VARIANT
+
+
+The supplied variant structure contains invalid data.
+
+0x0000025D
+
+ERROR_BAD_COMPRESSION_BUFFER
+
+
+The specified buffer contains ill-formed data.
+
+0x0000025E
+
+ERROR_AUDIT_FAILED
+
+
+{Audit Failed} An attempt to generate a security audit failed.
+
+0x0000025F
+
+ERROR_TIMER_RESOLUTION_NOT_SET
+
+
+The timer resolution was not previously set by the current process.
+
+0x00000260
+
+ERROR_INSUFFICIENT_LOGON_INFO
+
+
+There is insufficient account information to log you on.
+
+0x00000261
+
+ERROR_BAD_DLL_ENTRYPOINT
+
+
+{Invalid DLL Entrypoint} The dynamic link library %hs is not written correctly. The stack pointer has been left in an inconsistent state. The entry point should be declared as WINAPI or STDCALL. Select YES to fail the DLL load. Select NO to continue execution. Selecting NO can cause the application to operate incorrectly.
+
+0x00000262
+
+ERROR_BAD_SERVICE_ENTRYPOINT
+
+
+{Invalid Service Callback Entrypoint} The %hs service is not written correctly. The stack pointer has been left in an inconsistent state. The callback entry point should be declared as WINAPI or STDCALL. Selecting OK will cause the service to continue operation. However, the service process might operate incorrectly.
+
+0x00000263
+
+ERROR_IP_ADDRESS_CONFLICT1
+
+
+There is an IP address conflict with another system on the network.
+
+0x00000264
+
+ERROR_IP_ADDRESS_CONFLICT2
+
+
+There is an IP address conflict with another system on the network.
+
+0x00000265
+
+ERROR_REGISTRY_QUOTA_LIMIT
+
+
+{Low On Registry Space} The system has reached the maximum size allowed for the system part of the registry. Additional storage requests will be ignored.
+
+0x00000266
+
+ERROR_NO_CALLBACK_ACTIVE
+
+
+A callback return system service cannot be executed when no callback is active.
+
+0x00000267
+
+ERROR_PWD_TOO_SHORT
+
+
+The password provided is too short to meet the policy of your user account. Choose a longer password.
+
+0x00000268
+
+ERROR_PWD_TOO_RECENT
+
+
+The policy of your user account does not allow you to change passwords too frequently. This is done to prevent users from changing back to a familiar, but potentially discovered, password. If you feel your password has been compromised, contact your administrator immediately to have a new one assigned.
+
+0x00000269
+
+ERROR_PWD_HISTORY_CONFLICT
+
+
+You have attempted to change your password to one that you have used in the past. The policy of your user account does not allow this. Select a password that you have not previously used.
+
+0x0000026A
+
+ERROR_UNSUPPORTED_COMPRESSION
+
+
+The specified compression format is unsupported.
+
+0x0000026B
+
+ERROR_INVALID_HW_PROFILE
+
+
+The specified hardware profile configuration is invalid.
+
+0x0000026C
+
+ERROR_INVALID_PLUGPLAY_DEVICE_PATH
+
+
+The specified Plug and Play registry device path is invalid.
+
+0x0000026D
+
+ERROR_QUOTA_LIST_INCONSISTENT
+
+
+The specified quota list is internally inconsistent with its descriptor.
+
+0x0000026E
+
+ERROR_EVALUATION_EXPIRATION
+
+
+{Windows Evaluation Notification} The evaluation period for this installation of Windows has expired. This system will shut down in 1 hour. To restore access to this installation of Windows, upgrade this installation using a licensed distribution of this product.
+
+0x0000026F
+
+ERROR_ILLEGAL_DLL_RELOCATION
+
+
+{Illegal System DLL Relocation} The system DLL %hs was relocated in memory. The application will not run properly. The relocation occurred because the DLL %hs occupied an address range reserved for Windows system DLLs. The vendor supplying the DLL should be contacted for a new DLL.
+
+0x00000270
+
+ERROR_DLL_INIT_FAILED_LOGOFF
+
+
+{DLL Initialization Failed} The application failed to initialize because the window station is shutting down.
+
+0x00000271
+
+ERROR_VALIDATE_CONTINUE
+
+
+The validation process needs to continue on to the next step.
+
+0x00000272
+
+ERROR_NO_MORE_MATCHES
+
+
+There are no more matches for the current index enumeration.
+
+0x00000273
+
+ERROR_RANGE_LIST_CONFLICT
+
+
+The range could not be added to the range list because of a conflict.
+
+0x00000274
+
+ERROR_SERVER_SID_MISMATCH
+
+
+The server process is running under a SID different than that required by the client.
+
+0x00000275
+
+ERROR_CANT_ENABLE_DENY_ONLY
+
+
+A group marked use for deny only cannot be enabled.
+
+0x00000276
+
+ERROR_FLOAT_MULTIPLE_FAULTS
+
+
+{EXCEPTION} Multiple floating point faults.
+
+0x00000277
+
+ERROR_FLOAT_MULTIPLE_TRAPS
+
+
+{EXCEPTION} Multiple floating point traps.
+
+0x00000278
+
+ERROR_NOINTERFACE
+
+
+The requested interface is not supported.
+
+0x00000279
+
+ERROR_DRIVER_FAILED_SLEEP
+
+
+{System Standby Failed} The driver %hs does not support standby mode. Updating this driver might allow the system to go to standby mode.
+
+0x0000027A
+
+ERROR_CORRUPT_SYSTEM_FILE
+
+
+The system file %1 has become corrupt and has been replaced.
+
+0x0000027B
+
+ERROR_COMMITMENT_MINIMUM
+
+
+{Virtual Memory Minimum Too Low} Your system is low on virtual memory. Windows is increasing the size of your virtual memory paging file. During this process, memory requests for some applications might be denied. For more information, see Help.
+
+0x0000027C
+
+ERROR_PNP_RESTART_ENUMERATION
+
+
+A device was removed so enumeration must be restarted.
+
+0x0000027D
+
+ERROR_SYSTEM_IMAGE_BAD_SIGNATURE
+
+
+{Fatal System Error} The system image %s is not properly signed. The file has been replaced with the signed file. The system has been shut down.
+
+0x0000027E
+
+ERROR_PNP_REBOOT_REQUIRED
+
+
+Device will not start without a reboot.
+
+0x0000027F
+
+ERROR_INSUFFICIENT_POWER
+
+
+There is not enough power to complete the requested operation.
+
+0x00000281
+
+ERROR_SYSTEM_SHUTDOWN
+
+
+The system is in the process of shutting down.
+
+0x00000282
+
+ERROR_PORT_NOT_SET
+
+
+An attempt to remove a process DebugPort was made, but a port was not already associated with the process.
+
+0x00000283
+
+ERROR_DS_VERSION_CHECK_FAILURE
+
+
+This version of Windows is not compatible with the behavior version of directory forest, domain, or domain controller.
+
+0x00000284
+
+ERROR_RANGE_NOT_FOUND
+
+
+The specified range could not be found in the range list.
+
+0x00000286
+
+ERROR_NOT_SAFE_MODE_DRIVER
+
+
+The driver was not loaded because the system is booting into safe mode.
+
+0x00000287
+
+ERROR_FAILED_DRIVER_ENTRY
+
+
+The driver was not loaded because it failed its initialization call.
+
+0x00000288
+
+ERROR_DEVICE_ENUMERATION_ERROR
+
+
+The device encountered an error while applying power or reading the device configuration. This might be caused by a failure of your hardware or by a poor connection.
+
+0x00000289
+
+ERROR_MOUNT_POINT_NOT_RESOLVED
+
+
+The create operation failed because the name contained at least one mount point that resolves to a volume to which the specified device object is not attached.
+
+0x0000028A
+
+ERROR_INVALID_DEVICE_OBJECT_PARAMETER
+
+
+The device object parameter is either not a valid device object or is not attached to the volume specified by the file name.
+
+0x0000028B
+
+ERROR_MCA_OCCURED
+
+
+A machine check error has occurred. Check the system event log for additional information.
+
+0x0000028C
+
+ERROR_DRIVER_DATABASE_ERROR
+
+
+There was an error [%2] processing the driver database.
+
+0x0000028D
+
+ERROR_SYSTEM_HIVE_TOO_LARGE
+
+
+The system hive size has exceeded its limit.
+
+0x0000028E
+
+ERROR_DRIVER_FAILED_PRIOR_UNLOAD
+
+
+The driver could not be loaded because a previous version of the driver is still in memory.
+
+0x0000028F
+
+ERROR_VOLSNAP_PREPARE_HIBERNATE
+
+
+{Volume Shadow Copy Service} Wait while the Volume Shadow Copy Service prepares volume %hs for hibernation.
+
+0x00000290
+
+ERROR_HIBERNATION_FAILURE
+
+
+The system has failed to hibernate (the error code is %hs). Hibernation will be disabled until the system is restarted.
+
+0x00000299
+
+ERROR_FILE_SYSTEM_LIMITATION
+
+
+The requested operation could not be completed due to a file system limitation.
+
+0x0000029C
+
+ERROR_ASSERTION_FAILURE
+
+
+An assertion failure has occurred.
+
+0x0000029D
+
+ERROR_ACPI_ERROR
+
+
+An error occurred in the Advanced Configuration and Power Interface (ACPI) subsystem.
+
+0x0000029E
+
+ERROR_WOW_ASSERTION
+
+
+WOW assertion error.
+
+0x0000029F
+
+ERROR_PNP_BAD_MPS_TABLE
+
+
+A device is missing in the system BIOS MultiProcessor Specification (MPS) table. This device will not be used. Contact your system vendor for system BIOS update.
+
+0x000002A0
+
+ERROR_PNP_TRANSLATION_FAILED
+
+
+A translator failed to translate resources.
+
+0x000002A1
+
+ERROR_PNP_IRQ_TRANSLATION_FAILED
+
+
+An interrupt request (IRQ) translator failed to translate resources.
+
+0x000002A2
+
+ERROR_PNP_INVALID_ID
+
+
+Driver %2 returned invalid ID for a child device (%3).
+
+0x000002A3
+
+ERROR_WAKE_SYSTEM_DEBUGGER
+
+
+{Kernel Debugger Awakened} the system debugger was awakened by an interrupt.
+
+0x000002A4
+
+ERROR_HANDLES_CLOSED
+
+
+{Handles Closed} Handles to objects have been automatically closed because of the requested operation.
+
+0x000002A5
+
+ERROR_EXTRANEOUS_INFORMATION
+
+
+{Too Much Information} The specified ACL contained more information than was expected.
+
+0x000002A6
+
+ERROR_RXACT_COMMIT_NECESSARY
+
+
+This warning level status indicates that the transaction state already exists for the registry subtree, but that a transaction commit was previously aborted. The commit has NOT been completed, but it has not been rolled back either (so it can still be committed if desired).
+
+0x000002A7
+
+ERROR_MEDIA_CHECK
+
+
+{Media Changed} The media might have changed.
+
+0x000002A8
+
+ERROR_GUID_SUBSTITUTION_MADE
+
+
+{GUID Substitution} During the translation of a GUID to a Windows SID, no administratively defined GUID prefix was found. A substitute prefix was used, which will not compromise system security. However, this might provide more restrictive access than intended.
+
+0x000002A9
+
+ERROR_STOPPED_ON_SYMLINK
+
+
+The create operation stopped after reaching a symbolic link.
+
+0x000002AA
+
+ERROR_LONGJUMP
+
+
+A long jump has been executed.
+
+0x000002AB
+
+ERROR_PLUGPLAY_QUERY_VETOED
+
+
+The Plug and Play query operation was not successful.
+
+0x000002AC
+
+ERROR_UNWIND_CONSOLIDATE
+
+
+A frame consolidation has been executed.
+
+0x000002AD
+
+ERROR_REGISTRY_HIVE_RECOVERED
+
+
+{Registry Hive Recovered} Registry hive (file): %hs was corrupted and it has been recovered. Some data might have been lost.
+
+0x000002AE
+
+ERROR_DLL_MIGHT_BE_INSECURE
+
+
+The application is attempting to run executable code from the module %hs. This might be insecure. An alternative, %hs, is available. Should the application use the secure module %hs?
+
+0x000002AF
+
+ERROR_DLL_MIGHT_BE_INCOMPATIBLE
+
+
+The application is loading executable code from the module %hs. This is secure, but might be incompatible with previous releases of the operating system. An alternative, %hs, is available. Should the application use the secure module %hs?
+
+0x000002B0
+
+ERROR_DBG_EXCEPTION_NOT_HANDLED
+
+
+Debugger did not handle the exception.
+
+0x000002B1
+
+ERROR_DBG_REPLY_LATER
+
+
+Debugger will reply later.
+
+0x000002B2
+
+ERROR_DBG_UNABLE_TO_PROVIDE_HANDLE
+
+
+Debugger cannot provide handle.
+
+0x000002B3
+
+ERROR_DBG_TERMINATE_THREAD
+
+
+Debugger terminated thread.
+
+0x000002B4
+
+ERROR_DBG_TERMINATE_PROCESS
+
+
+Debugger terminated process.
+
+0x000002B5
+
+ERROR_DBG_CONTROL_C
+
+
+Debugger got control C.
+
+0x000002B6
+
+ERROR_DBG_PRINTEXCEPTION_C
+
+
+Debugger printed exception on control C.
+
+0x000002B7
+
+ERROR_DBG_RIPEXCEPTION
+
+
+Debugger received Routing Information Protocol (RIP) exception.
+
+0x000002B8
+
+ERROR_DBG_CONTROL_BREAK
+
+
+Debugger received control break.
+
+0x000002B9
+
+ERROR_DBG_COMMAND_EXCEPTION
+
+
+Debugger command communication exception.
+
+0x000002BA
+
+ERROR_OBJECT_NAME_EXISTS
+
+
+{Object Exists} An attempt was made to create an object and the object name already existed.
+
+0x000002BB
+
+ERROR_THREAD_WAS_SUSPENDED
+
+
+{Thread Suspended} A thread termination occurred while the thread was suspended. The thread was resumed and termination proceeded.
+
+0x000002BC
+
+ERROR_IMAGE_NOT_AT_BASE
+
+
+{Image Relocated} An image file could not be mapped at the address specified in the image file. Local fixes must be performed on this image.
+
+0x000002BD
+
+ERROR_RXACT_STATE_CREATED
+
+
+This informational level status indicates that a specified registry subtree transaction state did not yet exist and had to be created.
+
+0x000002BE
+
+ERROR_SEGMENT_NOTIFICATION
+
+
+{Segment Load} A virtual DOS machine (VDM) is loading, unloading, or moving an MS-DOS or Win16 program segment image. An exception is raised so a debugger can load, unload, or track symbols and breakpoints within these 16-bit segments.
+
+0x000002BF
+
+ERROR_BAD_CURRENT_DIRECTORY
+
+
+{Invalid Current Directory} The process cannot switch to the startup current directory %hs. Select OK to set current directory to %hs, or select CANCEL to exit.
+
+0x000002C0
+
+ERROR_FT_READ_RECOVERY_FROM_BACKUP
+
+
+{Redundant Read} To satisfy a read request, the NT fault-tolerant file system successfully read the requested data from a redundant copy. This was done because the file system encountered a failure on a member of the fault-tolerant volume, but it was unable to reassign the failing area of the device.
+
+0x000002C1
+
+ERROR_FT_WRITE_RECOVERY
+
+
+{Redundant Write} To satisfy a write request, the Windows NT operating system fault-tolerant file system successfully wrote a redundant copy of the information. This was done because the file system encountered a failure on a member of the fault-tolerant volume, but it was not able to reassign the failing area of the device.
+
+0x000002C2
+
+ERROR_IMAGE_MACHINE_TYPE_MISMATCH
+
+
+{Machine Type Mismatch} The image file %hs is valid, but is for a machine type other than the current machine. Select OK to continue, or CANCEL to fail the DLL load.
+
+0x000002C3
+
+ERROR_RECEIVE_PARTIAL
+
+
+{Partial Data Received} The network transport returned partial data to its client. The remaining data will be sent later.
+
+0x000002C4
+
+ERROR_RECEIVE_EXPEDITED
+
+
+{Expedited Data Received} The network transport returned data to its client that was marked as expedited by the remote system.
+
+0x000002C5
+
+ERROR_RECEIVE_PARTIAL_EXPEDITED
+
+
+{Partial Expedited Data Received} The network transport returned partial data to its client and this data was marked as expedited by the remote system. The remaining data will be sent later.
+
+0x000002C6
+
+ERROR_EVENT_DONE
+
+
+{TDI Event Done} The TDI indication has completed successfully.
+
+0x000002C7
+
+ERROR_EVENT_PENDING
+
+
+{TDI Event Pending} The TDI indication has entered the pending state.
+
+0x000002C8
+
+ERROR_CHECKING_FILE_SYSTEM
+
+
+Checking file system on %wZ.
+
+0x000002C9
+
+ERROR_FATAL_APP_EXIT
+
+
+{Fatal Application Exit} %hs.
+
+0x000002CA
+
+ERROR_PREDEFINED_HANDLE
+
+
+The specified registry key is referenced by a predefined handle.
+
+0x000002CB
+
+ERROR_WAS_UNLOCKED
+
+
+{Page Unlocked} The page protection of a locked page was changed to 'No Access' and the page was unlocked from memory and from the process.
+
+0x000002CD
+
+ERROR_WAS_LOCKED
+
+
+{Page Locked} One of the pages to lock was already locked.
+
+0x000002CF
+
+ERROR_ALREADY_WIN32
+
+
+The value already corresponds with a Win 32 error code.
+
+0x000002D0
+
+ERROR_IMAGE_MACHINE_TYPE_MISMATCH_EXE
+
+
+{Machine Type Mismatch} The image file %hs is valid, but is for a machine type other than the current machine.
+
+0x000002D1
+
+ERROR_NO_YIELD_PERFORMED
+
+
+A yield execution was performed and no thread was available to run.
+
+0x000002D2
+
+ERROR_TIMER_RESUME_IGNORED
+
+
+The resume flag to a timer API was ignored.
+
+0x000002D3
+
+ERROR_ARBITRATION_UNHANDLED
+
+
+The arbiter has deferred arbitration of these resources to its parent.
+
+0x000002D4
+
+ERROR_CARDBUS_NOT_SUPPORTED
+
+
+The inserted CardBus device cannot be started because of a configuration error on %hs"."
+
+0x000002D5
+
+ERROR_MP_PROCESSOR_MISMATCH
+
+
+The CPUs in this multiprocessor system are not all the same revision level. To use all processors the operating system restricts itself to the features of the least capable processor in the system. If problems occur with this system, contact the CPU manufacturer to see if this mix of processors is supported.
+
+0x000002D6
+
+ERROR_HIBERNATED
+
+
+The system was put into hibernation.
+
+0x000002D7
+
+ERROR_RESUME_HIBERNATION
+
+
+The system was resumed from hibernation.
+
+0x000002D8
+
+ERROR_FIRMWARE_UPDATED
+
+
+Windows has detected that the system firmware (BIOS) was updated (previous firmware date = %2, current firmware date %3).
+
+0x000002D9
+
+ERROR_DRIVERS_LEAKING_LOCKED_PAGES
+
+
+A device driver is leaking locked I/O pages, causing system degradation. The system has automatically enabled a tracking code to try and catch the culprit.
+
+0x000002DA
+
+ERROR_WAKE_SYSTEM
+
+
+The system has awoken.
+
+0x000002DF
+
+ERROR_ABANDONED_WAIT_0
+
+
+The call failed because the handle associated with it was closed.
+
+0x000002E4
+
+ERROR_ELEVATION_REQUIRED
+
+
+The requested operation requires elevation.
+
+0x000002E5
+
+ERROR_REPARSE
+
+
+A reparse should be performed by the object manager because the name of the file resulted in a symbolic link.
+
+0x000002E6
+
+ERROR_OPLOCK_BREAK_IN_PROGRESS
+
+
+An open/create operation completed while an oplock break is underway.
+
+0x000002E7
+
+ERROR_VOLUME_MOUNTED
+
+
+A new volume has been mounted by a file system.
+
+0x000002E8
+
+ERROR_RXACT_COMMITTED
+
+
+This success level status indicates that the transaction state already exists for the registry subtree, but that a transaction commit was previously aborted. The commit has now been completed.
+
+0x000002E9
+
+ERROR_NOTIFY_CLEANUP
+
+
+This indicates that a notify change request has been completed due to closing the handle which made the notify change request.
+
+0x000002EA
+
+ERROR_PRIMARY_TRANSPORT_CONNECT_FAILED
+
+
+{Connect Failure on Primary Transport} An attempt was made to connect to the remote server %hs on the primary transport, but the connection failed. The computer was able to connect on a secondary transport.
+
+0x000002EB
+
+ERROR_PAGE_FAULT_TRANSITION
+
+
+Page fault was a transition fault.
+
+0x000002EC
+
+ERROR_PAGE_FAULT_DEMAND_ZERO
+
+
+Page fault was a demand zero fault.
+
+0x000002ED
+
+ERROR_PAGE_FAULT_COPY_ON_WRITE
+
+
+Page fault was a demand zero fault.
+
+0x000002EE
+
+ERROR_PAGE_FAULT_GUARD_PAGE
+
+
+Page fault was a demand zero fault.
+
+0x000002EF
+
+ERROR_PAGE_FAULT_PAGING_FILE
+
+
+Page fault was satisfied by reading from a secondary storage device.
+
+0x000002F0
+
+ERROR_CACHE_PAGE_LOCKED
+
+
+Cached page was locked during operation.
+
+0x000002F1
+
+ERROR_CRASH_DUMP
+
+
+Crash dump exists in paging file.
+
+0x000002F2
+
+ERROR_BUFFER_ALL_ZEROS
+
+
+Specified buffer contains all zeros.
+
+0x000002F3
+
+ERROR_REPARSE_OBJECT
+
+
+A reparse should be performed by the object manager because the name of the file resulted in a symbolic link.
+
+0x000002F4
+
+ERROR_RESOURCE_REQUIREMENTS_CHANGED
+
+
+The device has succeeded a query-stop and its resource requirements have changed.
+
+0x000002F5
+
+ERROR_TRANSLATION_COMPLETE
+
+
+The translator has translated these resources into the global space and no further translations should be performed.
+
+0x000002F6
+
+ERROR_NOTHING_TO_TERMINATE
+
+
+A process being terminated has no threads to terminate.
+
+0x000002F7
+
+ERROR_PROCESS_NOT_IN_JOB
+
+
+The specified process is not part of a job.
+
+0x000002F8
+
+ERROR_PROCESS_IN_JOB
+
+
+The specified process is part of a job.
+
+0x000002F9
+
+ERROR_VOLSNAP_HIBERNATE_READY
+
+
+{Volume Shadow Copy Service} The system is now ready for hibernation.
+
+0x000002FA
+
+ERROR_FSFILTER_OP_COMPLETED_SUCCESSFULLY
+
+
+A file system or file system filter driver has successfully completed an FsFilter operation.
+
+0x000002FB
+
+ERROR_INTERRUPT_VECTOR_ALREADY_CONNECTED
+
+
+The specified interrupt vector was already connected.
+
+0x000002FC
+
+ERROR_INTERRUPT_STILL_CONNECTED
+
+
+The specified interrupt vector is still connected.
+
+0x000002FD
+
+ERROR_WAIT_FOR_OPLOCK
+
+
+An operation is blocked waiting for an oplock.
+
+0x000002FE
+
+ERROR_DBG_EXCEPTION_HANDLED
+
+
+Debugger handled exception.
+
+0x000002FF
+
+ERROR_DBG_CONTINUE
+
+
+Debugger continued.
+
+0x00000300
+
+ERROR_CALLBACK_POP_STACK
+
+
+An exception occurred in a user mode callback and the kernel callback frame should be removed.
+
+0x00000301
+
+ERROR_COMPRESSION_DISABLED
+
+
+Compression is disabled for this volume.
+
+0x00000302
+
+ERROR_CANTFETCHBACKWARDS
+
+
+The data provider cannot fetch backward through a result set.
+
+0x00000303
+
+ERROR_CANTSCROLLBACKWARDS
+
+
+The data provider cannot scroll backward through a result set.
+
+0x00000304
+
+ERROR_ROWSNOTRELEASED
+
+
+The data provider requires that previously fetched data is released before asking for more data.
+
+0x00000305
+
+ERROR_BAD_ACCESSOR_FLAGS
+
+
+The data provider was not able to interpret the flags set for a column binding in an accessor.
+
+0x00000306
+
+ERROR_ERRORS_ENCOUNTERED
+
+
+One or more errors occurred while processing the request.
+
+0x00000307
+
+ERROR_NOT_CAPABLE
+
+
+The implementation is not capable of performing the request.
+
+0x00000308
+
+ERROR_REQUEST_OUT_OF_SEQUENCE
+
+
+The client of a component requested an operation that is not valid given the state of the component instance.
+
+0x00000309
+
+ERROR_VERSION_PARSE_ERROR
+
+
+A version number could not be parsed.
+
+0x0000030A
+
+ERROR_BADSTARTPOSITION
+
+
+The iterator's start position is invalid.
+
+0x0000030B
+
+ERROR_MEMORY_HARDWARE
+
+
+The hardware has reported an uncorrectable memory error.
+
+0x0000030C
+
+ERROR_DISK_REPAIR_DISABLED
+
+
+The attempted operation required self-healing to be enabled.
+
+0x0000030D
+
+ERROR_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE
+
+
+The Desktop heap encountered an error while allocating session memory. There is more information in the system event log.
+
+0x0000030E
+
+ERROR_SYSTEM_POWERSTATE_TRANSITION
+
+
+The system power state is transitioning from %2 to %3.
+
+0x0000030F
+
+ERROR_SYSTEM_POWERSTATE_COMPLEX_TRANSITION
+
+
+The system power state is transitioning from %2 to %3 but could enter %4.
+
+0x00000310
+
+ERROR_MCA_EXCEPTION
+
+
+A thread is getting dispatched with MCA EXCEPTION because of MCA.
+
+0x00000311
+
+ERROR_ACCESS_AUDIT_BY_POLICY
+
+
+Access to %1 is monitored by policy rule %2.
+
+0x00000312
+
+ERROR_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY
+
+
+Access to %1 has been restricted by your administrator by policy rule %2.
+
+0x00000313
+
+ERROR_ABANDON_HIBERFILE
+
+
+A valid hibernation file has been invalidated and should be abandoned.
+
+0x00000314
+
+ERROR_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error can be caused by network connectivity issues. Try to save this file elsewhere.
+
+0x00000315
+
+ERROR_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error was returned by the server on which the file exists. Try to save this file elsewhere.
+
+0x00000316
+
+ERROR_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR
+
+
+{Delayed Write Failed} Windows was unable to save all the data for the file %hs; the data has been lost. This error can be caused if the device has been removed or the media is write-protected.
+
+0x000003E2
+
+ERROR_EA_ACCESS_DENIED
+
+
+Access to the extended attribute was denied.
+
+0x000003E3
+
+ERROR_OPERATION_ABORTED
+
+
+The I/O operation has been aborted because of either a thread exit or an application request.
+
+0x000003E4
+
+ERROR_IO_INCOMPLETE
+
+
+Overlapped I/O event is not in a signaled state.
+
+0x000003E5
+
+ERROR_IO_PENDING
+
+
+Overlapped I/O operation is in progress.
+
+0x000003E6
+
+ERROR_NOACCESS
+
+
+Invalid access to memory location.
+
+0x000003E7
+
+ERROR_SWAPERROR
+
+
+Error performing in-page operation.
+
+0x000003E9
+
+ERROR_STACK_OVERFLOW
+
+
+Recursion too deep; the stack overflowed.
+
+0x000003EA
+
+ERROR_INVALID_MESSAGE
+
+
+The window cannot act on the sent message.
+
+0x000003EB
+
+ERROR_CAN_NOT_COMPLETE
+
+
+Cannot complete this function.
+
+0x000003EC
+
+ERROR_INVALID_FLAGS
+
+
+Invalid flags.
+
+0x000003ED
+
+ERROR_UNRECOGNIZED_VOLUME
+
+
+The volume does not contain a recognized file system. Be sure that all required file system drivers are loaded and that the volume is not corrupted.
+
+0x000003EE
+
+ERROR_FILE_INVALID
+
+
+The volume for a file has been externally altered so that the opened file is no longer valid.
+
+0x000003EF
+
+ERROR_FULLSCREEN_MODE
+
+
+The requested operation cannot be performed in full-screen mode.
+
+0x000003F0
+
+ERROR_NO_TOKEN
+
+
+An attempt was made to reference a token that does not exist.
+
+0x000003F1
+
+ERROR_BADDB
+
+
+The configuration registry database is corrupt.
+
+0x000003F2
+
+ERROR_BADKEY
+
+
+The configuration registry key is invalid.
+
+0x000003F3
+
+ERROR_CANTOPEN
+
+
+The configuration registry key could not be opened.
+
+0x000003F4
+
+ERROR_CANTREAD
+
+
+The configuration registry key could not be read.
+
+0x000003F5
+
+ERROR_CANTWRITE
+
+
+The configuration registry key could not be written.
+
+0x000003F6
+
+ERROR_REGISTRY_RECOVERED
+
+
+One of the files in the registry database had to be recovered by use of a log or alternate copy. The recovery was successful.
+
+0x000003F7
+
+ERROR_REGISTRY_CORRUPT
+
+
+The registry is corrupted. The structure of one of the files containing registry data is corrupted, or the system's memory image of the file is corrupted, or the file could not be recovered because the alternate copy or log was absent or corrupted.
+
+0x000003F8
+
+ERROR_REGISTRY_IO_FAILED
+
+
+An I/O operation initiated by the registry failed and cannot be recovered. The registry could not read in, write out, or flush one of the files that contain the system's image of the registry.
+
+0x000003F9
+
+ERROR_NOT_REGISTRY_FILE
+
+
+The system attempted to load or restore a file into the registry, but the specified file is not in a registry file format.
+
+0x000003FA
+
+ERROR_KEY_DELETED
+
+
+Illegal operation attempted on a registry key that has been marked for deletion.
+
+0x000003FB
+
+ERROR_NO_LOG_SPACE
+
+
+System could not allocate the required space in a registry log.
+
+0x000003FC
+
+ERROR_KEY_HAS_CHILDREN
+
+
+Cannot create a symbolic link in a registry key that already has subkeys or values.
+
+0x000003FD
+
+ERROR_CHILD_MUST_BE_VOLATILE
+
+
+Cannot create a stable subkey under a volatile parent key.
+
+0x000003FE
+
+ERROR_NOTIFY_ENUM_DIR
+
+
+A notify change request is being completed and the information is not being returned in the caller's buffer. The caller now needs to enumerate the files to find the changes.
+
+0x0000041B
+
+ERROR_DEPENDENT_SERVICES_RUNNING
+
+
+A stop control has been sent to a service that other running services are dependent on.
+
+0x0000041C
+
+ERROR_INVALID_SERVICE_CONTROL
+
+
+The requested control is not valid for this service.
+
+0x0000041D
+
+ERROR_SERVICE_REQUEST_TIMEOUT
+
+
+The service did not respond to the start or control request in a timely fashion.
+
+0x0000041E
+
+ERROR_SERVICE_NO_THREAD
+
+
+A thread could not be created for the service.
+
+0x0000041F
+
+ERROR_SERVICE_DATABASE_LOCKED
+
+
+The service database is locked.
+
+0x00000420
+
+ERROR_SERVICE_ALREADY_RUNNING
+
+
+An instance of the service is already running.
+
+0x00000421
+
+ERROR_INVALID_SERVICE_ACCOUNT
+
+
+The account name is invalid or does not exist, or the password is invalid for the account name specified.
+
+0x00000422
+
+ERROR_SERVICE_DISABLED
+
+
+The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.
+
+0x00000423
+
+ERROR_CIRCULAR_DEPENDENCY
+
+
+Circular service dependency was specified.
+
+0x00000424
+
+ERROR_SERVICE_DOES_NOT_EXIST
+
+
+The specified service does not exist as an installed service.
+
+0x00000425
+
+ERROR_SERVICE_CANNOT_ACCEPT_CTRL
+
+
+The service cannot accept control messages at this time.
+
+0x00000426
+
+ERROR_SERVICE_NOT_ACTIVE
+
+
+The service has not been started.
+
+0x00000427
+
+ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
+
+
+The service process could not connect to the service controller.
+
+0x00000428
+
+ERROR_EXCEPTION_IN_SERVICE
+
+
+An exception occurred in the service when handling the control request.
+
+0x00000429
+
+ERROR_DATABASE_DOES_NOT_EXIST
+
+
+The database specified does not exist.
+
+0x0000042A
+
+ERROR_SERVICE_SPECIFIC_ERROR
+
+
+The service has returned a service-specific error code.
+
+0x0000042B
+
+ERROR_PROCESS_ABORTED
+
+
+The process terminated unexpectedly.
+
+0x0000042C
+
+ERROR_SERVICE_DEPENDENCY_FAIL
+
+
+The dependency service or group failed to start.
+
+0x0000042D
+
+ERROR_SERVICE_LOGON_FAILED
+
+
+The service did not start due to a logon failure.
+
+0x0000042E
+
+ERROR_SERVICE_START_HANG
+
+
+After starting, the service stopped responding in a start-pending state.
+
+0x0000042F
+
+ERROR_INVALID_SERVICE_LOCK
+
+
+The specified service database lock is invalid.
+
+0x00000430
+
+ERROR_SERVICE_MARKED_FOR_DELETE
+
+
+The specified service has been marked for deletion.
+
+0x00000431
+
+ERROR_SERVICE_EXISTS
+
+
+The specified service already exists.
+
+0x00000432
+
+ERROR_ALREADY_RUNNING_LKG
+
+
+The system is currently running with the last-known-good configuration.
+
+0x00000433
+
+ERROR_SERVICE_DEPENDENCY_DELETED
+
+
+The dependency service does not exist or has been marked for deletion.
+
+0x00000434
+
+ERROR_BOOT_ALREADY_ACCEPTED
+
+
+The current boot has already been accepted for use as the last-known-good control set.
+
+0x00000435
+
+ERROR_SERVICE_NEVER_STARTED
+
+
+No attempts to start the service have been made since the last boot.
+
+0x00000436
+
+ERROR_DUPLICATE_SERVICE_NAME
+
+
+The name is already in use as either a service name or a service display name.
+
+0x00000437
+
+ERROR_DIFFERENT_SERVICE_ACCOUNT
+
+
+The account specified for this service is different from the account specified for other services running in the same process.
+
+0x00000438
+
+ERROR_CANNOT_DETECT_DRIVER_FAILURE
+
+
+Failure actions can only be set for Win32 services, not for drivers.
+
+0x00000439
+
+ERROR_CANNOT_DETECT_PROCESS_ABORT
+
+
+This service runs in the same process as the service control manager. Therefore, the service control manager cannot take action if this service's process terminates unexpectedly.
+
+0x0000043A
+
+ERROR_NO_RECOVERY_PROGRAM
+
+
+No recovery program has been configured for this service.
+
+0x0000043B
+
+ERROR_SERVICE_NOT_IN_EXE
+
+
+The executable program that this service is configured to run in does not implement the service.
+
+0x0000043C
+
+ERROR_NOT_SAFEBOOT_SERVICE
+
+
+This service cannot be started in Safe Mode.
+
+0x0000044C
+
+ERROR_END_OF_MEDIA
+
+
+The physical end of the tape has been reached.
+
+0x0000044D
+
+ERROR_FILEMARK_DETECTED
+
+
+A tape access reached a filemark.
+
+0x0000044E
+
+ERROR_BEGINNING_OF_MEDIA
+
+
+The beginning of the tape or a partition was encountered.
+
+0x0000044F
+
+ERROR_SETMARK_DETECTED
+
+
+A tape access reached the end of a set of files.
+
+0x00000450
+
+ERROR_NO_DATA_DETECTED
+
+
+No more data is on the tape.
+
+0x00000451
+
+ERROR_PARTITION_FAILURE
+
+
+Tape could not be partitioned.
+
+0x00000452
+
+ERROR_INVALID_BLOCK_LENGTH
+
+
+When accessing a new tape of a multivolume partition, the current block size is incorrect.
+
+0x00000453
+
+ERROR_DEVICE_NOT_PARTITIONED
+
+
+Tape partition information could not be found when loading a tape.
+
+0x00000454
+
+ERROR_UNABLE_TO_LOCK_MEDIA
+
+
+Unable to lock the media eject mechanism.
+
+0x00000455
+
+ERROR_UNABLE_TO_UNLOAD_MEDIA
+
+
+Unable to unload the media.
+
+0x00000456
+
+ERROR_MEDIA_CHANGED
+
+
+The media in the drive might have changed.
+
+0x00000457
+
+ERROR_BUS_RESET
+
+
+The I/O bus was reset.
+
+0x00000458
+
+ERROR_NO_MEDIA_IN_DRIVE
+
+
+No media in drive.
+
+0x00000459
+
+ERROR_NO_UNICODE_TRANSLATION
+
+
+No mapping for the Unicode character exists in the target multibyte code page.
+
+0x0000045A
+
+ERROR_DLL_INIT_FAILED
+
+
+A DLL initialization routine failed.
+
+0x0000045B
+
+ERROR_SHUTDOWN_IN_PROGRESS
+
+
+A system shutdown is in progress.
+
+0x0000045C
+
+ERROR_NO_SHUTDOWN_IN_PROGRESS
+
+
+Unable to abort the system shutdown because no shutdown was in progress.
+
+0x0000045D
+
+ERROR_IO_DEVICE
+
+
+The request could not be performed because of an I/O device error.
+
+0x0000045E
+
+ERROR_SERIAL_NO_DEVICE
+
+
+No serial device was successfully initialized. The serial driver will unload.
+
+0x0000045F
+
+ERROR_IRQ_BUSY
+
+
+Unable to open a device that was sharing an IRQ with other devices. At least one other device that uses that IRQ was already opened.
+
+0x00000460
+
+ERROR_MORE_WRITES
+
+
+A serial I/O operation was completed by another write to the serial port. (The IOCTL_SERIAL_XOFF_COUNTER reached zero.)
+
+0x00000461
+
+ERROR_COUNTER_TIMEOUT
+
+
+A serial I/O operation completed because the time-out period expired. (The IOCTL_SERIAL_XOFF_COUNTER did not reach zero.)
+
+0x00000462
+
+ERROR_FLOPPY_ID_MARK_NOT_FOUND
+
+
+No ID address mark was found on the floppy disk.
+
+0x00000463
+
+ERROR_FLOPPY_WRONG_CYLINDER
+
+
+Mismatch between the floppy disk sector ID field and the floppy disk controller track address.
+
+0x00000464
+
+ERROR_FLOPPY_UNKNOWN_ERROR
+
+
+The floppy disk controller reported an error that is not recognized by the floppy disk driver.
+
+0x00000465
+
+ERROR_FLOPPY_BAD_REGISTERS
+
+
+The floppy disk controller returned inconsistent results in its registers.
+
+0x00000466
+
+ERROR_DISK_RECALIBRATE_FAILED
+
+
+While accessing the hard disk, a recalibrate operation failed, even after retries.
+
+0x00000467
+
+ERROR_DISK_OPERATION_FAILED
+
+
+While accessing the hard disk, a disk operation failed even after retries.
+
+0x00000468
+
+ERROR_DISK_RESET_FAILED
+
+
+While accessing the hard disk, a disk controller reset was needed, but that also failed.
+
+0x00000469
+
+ERROR_EOM_OVERFLOW
+
+
+Physical end of tape encountered.
+
+0x0000046A
+
+ERROR_NOT_ENOUGH_SERVER_MEMORY
+
+
+Not enough server storage is available to process this command.
+
+0x0000046B
+
+ERROR_POSSIBLE_DEADLOCK
+
+
+A potential deadlock condition has been detected.
+
+0x0000046C
+
+ERROR_MAPPED_ALIGNMENT
+
+
+The base address or the file offset specified does not have the proper alignment.
+
+0x00000474
+
+ERROR_SET_POWER_STATE_VETOED
+
+
+An attempt to change the system power state was vetoed by another application or driver.
+
+0x00000475
+
+ERROR_SET_POWER_STATE_FAILED
+
+
+The system BIOS failed an attempt to change the system power state.
+
+0x00000476
+
+ERROR_TOO_MANY_LINKS
+
+
+An attempt was made to create more links on a file than the file system supports.
+
+0x0000047E
+
+ERROR_OLD_WIN_VERSION
+
+
+The specified program requires a newer version of Windows.
+
+0x0000047F
+
+ERROR_APP_WRONG_OS
+
+
+The specified program is not a Windows or MS-DOS program.
+
+0x00000480
+
+ERROR_SINGLE_INSTANCE_APP
+
+
+Cannot start more than one instance of the specified program.
+
+0x00000481
+
+ERROR_RMODE_APP
+
+
+The specified program was written for an earlier version of Windows.
+
+0x00000482
+
+ERROR_INVALID_DLL
+
+
+One of the library files needed to run this application is damaged.
+
+0x00000483
+
+ERROR_NO_ASSOCIATION
+
+
+No application is associated with the specified file for this operation.
+
+0x00000484
+
+ERROR_DDE_FAIL
+
+
+An error occurred in sending the command to the application.
+
+0x00000485
+
+ERROR_DLL_NOT_FOUND
+
+
+One of the library files needed to run this application cannot be found.
+
+0x00000486
+
+ERROR_NO_MORE_USER_HANDLES
+
+
+The current process has used all of its system allowance of handles for Windows manager objects.
+
+0x00000487
+
+ERROR_MESSAGE_SYNC_ONLY
+
+
+The message can be used only with synchronous operations.
+
+0x00000488
+
+ERROR_SOURCE_ELEMENT_EMPTY
+
+
+The indicated source element has no media.
+
+0x00000489
+
+ERROR_DESTINATION_ELEMENT_FULL
+
+
+The indicated destination element already contains media.
+
+0x0000048A
+
+ERROR_ILLEGAL_ELEMENT_ADDRESS
+
+
+The indicated element does not exist.
+
+0x0000048B
+
+ERROR_MAGAZINE_NOT_PRESENT
+
+
+The indicated element is part of a magazine that is not present.
+
+0x0000048C
+
+ERROR_DEVICE_REINITIALIZATION_NEEDED
+
+
+The indicated device requires re-initialization due to hardware errors.
+
+0x0000048D
+
+ERROR_DEVICE_REQUIRES_CLEANING
+
+
+The device has indicated that cleaning is required before further operations are attempted.
+
+0x0000048E
+
+ERROR_DEVICE_DOOR_OPEN
+
+
+The device has indicated that its door is open.
+
+0x0000048F
+
+ERROR_DEVICE_NOT_CONNECTED
+
+
+The device is not connected.
+
+0x00000490
+
+ERROR_NOT_FOUND
+
+
+Element not found.
+
+0x00000491
+
+ERROR_NO_MATCH
+
+
+There was no match for the specified key in the index.
+
+0x00000492
+
+ERROR_SET_NOT_FOUND
+
+
+The property set specified does not exist on the object.
+
+0x00000493
+
+ERROR_POINT_NOT_FOUND
+
+
+The point passed to GetMouseMovePoints is not in the buffer.
+
+0x00000494
+
+ERROR_NO_TRACKING_SERVICE
+
+
+The tracking (workstation) service is not running.
+
+0x00000495
+
+ERROR_NO_VOLUME_ID
+
+
+The volume ID could not be found.
+
+0x00000497
+
+ERROR_UNABLE_TO_REMOVE_REPLACED
+
+
+Unable to remove the file to be replaced.
+
+0x00000498
+
+ERROR_UNABLE_TO_MOVE_REPLACEMENT
+
+
+Unable to move the replacement file to the file to be replaced. The file to be replaced has retained its original name.
+
+0x00000499
+
+ERROR_UNABLE_TO_MOVE_REPLACEMENT_2
+
+
+Unable to move the replacement file to the file to be replaced. The file to be replaced has been renamed using the backup name.
+
+0x0000049A
+
+ERROR_JOURNAL_DELETE_IN_PROGRESS
+
+
+The volume change journal is being deleted.
+
+0x0000049B
+
+ERROR_JOURNAL_NOT_ACTIVE
+
+
+The volume change journal is not active.
+
+0x0000049C
+
+ERROR_POTENTIAL_FILE_FOUND
+
+
+A file was found, but it might not be the correct file.
+
+0x0000049D
+
+ERROR_JOURNAL_ENTRY_DELETED
+
+
+The journal entry has been deleted from the journal.
+
+0x000004A6
+
+ERROR_SHUTDOWN_IS_SCHEDULED
+
+
+A system shutdown has already been scheduled.
+
+0x000004A7
+
+ERROR_SHUTDOWN_USERS_LOGGED_ON
+
+
+The system shutdown cannot be initiated because there are other users logged on to the computer.
+
+0x000004B0
+
+ERROR_BAD_DEVICE
+
+
+The specified device name is invalid.
+
+0x000004B1
+
+ERROR_CONNECTION_UNAVAIL
+
+
+The device is not currently connected but it is a remembered connection.
+
+0x000004B2
+
+ERROR_DEVICE_ALREADY_REMEMBERED
+
+
+The local device name has a remembered connection to another network resource.
+
+0x000004B3
+
+ERROR_NO_NET_OR_BAD_PATH
+
+
+The network path was either typed incorrectly, does not exist, or the network provider is not currently available. Try retyping the path or contact your network administrator.
+
+0x000004B4
+
+ERROR_BAD_PROVIDER
+
+
+The specified network provider name is invalid.
+
+0x000004B5
+
+ERROR_CANNOT_OPEN_PROFILE
+
+
+Unable to open the network connection profile.
+
+0x000004B6
+
+ERROR_BAD_PROFILE
+
+
+The network connection profile is corrupted.
+
+0x000004B7
+
+ERROR_NOT_CONTAINER
+
+
+Cannot enumerate a noncontainer.
+
+0x000004B8
+
+ERROR_EXTENDED_ERROR
+
+
+An extended error has occurred.
+
+0x000004B9
+
+ERROR_INVALID_GROUPNAME
+
+
+The format of the specified group name is invalid.
+
+0x000004BA
+
+ERROR_INVALID_COMPUTERNAME
+
+
+The format of the specified computer name is invalid.
+
+0x000004BB
+
+ERROR_INVALID_EVENTNAME
+
+
+The format of the specified event name is invalid.
+
+0x000004BC
+
+ERROR_INVALID_DOMAINNAME
+
+
+The format of the specified domain name is invalid.
+
+0x000004BD
+
+ERROR_INVALID_SERVICENAME
+
+
+The format of the specified service name is invalid.
+
+0x000004BE
+
+ERROR_INVALID_NETNAME
+
+
+The format of the specified network name is invalid.
+
+0x000004BF
+
+ERROR_INVALID_SHARENAME
+
+
+The format of the specified share name is invalid.
+
+0x000004C0
+
+ERROR_INVALID_PASSWORDNAME
+
+
+The format of the specified password is invalid.
+
+0x000004C1
+
+ERROR_INVALID_MESSAGENAME
+
+
+The format of the specified message name is invalid.
+
+0x000004C2
+
+ERROR_INVALID_MESSAGEDEST
+
+
+The format of the specified message destination is invalid.
+
+0x000004C3
+
+ERROR_SESSION_CREDENTIAL_CONFLICT
+
+
+Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.
+
+0x000004C4
+
+ERROR_REMOTE_SESSION_LIMIT_EXCEEDED
+
+
+An attempt was made to establish a session to a network server, but there are already too many sessions established to that server.
+
+0x000004C5
+
+ERROR_DUP_DOMAINNAME
+
+
+The workgroup or domain name is already in use by another computer on the network.
+
+0x000004C6
+
+ERROR_NO_NETWORK
+
+
+The network is not present or not started.
+
+0x000004C7
+
+ERROR_CANCELLED
+
+
+The operation was canceled by the user.
+
+0x000004C8
+
+ERROR_USER_MAPPED_FILE
+
+
+The requested operation cannot be performed on a file with a user-mapped section open.
+
+0x000004C9
+
+ERROR_CONNECTION_REFUSED
+
+
+The remote system refused the network connection.
+
+0x000004CA
+
+ERROR_GRACEFUL_DISCONNECT
+
+
+The network connection was gracefully closed.
+
+0x000004CB
+
+ERROR_ADDRESS_ALREADY_ASSOCIATED
+
+
+The network transport endpoint already has an address associated with it.
+
+0x000004CC
+
+ERROR_ADDRESS_NOT_ASSOCIATED
+
+
+An address has not yet been associated with the network endpoint.
+
+0x000004CD
+
+ERROR_CONNECTION_INVALID
+
+
+An operation was attempted on a nonexistent network connection.
+
+0x000004CE
+
+ERROR_CONNECTION_ACTIVE
+
+
+An invalid operation was attempted on an active network connection.
+
+0x000004CF
+
+ERROR_NETWORK_UNREACHABLE
+
+
+The network location cannot be reached. For information about network troubleshooting, see Windows Help.
+
+0x000004D0
+
+ERROR_HOST_UNREACHABLE
+
+
+The network location cannot be reached. For information about network troubleshooting, see Windows Help.
+
+0x000004D1
+
+ERROR_PROTOCOL_UNREACHABLE
+
+
+The network location cannot be reached. For information about network troubleshooting, see Windows Help.
+
+0x000004D2
+
+ERROR_PORT_UNREACHABLE
+
+
+No service is operating at the destination network endpoint on the remote system.
+
+0x000004D3
+
+ERROR_REQUEST_ABORTED
+
+
+The request was aborted.
+
+0x000004D4
+
+ERROR_CONNECTION_ABORTED
+
+
+The network connection was aborted by the local system.
+
+0x000004D5
+
+ERROR_RETRY
+
+
+The operation could not be completed. A retry should be performed.
+
+0x000004D6
+
+ERROR_CONNECTION_COUNT_LIMIT
+
+
+A connection to the server could not be made because the limit on the number of concurrent connections for this account has been reached.
+
+0x000004D7
+
+ERROR_LOGIN_TIME_RESTRICTION
+
+
+Attempting to log on during an unauthorized time of day for this account.
+
+0x000004D8
+
+ERROR_LOGIN_WKSTA_RESTRICTION
+
+
+The account is not authorized to log on from this station.
+
+0x000004D9
+
+ERROR_INCORRECT_ADDRESS
+
+
+The network address could not be used for the operation requested.
+
+0x000004DA
+
+ERROR_ALREADY_REGISTERED
+
+
+The service is already registered.
+
+0x000004DB
+
+ERROR_SERVICE_NOT_FOUND
+
+
+The specified service does not exist.
+
+0x000004DC
+
+ERROR_NOT_AUTHENTICATED
+
+
+The operation being requested was not performed because the user has not been authenticated.
+
+0x000004DD
+
+ERROR_NOT_LOGGED_ON
+
+
+The operation being requested was not performed because the user has not logged on to the network. The specified service does not exist.
+
+0x000004DE
+
+ERROR_CONTINUE
+
+
+Continue with work in progress.
+
+0x000004DF
+
+ERROR_ALREADY_INITIALIZED
+
+
+An attempt was made to perform an initialization operation when initialization has already been completed.
+
+0x000004E0
+
+ERROR_NO_MORE_DEVICES
+
+
+No more local devices.
+
+0x000004E1
+
+ERROR_NO_SUCH_SITE
+
+
+The specified site does not exist.
+
+0x000004E2
+
+ERROR_DOMAIN_CONTROLLER_EXISTS
+
+
+A domain controller with the specified name already exists.
+
+0x000004E3
+
+ERROR_ONLY_IF_CONNECTED
+
+
+This operation is supported only when you are connected to the server.
+
+0x000004E4
+
+ERROR_OVERRIDE_NOCHANGES
+
+
+The group policy framework should call the extension even if there are no changes.
+
+0x000004E5
+
+ERROR_BAD_USER_PROFILE
+
+
+The specified user does not have a valid profile.
+
+0x000004E6
+
+ERROR_NOT_SUPPORTED_ON_SBS
+
+
+This operation is not supported on a computer running Windows Server 2003 operating system for Small Business Server.
+
+0x000004E7
+
+ERROR_SERVER_SHUTDOWN_IN_PROGRESS
+
+
+The server machine is shutting down.
+
+0x000004E8
+
+ERROR_HOST_DOWN
+
+
+The remote system is not available. For information about network troubleshooting, see Windows Help.
+
+0x000004E9
+
+ERROR_NON_ACCOUNT_SID
+
+
+The security identifier provided is not from an account domain.
+
+0x000004EA
+
+ERROR_NON_DOMAIN_SID
+
+
+The security identifier provided does not have a domain component.
+
+0x000004EB
+
+ERROR_APPHELP_BLOCK
+
+
+AppHelp dialog canceled, thus preventing the application from starting.
+
+0x000004EC
+
+ERROR_ACCESS_DISABLED_BY_POLICY
+
+
+This program is blocked by Group Policy. For more information, contact your system administrator.
+
+0x000004ED
+
+ERROR_REG_NAT_CONSUMPTION
+
+
+A program attempt to use an invalid register value. Normally caused by an uninitialized register. This error is Itanium specific.
+
+0x000004EE
+
+ERROR_CSCSHARE_OFFLINE
+
+
+The share is currently offline or does not exist.
+
+0x000004EF
+
+ERROR_PKINIT_FAILURE
+
+
+The Kerberos protocol encountered an error while validating the KDC certificate during smartcard logon. There is more information in the system event log.
+
+0x000004F0
+
+ERROR_SMARTCARD_SUBSYSTEM_FAILURE
+
+
+The Kerberos protocol encountered an error while attempting to utilize the smartcard subsystem.
+
+0x000004F1
+
+ERROR_DOWNGRADE_DETECTED
+
+
+The system detected a possible attempt to compromise security. Ensure that you can contact the server that authenticated you.
+
+0x000004F7
+
+ERROR_MACHINE_LOCKED
+
+
+The machine is locked and cannot be shut down without the force option.
+
+0x000004F9
+
+ERROR_CALLBACK_SUPPLIED_INVALID_DATA
+
+
+An application-defined callback gave invalid data when called.
+
+0x000004FA
+
+ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED
+
+
+The Group Policy framework should call the extension in the synchronous foreground policy refresh.
+
+0x000004FB
+
+ERROR_DRIVER_BLOCKED
+
+
+This driver has been blocked from loading.
+
+0x000004FC
+
+ERROR_INVALID_IMPORT_OF_NON_DLL
+
+
+A DLL referenced a module that was neither a DLL nor the process's executable image.
+
+0x000004FD
+
+ERROR_ACCESS_DISABLED_WEBBLADE
+
+
+Windows cannot open this program because it has been disabled.
+
+0x000004FE
+
+ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER
+
+
+Windows cannot open this program because the license enforcement system has been tampered with or become corrupted.
+
+0x000004FF
+
+ERROR_RECOVERY_FAILURE
+
+
+A transaction recover failed.
+
+0x00000500
+
+ERROR_ALREADY_FIBER
+
+
+The current thread has already been converted to a fiber.
+
+0x00000501
+
+ERROR_ALREADY_THREAD
+
+
+The current thread has already been converted from a fiber.
+
+0x00000502
+
+ERROR_STACK_BUFFER_OVERRUN
+
+
+The system detected an overrun of a stack-based buffer in this application. This overrun could potentially allow a malicious user to gain control of this application.
+
+0x00000503
+
+ERROR_PARAMETER_QUOTA_EXCEEDED
+
+
+Data present in one of the parameters is more than the function can operate on.
+
+0x00000504
+
+ERROR_DEBUGGER_INACTIVE
+
+
+An attempt to perform an operation on a debug object failed because the object is in the process of being deleted.
+
+0x00000505
+
+ERROR_DELAY_LOAD_FAILED
+
+
+An attempt to delay-load a .dll or get a function address in a delay-loaded .dll failed.
+
+0x00000506
+
+ERROR_VDM_DISALLOWED
+
+
+%1 is a 16-bit application. You do not have permissions to execute 16-bit applications. Check your permissions with your system administrator.
+
+0x00000507
+
+ERROR_UNIDENTIFIED_ERROR
+
+
+Insufficient information exists to identify the cause of failure.
+
+0x00000508
+
+ERROR_INVALID_CRUNTIME_PARAMETER
+
+
+The parameter passed to a C runtime function is incorrect.
+
+0x00000509
+
+ERROR_BEYOND_VDL
+
+
+The operation occurred beyond the valid data length of the file.
+
+0x0000050A
+
+ERROR_INCOMPATIBLE_SERVICE_SID_TYPE
+
+
+The service start failed because one or more services in the same process have an incompatible service SID type setting. A service with a restricted service SID type can only coexist in the same process with other services with a restricted SID type.
+
+0x0000050B
+
+ERROR_DRIVER_PROCESS_TERMINATED
+
+
+The process hosting the driver for this device has been terminated.
+
+0x0000050C
+
+ERROR_IMPLEMENTATION_LIMIT
+
+
+An operation attempted to exceed an implementation-defined limit.
+
+0x0000050D
+
+ERROR_PROCESS_IS_PROTECTED
+
+
+Either the target process, or the target thread's containing process, is a protected process.
+
+0x0000050E
+
+ERROR_SERVICE_NOTIFY_CLIENT_LAGGING
+
+
+The service notification client is lagging too far behind the current state of services in the machine.
+
+0x0000050F
+
+ERROR_DISK_QUOTA_EXCEEDED
+
+
+An operation failed because the storage quota was exceeded.
+
+0x00000510
+
+ERROR_CONTENT_BLOCKED
+
+
+An operation failed because the content was blocked.
+
+0x00000511
+
+ERROR_INCOMPATIBLE_SERVICE_PRIVILEGE
+
+
+A privilege that the service requires to function properly does not exist in the service account configuration. The Services Microsoft Management Console (MMC) snap-in (Services.msc) and the Local Security Settings MMC snap-in (Secpol.msc) can be used to view the service configuration and the account configuration.
+
+0x00000513
+
+ERROR_INVALID_LABEL
+
+
+Indicates a particular SID cannot be assigned as the label of an object.
+
+0x00000514
+
+ERROR_NOT_ALL_ASSIGNED
+
+
+Not all privileges or groups referenced are assigned to the caller.
+
+0x00000515
+
+ERROR_SOME_NOT_MAPPED
+
+
+Some mapping between account names and SIDs was not done.
+
+0x00000516
+
+ERROR_NO_QUOTAS_FOR_ACCOUNT
+
+
+No system quota limits are specifically set for this account.
+
+0x00000517
+
+ERROR_LOCAL_USER_SESSION_KEY
+
+
+No encryption key is available. A well-known encryption key was returned.
+
+0x00000518
+
+ERROR_NULL_LM_PASSWORD
+
+
+The password is too complex to be converted to a LAN Manager password. The LAN Manager password returned is a null string.
+
+0x00000519
+
+ERROR_UNKNOWN_REVISION
+
+
+The revision level is unknown.
+
+0x0000051A
+
+ERROR_REVISION_MISMATCH
+
+
+Indicates two revision levels are incompatible.
+
+0x0000051B
+
+ERROR_INVALID_OWNER
+
+
+This SID cannot be assigned as the owner of this object.
+
+ 0x0000051C
+
+ERROR_INVALID_PRIMARY_GROUP
+
+
+This SID cannot be assigned as the primary group of an object.
+
+0x0000051D
+
+ERROR_NO_IMPERSONATION_TOKEN
+
+
+An attempt has been made to operate on an impersonation token by a thread that is not currently impersonating a client.
+
+0x0000051E
+
+ERROR_CANT_DISABLE_MANDATORY
+
+
+The group cannot be disabled.
+
+0x0000051F
+
+ERROR_NO_LOGON_SERVERS
+
+
+There are currently no logon servers available to service the logon request.
+
+0x00000520
+
+ERROR_NO_SUCH_LOGON_SESSION
+
+
+A specified logon session does not exist. It might already have been terminated.
+
+0x00000521
+
+ERROR_NO_SUCH_PRIVILEGE
+
+
+A specified privilege does not exist.
+
+0x00000522
+
+ERROR_PRIVILEGE_NOT_HELD
+
+
+A required privilege is not held by the client.
+
+0x00000523
+
+ERROR_INVALID_ACCOUNT_NAME
+
+
+The name provided is not a properly formed account name.
+
+0x00000524
+
+ERROR_USER_EXISTS
+
+
+The specified account already exists.
+
+0x00000525
+
+ERROR_NO_SUCH_USER
+
+
+The specified account does not exist.
+
+0x00000526
+
+ERROR_GROUP_EXISTS
+
+
+The specified group already exists.
+
+0x00000527
+
+ERROR_NO_SUCH_GROUP
+
+
+The specified group does not exist.
+
+0x00000528
+
+ERROR_MEMBER_IN_GROUP
+
+
+Either the specified user account is already a member of the specified group, or the specified group cannot be deleted because it contains a member.
+
+0x00000529
+
+ERROR_MEMBER_NOT_IN_GROUP
+
+
+The specified user account is not a member of the specified group account.
+
+0x0000052A
+
+ERROR_LAST_ADMIN
+
+
+The last remaining administration account cannot be disabled or deleted.
+
+0x0000052B
+
+ERROR_WRONG_PASSWORD
+
+
+Unable to update the password. The value provided as the current password is incorrect.
+
+0x0000052C
+
+ERROR_ILL_FORMED_PASSWORD
+
+
+Unable to update the password. The value provided for the new password contains values that are not allowed in passwords.
+
+0x0000052D
+
+ERROR_PASSWORD_RESTRICTION
+
+
+Unable to update the password. The value provided for the new password does not meet the length, complexity, or history requirements of the domain.
+
+0x0000052E
+
+ERROR_LOGON_FAILURE
+
+
+Logon failure: Unknown user name or bad password.
+
+0x0000052F
+
+ERROR_ACCOUNT_RESTRICTION
+
+
+Logon failure: User account restriction. Possible reasons are blank passwords not allowed, logon hour restrictions, or a policy restriction has been enforced.
+
+0x00000530
+
+ERROR_INVALID_LOGON_HOURS
+
+
+Logon failure: Account logon time restriction violation.
+
+0x00000531
+
+ERROR_INVALID_WORKSTATION
+
+
+Logon failure: User not allowed to log on to this computer.
+
+0x00000532
+
+ERROR_PASSWORD_EXPIRED
+
+
+Logon failure: The specified account password has expired.
+
+0x00000533
+
+ERROR_ACCOUNT_DISABLED
+
+
+Logon failure: Account currently disabled.
+
+0x00000534
+
+ERROR_NONE_MAPPED
+
+
+No mapping between account names and SIDs was done.
+
+0x00000535
+
+ERROR_TOO_MANY_LUIDS_REQUESTED
+
+
+Too many local user identifiers (LUIDs) were requested at one time.
+
+0x00000536
+
+ERROR_LUIDS_EXHAUSTED
+
+
+No more LUIDs are available.
+
+0x00000537
+
+ERROR_INVALID_SUB_AUTHORITY
+
+
+The sub-authority part of an SID is invalid for this particular use.
+
+0x00000538
+
+ERROR_INVALID_ACL
+
+
+The ACL structure is invalid.
+
+0x00000539
+
+ERROR_INVALID_SID
+
+
+The SID structure is invalid.
+
+0x0000053A
+
+ERROR_INVALID_SECURITY_DESCR
+
+
+The security descriptor structure is invalid.
+
+0x0000053C
+
+ERROR_BAD_INHERITANCE_ACL
+
+
+The inherited ACL or ACE could not be built.
+
+0x0000053D
+
+ERROR_SERVER_DISABLED
+
+
+The server is currently disabled.
+
+0x0000053E
+
+ERROR_SERVER_NOT_DISABLED
+
+
+The server is currently enabled.
+
+0x0000053F
+
+ERROR_INVALID_ID_AUTHORITY
+
+
+The value provided was an invalid value for an identifier authority.
+
+0x00000540
+
+ERROR_ALLOTTED_SPACE_EXCEEDED
+
+
+No more memory is available for security information updates.
+
+0x00000541
+
+ERROR_INVALID_GROUP_ATTRIBUTES
+
+
+The specified attributes are invalid, or incompatible with the attributes for the group as a whole.
+
+0x00000542
+
+ERROR_BAD_IMPERSONATION_LEVEL
+
+
+Either a required impersonation level was not provided, or the provided impersonation level is invalid.
+
+0x00000543
+
+ERROR_CANT_OPEN_ANONYMOUS
+
+
+Cannot open an anonymous level security token.
+
+0x00000544
+
+ERROR_BAD_VALIDATION_CLASS
+
+
+The validation information class requested was invalid.
+
+0x00000545
+
+ERROR_BAD_TOKEN_TYPE
+
+
+The type of the token is inappropriate for its attempted use.
+
+0x00000546
+
+ERROR_NO_SECURITY_ON_OBJECT
+
+
+Unable to perform a security operation on an object that has no associated security.
+
+0x00000547
+
+ERROR_CANT_ACCESS_DOMAIN_INFO
+
+
+Configuration information could not be read from the domain controller, either because the machine is unavailable, or access has been denied.
+
+0x00000548
+
+ERROR_INVALID_SERVER_STATE
+
+
+The SAM or local security authority (LSA) server was in the wrong state to perform the security operation.
+
+0x00000549
+
+ERROR_INVALID_DOMAIN_STATE
+
+
+The domain was in the wrong state to perform the security operation.
+
+0x0000054A
+
+ERROR_INVALID_DOMAIN_ROLE
+
+
+This operation is only allowed for the PDC of the domain.
+
+0x0000054B
+
+ERROR_NO_SUCH_DOMAIN
+
+
+The specified domain either does not exist or could not be contacted.
+
+0x0000054C
+
+ERROR_DOMAIN_EXISTS
+
+
+The specified domain already exists.
+
+0x0000054D
+
+ERROR_DOMAIN_LIMIT_EXCEEDED
+
+
+An attempt was made to exceed the limit on the number of domains per server.
+
+0x0000054E
+
+ERROR_INTERNAL_DB_CORRUPTION
+
+
+Unable to complete the requested operation because of either a catastrophic media failure or a data structure corruption on the disk.
+
+0x0000054F
+
+ERROR_INTERNAL_ERROR
+
+
+An internal error occurred.
+
+0x00000550
+
+ERROR_GENERIC_NOT_MAPPED
+
+
+Generic access types were contained in an access mask that should already be mapped to nongeneric types.
+
+0x00000551
+
+ERROR_BAD_DESCRIPTOR_FORMAT
+
+
+A security descriptor is not in the right format (absolute or self-relative).
+
+0x00000552
+
+ERROR_NOT_LOGON_PROCESS
+
+
+The requested action is restricted for use by logon processes only. The calling process has not registered as a logon process.
+
+0x00000553
+
+ERROR_LOGON_SESSION_EXISTS
+
+
+Cannot start a new logon session with an ID that is already in use.
+
+0x00000554
+
+ERROR_NO_SUCH_PACKAGE
+
+
+A specified authentication package is unknown.
+
+0x00000555
+
+ERROR_BAD_LOGON_SESSION_STATE
+
+
+The logon session is not in a state that is consistent with the requested operation.
+
+0x00000556
+
+ERROR_LOGON_SESSION_COLLISION
+
+
+The logon session ID is already in use.
+
+0x00000557
+
+ERROR_INVALID_LOGON_TYPE
+
+
+A logon request contained an invalid logon type value.
+
+0x00000558
+
+ERROR_CANNOT_IMPERSONATE
+
+
+Unable to impersonate using a named pipe until data has been read from that pipe.
+
+0x00000559
+
+ERROR_RXACT_INVALID_STATE
+
+
+The transaction state of a registry subtree is incompatible with the requested operation.
+
+0x0000055A
+
+ERROR_RXACT_COMMIT_FAILURE
+
+
+An internal security database corruption has been encountered.
+
+0x0000055B
+
+ERROR_SPECIAL_ACCOUNT
+
+
+Cannot perform this operation on built-in accounts.
+
+0x0000055C
+
+ERROR_SPECIAL_GROUP
+
+
+Cannot perform this operation on this built-in special group.
+
+0x0000055D
+
+ERROR_SPECIAL_USER
+
+
+Cannot perform this operation on this built-in special user.
+
+0x0000055E
+
+ERROR_MEMBERS_PRIMARY_GROUP
+
+
+The user cannot be removed from a group because the group is currently the user's primary group.
+
+0x0000055F
+
+ERROR_TOKEN_ALREADY_IN_USE
+
+
+The token is already in use as a primary token.
+
+0x00000560
+
+ERROR_NO_SUCH_ALIAS
+
+
+The specified local group does not exist.
+
+0x00000561
+
+ERROR_MEMBER_NOT_IN_ALIAS
+
+
+The specified account name is not a member of the group.
+
+0x00000562
+
+ERROR_MEMBER_IN_ALIAS
+
+
+The specified account name is already a member of the group.
+
+0x00000563
+
+ERROR_ALIAS_EXISTS
+
+
+The specified local group already exists.
+
+0x00000564
+
+ERROR_LOGON_NOT_GRANTED
+
+
+Logon failure: The user has not been granted the requested logon type at this computer.
+
+0x00000565
+
+ERROR_TOO_MANY_SECRETS
+
+
+The maximum number of secrets that can be stored in a single system has been exceeded.
+
+0x00000566
+
+ERROR_SECRET_TOO_LONG
+
+
+The length of a secret exceeds the maximum length allowed.
+
+0x00000567
+
+ERROR_INTERNAL_DB_ERROR
+
+
+The local security authority database contains an internal inconsistency.
+
+0x00000568
+
+ERROR_TOO_MANY_CONTEXT_IDS
+
+
+During a logon attempt, the user's security context accumulated too many SIDs.
+
+0x00000569
+
+ERROR_LOGON_TYPE_NOT_GRANTED
+
+
+Logon failure: The user has not been granted the requested logon type at this computer.
+
+0x0000056A
+
+ERROR_NT_CROSS_ENCRYPTION_REQUIRED
+
+
+A cross-encrypted password is necessary to change a user password.
+
+0x0000056B
+
+ERROR_NO_SUCH_MEMBER
+
+
+A member could not be added to or removed from the local group because the member does not exist.
+
+0x0000056C
+
+ERROR_INVALID_MEMBER
+
+
+A new member could not be added to a local group because the member has the wrong account type.
+
+0x0000056D
+
+ERROR_TOO_MANY_SIDS
+
+
+Too many SIDs have been specified.
+
+0x0000056E
+
+ERROR_LM_CROSS_ENCRYPTION_REQUIRED
+
+
+A cross-encrypted password is necessary to change this user password.
+
+0x0000056F
+
+ERROR_NO_INHERITANCE
+
+
+Indicates an ACL contains no inheritable components.
+
+0x00000570
+
+ERROR_FILE_CORRUPT
+
+
+The file or directory is corrupted and unreadable.
+
+0x00000571
+
+ERROR_DISK_CORRUPT
+
+
+The disk structure is corrupted and unreadable.
+
+0x00000572
+
+ERROR_NO_USER_SESSION_KEY
+
+
+There is no user session key for the specified logon session.
+
+0x00000573
+
+ERROR_LICENSE_QUOTA_EXCEEDED
+
+
+The service being accessed is licensed for a particular number of connections. No more connections can be made to the service at this time because the service has accepted the maximum number of connections.
+
+0x00000574
+
+ERROR_WRONG_TARGET_NAME
+
+
+Logon failure: The target account name is incorrect.
+
+0x00000575
+
+ERROR_MUTUAL_AUTH_FAILED
+
+
+Mutual authentication failed. The server's password is out of date at the domain controller.
+
+0x00000576
+
+ERROR_TIME_SKEW
+
+
+There is a time and/or date difference between the client and server.
+
+0x00000577
+
+ERROR_CURRENT_DOMAIN_NOT_ALLOWED
+
+
+This operation cannot be performed on the current domain.
+
+0x00000578
+
+ERROR_INVALID_WINDOW_HANDLE
+
+
+Invalid window handle.
+
+0x00000579
+
+ERROR_INVALID_MENU_HANDLE
+
+
+Invalid menu handle.
+
+0x0000057A
+
+ERROR_INVALID_CURSOR_HANDLE
+
+
+Invalid cursor handle.
+
+0x0000057B
+
+ERROR_INVALID_ACCEL_HANDLE
+
+
+Invalid accelerator table handle.
+
+0x0000057C
+
+ERROR_INVALID_HOOK_HANDLE
+
+
+Invalid hook handle.
+
+0x0000057D
+
+ERROR_INVALID_DWP_HANDLE
+
+
+Invalid handle to a multiple-window position structure.
+
+0x0000057E
+
+ERROR_TLW_WITH_WSCHILD
+
+
+Cannot create a top-level child window.
+
+0x0000057F
+
+ERROR_CANNOT_FIND_WND_CLASS
+
+
+Cannot find window class.
+
+0x00000580
+
+ERROR_WINDOW_OF_OTHER_THREAD
+
+
+Invalid window; it belongs to other thread.
+
+0x00000581
+
+ERROR_HOTKEY_ALREADY_REGISTERED
+
+
+Hot key is already registered.
+
+0x00000582
+
+ERROR_CLASS_ALREADY_EXISTS
+
+
+Class already exists.
+
+0x00000583
+
+ERROR_CLASS_DOES_NOT_EXIST
+
+
+Class does not exist.
+
+0x00000584
+
+ERROR_CLASS_HAS_WINDOWS
+
+
+Class still has open windows.
+
+0x00000585
+
+ERROR_INVALID_INDEX
+
+
+Invalid index.
+
+0x00000586
+
+ERROR_INVALID_ICON_HANDLE
+
+
+Invalid icon handle.
+
+0x00000587
+
+ERROR_PRIVATE_DIALOG_INDEX
+
+
+Using private DIALOG window words.
+
+0x00000588
+
+ERROR_LISTBOX_ID_NOT_FOUND
+
+
+The list box identifier was not found.
+
+0x00000589
+
+ERROR_NO_WILDCARD_CHARACTERS
+
+
+No wildcards were found.
+
+0x0000058A
+
+ERROR_CLIPBOARD_NOT_OPEN
+
+
+Thread does not have a clipboard open.
+
+0x0000058B
+
+ERROR_HOTKEY_NOT_REGISTERED
+
+
+Hot key is not registered.
+
+0x0000058C
+
+ERROR_WINDOW_NOT_DIALOG
+
+
+The window is not a valid dialog window.
+
+0x0000058D
+
+ERROR_CONTROL_ID_NOT_FOUND
+
+
+Control ID not found.
+
+0x0000058E
+
+ERROR_INVALID_COMBOBOX_MESSAGE
+
+
+Invalid message for a combo box because it does not have an edit control.
+
+0x0000058F
+
+ERROR_WINDOW_NOT_COMBOBOX
+
+
+The window is not a combo box.
+
+0x00000590
+
+ERROR_INVALID_EDIT_HEIGHT
+
+
+Height must be less than 256.
+
+0x00000591
+
+ERROR_DC_NOT_FOUND
+
+
+Invalid device context (DC) handle.
+
+0x00000592
+
+ERROR_INVALID_HOOK_FILTER
+
+
+Invalid hook procedure type.
+
+0x00000593
+
+ERROR_INVALID_FILTER_PROC
+
+
+Invalid hook procedure.
+
+0x00000594
+
+ERROR_HOOK_NEEDS_HMOD
+
+
+Cannot set nonlocal hook without a module handle.
+
+0x00000595
+
+ERROR_GLOBAL_ONLY_HOOK
+
+
+This hook procedure can only be set globally.
+
+0x00000596
+
+ERROR_JOURNAL_HOOK_SET
+
+
+The journal hook procedure is already installed.
+
+0x00000597
+
+ERROR_HOOK_NOT_INSTALLED
+
+
+The hook procedure is not installed.
+
+0x00000598
+
+ERROR_INVALID_LB_MESSAGE
+
+
+Invalid message for single-selection list box.
+
+0x00000599
+
+ERROR_SETCOUNT_ON_BAD_LB
+
+
+LB_SETCOUNT sent to non-lazy list box.
+
+0x0000059A
+
+ERROR_LB_WITHOUT_TABSTOPS
+
+
+This list box does not support tab stops.
+
+0x0000059B
+
+ERROR_DESTROY_OBJECT_OF_OTHER_THREAD
+
+
+Cannot destroy object created by another thread.
+
+0x0000059C
+
+ERROR_CHILD_WINDOW_MENU
+
+
+Child windows cannot have menus.
+
+0x0000059D
+
+ERROR_NO_SYSTEM_MENU
+
+
+The window does not have a system menu.
+
+0x0000059E
+
+ERROR_INVALID_MSGBOX_STYLE
+
+
+Invalid message box style.
+
+0x0000059F
+
+ERROR_INVALID_SPI_VALUE
+
+
+Invalid system-wide (SPI_*) parameter.
+
+0x000005A0
+
+ERROR_SCREEN_ALREADY_LOCKED
+
+
+Screen already locked.
+
+0x000005A1
+
+ERROR_HWNDS_HAVE_DIFF_PARENT
+
+
+All handles to windows in a multiple-window position structure must have the same parent.
+
+0x000005A2
+
+ERROR_NOT_CHILD_WINDOW
+
+
+The window is not a child window.
+
+0x000005A3
+
+ERROR_INVALID_GW_COMMAND
+
+
+Invalid GW_* command.
+
+0x000005A4
+
+ERROR_INVALID_THREAD_ID
+
+
+Invalid thread identifier.
+
+0x000005A5
+
+ERROR_NON_MDICHILD_WINDOW
+
+
+Cannot process a message from a window that is not a multiple document interface (MDI) window.
+
+0x000005A6
+
+ERROR_POPUP_ALREADY_ACTIVE
+
+
+Pop-up menu already active.
+
+0x000005A7
+
+ERROR_NO_SCROLLBARS
+
+
+The window does not have scroll bars.
+
+0x000005A8
+
+ERROR_INVALID_SCROLLBAR_RANGE
+
+
+Scroll bar range cannot be greater than MAXLONG.
+
+0x000005A9
+
+ERROR_INVALID_SHOWWIN_COMMAND
+
+
+Cannot show or remove the window in the way specified.
+
+0x000005AA
+
+ERROR_NO_SYSTEM_RESOURCES
+
+
+Insufficient system resources exist to complete the requested service.
+
+0x000005AB
+
+ERROR_NONPAGED_SYSTEM_RESOURCES
+
+
+Insufficient system resources exist to complete the requested service.
+
+0x000005AC
+
+ERROR_PAGED_SYSTEM_RESOURCES
+
+
+Insufficient system resources exist to complete the requested service.
+
+0x000005AD
+
+ERROR_WORKING_SET_QUOTA
+
+
+Insufficient quota to complete the requested service.
+
+0x000005AE
+
+ERROR_PAGEFILE_QUOTA
+
+
+Insufficient quota to complete the requested service.
+
+0x000005AF
+
+ERROR_COMMITMENT_LIMIT
+
+
+The paging file is too small for this operation to complete.
+
+0x000005B0
+
+ERROR_MENU_ITEM_NOT_FOUND
+
+
+A menu item was not found.
+
+0x000005B1
+
+ERROR_INVALID_KEYBOARD_HANDLE
+
+
+Invalid keyboard layout handle.
+
+0x000005B2
+
+ERROR_HOOK_TYPE_NOT_ALLOWED
+
+
+Hook type not allowed.
+
+0x000005B3
+
+ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION
+
+
+This operation requires an interactive window station.
+
+0x000005B4
+
+ERROR_TIMEOUT
+
+
+This operation returned because the time-out period expired.
+
+0x000005B5
+
+ERROR_INVALID_MONITOR_HANDLE
+
+
+Invalid monitor handle.
+
+0x000005B6
+
+ERROR_INCORRECT_SIZE
+
+
+Incorrect size argument.
+
+0x000005B7
+
+ERROR_SYMLINK_CLASS_DISABLED
+
+
+The symbolic link cannot be followed because its type is disabled.
+
+0x000005B8
+
+ERROR_SYMLINK_NOT_SUPPORTED
+
+
+This application does not support the current operation on symbolic links.
+
+0x000005DC
+
+ERROR_EVENTLOG_FILE_CORRUPT
+
+
+The event log file is corrupted.
+
+0x000005DD
+
+ERROR_EVENTLOG_CANT_START
+
+
+No event log file could be opened, so the event logging service did not start.
+
+0x000005DE
+
+ERROR_LOG_FILE_FULL
+
+
+The event log file is full.
+
+0x000005DF
+
+ERROR_EVENTLOG_FILE_CHANGED
+
+
+The event log file has changed between read operations.
+
+0x0000060E
+
+ERROR_INVALID_TASK_NAME
+
+
+The specified task name is invalid.
+
+0x0000060F
+
+ERROR_INVALID_TASK_INDEX
+
+
+The specified task index is invalid.
+
+0x00000610
+
+ERROR_THREAD_ALREADY_IN_TASK
+
+
+The specified thread is already joining a task.
+
+0x00000641
+
+ERROR_INSTALL_SERVICE_FAILURE
+
+
+The Windows Installer service could not be accessed. This can occur if the Windows Installer is not correctly installed. Contact your support personnel for assistance.
+
+0x00000642
+
+ERROR_INSTALL_USEREXIT
+
+
+User canceled installation.
+
+0x00000643
+
+ERROR_INSTALL_FAILURE
+
+
+Fatal error during installation.
+
+0x00000644
+
+ERROR_INSTALL_SUSPEND
+
+
+Installation suspended, incomplete.
+
+0x00000645
+
+ERROR_UNKNOWN_PRODUCT
+
+
+This action is valid only for products that are currently installed.
+
+0x00000646
+
+ERROR_UNKNOWN_FEATURE
+
+
+Feature ID not registered.
+
+0x00000647
+
+ERROR_UNKNOWN_COMPONENT
+
+
+Component ID not registered.
+
+0x00000648
+
+ERROR_UNKNOWN_PROPERTY
+
+
+Unknown property.
+
+0x00000649
+
+ERROR_INVALID_HANDLE_STATE
+
+
+Handle is in an invalid state.
+
+0x0000064A
+
+ERROR_BAD_CONFIGURATION
+
+
+The configuration data for this product is corrupt. Contact your support personnel.
+
+0x0000064B
+
+ERROR_INDEX_ABSENT
+
+
+Component qualifier not present.
+
+0x0000064C
+
+ERROR_INSTALL_SOURCE_ABSENT
+
+
+The installation source for this product is not available. Verify that the source exists and that you can access it.
+
+0x0000064D
+
+ERROR_INSTALL_PACKAGE_VERSION
+
+
+This installation package cannot be installed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.
+
+0x0000064E
+
+ERROR_PRODUCT_UNINSTALLED
+
+
+Product is uninstalled.
+
+0x0000064F
+
+ERROR_BAD_QUERY_SYNTAX
+
+
+SQL query syntax invalid or unsupported.
+
+0x00000650
+
+ERROR_INVALID_FIELD
+
+
+Record field does not exist.
+
+0x00000651
+
+ERROR_DEVICE_REMOVED
+
+
+The device has been removed.
+
+0x00000652
+
+ERROR_INSTALL_ALREADY_RUNNING
+
+
+Another installation is already in progress. Complete that installation before proceeding with this install.
+
+0x00000653
+
+ERROR_INSTALL_PACKAGE_OPEN_FAILED
+
+
+This installation package could not be opened. Verify that the package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer package.
+
+0x00000654
+
+ERROR_INSTALL_PACKAGE_INVALID
+
+
+This installation package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer package.
+
+0x00000655
+
+ERROR_INSTALL_UI_FAILURE
+
+
+There was an error starting the Windows Installer service user interface. Contact your support personnel.
+
+0x00000656
+
+ERROR_INSTALL_LOG_FAILURE
+
+
+Error opening installation log file. Verify that the specified log file location exists and that you can write to it.
+
+0x00000657
+
+ERROR_INSTALL_LANGUAGE_UNSUPPORTED
+
+
+The language of this installation package is not supported by your system.
+
+0x00000658
+
+ERROR_INSTALL_TRANSFORM_FAILURE
+
+
+Error applying transforms. Verify that the specified transform paths are valid.
+
+0x00000659
+
+ERROR_INSTALL_PACKAGE_REJECTED
+
+
+This installation is forbidden by system policy. Contact your system administrator.
+
+0x0000065A
+
+ERROR_FUNCTION_NOT_CALLED
+
+
+Function could not be executed.
+
+0x0000065B
+
+ERROR_FUNCTION_FAILED
+
+
+Function failed during execution.
+
+0x0000065C
+
+ERROR_INVALID_TABLE
+
+
+Invalid or unknown table specified.
+
+0x0000065D
+
+ERROR_DATATYPE_MISMATCH
+
+
+Data supplied is of wrong type.
+
+0x0000065E
+
+ERROR_UNSUPPORTED_TYPE
+
+
+Data of this type is not supported.
+
+0x0000065F
+
+ERROR_CREATE_FAILED
+
+
+The Windows Installer service failed to start. Contact your support personnel.
+
+0x00000660
+
+ERROR_INSTALL_TEMP_UNWRITABLE
+
+
+The Temp folder is on a drive that is full or is inaccessible. Free up space on the drive or verify that you have write permission on the Temp folder.
+
+0x00000661
+
+ERROR_INSTALL_PLATFORM_UNSUPPORTED
+
+
+This installation package is not supported by this processor type. Contact your product vendor.
+
+0x00000662
+
+ERROR_INSTALL_NOTUSED
+
+
+Component not used on this computer.
+
+0x00000663
+
+ERROR_PATCH_PACKAGE_OPEN_FAILED
+
+
+This update package could not be opened. Verify that the update package exists and that you can access it, or contact the application vendor to verify that this is a valid Windows Installer update package.
+
+0x00000664
+
+ERROR_PATCH_PACKAGE_INVALID
+
+
+This update package could not be opened. Contact the application vendor to verify that this is a valid Windows Installer update package.
+
+0x00000665
+
+ERROR_PATCH_PACKAGE_UNSUPPORTED
+
+
+This update package cannot be processed by the Windows Installer service. You must install a Windows service pack that contains a newer version of the Windows Installer service.
+
+0x00000666
+
+ERROR_PRODUCT_VERSION
+
+
+Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product, use Add/Remove Programs in Control Panel.
+
+0x00000667
+
+ERROR_INVALID_COMMAND_LINE
+
+
+Invalid command-line argument. Consult the Windows Installer SDK for detailed command line help.
+
+0x00000668
+
+ERROR_INSTALL_REMOTE_DISALLOWED
+
+
+Only administrators have permission to add, remove, or configure server software during a Terminal Services remote session. If you want to install or configure software on the server, contact your network administrator.
+
+0x00000669
+
+ERROR_SUCCESS_REBOOT_INITIATED
+
+
+The requested operation completed successfully. The system will be restarted so the changes can take effect.
+
+0x0000066A
+
+ERROR_PATCH_TARGET_NOT_FOUND
+
+
+The upgrade cannot be installed by the Windows Installer service because the program to be upgraded might be missing, or the upgrade might update a different version of the program. Verify that the program to be upgraded exists on your computer and that you have the correct upgrade.
+
+0x0000066B
+
+ERROR_PATCH_PACKAGE_REJECTED
+
+
+The update package is not permitted by a software restriction policy.
+
+0x0000066C
+
+ERROR_INSTALL_TRANSFORM_REJECTED
+
+
+One or more customizations are not permitted by a software restriction policy.
+
+0x0000066D
+
+ERROR_INSTALL_REMOTE_PROHIBITED
+
+
+The Windows Installer does not permit installation from a Remote Desktop Connection.
+
+0x0000066E
+
+ERROR_PATCH_REMOVAL_UNSUPPORTED
+
+
+Uninstallation of the update package is not supported.
+
+0x0000066F
+
+ERROR_UNKNOWN_PATCH
+
+
+The update is not applied to this product.
+
+0x00000670
+
+ERROR_PATCH_NO_SEQUENCE
+
+
+No valid sequence could be found for the set of updates.
+
+0x00000671
+
+ERROR_PATCH_REMOVAL_DISALLOWED
+
+
+Update removal was disallowed by policy.
+
+0x00000672
+
+ERROR_INVALID_PATCH_XML
+
+
+The XML update data is invalid.
+
+0x00000673
+
+ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT
+
+
+Windows Installer does not permit updating of managed advertised products. At least one feature of the product must be installed before applying the update.
+
+0x00000674
+
+ERROR_INSTALL_SERVICE_SAFEBOOT
+
+
+The Windows Installer service is not accessible in Safe Mode. Try again when your computer is not in Safe Mode or you can use System Restore to return your machine to a previous good state.
+
+0x000006A4
+
+RPC_S_INVALID_STRING_BINDING
+
+
+The string binding is invalid.
+
+0x000006A5
+
+RPC_S_WRONG_KIND_OF_BINDING
+
+
+The binding handle is not the correct type.
+
+0x000006A6
+
+RPC_S_INVALID_BINDING
+
+
+The binding handle is invalid.
+
+0x000006A7
+
+RPC_S_PROTSEQ_NOT_SUPPORTED
+
+
+The RPC protocol sequence is not supported.
+
+0x000006A8
+
+RPC_S_INVALID_RPC_PROTSEQ
+
+
+The RPC protocol sequence is invalid.
+
+0x000006A9
+
+RPC_S_INVALID_STRING_UUID
+
+
+The string UUID is invalid.
+
+0x000006AA
+
+RPC_S_INVALID_ENDPOINT_FORMAT
+
+
+The endpoint format is invalid.
+
+0x000006AB
+
+RPC_S_INVALID_NET_ADDR
+
+
+The network address is invalid.
+
+0x000006AC
+
+RPC_S_NO_ENDPOINT_FOUND
+
+
+No endpoint was found.
+
+0x000006AD
+
+RPC_S_INVALID_TIMEOUT
+
+
+The time-out value is invalid.
+
+0x000006AE
+
+RPC_S_OBJECT_NOT_FOUND
+
+
+The object UUID) was not found.
+
+0x000006AF
+
+RPC_S_ALREADY_REGISTERED
+
+
+The object UUID) has already been registered.
+
+0x000006B0
+
+RPC_S_TYPE_ALREADY_REGISTERED
+
+
+The type UUID has already been registered.
+
+0x000006B1
+
+RPC_S_ALREADY_LISTENING
+
+
+The RPC server is already listening.
+
+0x000006B2
+
+RPC_S_NO_PROTSEQS_REGISTERED
+
+
+No protocol sequences have been registered.
+
+0x000006B3
+
+RPC_S_NOT_LISTENING
+
+
+The RPC server is not listening.
+
+0x000006B4
+
+RPC_S_UNKNOWN_MGR_TYPE
+
+
+The manager type is unknown.
+
+0x000006B5
+
+RPC_S_UNKNOWN_IF
+
+
+The interface is unknown.
+
+0x000006B6
+
+RPC_S_NO_BINDINGS
+
+
+There are no bindings.
+
+0x000006B7
+
+RPC_S_NO_PROTSEQS
+
+
+There are no protocol sequences.
+
+0x000006B8
+
+RPC_S_CANT_CREATE_ENDPOINT
+
+
+The endpoint cannot be created.
+
+0x000006B9
+
+RPC_S_OUT_OF_RESOURCES
+
+
+Not enough resources are available to complete this operation.
+
+0x000006BA
+
+RPC_S_SERVER_UNAVAILABLE
+
+
+The RPC server is unavailable.
+
+0x000006BB
+
+RPC_S_SERVER_TOO_BUSY
+
+
+The RPC server is too busy to complete this operation.
+
+0x000006BC
+
+RPC_S_INVALID_NETWORK_OPTIONS
+
+
+The network options are invalid.
+
+0x000006BD
+
+RPC_S_NO_CALL_ACTIVE
+
+
+There are no RPCs active on this thread.
+
+0x000006BE
+
+RPC_S_CALL_FAILED
+
+
+The RPC failed.
+
+0x000006BF
+
+RPC_S_CALL_FAILED_DNE
+
+
+The RPC failed and did not execute.
+
+0x000006C0
+
+RPC_S_PROTOCOL_ERROR
+
+
+An RPC protocol error occurred.
+
+0x000006C1
+
+RPC_S_PROXY_ACCESS_DENIED
+
+
+Access to the HTTP proxy is denied.
+
+0x000006C2
+
+RPC_S_UNSUPPORTED_TRANS_SYN
+
+
+The transfer syntax is not supported by the RPC server.
+
+0x000006C4
+
+RPC_S_UNSUPPORTED_TYPE
+
+
+The UUID type is not supported.
+
+0x000006C5
+
+RPC_S_INVALID_TAG
+
+
+The tag is invalid.
+
+0x000006C6
+
+RPC_S_INVALID_BOUND
+
+
+The array bounds are invalid.
+
+0x000006C7
+
+RPC_S_NO_ENTRY_NAME
+
+
+The binding does not contain an entry name.
+
+0x000006C8
+
+RPC_S_INVALID_NAME_SYNTAX
+
+
+The name syntax is invalid.
+
+0x000006C9
+
+RPC_S_UNSUPPORTED_NAME_SYNTAX
+
+
+The name syntax is not supported.
+
+0x000006CB
+
+RPC_S_UUID_NO_ADDRESS
+
+
+No network address is available to use to construct a UUID.
+
+0x000006CC
+
+RPC_S_DUPLICATE_ENDPOINT
+
+
+The endpoint is a duplicate.
+
+0x000006CD
+
+RPC_S_UNKNOWN_AUTHN_TYPE
+
+
+The authentication type is unknown.
+
+0x000006CE
+
+RPC_S_MAX_CALLS_TOO_SMALL
+
+
+The maximum number of calls is too small.
+
+0x000006CF
+
+RPC_S_STRING_TOO_LONG
+
+
+The string is too long.
+
+0x000006D0
+
+RPC_S_PROTSEQ_NOT_FOUND
+
+
+The RPC protocol sequence was not found.
+
+0x000006D1
+
+RPC_S_PROCNUM_OUT_OF_RANGE
+
+
+The procedure number is out of range.
+
+0x000006D2
+
+RPC_S_BINDING_HAS_NO_AUTH
+
+
+The binding does not contain any authentication information.
+
+0x000006D3
+
+RPC_S_UNKNOWN_AUTHN_SERVICE
+
+
+The authentication service is unknown.
+
+0x000006D4
+
+RPC_S_UNKNOWN_AUTHN_LEVEL
+
+
+The authentication level is unknown.
+
+0x000006D5
+
+RPC_S_INVALID_AUTH_IDENTITY
+
+
+The security context is invalid.
+
+0x000006D6
+
+RPC_S_UNKNOWN_AUTHZ_SERVICE
+
+
+The authorization service is unknown.
+
+0x000006D7
+
+EPT_S_INVALID_ENTRY
+
+
+The entry is invalid.
+
+0x000006D8
+
+EPT_S_CANT_PERFORM_OP
+
+
+The server endpoint cannot perform the operation.
+
+0x000006D9
+
+EPT_S_NOT_REGISTERED
+
+
+There are no more endpoints available from the endpoint mapper.
+
+0x000006DA
+
+RPC_S_NOTHING_TO_EXPORT
+
+
+No interfaces have been exported.
+
+0x000006DB
+
+RPC_S_INCOMPLETE_NAME
+
+
+The entry name is incomplete.
+
+0x000006DC
+
+RPC_S_INVALID_VERS_OPTION
+
+
+The version option is invalid.
+
+0x000006DD
+
+RPC_S_NO_MORE_MEMBERS
+
+
+There are no more members.
+
+0x000006DE
+
+RPC_S_NOT_ALL_OBJS_UNEXPORTED
+
+
+There is nothing to unexport.
+
+0x000006DF
+
+RPC_S_INTERFACE_NOT_FOUND
+
+
+The interface was not found.
+
+0x000006E0
+
+RPC_S_ENTRY_ALREADY_EXISTS
+
+
+The entry already exists.
+
+0x000006E1
+
+RPC_S_ENTRY_NOT_FOUND
+
+
+The entry is not found.
+
+0x000006E2
+
+RPC_S_NAME_SERVICE_UNAVAILABLE
+
+
+The name service is unavailable.
+
+0x000006E3
+
+RPC_S_INVALID_NAF_ID
+
+
+The network address family is invalid.
+
+0x000006E4
+
+RPC_S_CANNOT_SUPPORT
+
+
+The requested operation is not supported.
+
+0x000006E5
+
+RPC_S_NO_CONTEXT_AVAILABLE
+
+
+No security context is available to allow impersonation.
+
+0x000006E6
+
+RPC_S_INTERNAL_ERROR
+
+
+An internal error occurred in an RPC.
+
+0x000006E7
+
+RPC_S_ZERO_DIVIDE
+
+
+The RPC server attempted an integer division by zero.
+
+0x000006E8
+
+RPC_S_ADDRESS_ERROR
+
+
+An addressing error occurred in the RPC server.
+
+0x000006E9
+
+RPC_S_FP_DIV_ZERO
+
+
+A floating-point operation at the RPC server caused a division by zero.
+
+0x000006EA
+
+RPC_S_FP_UNDERFLOW
+
+
+A floating-point underflow occurred at the RPC server.
+
+0x000006EB
+
+RPC_S_FP_OVERFLOW
+
+
+A floating-point overflow occurred at the RPC server.
+
+0x000006EC
+
+RPC_X_NO_MORE_ENTRIES
+
+
+The list of RPC servers available for the binding of auto handles has been exhausted.
+
+0x000006ED
+
+RPC_X_SS_CHAR_TRANS_OPEN_FAIL
+
+
+Unable to open the character translation table file.
+
+0x000006EE
+
+RPC_X_SS_CHAR_TRANS_SHORT_FILE
+
+
+The file containing the character translation table has fewer than 512 bytes.
+
+0x000006EF
+
+RPC_X_SS_IN_NULL_CONTEXT
+
+
+A null context handle was passed from the client to the host during an RPC.
+
+0x000006F1
+
+RPC_X_SS_CONTEXT_DAMAGED
+
+
+The context handle changed during an RPC.
+
+0x000006F2
+
+RPC_X_SS_HANDLES_MISMATCH
+
+
+The binding handles passed to an RPC do not match.
+
+0x000006F3
+
+RPC_X_SS_CANNOT_GET_CALL_HANDLE
+
+
+The stub is unable to get the RPC handle.
+
+0x000006F4
+
+RPC_X_NULL_REF_POINTER
+
+
+A null reference pointer was passed to the stub.
+
+0x000006F5
+
+RPC_X_ENUM_VALUE_OUT_OF_RANGE
+
+
+The enumeration value is out of range.
+
+0x000006F6
+
+RPC_X_BYTE_COUNT_TOO_SMALL
+
+
+The byte count is too small.
+
+0x000006F7
+
+RPC_X_BAD_STUB_DATA
+
+
+The stub received bad data.
+
+0x000006F8
+
+ERROR_INVALID_USER_BUFFER
+
+
+The supplied user buffer is not valid for the requested operation.
+
+0x000006F9
+
+ERROR_UNRECOGNIZED_MEDIA
+
+
+The disk media is not recognized. It might not be formatted.
+
+0x000006FA
+
+ERROR_NO_TRUST_LSA_SECRET
+
+
+The workstation does not have a trust secret.
+
+0x000006FB
+
+ERROR_NO_TRUST_SAM_ACCOUNT
+
+
+The security database on the server does not have a computer account for this workstation trust relationship.
+
+0x000006FC
+
+ERROR_TRUSTED_DOMAIN_FAILURE
+
+
+The trust relationship between the primary domain and the trusted domain failed.
+
+0x000006FD
+
+ERROR_TRUSTED_RELATIONSHIP_FAILURE
+
+
+The trust relationship between this workstation and the primary domain failed.
+
+0x000006FE
+
+ERROR_TRUST_FAILURE
+
+
+The network logon failed.
+
+0x000006FF
+
+RPC_S_CALL_IN_PROGRESS
+
+
+An RPC is already in progress for this thread.
+
+0x00000700
+
+ERROR_NETLOGON_NOT_STARTED
+
+
+An attempt was made to log on, but the network logon service was not started.
+
+0x00000701
+
+ERROR_ACCOUNT_EXPIRED
+
+
+The user's account has expired.
+
+0x00000702
+
+ERROR_REDIRECTOR_HAS_OPEN_HANDLES
+
+
+The redirector is in use and cannot be unloaded.
+
+0x00000703
+
+ERROR_PRINTER_DRIVER_ALREADY_INSTALLED
+
+
+The specified printer driver is already installed.
+
+0x00000704
+
+ERROR_UNKNOWN_PORT
+
+
+The specified port is unknown.
+
+0x00000705
+
+ERROR_UNKNOWN_PRINTER_DRIVER
+
+
+The printer driver is unknown.
+
+0x00000706
+
+ERROR_UNKNOWN_PRINTPROCESSOR
+
+
+The print processor is unknown.
+
+0x00000707
+
+ERROR_INVALID_SEPARATOR_FILE
+
+
+The specified separator file is invalid.
+
+0x00000708
+
+ERROR_INVALID_PRIORITY
+
+
+The specified priority is invalid.
+
+0x00000709
+
+ERROR_INVALID_PRINTER_NAME
+
+
+The printer name is invalid.
+
+0x0000070A
+
+ERROR_PRINTER_ALREADY_EXISTS
+
+
+The printer already exists.
+
+0x0000070B
+
+ERROR_INVALID_PRINTER_COMMAND
+
+
+The printer command is invalid.
+
+0x0000070C
+
+ERROR_INVALID_DATATYPE
+
+
+The specified data type is invalid.
+
+0x0000070D
+
+ERROR_INVALID_ENVIRONMENT
+
+
+The environment specified is invalid.
+
+0x0000070E
+
+RPC_S_NO_MORE_BINDINGS
+
+
+There are no more bindings.
+
+0x0000070F
+
+ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
+
+
+The account used is an interdomain trust account. Use your global user account or local user account to access this server.
+
+0x00000710
+
+ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+
+
+The account used is a computer account. Use your global user account or local user account to access this server.
+
+0x00000711
+
+ERROR_NOLOGON_SERVER_TRUST_ACCOUNT
+
+
+The account used is a server trust account. Use your global user account or local user account to access this server.
+
+0x00000712
+
+ERROR_DOMAIN_TRUST_INCONSISTENT
+
+
+The name or SID of the domain specified is inconsistent with the trust information for that domain.
+
+0x00000713
+
+ERROR_SERVER_HAS_OPEN_HANDLES
+
+
+The server is in use and cannot be unloaded.
+
+0x00000714
+
+ERROR_RESOURCE_DATA_NOT_FOUND
+
+
+The specified image file did not contain a resource section.
+
+0x00000715
+
+ERROR_RESOURCE_TYPE_NOT_FOUND
+
+
+The specified resource type cannot be found in the image file.
+
+0x00000716
+
+ERROR_RESOURCE_NAME_NOT_FOUND
+
+
+The specified resource name cannot be found in the image file.
+
+0x00000717
+
+ERROR_RESOURCE_LANG_NOT_FOUND
+
+
+The specified resource language ID cannot be found in the image file.
+
+0x00000718
+
+ERROR_NOT_ENOUGH_QUOTA
+
+
+Not enough quota is available to process this command.
+
+0x00000719
+
+RPC_S_NO_INTERFACES
+
+
+No interfaces have been registered.
+
+0x0000071A
+
+RPC_S_CALL_CANCELLED
+
+
+The RPC was canceled.
+
+0x0000071B
+
+RPC_S_BINDING_INCOMPLETE
+
+
+The binding handle does not contain all the required information.
+
+0x0000071C
+
+RPC_S_COMM_FAILURE
+
+
+A communications failure occurred during an RPC.
+
+0x0000071D
+
+RPC_S_UNSUPPORTED_AUTHN_LEVEL
+
+
+The requested authentication level is not supported.
+
+0x0000071E
+
+RPC_S_NO_PRINC_NAME
+
+
+No principal name is registered.
+
+0x0000071F
+
+RPC_S_NOT_RPC_ERROR
+
+
+The error specified is not a valid Windows RPC error code.
+
+0x00000720
+
+RPC_S_UUID_LOCAL_ONLY
+
+
+A UUID that is valid only on this computer has been allocated.
+
+0x00000721
+
+RPC_S_SEC_PKG_ERROR
+
+
+A security package-specific error occurred.
+
+0x00000722
+
+RPC_S_NOT_CANCELLED
+
+
+The thread is not canceled.
+
+0x00000723
+
+RPC_X_INVALID_ES_ACTION
+
+
+Invalid operation on the encoding/decoding handle.
+
+0x00000724
+
+RPC_X_WRONG_ES_VERSION
+
+
+Incompatible version of the serializing package.
+
+0x00000725
+
+RPC_X_WRONG_STUB_VERSION
+
+
+Incompatible version of the RPC stub.
+
+0x00000726
+
+RPC_X_INVALID_PIPE_OBJECT
+
+
+The RPC pipe object is invalid or corrupted.
+
+0x00000727
+
+RPC_X_WRONG_PIPE_ORDER
+
+
+An invalid operation was attempted on an RPC pipe object.
+
+0x00000728
+
+RPC_X_WRONG_PIPE_VERSION
+
+
+Unsupported RPC pipe version.
+
+0x0000076A
+
+RPC_S_GROUP_MEMBER_NOT_FOUND
+
+
+The group member was not found.
+
+0x0000076B
+
+EPT_S_CANT_CREATE
+
+
+The endpoint mapper database entry could not be created.
+
+0x0000076C
+
+RPC_S_INVALID_OBJECT
+
+
+The object UUID is the nil UUID.
+
+0x0000076D
+
+ERROR_INVALID_TIME
+
+
+The specified time is invalid.
+
+0x0000076E
+
+ERROR_INVALID_FORM_NAME
+
+
+The specified form name is invalid.
+
+0x0000076F
+
+ERROR_INVALID_FORM_SIZE
+
+
+The specified form size is invalid.
+
+0x00000770
+
+ERROR_ALREADY_WAITING
+
+
+The specified printer handle is already being waited on.
+
+0x00000771
+
+ERROR_PRINTER_DELETED
+
+
+The specified printer has been deleted.
+
+0x00000772
+
+ERROR_INVALID_PRINTER_STATE
+
+
+The state of the printer is invalid.
+
+0x00000773
+
+ERROR_PASSWORD_MUST_CHANGE
+
+
+The user's password must be changed before logging on the first time.
+
+0x00000774
+
+ERROR_DOMAIN_CONTROLLER_NOT_FOUND
+
+
+Could not find the domain controller for this domain.
+
+0x00000775
+
+ERROR_ACCOUNT_LOCKED_OUT
+
+
+The referenced account is currently locked out and cannot be logged on to.
+
+0x00000776
+
+OR_INVALID_OXID
+
+
+The object exporter specified was not found.
+
+0x00000777
+
+OR_INVALID_OID
+
+
+The object specified was not found.
+
+0x00000778
+
+OR_INVALID_SET
+
+
+The object set specified was not found.
+
+0x00000779
+
+RPC_S_SEND_INCOMPLETE
+
+
+Some data remains to be sent in the request buffer.
+
+0x0000077A
+
+RPC_S_INVALID_ASYNC_HANDLE
+
+
+Invalid asynchronous RPC handle.
+
+0x0000077B
+
+RPC_S_INVALID_ASYNC_CALL
+
+
+Invalid asynchronous RPC call handle for this operation.
+
+0x0000077C
+
+RPC_X_PIPE_CLOSED
+
+
+The RPC pipe object has already been closed.
+
+0x0000077D
+
+RPC_X_PIPE_DISCIPLINE_ERROR
+
+
+The RPC call completed before all pipes were processed.
+
+0x0000077E
+
+RPC_X_PIPE_EMPTY
+
+
+No more data is available from the RPC pipe.
+
+0x0000077F
+
+ERROR_NO_SITENAME
+
+
+No site name is available for this machine.
+
+0x00000780
+
+ERROR_CANT_ACCESS_FILE
+
+
+The file cannot be accessed by the system.
+
+0x00000781
+
+ERROR_CANT_RESOLVE_FILENAME
+
+
+The name of the file cannot be resolved by the system.
+
+0x00000782
+
+RPC_S_ENTRY_TYPE_MISMATCH
+
+
+The entry is not of the expected type.
+
+0x00000783
+
+RPC_S_NOT_ALL_OBJS_EXPORTED
+
+
+Not all object UUIDs could be exported to the specified entry.
+
+0x00000784
+
+RPC_S_INTERFACE_NOT_EXPORTED
+
+
+The interface could not be exported to the specified entry.
+
+0x00000785
+
+RPC_S_PROFILE_NOT_ADDED
+
+
+The specified profile entry could not be added.
+
+0x00000786
+
+RPC_S_PRF_ELT_NOT_ADDED
+
+
+The specified profile element could not be added.
+
+0x00000787
+
+RPC_S_PRF_ELT_NOT_REMOVED
+
+
+The specified profile element could not be removed.
+
+0x00000788
+
+RPC_S_GRP_ELT_NOT_ADDED
+
+
+The group element could not be added.
+
+0x00000789
+
+RPC_S_GRP_ELT_NOT_REMOVED
+
+
+The group element could not be removed.
+
+0x0000078A
+
+ERROR_KM_DRIVER_BLOCKED
+
+
+The printer driver is not compatible with a policy enabled on your computer that blocks Windows NT 4.0 operating system drivers.
+
+0x0000078B
+
+ERROR_CONTEXT_EXPIRED
+
+
+The context has expired and can no longer be used.
+
+0x0000078C
+
+ERROR_PER_USER_TRUST_QUOTA_EXCEEDED
+
+
+The current user's delegated trust creation quota has been exceeded.
+
+0x0000078D
+
+ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED
+
+
+The total delegated trust creation quota has been exceeded.
+
+0x0000078E
+
+ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED
+
+
+The current user's delegated trust deletion quota has been exceeded.
+
+0x0000078F
+
+ERROR_AUTHENTICATION_FIREWALL_FAILED
+
+
+Logon failure: The machine you are logging on to is protected by an authentication firewall. The specified account is not allowed to authenticate to the machine.
+
+0x00000790
+
+ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED
+
+
+Remote connections to the Print Spooler are blocked by a policy set on your machine.
+
+0x000007D0
+
+ERROR_INVALID_PIXEL_FORMAT
+
+
+The pixel format is invalid.
+
+0x000007D1
+
+ERROR_BAD_DRIVER
+
+
+The specified driver is invalid.
+
+0x000007D2
+
+ERROR_INVALID_WINDOW_STYLE
+
+
+The window style or class attribute is invalid for this operation.
+
+0x000007D3
+
+ERROR_METAFILE_NOT_SUPPORTED
+
+
+The requested metafile operation is not supported.
+
+0x000007D4
+
+ERROR_TRANSFORM_NOT_SUPPORTED
+
+
+The requested transformation operation is not supported.
+
+0x000007D5
+
+ERROR_CLIPPING_NOT_SUPPORTED
+
+
+The requested clipping operation is not supported.
+
+0x000007DA
+
+ERROR_INVALID_CMM
+
+
+The specified color management module is invalid.
+
+0x000007DB
+
+ERROR_INVALID_PROFILE
+
+
+The specified color profile is invalid.
+
+0x000007DC
+
+ERROR_TAG_NOT_FOUND
+
+
+The specified tag was not found.
+
+0x000007DD
+
+ERROR_TAG_NOT_PRESENT
+
+
+A required tag is not present.
+
+0x000007DE
+
+ERROR_DUPLICATE_TAG
+
+
+The specified tag is already present.
+
+0x000007DF
+
+ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE
+
+
+The specified color profile is not associated with any device.
+
+0x000007E0
+
+ERROR_PROFILE_NOT_FOUND
+
+
+The specified color profile was not found.
+
+0x000007E1
+
+ERROR_INVALID_COLORSPACE
+
+
+The specified color space is invalid.
+
+0x000007E2
+
+ERROR_ICM_NOT_ENABLED
+
+
+Image Color Management is not enabled.
+
+0x000007E3
+
+ERROR_DELETING_ICM_XFORM
+
+
+There was an error while deleting the color transform.
+
+0x000007E4
+
+ERROR_INVALID_TRANSFORM
+
+
+The specified color transform is invalid.
+
+0x000007E5
+
+ERROR_COLORSPACE_MISMATCH
+
+
+The specified transform does not match the bitmap's color space.
+
+0x000007E6
+
+ERROR_INVALID_COLORINDEX
+
+
+The specified named color index is not present in the profile.
+
+0x000007E7
+
+ERROR_PROFILE_DOES_NOT_MATCH_DEVICE
+
+
+The specified profile is intended for a device of a different type than the specified device.
+
+0x00000836
+
+NERR_NetNotStarted
+
+
+The workstation driver is not installed.
+
+0x00000837
+
+NERR_UnknownServer
+
+
+The server could not be located.
+
+0x00000838
+
+NERR_ShareMem
+
+
+An internal error occurred. The network cannot access a shared memory segment.
+
+0x00000839
+
+NERR_NoNetworkResource
+
+
+A network resource shortage occurred.
+
+0x0000083A
+
+NERR_RemoteOnly
+
+
+This operation is not supported on workstations.
+
+0x0000083B
+
+NERR_DevNotRedirected
+
+
+The device is not connected.
+
+0x0000083C
+
+ERROR_CONNECTED_OTHER_PASSWORD
+
+
+The network connection was made successfully, but the user had to be prompted for a password other than the one originally specified.
+
+0x0000083D
+
+ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT
+
+
+The network connection was made successfully using default credentials.
+
+0x00000842
+
+NERR_ServerNotStarted
+
+
+The Server service is not started.
+
+0x00000843
+
+NERR_ItemNotFound
+
+
+The queue is empty.
+
+0x00000844
+
+NERR_UnknownDevDir
+
+
+The device or directory does not exist.
+
+0x00000845
+
+NERR_RedirectedPath
+
+
+The operation is invalid on a redirected resource.
+
+0x00000846
+
+NERR_DuplicateShare
+
+
+The name has already been shared.
+
+0x00000847
+
+NERR_NoRoom
+
+
+The server is currently out of the requested resource.
+
+0x00000849
+
+NERR_TooManyItems
+
+
+Requested addition of items exceeds the maximum allowed.
+
+0x0000084A
+
+NERR_InvalidMaxUsers
+
+
+The Peer service supports only two simultaneous users.
+
+0x0000084B
+
+NERR_BufTooSmall
+
+
+The API return buffer is too small.
+
+0x0000084F
+
+NERR_RemoteErr
+
+
+A remote API error occurred.
+
+0x00000853
+
+NERR_LanmanIniError
+
+
+An error occurred when opening or reading the configuration file.
+
+0x00000858
+
+NERR_NetworkError
+
+
+A general network error occurred.
+
+0x00000859
+
+NERR_WkstaInconsistentState
+
+
+The Workstation service is in an inconsistent state. Restart the computer before restarting the Workstation service.
+
+0x0000085A
+
+NERR_WkstaNotStarted
+
+
+The Workstation service has not been started.
+
+0x0000085B
+
+NERR_BrowserNotStarted
+
+
+The requested information is not available.
+
+0x0000085C
+
+NERR_InternalError
+
+
+An internal error occurred.
+
+0x0000085D
+
+NERR_BadTransactConfig
+
+
+The server is not configured for transactions.
+
+0x0000085E
+
+NERR_InvalidAPI
+
+
+The requested API is not supported on the remote server.
+
+0x0000085F
+
+NERR_BadEventName
+
+
+The event name is invalid.
+
+0x00000860
+
+NERR_DupNameReboot
+
+
+The computer name already exists on the network. Change it and reboot the computer.
+
+0x00000862
+
+NERR_CfgCompNotFound
+
+
+The specified component could not be found in the configuration information.
+
+0x00000863
+
+NERR_CfgParamNotFound
+
+
+The specified parameter could not be found in the configuration information.
+
+0x00000865
+
+NERR_LineTooLong
+
+
+A line in the configuration file is too long.
+
+0x00000866
+
+NERR_QNotFound
+
+
+The printer does not exist.
+
+0x00000867
+
+NERR_JobNotFound
+
+
+The print job does not exist.
+
+0x00000868
+
+NERR_DestNotFound
+
+
+The printer destination cannot be found.
+
+0x00000869
+
+NERR_DestExists
+
+
+The printer destination already exists.
+
+0x0000086A
+
+NERR_QExists
+
+
+The print queue already exists.
+
+0x0000086B
+
+NERR_QNoRoom
+
+
+No more printers can be added.
+
+0x0000086C
+
+NERR_JobNoRoom
+
+
+No more print jobs can be added.
+
+0x0000086D
+
+NERR_DestNoRoom
+
+
+No more printer destinations can be added.
+
+0x0000086E
+
+NERR_DestIdle
+
+
+This printer destination is idle and cannot accept control operations.
+
+0x0000086F
+
+NERR_DestInvalidOp
+
+
+This printer destination request contains an invalid control function.
+
+0x00000870
+
+NERR_ProcNoRespond
+
+
+The print processor is not responding.
+
+0x00000871
+
+NERR_SpoolerNotLoaded
+
+
+The spooler is not running.
+
+0x00000872
+
+NERR_DestInvalidState
+
+
+This operation cannot be performed on the print destination in its current state.
+
+0x00000873
+
+NERR_QinvalidState
+
+
+This operation cannot be performed on the print queue in its current state.
+
+0x00000874
+
+NERR_JobInvalidState
+
+
+This operation cannot be performed on the print job in its current state.
+
+0x00000875
+
+NERR_SpoolNoMemory
+
+
+A spooler memory allocation failure occurred.
+
+0x00000876
+
+NERR_DriverNotFound
+
+
+The device driver does not exist.
+
+0x00000877
+
+NERR_DataTypeInvalid
+
+
+The data type is not supported by the print processor.
+
+0x00000878
+
+NERR_ProcNotFound
+
+
+The print processor is not installed.
+
+0x00000884
+
+NERR_ServiceTableLocked
+
+
+The service database is locked.
+
+0x00000885
+
+NERR_ServiceTableFull
+
+
+The service table is full.
+
+0x00000886
+
+NERR_ServiceInstalled
+
+
+The requested service has already been started.
+
+0x00000887
+
+NERR_ServiceEntryLocked
+
+
+The service does not respond to control actions.
+
+0x00000888
+
+NERR_ServiceNotInstalled
+
+
+The service has not been started.
+
+0x00000889
+
+NERR_BadServiceName
+
+
+The service name is invalid.
+
+0x0000088A
+
+NERR_ServiceCtlTimeout
+
+
+The service is not responding to the control function.
+
+0x0000088B
+
+NERR_ServiceCtlBusy
+
+
+The service control is busy.
+
+0x0000088C
+
+NERR_BadServiceProgName
+
+
+The configuration file contains an invalid service program name.
+
+0x0000088D
+
+NERR_ServiceNotCtrl
+
+
+The service could not be controlled in its present state.
+
+0x0000088E
+
+NERR_ServiceKillProc
+
+
+The service ended abnormally.
+
+0x0000088F
+
+NERR_ServiceCtlNotValid
+
+
+The requested pause or stop is not valid for this service.
+
+0x00000890
+
+NERR_NotInDispatchTbl
+
+
+The service control dispatcher could not find the service name in the dispatch table.
+
+0x00000891
+
+NERR_BadControlRecv
+
+
+The service control dispatcher pipe read failed.
+
+0x00000892
+
+NERR_ServiceNotStarting
+
+
+A thread for the new service could not be created.
+
+0x00000898
+
+NERR_AlreadyLoggedOn
+
+
+This workstation is already logged on to the LAN.
+
+0x00000899
+
+NERR_NotLoggedOn
+
+
+The workstation is not logged on to the LAN.
+
+0x0000089A
+
+NERR_BadUsername
+
+
+The user name or group name parameter is invalid.
+
+0x0000089B
+
+NERR_BadPassword
+
+
+The password parameter is invalid.
+
+0x0000089C
+
+NERR_UnableToAddName_W
+
+
+The logon processor did not add the message alias.
+
+0x0000089D
+
+NERR_UnableToAddName_F
+
+
+The logon processor did not add the message alias.
+
+0x0000089E
+
+NERR_UnableToDelName_W
+
+
+The logoff processor did not delete the message alias.
+
+0x0000089F
+
+NERR_UnableToDelName_F
+
+
+The logoff processor did not delete the message alias.
+
+0x000008A1
+
+NERR_LogonsPaused
+
+
+Network logons are paused.
+
+0x000008A2
+
+NERR_LogonServerConflict
+
+
+A centralized logon server conflict occurred.
+
+0x000008A3
+
+NERR_LogonNoUserPath
+
+
+The server is configured without a valid user path.
+
+0x000008A4
+
+NERR_LogonScriptError
+
+
+An error occurred while loading or running the logon script.
+
+0x000008A6
+
+NERR_StandaloneLogon
+
+
+The logon server was not specified. The computer will be logged on as STANDALONE.
+
+0x000008A7
+
+NERR_LogonServerNotFound
+
+
+The logon server could not be found.
+
+0x000008A8
+
+NERR_LogonDomainExists
+
+
+There is already a logon domain for this computer.
+
+0x000008A9
+
+NERR_NonValidatedLogon
+
+
+The logon server could not validate the logon.
+
+0x000008AB
+
+NERR_ACFNotFound
+
+
+The security database could not be found.
+
+0x000008AC
+
+NERR_GroupNotFound
+
+
+The group name could not be found.
+
+0x000008AD
+
+NERR_UserNotFound
+
+
+The user name could not be found.
+
+0x000008AE
+
+NERR_ResourceNotFound
+
+
+The resource name could not be found.
+
+0x000008AF
+
+NERR_GroupExists
+
+
+The group already exists.
+
+0x000008B0
+
+NERR_UserExists
+
+
+The user account already exists.
+
+0x000008B1
+
+NERR_ResourceExists
+
+
+The resource permission list already exists.
+
+0x000008B2
+
+NERR_NotPrimary
+
+
+This operation is allowed only on the PDC of the domain.
+
+0x000008B3
+
+NERR_ACFNotLoaded
+
+
+The security database has not been started.
+
+0x000008B4
+
+NERR_ACFNoRoom
+
+
+There are too many names in the user accounts database.
+
+0x000008B5
+
+NERR_ACFFileIOFail
+
+
+A disk I/O failure occurred.
+
+0x000008B6
+
+NERR_ACFTooManyLists
+
+
+The limit of 64 entries per resource was exceeded.
+
+0x000008B7
+
+NERR_UserLogon
+
+
+Deleting a user with a session is not allowed.
+
+0x000008B8
+
+NERR_ACFNoParent
+
+
+The parent directory could not be located.
+
+0x000008B9
+
+NERR_CanNotGrowSegment
+
+
+Unable to add to the security database session cache segment.
+
+0x000008BA
+
+NERR_SpeGroupOp
+
+
+This operation is not allowed on this special group.
+
+0x000008BB
+
+NERR_NotInCache
+
+
+This user is not cached in the user accounts database session cache.
+
+0x000008BC
+
+NERR_UserInGroup
+
+
+The user already belongs to this group.
+
+0x000008BD
+
+NERR_UserNotInGroup
+
+
+The user does not belong to this group.
+
+0x000008BE
+
+NERR_AccountUndefined
+
+
+This user account is undefined.
+
+0x000008BF
+
+NERR_AccountExpired
+
+
+This user account has expired.
+
+0x000008C0
+
+NERR_InvalidWorkstation
+
+
+The user is not allowed to log on from this workstation.
+
+0x000008C1
+
+NERR_InvalidLogonHours
+
+
+The user is not allowed to log on at this time.
+
+0x000008C2
+
+NERR_PasswordExpired
+
+
+The password of this user has expired.
+
+0x000008C3
+
+NERR_PasswordCantChange
+
+
+The password of this user cannot change.
+
+0x000008C4
+
+NERR_PasswordHistConflict
+
+
+This password cannot be used now.
+
+0x000008C5
+
+NERR_PasswordTooShort
+
+
+The password does not meet the password policy requirements. Check the minimum password length, password complexity, and password history requirements.
+
+0x000008C6
+
+NERR_PasswordTooRecent
+
+
+The password of this user is too recent to change.
+
+0x000008C7
+
+NERR_InvalidDatabase
+
+
+The security database is corrupted.
+
+0x000008C8
+
+NERR_DatabaseUpToDate
+
+
+No updates are necessary to this replicant network or local security database.
+
+0x000008C9
+
+NERR_SyncRequired
+
+
+This replicant database is outdated; synchronization is required.
+
+0x000008CA
+
+NERR_UseNotFound
+
+
+The network connection could not be found.
+
+0x000008CB
+
+NERR_BadAsgType
+
+
+This asg_type is invalid.
+
+0x000008CC
+
+NERR_DeviceIsShared
+
+
+This device is currently being shared.
+
+0x000008DE
+
+NERR_NoComputerName
+
+
+The computer name could not be added as a message alias. The name might already exist on the network.
+
+0x000008DF
+
+NERR_MsgAlreadyStarted
+
+
+The Messenger service is already started.
+
+0x000008E0
+
+NERR_MsgInitFailed
+
+
+The Messenger service failed to start.
+
+0x000008E1
+
+NERR_NameNotFound
+
+
+The message alias could not be found on the network.
+
+0x000008E2
+
+NERR_AlreadyForwarded
+
+
+This message alias has already been forwarded.
+
+0x000008E3
+
+NERR_AddForwarded
+
+
+This message alias has been added but is still forwarded.
+
+0x000008E4
+
+NERR_AlreadyExists
+
+
+This message alias already exists locally.
+
+0x000008E5
+
+NERR_TooManyNames
+
+
+The maximum number of added message aliases has been exceeded.
+
+0x000008E6
+
+NERR_DelComputerName
+
+
+The computer name could not be deleted.
+
+0x000008E7
+
+NERR_LocalForward
+
+
+Messages cannot be forwarded back to the same workstation.
+
+0x000008E8
+
+NERR_GrpMsgProcessor
+
+
+An error occurred in the domain message processor.
+
+0x000008E9
+
+NERR_PausedRemote
+
+
+The message was sent, but the recipient has paused the Messenger service.
+
+0x000008EA
+
+NERR_BadReceive
+
+
+The message was sent but not received.
+
+0x000008EB
+
+NERR_NameInUse
+
+
+The message alias is currently in use. Try again later.
+
+0x000008EC
+
+NERR_MsgNotStarted
+
+
+The Messenger service has not been started.
+
+0x000008ED
+
+NERR_NotLocalName
+
+
+The name is not on the local computer.
+
+0x000008EE
+
+NERR_NoForwardName
+
+
+The forwarded message alias could not be found on the network.
+
+0x000008EF
+
+NERR_RemoteFull
+
+
+The message alias table on the remote station is full.
+
+0x000008F0
+
+NERR_NameNotForwarded
+
+
+Messages for this alias are not currently being forwarded.
+
+0x000008F1
+
+NERR_TruncatedBroadcast
+
+
+The broadcast message was truncated.
+
+0x000008F6
+
+NERR_InvalidDevice
+
+
+This is an invalid device name.
+
+0x000008F7
+
+NERR_WriteFault
+
+
+A write fault occurred.
+
+0x000008F9
+
+NERR_DuplicateName
+
+
+A duplicate message alias exists on the network.
+
+0x000008FA
+
+NERR_DeleteLater
+
+
+This message alias will be deleted later.
+
+0x000008FB
+
+NERR_IncompleteDel
+
+
+The message alias was not successfully deleted from all networks.
+
+0x000008FC
+
+NERR_MultipleNets
+
+
+This operation is not supported on computers with multiple networks.
+
+0x00000906
+
+NERR_NetNameNotFound
+
+
+This shared resource does not exist.
+
+0x00000907
+
+NERR_DeviceNotShared
+
+
+This device is not shared.
+
+0x00000908
+
+NERR_ClientNameNotFound
+
+
+A session does not exist with that computer name.
+
+0x0000090A
+
+NERR_FileIdNotFound
+
+
+There is not an open file with that identification number.
+
+0x0000090B
+
+NERR_ExecFailure
+
+
+A failure occurred when executing a remote administration command.
+
+0x0000090C
+
+NERR_TmpFile
+
+
+A failure occurred when opening a remote temporary file.
+
+0x0000090D
+
+NERR_TooMuchData
+
+
+The data returned from a remote administration command has been truncated to 64 KB.
+
+0x0000090E
+
+NERR_DeviceShareConflict
+
+
+This device cannot be shared as both a spooled and a nonspooled resource.
+
+0x0000090F
+
+NERR_BrowserTableIncomplete
+
+
+The information in the list of servers might be incorrect.
+
+0x00000910
+
+NERR_NotLocalDomain
+
+
+The computer is not active in this domain.
+
+0x00000911
+
+NERR_IsDfsShare
+
+
+The share must be removed from the Distributed File System (DFS) before it can be deleted.
+
+0x0000091B
+
+NERR_DevInvalidOpCode
+
+
+The operation is invalid for this device.
+
+0x0000091C
+
+NERR_DevNotFound
+
+
+This device cannot be shared.
+
+0x0000091D
+
+NERR_DevNotOpen
+
+
+This device was not open.
+
+0x0000091E
+
+NERR_BadQueueDevString
+
+
+This device name list is invalid.
+
+0x0000091F
+
+NERR_BadQueuePriority
+
+
+The queue priority is invalid.
+
+0x00000921
+
+NERR_NoCommDevs
+
+
+There are no shared communication devices.
+
+0x00000922
+
+NERR_QueueNotFound
+
+
+The queue you specified does not exist.
+
+0x00000924
+
+NERR_BadDevString
+
+
+This list of devices is invalid.
+
+0x00000925
+
+NERR_BadDev
+
+
+The requested device is invalid.
+
+0x00000926
+
+NERR_InUseBySpooler
+
+
+This device is already in use by the spooler.
+
+0x00000927
+
+NERR_CommDevInUse
+
+
+This device is already in use as a communication device.
+
+0x0000092F
+
+NERR_InvalidComputer
+
+
+This computer name is invalid.
+
+0x00000932
+
+NERR_MaxLenExceeded
+
+
+The string and prefix specified are too long.
+
+0x00000934
+
+NERR_BadComponent
+
+
+This path component is invalid.
+
+0x00000935
+
+NERR_CantType
+
+
+Could not determine the type of input.
+
+0x0000093A
+
+NERR_TooManyEntries
+
+
+The buffer for types is not big enough.
+
+0x00000942
+
+NERR_ProfileFileTooBig
+
+
+Profile files cannot exceed 64 KB.
+
+0x00000943
+
+NERR_ProfileOffset
+
+
+The start offset is out of range.
+
+0x00000944
+
+NERR_ProfileCleanup
+
+
+The system cannot delete current connections to network resources.
+
+0x00000945
+
+NERR_ProfileUnknownCmd
+
+
+The system was unable to parse the command line in this file.
+
+0x00000946
+
+NERR_ProfileLoadErr
+
+
+An error occurred while loading the profile file.
+
+0x00000947
+
+NERR_ProfileSaveErr
+
+
+Errors occurred while saving the profile file. The profile was partially saved.
+
+0x00000949
+
+NERR_LogOverflow
+
+
+Log file %1 is full.
+
+0x0000094A
+
+NERR_LogFileChanged
+
+
+This log file has changed between reads.
+
+0x0000094B
+
+NERR_LogFileCorrupt
+
+
+Log file %1 is corrupt.
+
+0x0000094C
+
+NERR_SourceIsDir
+
+
+The source path cannot be a directory.
+
+0x0000094D
+
+NERR_BadSource
+
+
+The source path is illegal.
+
+0x0000094E
+
+NERR_BadDest
+
+
+The destination path is illegal.
+
+0x0000094F
+
+NERR_DifferentServers
+
+
+The source and destination paths are on different servers.
+
+0x00000951
+
+NERR_RunSrvPaused
+
+
+The Run server you requested is paused.
+
+0x00000955
+
+NERR_ErrCommRunSrv
+
+
+An error occurred when communicating with a Run server.
+
+0x00000957
+
+NERR_ErrorExecingGhost
+
+
+An error occurred when starting a background process.
+
+0x00000958
+
+NERR_ShareNotFound
+
+
+The shared resource you are connected to could not be found.
+
+0x00000960
+
+NERR_InvalidLana
+
+
+The LAN adapter number is invalid.
+
+0x00000961
+
+NERR_OpenFiles
+
+
+There are open files on the connection.
+
+0x00000962
+
+NERR_ActiveConns
+
+
+Active connections still exist.
+
+0x00000963
+
+NERR_BadPasswordCore
+
+
+This share name or password is invalid.
+
+0x00000964
+
+NERR_DevInUse
+
+
+The device is being accessed by an active process.
+
+0x00000965
+
+NERR_LocalDrive
+
+
+The drive letter is in use locally.
+
+0x0000097E
+
+NERR_AlertExists
+
+
+The specified client is already registered for the specified event.
+
+0x0000097F
+
+NERR_TooManyAlerts
+
+
+The alert table is full.
+
+0x00000980
+
+NERR_NoSuchAlert
+
+
+An invalid or nonexistent alert name was raised.
+
+0x00000981
+
+NERR_BadRecipient
+
+
+The alert recipient is invalid.
+
+0x00000982
+
+NERR_AcctLimitExceeded
+
+
+A user's session with this server has been deleted.
+
+0x00000988
+
+NERR_InvalidLogSeek
+
+
+The log file does not contain the requested record number.
+
+0x00000992
+
+NERR_BadUasConfig
+
+
+The user accounts database is not configured correctly.
+
+0x00000993
+
+NERR_InvalidUASOp
+
+
+This operation is not permitted when the Net Logon service is running.
+
+0x00000994
+
+NERR_LastAdmin
+
+
+This operation is not allowed on the last administrative account.
+
+0x00000995
+
+NERR_DCNotFound
+
+
+Could not find the domain controller for this domain.
+
+0x00000996
+
+NERR_LogonTrackingError
+
+
+Could not set logon information for this user.
+
+0x00000997
+
+NERR_NetlogonNotStarted
+
+
+The Net Logon service has not been started.
+
+0x00000998
+
+NERR_CanNotGrowUASFile
+
+
+Unable to add to the user accounts database.
+
+0x00000999
+
+NERR_TimeDiffAtDC
+
+
+This server's clock is not synchronized with the PDC's clock.
+
+0x0000099A
+
+NERR_PasswordMismatch
+
+
+A password mismatch has been detected.
+
+0x0000099C
+
+NERR_NoSuchServer
+
+
+The server identification does not specify a valid server.
+
+0x0000099D
+
+NERR_NoSuchSession
+
+
+The session identification does not specify a valid session.
+
+0x0000099E
+
+NERR_NoSuchConnection
+
+
+The connection identification does not specify a valid connection.
+
+0x0000099F
+
+NERR_TooManyServers
+
+
+There is no space for another entry in the table of available servers.
+
+0x000009A0
+
+NERR_TooManySessions
+
+
+The server has reached the maximum number of sessions it supports.
+
+0x000009A1
+
+NERR_TooManyConnections
+
+
+The server has reached the maximum number of connections it supports.
+
+0x000009A2
+
+NERR_TooManyFiles
+
+
+The server cannot open more files because it has reached its maximum number.
+
+0x000009A3
+
+NERR_NoAlternateServers
+
+
+There are no alternate servers registered on this server.
+
+0x000009A6
+
+NERR_TryDownLevel
+
+
+Try the down-level (remote admin protocol) version of API instead.
+
+0x000009B0
+
+NERR_UPSDriverNotStarted
+
+
+The uninterruptible power supply (UPS) driver could not be accessed by the UPS service.
+
+0x000009B1
+
+NERR_UPSInvalidConfig
+
+
+The UPS service is not configured correctly.
+
+0x000009B2
+
+NERR_UPSInvalidCommPort
+
+
+The UPS service could not access the specified Comm Port.
+
+0x000009B3
+
+NERR_UPSSignalAsserted
+
+
+The UPS indicated a line fail or low battery situation. Service not started.
+
+0x000009B4
+
+NERR_UPSShutdownFailed
+
+
+The UPS service failed to perform a system shut down.
+
+0x000009C4
+
+NERR_BadDosRetCode
+
+
+The program below returned an MS-DOS error code.
+
+0x000009C5
+
+NERR_ProgNeedsExtraMem
+
+
+The program below needs more memory.
+
+0x000009C6
+
+NERR_BadDosFunction
+
+
+The program below called an unsupported MS-DOS function.
+
+0x000009C7
+
+NERR_RemoteBootFailed
+
+
+The workstation failed to boot.
+
+0x000009C8
+
+NERR_BadFileCheckSum
+
+
+The file below is corrupt.
+
+0x000009C9
+
+NERR_NoRplBootSystem
+
+
+No loader is specified in the boot-block definition file.
+
+0x000009CA
+
+NERR_RplLoadrNetBiosErr
+
+
+NetBIOS returned an error: The network control blocks (NCBs) and Server Message Block (SMB) are dumped above.
+
+0x000009CB
+
+NERR_RplLoadrDiskErr
+
+
+A disk I/O error occurred.
+
+0x000009CC
+
+NERR_ImageParamErr
+
+
+Image parameter substitution failed.
+
+0x000009CD
+
+NERR_TooManyImageParams
+
+
+Too many image parameters cross disk sector boundaries.
+
+0x000009CE
+
+NERR_NonDosFloppyUsed
+
+
+The image was not generated from an MS-DOS disk formatted with /S.
+
+0x000009CF
+
+NERR_RplBootRestart
+
+
+Remote boot will be restarted later.
+
+0x000009D0
+
+NERR_RplSrvrCallFailed
+
+
+The call to the Remoteboot server failed.
+
+0x000009D1
+
+NERR_CantConnectRplSrvr
+
+
+Cannot connect to the Remoteboot server.
+
+0x000009D2
+
+NERR_CantOpenImageFile
+
+
+Cannot open image file on the Remoteboot server.
+
+0x000009D3
+
+NERR_CallingRplSrvr
+
+
+Connecting to the Remoteboot server.
+
+0x000009D4
+
+NERR_StartingRplBoot
+
+
+Connecting to the Remoteboot server.
+
+0x000009D5
+
+NERR_RplBootServiceTerm
+
+
+Remote boot service was stopped, check the error log for the cause of the problem.
+
+0x000009D6
+
+NERR_RplBootStartFailed
+
+
+Remote boot startup failed; check the error log for the cause of the problem.
+
+0x000009D7
+
+NERR_RPL_CONNECTED
+
+
+A second connection to a Remoteboot resource is not allowed.
+
+0x000009F6
+
+NERR_BrowserConfiguredToNotRun
+
+
+The browser service was configured with MaintainServerList=No.
+
+0x00000A32
+
+NERR_RplNoAdaptersStarted
+
+
+Service failed to start because none of the network adapters started with this service.
+
+0x00000A33
+
+NERR_RplBadRegistry
+
+
+Service failed to start due to bad startup information in the registry.
+
+0x00000A34
+
+NERR_RplBadDatabase
+
+
+Service failed to start because its database is absent or corrupt.
+
+0x00000A35
+
+NERR_RplRplfilesShare
+
+
+Service failed to start because the RPLFILES share is absent.
+
+0x00000A36
+
+NERR_RplNotRplServer
+
+
+Service failed to start because the RPLUSER group is absent.
+
+0x00000A37
+
+NERR_RplCannotEnum
+
+
+Cannot enumerate service records.
+
+0x00000A38
+
+NERR_RplWkstaInfoCorrupted
+
+
+Workstation record information has been corrupted.
+
+0x00000A39
+
+NERR_RplWkstaNotFound
+
+
+Workstation record was not found.
+
+0x00000A3A
+
+NERR_RplWkstaNameUnavailable
+
+
+Workstation name is in use by some other workstation.
+
+0x00000A3B
+
+NERR_RplProfileInfoCorrupted
+
+
+Profile record information has been corrupted.
+
+0x00000A3C
+
+NERR_RplProfileNotFound
+
+
+Profile record was not found.
+
+0x00000A3D
+
+NERR_RplProfileNameUnavailable
+
+
+Profile name is in use by some other profile.
+
+0x00000A3E
+
+NERR_RplProfileNotEmpty
+
+
+There are workstations using this profile.
+
+0x00000A3F
+
+NERR_RplConfigInfoCorrupted
+
+
+Configuration record information has been corrupted.
+
+0x00000A40
+
+NERR_RplConfigNotFound
+
+
+Configuration record was not found.
+
+0x00000A41
+
+NERR_RplAdapterInfoCorrupted
+
+
+Adapter ID record information has been corrupted.
+
+0x00000A42
+
+NERR_RplInternal
+
+
+An internal service error has occurred.
+
+0x00000A43
+
+NERR_RplVendorInfoCorrupted
+
+
+Vendor ID record information has been corrupted.
+
+0x00000A44
+
+NERR_RplBootInfoCorrupted
+
+
+Boot block record information has been corrupted.
+
+0x00000A45
+
+NERR_RplWkstaNeedsUserAcct
+
+
+The user account for this workstation record is missing.
+
+0x00000A46
+
+NERR_RplNeedsRPLUSERAcct
+
+
+The RPLUSER local group could not be found.
+
+0x00000A47
+
+NERR_RplBootNotFound
+
+
+Boot block record was not found.
+
+0x00000A48
+
+NERR_RplIncompatibleProfile
+
+
+Chosen profile is incompatible with this workstation.
+
+0x00000A49
+
+NERR_RplAdapterNameUnavailable
+
+
+Chosen network adapter ID is in use by some other workstation.
+
+0x00000A4A
+
+NERR_RplConfigNotEmpty
+
+
+There are profiles using this configuration.
+
+0x00000A4B
+
+NERR_RplBootInUse
+
+
+There are workstations, profiles, or configurations using this boot block.
+
+0x00000A4C
+
+NERR_RplBackupDatabase
+
+
+Service failed to back up the Remoteboot database.
+
+0x00000A4D
+
+NERR_RplAdapterNotFound
+
+
+Adapter record was not found.
+
+0x00000A4E
+
+NERR_RplVendorNotFound
+
+
+Vendor record was not found.
+
+0x00000A4F
+
+NERR_RplVendorNameUnavailable
+
+
+Vendor name is in use by some other vendor record.
+
+0x00000A50
+
+NERR_RplBootNameUnavailable
+
+
+The boot name or vendor ID is in use by some other boot block record.
+
+0x00000A51
+
+NERR_RplConfigNameUnavailable
+
+
+The configuration name is in use by some other configuration.
+
+0x00000A64
+
+NERR_DfsInternalCorruption
+
+
+The internal database maintained by the DFS service is corrupt.
+
+0x00000A65
+
+NERR_DfsVolumeDataCorrupt
+
+
+One of the records in the internal DFS database is corrupt.
+
+0x00000A66
+
+NERR_DfsNoSuchVolume
+
+
+There is no DFS name whose entry path matches the input entry path.
+
+0x00000A67
+
+NERR_DfsVolumeAlreadyExists
+
+
+A root or link with the given name already exists.
+
+0x00000A68
+
+NERR_DfsAlreadyShared
+
+
+The server share specified is already shared in the DFS.
+
+0x00000A69
+
+NERR_DfsNoSuchShare
+
+
+The indicated server share does not support the indicated DFS namespace.
+
+0x00000A6A
+
+NERR_DfsNotALeafVolume
+
+
+The operation is not valid in this portion of the namespace.
+
+0x00000A6B
+
+NERR_DfsLeafVolume
+
+
+The operation is not valid in this portion of the namespace.
+
+0x00000A6C
+
+NERR_DfsVolumeHasMultipleServers
+
+
+The operation is ambiguous because the link has multiple servers.
+
+0x00000A6D
+
+NERR_DfsCantCreateJunctionPoint
+
+
+Unable to create a link.
+
+0x00000A6E
+
+NERR_DfsServerNotDfsAware
+
+
+The server is not DFS-aware.
+
+0x00000A6F
+
+NERR_DfsBadRenamePath
+
+
+The specified rename target path is invalid.
+
+0x00000A70
+
+NERR_DfsVolumeIsOffline
+
+
+The specified DFS link is offline.
+
+0x00000A71
+
+NERR_DfsNoSuchServer
+
+
+The specified server is not a server for this link.
+
+0x00000A72
+
+NERR_DfsCyclicalName
+
+
+A cycle in the DFS name was detected.
+
+0x00000A73
+
+NERR_DfsNotSupportedInServerDfs
+
+
+The operation is not supported on a server-based DFS.
+
+0x00000A74
+
+NERR_DfsDuplicateService
+
+
+This link is already supported by the specified server share.
+
+0x00000A75
+
+NERR_DfsCantRemoveLastServerShare
+
+
+Cannot remove the last server share supporting this root or link.
+
+0x00000A76
+
+NERR_DfsVolumeIsInterDfs
+
+
+The operation is not supported for an inter-DFS link.
+
+0x00000A77
+
+NERR_DfsInconsistent
+
+
+The internal state of the DFS Service has become inconsistent.
+
+0x00000A78
+
+NERR_DfsServerUpgraded
+
+
+The DFS Service has been installed on the specified server.
+
+0x00000A79
+
+NERR_DfsDataIsIdentical
+
+
+The DFS data being reconciled is identical.
+
+0x00000A7A
+
+NERR_DfsCantRemoveDfsRoot
+
+
+The DFS root cannot be deleted. Uninstall DFS if required.
+
+0x00000A7B
+
+NERR_DfsChildOrParentInDfs
+
+
+A child or parent directory of the share is already in a DFS.
+
+0x00000A82
+
+NERR_DfsInternalError
+
+
+DFS internal error.
+
+0x00000A83
+
+NERR_SetupAlreadyJoined
+
+
+This machine is already joined to a domain.
+
+0x00000A84
+
+NERR_SetupNotJoined
+
+
+This machine is not currently joined to a domain.
+
+0x00000A85
+
+NERR_SetupDomainController
+
+
+This machine is a domain controller and cannot be unjoined from a domain.
+
+0x00000A86
+
+NERR_DefaultJoinRequired
+
+
+The destination domain controller does not support creating machine accounts in organizational units (OUs).
+
+0x00000A87
+
+NERR_InvalidWorkgroupName
+
+
+The specified workgroup name is invalid.
+
+0x00000A88
+
+NERR_NameUsesIncompatibleCodePage
+
+
+The specified computer name is incompatible with the default language used on the domain controller.
+
+0x00000A89
+
+NERR_ComputerAccountNotFound
+
+
+The specified computer account could not be found.
+
+0x00000A8A
+
+NERR_PersonalSku
+
+
+This version of Windows cannot be joined to a domain.
+
+0x00000A8D
+
+NERR_PasswordMustChange
+
+
+The password must change at the next logon.
+
+0x00000A8E
+
+NERR_AccountLockedOut
+
+
+The account is locked out.
+
+0x00000A8F
+
+NERR_PasswordTooLong
+
+
+The password is too long.
+
+0x00000A90
+
+NERR_PasswordNotComplexEnough
+
+
+The password does not meet the complexity policy.
+
+0x00000A91
+
+NERR_PasswordFilterError
+
+
+The password does not meet the requirements of the password filter DLLs.
+
+0x00000BB8
+
+ERROR_UNKNOWN_PRINT_MONITOR
+
+
+The specified print monitor is unknown.
+
+0x00000BB9
+
+ERROR_PRINTER_DRIVER_IN_USE
+
+
+The specified printer driver is currently in use.
+
+0x00000BBA
+
+ERROR_SPOOL_FILE_NOT_FOUND
+
+
+The spool file was not found.
+
+0x00000BBB
+
+ERROR_SPL_NO_STARTDOC
+
+
+A StartDocPrinter call was not issued.
+
+0x00000BBC
+
+ERROR_SPL_NO_ADDJOB
+
+
+An AddJob call was not issued.
+
+0x00000BBD
+
+ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED
+
+
+The specified print processor has already been installed.
+
+0x00000BBE
+
+ERROR_PRINT_MONITOR_ALREADY_INSTALLED
+
+
+The specified print monitor has already been installed.
+
+0x00000BBF
+
+ERROR_INVALID_PRINT_MONITOR
+
+
+The specified print monitor does not have the required functions.
+
+0x00000BC0
+
+ERROR_PRINT_MONITOR_IN_USE
+
+
+The specified print monitor is currently in use.
+
+0x00000BC1
+
+ERROR_PRINTER_HAS_JOBS_QUEUED
+
+
+The requested operation is not allowed when there are jobs queued to the printer.
+
+0x00000BC2
+
+ERROR_SUCCESS_REBOOT_REQUIRED
+
+
+The requested operation is successful. Changes will not be effective until the system is rebooted.
+
+0x00000BC3
+
+ERROR_SUCCESS_RESTART_REQUIRED
+
+
+The requested operation is successful. Changes will not be effective until the service is restarted.
+
+0x00000BC4
+
+ERROR_PRINTER_NOT_FOUND
+
+
+No printers were found.
+
+0x00000BC5
+
+ERROR_PRINTER_DRIVER_WARNED
+
+
+The printer driver is known to be unreliable.
+
+0x00000BC6
+
+ERROR_PRINTER_DRIVER_BLOCKED
+
+
+The printer driver is known to harm the system.
+
+0x00000BC7
+
+ERROR_PRINTER_DRIVER_PACKAGE_IN_USE
+
+
+The specified printer driver package is currently in use.
+
+0x00000BC8
+
+ERROR_CORE_DRIVER_PACKAGE_NOT_FOUND
+
+
+Unable to find a core driver package that is required by the printer driver package.
+
+0x00000BC9
+
+ERROR_FAIL_REBOOT_REQUIRED
+
+
+The requested operation failed. A system reboot is required to roll back changes made.
+
+0x00000BCA
+
+ERROR_FAIL_REBOOT_INITIATED
+
+
+The requested operation failed. A system reboot has been initiated to roll back changes made.
+
+0x00000BCB
+ERROR_PRINTER_DRIVER_DOWNLOAD_NEEDED
+
+
+The specified printer driver was not found on the system and needs to be downloaded.
+
+0x00000BCE
+
+ERROR_PRINTER_NOT_SHAREABLE
+
+
+The specified printer cannot be shared.
+
+0x00000F6E
+
+ERROR_IO_REISSUE_AS_CACHED
+
+
+Reissue the given operation as a cached I/O operation.
+
+0x00000FA0
+
+ERROR_WINS_INTERNAL
+
+
+Windows Internet Name Service (WINS) encountered an error while processing the command.
+
+0x00000FA1
+
+ERROR_CAN_NOT_DEL_LOCAL_WINS
+
+
+The local WINS cannot be deleted.
+
+0x00000FA2
+
+ERROR_STATIC_INIT
+
+
+The importation from the file failed.
+
+0x00000FA3
+
+ERROR_INC_BACKUP
+
+
+The backup failed. Was a full backup done before?
+
+0x00000FA4
+
+ERROR_FULL_BACKUP
+
+
+The backup failed. Check the directory to which you are backing the database.
+
+0x00000FA5
+
+ERROR_REC_NON_EXISTENT
+
+
+The name does not exist in the WINS database.
+
+0x00000FA6
+
+ERROR_RPL_NOT_ALLOWED
+
+
+Replication with a nonconfigured partner is not allowed.
+
+0x00000FD2
+
+PEERDIST_ERROR_CONTENTINFO_VERSION_UNSUPPORTED
+
+
+The version of the supplied content information is not supported.
+
+0x00000FD3
+
+PEERDIST_ERROR_CANNOT_PARSE_CONTENTINFO
+
+
+The supplied content information is malformed.
+
+0x00000FD4
+
+PEERDIST_ERROR_MISSING_DATA
+
+
+The requested data cannot be found in local or peer caches.
+
+0x00000FD5
+
+PEERDIST_ERROR_NO_MORE
+
+
+No more data is available or required.
+
+0x00000FD6
+
+PEERDIST_ERROR_NOT_INITIALIZED
+
+
+The supplied object has not been initialized.
+
+0x00000FD7
+
+PEERDIST_ERROR_ALREADY_INITIALIZED
+
+
+The supplied object has already been initialized.
+
+0x00000FD8
+
+PEERDIST_ERROR_SHUTDOWN_IN_PROGRESS
+
+
+A shutdown operation is already in progress.
+
+0x00000FD9
+
+PEERDIST_ERROR_INVALIDATED
+
+
+The supplied object has already been invalidated.
+
+0x00000FDA
+
+PEERDIST_ERROR_ALREADY_EXISTS
+
+
+An element already exists and was not replaced.
+
+0x00000FDB
+
+PEERDIST_ERROR_OPERATION_NOTFOUND
+
+
+Cannot cancel the requested operation as it has already been completed.
+
+0x00000FDC
+
+PEERDIST_ERROR_ALREADY_COMPLETED
+
+
+Cannot perform the requested operation because it has already been carried out.
+
+0x00000FDD
+
+PEERDIST_ERROR_OUT_OF_BOUNDS
+
+
+An operation accessed data beyond the bounds of valid data.
+
+0x00000FDE
+
+PEERDIST_ERROR_VERSION_UNSUPPORTED
+
+
+The requested version is not supported.
+
+0x00000FDF
+
+PEERDIST_ERROR_INVALID_CONFIGURATION
+
+
+A configuration value is invalid.
+
+0x00000FE0
+
+PEERDIST_ERROR_NOT_LICENSED
+
+
+The SKU is not licensed.
+
+0x00000FE1
+
+PEERDIST_ERROR_SERVICE_UNAVAILABLE
+
+
+PeerDist Service is still initializing and will be available shortly.
+
+0x00001004
+
+ERROR_DHCP_ADDRESS_CONFLICT
+
+
+The Dynamic Host Configuration Protocol (DHCP) client has obtained an IP address that is already in use on the network. The local interface will be disabled until the DHCP client can obtain a new address.
+
+0x00001068
+
+ERROR_WMI_GUID_NOT_FOUND
+
+
+The GUID passed was not recognized as valid by a WMI data provider.
+
+0x00001069
+
+ERROR_WMI_INSTANCE_NOT_FOUND
+
+
+The instance name passed was not recognized as valid by a WMI data provider.
+
+0x0000106A
+
+ERROR_WMI_ITEMID_NOT_FOUND
+
+
+The data item ID passed was not recognized as valid by a WMI data provider.
+
+0x0000106B
+
+ERROR_WMI_TRY_AGAIN
+
+
+The WMI request could not be completed and should be retried.
+
+0x0000106C
+
+ERROR_WMI_DP_NOT_FOUND
+
+
+The WMI data provider could not be located.
+
+0x0000106D
+
+ERROR_WMI_UNRESOLVED_INSTANCE_REF
+
+
+The WMI data provider references an instance set that has not been registered.
+
+0x0000106E
+
+ERROR_WMI_ALREADY_ENABLED
+
+
+The WMI data block or event notification has already been enabled.
+
+0x0000106F
+
+ERROR_WMI_GUID_DISCONNECTED
+
+
+The WMI data block is no longer available.
+
+0x00001070
+
+ERROR_WMI_SERVER_UNAVAILABLE
+
+
+The WMI data service is not available.
+
+0x00001071
+
+ERROR_WMI_DP_FAILED
+
+
+The WMI data provider failed to carry out the request.
+
+0x00001072
+
+ERROR_WMI_INVALID_MOF
+
+
+The WMI Managed Object Format (MOF) information is not valid.
+
+0x00001073
+
+ERROR_WMI_INVALID_REGINFO
+
+
+The WMI registration information is not valid.
+
+0x00001074
+
+ERROR_WMI_ALREADY_DISABLED
+
+
+The WMI data block or event notification has already been disabled.
+
+0x00001075
+
+ERROR_WMI_READ_ONLY
+
+
+The WMI data item or data block is read-only.
+
+0x00001076
+
+ERROR_WMI_SET_FAILURE
+
+
+The WMI data item or data block could not be changed.
+
+0x000010CC
+
+ERROR_INVALID_MEDIA
+
+
+The media identifier does not represent a valid medium.
+
+0x000010CD
+
+ERROR_INVALID_LIBRARY
+
+
+The library identifier does not represent a valid library.
+
+0x000010CE
+
+ERROR_INVALID_MEDIA_POOL
+
+
+The media pool identifier does not represent a valid media pool.
+
+0x000010CF
+
+ERROR_DRIVE_MEDIA_MISMATCH
+
+
+The drive and medium are not compatible, or they exist in different libraries.
+
+0x000010D0
+
+ERROR_MEDIA_OFFLINE
+
+
+The medium currently exists in an offline library and must be online to perform this operation.
+
+0x000010D1
+
+ERROR_LIBRARY_OFFLINE
+
+
+The operation cannot be performed on an offline library.
+
+0x000010D2
+
+ERROR_EMPTY
+
+
+The library, drive, or media pool is empty.
+
+0x000010D3
+
+ERROR_NOT_EMPTY
+
+
+The library, drive, or media pool must be empty to perform this operation.
+
+0x000010D4
+
+ERROR_MEDIA_UNAVAILABLE
+
+
+No media is currently available in this media pool or library.
+
+0x000010D5
+
+ERROR_RESOURCE_DISABLED
+
+
+A resource required for this operation is disabled.
+
+0x000010D6
+
+ERROR_INVALID_CLEANER
+
+
+The media identifier does not represent a valid cleaner.
+
+0x000010D7
+
+ERROR_UNABLE_TO_CLEAN
+
+
+The drive cannot be cleaned or does not support cleaning.
+
+0x000010D8
+
+ERROR_OBJECT_NOT_FOUND
+
+
+The object identifier does not represent a valid object.
+
+0x000010D9
+
+ERROR_DATABASE_FAILURE
+
+
+Unable to read from or write to the database.
+
+0x000010DA
+
+ERROR_DATABASE_FULL
+
+
+The database is full.
+
+0x000010DB
+
+ERROR_MEDIA_INCOMPATIBLE
+
+
+The medium is not compatible with the device or media pool.
+
+0x000010DC
+
+ERROR_RESOURCE_NOT_PRESENT
+
+
+The resource required for this operation does not exist.
+
+0x000010DD
+
+ERROR_INVALID_OPERATION
+
+
+The operation identifier is not valid.
+
+0x000010DE
+
+ERROR_MEDIA_NOT_AVAILABLE
+
+
+The media is not mounted or ready for use.
+
+0x000010DF
+
+ERROR_DEVICE_NOT_AVAILABLE
+
+
+The device is not ready for use.
+
+0x000010E0
+
+ERROR_REQUEST_REFUSED
+
+
+The operator or administrator has refused the request.
+
+0x000010E1
+
+ERROR_INVALID_DRIVE_OBJECT
+
+
+The drive identifier does not represent a valid drive.
+
+0x000010E2
+
+ERROR_LIBRARY_FULL
+
+
+Library is full. No slot is available for use.
+
+0x000010E3
+
+ERROR_MEDIUM_NOT_ACCESSIBLE
+
+
+The transport cannot access the medium.
+
+0x000010E4
+
+ERROR_UNABLE_TO_LOAD_MEDIUM
+
+
+Unable to load the medium into the drive.
+
+0x000010E5
+
+ERROR_UNABLE_TO_INVENTORY_DRIVE
+
+
+Unable to retrieve the drive status.
+
+0x000010E6
+
+ERROR_UNABLE_TO_INVENTORY_SLOT
+
+
+Unable to retrieve the slot status.
+
+0x000010E7
+
+ERROR_UNABLE_TO_INVENTORY_TRANSPORT
+
+
+Unable to retrieve status about the transport.
+
+0x000010E8
+
+ERROR_TRANSPORT_FULL
+
+
+Cannot use the transport because it is already in use.
+
+0x000010E9
+
+ERROR_CONTROLLING_IEPORT
+
+
+Unable to open or close the inject/eject port.
+
+0x000010EA
+
+ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA
+
+
+Unable to eject the medium because it is in a drive.
+
+0x000010EB
+
+ERROR_CLEANER_SLOT_SET
+
+
+A cleaner slot is already reserved.
+
+0x000010EC
+
+ERROR_CLEANER_SLOT_NOT_SET
+
+
+A cleaner slot is not reserved.
+
+0x000010ED
+
+ERROR_CLEANER_CARTRIDGE_SPENT
+
+
+The cleaner cartridge has performed the maximum number of drive cleanings.
+
+0x000010EE
+
+ERROR_UNEXPECTED_OMID
+
+
+Unexpected on-medium identifier.
+
+0x000010EF
+
+ERROR_CANT_DELETE_LAST_ITEM
+
+
+The last remaining item in this group or resource cannot be deleted.
+
+0x000010F0
+
+ERROR_MESSAGE_EXCEEDS_MAX_SIZE
+
+
+The message provided exceeds the maximum size allowed for this parameter.
+
+0x000010F1
+
+ERROR_VOLUME_CONTAINS_SYS_FILES
+
+
+The volume contains system or paging files.
+
+0x000010F2
+
+ERROR_INDIGENOUS_TYPE
+
+
+The media type cannot be removed from this library because at least one drive in the library reports it can support this media type.
+
+0x000010F3
+
+ERROR_NO_SUPPORTING_DRIVES
+
+
+This offline media cannot be mounted on this system because no enabled drives are present that can be used.
+
+0x000010F4
+
+ERROR_CLEANER_CARTRIDGE_INSTALLED
+
+
+A cleaner cartridge is present in the tape library.
+
+0x000010F5
+
+ERROR_IEPORT_FULL
+
+
+Cannot use the IEport because it is not empty.
+
+0x000010FE
+
+ERROR_FILE_OFFLINE
+
+
+The remote storage service was not able to recall the file.
+
+0x000010FF
+
+ERROR_REMOTE_STORAGE_NOT_ACTIVE
+
+
+The remote storage service is not operational at this time.
+
+0x00001100
+
+ERROR_REMOTE_STORAGE_MEDIA_ERROR
+
+
+The remote storage service encountered a media error.
+
+0x00001126
+
+ERROR_NOT_A_REPARSE_POINT
+
+
+The file or directory is not a reparse point.
+
+0x00001127
+
+ERROR_REPARSE_ATTRIBUTE_CONFLICT
+
+
+The reparse point attribute cannot be set because it conflicts with an existing attribute.
+
+0x00001128
+
+ERROR_INVALID_REPARSE_DATA
+
+
+The data present in the reparse point buffer is invalid.
+
+0x00001129
+
+ERROR_REPARSE_TAG_INVALID
+
+
+The tag present in the reparse point buffer is invalid.
+
+0x0000112A
+
+ERROR_REPARSE_TAG_MISMATCH
+
+
+There is a mismatch between the tag specified in the request and the tag present in the reparse point.
+
+0x00001194
+
+ERROR_VOLUME_NOT_SIS_ENABLED
+
+
+Single Instance Storage (SIS) is not available on this volume.
+
+0x00001389
+
+ERROR_DEPENDENT_RESOURCE_EXISTS
+
+
+The operation cannot be completed because other resources depend on this resource.
+
+0x0000138A
+
+ERROR_DEPENDENCY_NOT_FOUND
+
+
+The cluster resource dependency cannot be found.
+
+0x0000138B
+
+ERROR_DEPENDENCY_ALREADY_EXISTS
+
+
+The cluster resource cannot be made dependent on the specified resource because it is already dependent.
+
+0x0000138C
+
+ERROR_RESOURCE_NOT_ONLINE
+
+
+The cluster resource is not online.
+
+0x0000138D
+
+ERROR_HOST_NODE_NOT_AVAILABLE
+
+
+A cluster node is not available for this operation.
+
+0x0000138E
+
+ERROR_RESOURCE_NOT_AVAILABLE
+
+
+The cluster resource is not available.
+
+0x0000138F
+
+ERROR_RESOURCE_NOT_FOUND
+
+
+The cluster resource could not be found.
+
+0x00001390
+
+ERROR_SHUTDOWN_CLUSTER
+
+
+The cluster is being shut down.
+
+0x00001391
+
+ERROR_CANT_EVICT_ACTIVE_NODE
+
+
+A cluster node cannot be evicted from the cluster unless the node is down or it is the last node.
+
+0x00001392
+
+ERROR_OBJECT_ALREADY_EXISTS
+
+
+The object already exists.
+
+0x00001393
+
+ERROR_OBJECT_IN_LIST
+
+
+The object is already in the list.
+
+0x00001394
+
+ERROR_GROUP_NOT_AVAILABLE
+
+
+The cluster group is not available for any new requests.
+
+0x00001395
+
+ERROR_GROUP_NOT_FOUND
+
+
+The cluster group could not be found.
+
+0x00001396
+
+ERROR_GROUP_NOT_ONLINE
+
+
+The operation could not be completed because the cluster group is not online.
+
+0x00001397
+
+ERROR_HOST_NODE_NOT_RESOURCE_OWNER
+
+
+The operation failed because either the specified cluster node is not the owner of the resource, or the node is not a possible owner of the resource.
+
+0x00001398
+
+ERROR_HOST_NODE_NOT_GROUP_OWNER
+
+
+The operation failed because either the specified cluster node is not the owner of the group, or the node is not a possible owner of the group.
+
+0x00001399
+
+ERROR_RESMON_CREATE_FAILED
+
+
+The cluster resource could not be created in the specified resource monitor.
+
+0x0000139A
+
+ERROR_RESMON_ONLINE_FAILED
+
+
+The cluster resource could not be brought online by the resource monitor.
+
+0x0000139B
+
+ERROR_RESOURCE_ONLINE
+
+
+The operation could not be completed because the cluster resource is online.
+
+0x0000139C
+
+ERROR_QUORUM_RESOURCE
+
+
+The cluster resource could not be deleted or brought offline because it is the quorum resource.
+
+0x0000139D
+
+ERROR_NOT_QUORUM_CAPABLE
+
+
+The cluster could not make the specified resource a quorum resource because it is not capable of being a quorum resource.
+
+0x0000139E
+
+ERROR_CLUSTER_SHUTTING_DOWN
+
+
+The cluster software is shutting down.
+
+0x0000139F
+
+ERROR_INVALID_STATE
+
+
+The group or resource is not in the correct state to perform the requested operation.
+
+0x000013A0
+
+ERROR_RESOURCE_PROPERTIES_STORED
+
+
+The properties were stored but not all changes will take effect until the next time the resource is brought online.
+
+0x000013A1
+
+ERROR_NOT_QUORUM_CLASS
+
+
+The cluster could not make the specified resource a quorum resource because it does not belong to a shared storage class.
+
+0x000013A2
+
+ERROR_CORE_RESOURCE
+
+
+The cluster resource could not be deleted because it is a core resource.
+
+0x000013A3
+
+ERROR_QUORUM_RESOURCE_ONLINE_FAILED
+
+
+The quorum resource failed to come online.
+
+0x000013A4
+
+ERROR_QUORUMLOG_OPEN_FAILED
+
+
+The quorum log could not be created or mounted successfully.
+
+0x000013A5
+
+ERROR_CLUSTERLOG_CORRUPT
+
+
+The cluster log is corrupt.
+
+0x000013A6
+
+ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE
+
+
+The record could not be written to the cluster log because it exceeds the maximum size.
+
+0x000013A7
+
+ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE
+
+
+The cluster log exceeds its maximum size.
+
+0x000013A8
+
+ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND
+
+
+No checkpoint record was found in the cluster log.
+
+0x000013A9
+
+ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE
+
+
+The minimum required disk space needed for logging is not available.
+
+0x000013AA
+
+ERROR_QUORUM_OWNER_ALIVE
+
+
+The cluster node failed to take control of the quorum resource because the resource is owned by another active node.
+
+0x000013AB
+
+ERROR_NETWORK_NOT_AVAILABLE
+
+
+A cluster network is not available for this operation.
+
+0x000013AC
+
+ERROR_NODE_NOT_AVAILABLE
+
+
+A cluster node is not available for this operation.
+
+0x000013AD
+
+ERROR_ALL_NODES_NOT_AVAILABLE
+
+
+All cluster nodes must be running to perform this operation.
+
+0x000013AE
+
+ERROR_RESOURCE_FAILED
+
+
+A cluster resource failed.
+
+0x000013AF
+
+ERROR_CLUSTER_INVALID_NODE
+
+
+The cluster node is not valid.
+
+0x000013B0
+
+ERROR_CLUSTER_NODE_EXISTS
+
+
+The cluster node already exists.
+
+0x000013B1
+
+ERROR_CLUSTER_JOIN_IN_PROGRESS
+
+
+A node is in the process of joining the cluster.
+
+0x000013B2
+
+ERROR_CLUSTER_NODE_NOT_FOUND
+
+
+The cluster node was not found.
+
+0x000013B3
+
+ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND
+
+
+The cluster local node information was not found.
+
+0x000013B4
+
+ERROR_CLUSTER_NETWORK_EXISTS
+
+
+The cluster network already exists.
+
+0x000013B5
+
+ERROR_CLUSTER_NETWORK_NOT_FOUND
+
+
+The cluster network was not found.
+
+0x000013B6
+
+ERROR_CLUSTER_NETINTERFACE_EXISTS
+
+
+The cluster network interface already exists.
+
+0x000013B7
+
+ERROR_CLUSTER_NETINTERFACE_NOT_FOUND
+
+
+The cluster network interface was not found.
+
+0x000013B8
+
+ERROR_CLUSTER_INVALID_REQUEST
+
+
+The cluster request is not valid for this object.
+
+0x000013B9
+
+ERROR_CLUSTER_INVALID_NETWORK_PROVIDER
+
+
+The cluster network provider is not valid.
+
+0x000013BA
+
+ERROR_CLUSTER_NODE_DOWN
+
+
+The cluster node is down.
+
+0x000013BB
+
+ERROR_CLUSTER_NODE_UNREACHABLE
+
+
+The cluster node is not reachable.
+
+0x000013BC
+
+ERROR_CLUSTER_NODE_NOT_MEMBER
+
+
+The cluster node is not a member of the cluster.
+
+0x000013BD
+
+ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS
+
+
+A cluster join operation is not in progress.
+
+0x000013BE
+
+ERROR_CLUSTER_INVALID_NETWORK
+
+
+The cluster network is not valid.
+
+0x000013C0
+
+ERROR_CLUSTER_NODE_UP
+
+
+The cluster node is up.
+
+0x000013C1
+
+ERROR_CLUSTER_IPADDR_IN_USE
+
+
+The cluster IP address is already in use.
+
+0x000013C2
+
+ERROR_CLUSTER_NODE_NOT_PAUSED
+
+
+The cluster node is not paused.
+
+0x000013C3
+
+ERROR_CLUSTER_NO_SECURITY_CONTEXT
+
+
+No cluster security context is available.
+
+0x000013C4
+
+ERROR_CLUSTER_NETWORK_NOT_INTERNAL
+
+
+The cluster network is not configured for internal cluster communication.
+
+0x000013C5
+
+ERROR_CLUSTER_NODE_ALREADY_UP
+
+
+The cluster node is already up.
+
+0x000013C6
+
+ERROR_CLUSTER_NODE_ALREADY_DOWN
+
+
+The cluster node is already down.
+
+0x000013C7
+
+ERROR_CLUSTER_NETWORK_ALREADY_ONLINE
+
+
+The cluster network is already online.
+
+0x000013C8
+
+ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE
+
+
+The cluster network is already offline.
+
+0x000013C9
+
+ERROR_CLUSTER_NODE_ALREADY_MEMBER
+
+
+The cluster node is already a member of the cluster.
+
+0x000013CA
+
+ERROR_CLUSTER_LAST_INTERNAL_NETWORK
+
+
+The cluster network is the only one configured for internal cluster communication between two or more active cluster nodes. The internal communication capability cannot be removed from the network.
+
+0x000013CB
+
+ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS
+
+
+One or more cluster resources depend on the network to provide service to clients. The client access capability cannot be removed from the network.
+
+0x000013CC
+
+ERROR_INVALID_OPERATION_ON_QUORUM
+
+
+This operation cannot be performed on the cluster resource because it is the quorum resource. This quorum resource cannot be brought offline and its possible owners list cannot be modified.
+
+0x000013CD
+
+ERROR_DEPENDENCY_NOT_ALLOWED
+
+
+The cluster quorum resource is not allowed to have any dependencies.
+
+0x000013CE
+
+ERROR_CLUSTER_NODE_PAUSED
+
+
+The cluster node is paused.
+
+0x000013CF
+
+ERROR_NODE_CANT_HOST_RESOURCE
+
+
+The cluster resource cannot be brought online. The owner node cannot run this resource.
+
+0x000013D0
+
+ERROR_CLUSTER_NODE_NOT_READY
+
+
+The cluster node is not ready to perform the requested operation.
+
+0x000013D1
+
+ERROR_CLUSTER_NODE_SHUTTING_DOWN
+
+
+The cluster node is shutting down.
+
+0x000013D2
+
+ERROR_CLUSTER_JOIN_ABORTED
+
+
+The cluster join operation was aborted.
+
+0x000013D3
+
+ERROR_CLUSTER_INCOMPATIBLE_VERSIONS
+
+
+The cluster join operation failed due to incompatible software versions between the joining node and its sponsor.
+
+0x000013D4
+
+ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED
+
+
+This resource cannot be created because the cluster has reached the limit on the number of resources it can monitor.
+
+0x000013D5
+
+ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED
+
+
+The system configuration changed during the cluster join or form operation. The join or form operation was aborted.
+
+0x000013D6
+
+ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND
+
+
+The specified resource type was not found.
+
+0x000013D7
+
+ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED
+
+
+The specified node does not support a resource of this type. This might be due to version inconsistencies or due to the absence of the resource DLL on this node.
+
+0x000013D8
+
+ERROR_CLUSTER_RESNAME_NOT_FOUND
+
+
+The specified resource name is not supported by this resource DLL. This might be due to a bad (or changed) name supplied to the resource DLL.
+
+0x000013D9
+
+ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED
+
+
+No authentication package could be registered with the RPC server.
+
+0x000013DA
+
+ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST
+
+
+You cannot bring the group online because the owner of the group is not in the preferred list for the group. To change the owner node for the group, move the group.
+
+0x000013DB
+
+ERROR_CLUSTER_DATABASE_SEQMISMATCH
+
+
+The join operation failed because the cluster database sequence number has changed or is incompatible with the locker node. This can happen during a join operation if the cluster database was changing during the join.
+
+0x000013DC
+
+ERROR_RESMON_INVALID_STATE
+
+
+The resource monitor will not allow the fail operation to be performed while the resource is in its current state. This can happen if the resource is in a pending state.
+
+0x000013DD
+
+ERROR_CLUSTER_GUM_NOT_LOCKER
+
+
+A non-locker code received a request to reserve the lock for making global updates.
+
+0x000013DE
+
+ERROR_QUORUM_DISK_NOT_FOUND
+
+
+The quorum disk could not be located by the cluster service.
+
+0x000013DF
+
+ERROR_DATABASE_BACKUP_CORRUPT
+
+
+The backed-up cluster database is possibly corrupt.
+
+0x000013E0
+
+ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT
+
+
+A DFS root already exists in this cluster node.
+
+0x000013E1
+
+ERROR_RESOURCE_PROPERTY_UNCHANGEABLE
+
+
+An attempt to modify a resource property failed because it conflicts with another existing property.
+
+0x00001702
+
+ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE
+
+
+An operation was attempted that is incompatible with the current membership state of the node.
+
+0x00001703
+
+ERROR_CLUSTER_QUORUMLOG_NOT_FOUND
+
+
+The quorum resource does not contain the quorum log.
+
+0x00001704
+
+ERROR_CLUSTER_MEMBERSHIP_HALT
+
+
+The membership engine requested shutdown of the cluster service on this node.
+
+0x00001705
+
+ERROR_CLUSTER_INSTANCE_ID_MISMATCH
+
+
+The join operation failed because the cluster instance ID of the joining node does not match the cluster instance ID of the sponsor node.
+
+0x00001706
+
+ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP
+
+
+A matching cluster network for the specified IP address could not be found.
+
+0x00001707
+
+ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH
+
+
+The actual data type of the property did not match the expected data type of the property.
+
+0x00001708
+
+ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP
+
+
+The cluster node was evicted from the cluster successfully, but the node was not cleaned up. To determine what clean-up steps failed and how to recover, see the Failover Clustering application event log using Event Viewer.
+
+0x00001709
+
+ERROR_CLUSTER_PARAMETER_MISMATCH
+
+
+Two or more parameter values specified for a resource's properties are in conflict.
+
+0x0000170A
+
+ERROR_NODE_CANNOT_BE_CLUSTERED
+
+
+This computer cannot be made a member of a cluster.
+
+0x0000170B
+
+ERROR_CLUSTER_WRONG_OS_VERSION
+
+
+This computer cannot be made a member of a cluster because it does not have the correct version of Windows installed.
+
+0x0000170C
+
+ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME
+
+
+A cluster cannot be created with the specified cluster name because that cluster name is already in use. Specify a different name for the cluster.
+
+0x0000170D
+
+ERROR_CLUSCFG_ALREADY_COMMITTED
+
+
+The cluster configuration action has already been committed.
+
+0x0000170E
+
+ERROR_CLUSCFG_ROLLBACK_FAILED
+
+
+The cluster configuration action could not be rolled back.
+
+0x0000170F
+
+ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT
+
+
+The drive letter assigned to a system disk on one node conflicted with the drive letter assigned to a disk on another node.
+
+0x00001710
+
+ERROR_CLUSTER_OLD_VERSION
+
+
+One or more nodes in the cluster are running a version of Windows that does not support this operation.
+
+0x00001711
+
+ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME
+
+
+The name of the corresponding computer account does not match the network name for this resource.
+
+0x00001712
+
+ERROR_CLUSTER_NO_NET_ADAPTERS
+
+
+No network adapters are available.
+
+0x00001713
+
+ERROR_CLUSTER_POISONED
+
+
+The cluster node has been poisoned.
+
+0x00001714
+
+ERROR_CLUSTER_GROUP_MOVING
+
+
+The group is unable to accept the request because it is moving to another node.
+
+0x00001715
+
+ERROR_CLUSTER_RESOURCE_TYPE_BUSY
+
+
+The resource type cannot accept the request because it is too busy performing another operation.
+
+0x00001716
+
+ERROR_RESOURCE_CALL_TIMED_OUT
+
+
+The call to the cluster resource DLL timed out.
+
+0x00001717
+
+ERROR_INVALID_CLUSTER_IPV6_ADDRESS
+
+
+The address is not valid for an IPv6 Address resource. A global IPv6 address is required, and it must match a cluster network. Compatibility addresses are not permitted.
+
+0x00001718
+
+ERROR_CLUSTER_INTERNAL_INVALID_FUNCTION
+
+
+An internal cluster error occurred. A call to an invalid function was attempted.
+
+0x00001719
+
+ERROR_CLUSTER_PARAMETER_OUT_OF_BOUNDS
+
+
+A parameter value is out of acceptable range.
+
+0x0000171A
+
+ERROR_CLUSTER_PARTIAL_SEND
+
+
+A network error occurred while sending data to another node in the cluster. The number of bytes transmitted was less than required.
+
+0x0000171B
+
+ERROR_CLUSTER_REGISTRY_INVALID_FUNCTION
+
+
+An invalid cluster registry operation was attempted.
+
+0x0000171C
+
+ERROR_CLUSTER_INVALID_STRING_TERMINATION
+
+
+An input string of characters is not properly terminated.
+
+0x0000171D
+
+ERROR_CLUSTER_INVALID_STRING_FORMAT
+
+
+An input string of characters is not in a valid format for the data it represents.
+
+0x0000171E
+
+ERROR_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS
+
+
+An internal cluster error occurred. A cluster database transaction was attempted while a transaction was already in progress.
+
+0x0000171F
+
+ERROR_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS
+
+
+An internal cluster error occurred. There was an attempt to commit a cluster database transaction while no transaction was in progress.
+
+0x00001720
+
+ERROR_CLUSTER_NULL_DATA
+
+
+An internal cluster error occurred. Data was not properly initialized.
+
+0x00001721
+
+ERROR_CLUSTER_PARTIAL_READ
+
+
+An error occurred while reading from a stream of data. An unexpected number of bytes was returned.
+
+0x00001722
+
+ERROR_CLUSTER_PARTIAL_WRITE
+
+
+An error occurred while writing to a stream of data. The required number of bytes could not be written.
+
+0x00001723
+
+ERROR_CLUSTER_CANT_DESERIALIZE_DATA
+
+
+An error occurred while deserializing a stream of cluster data.
+
+0x00001724
+
+ERROR_DEPENDENT_RESOURCE_PROPERTY_CONFLICT
+
+
+One or more property values for this resource are in conflict with one or more property values associated with its dependent resources.
+
+0x00001725
+
+ERROR_CLUSTER_NO_QUORUM
+
+
+A quorum of cluster nodes was not present to form a cluster.
+
+0x00001726
+
+ERROR_CLUSTER_INVALID_IPV6_NETWORK
+
+
+The cluster network is not valid for an IPv6 address resource, or it does not match the configured address.
+
+0x00001727
+
+ERROR_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK
+
+
+The cluster network is not valid for an IPv6 tunnel resource. Check the configuration of the IP Address resource on which the IPv6 tunnel resource depends.
+
+0x00001728
+
+ERROR_QUORUM_NOT_ALLOWED_IN_THIS_GROUP
+
+
+Quorum resource cannot reside in the available storage group.
+
+0x00001770
+
+ERROR_ENCRYPTION_FAILED
+
+
+The specified file could not be encrypted.
+
+0x00001771
+
+ERROR_DECRYPTION_FAILED
+
+
+The specified file could not be decrypted.
+
+0x00001772
+
+ERROR_FILE_ENCRYPTED
+
+
+The specified file is encrypted and the user does not have the ability to decrypt it.
+
+0x00001773
+
+ERROR_NO_RECOVERY_POLICY
+
+
+There is no valid encryption recovery policy configured for this system.
+
+0x00001774
+
+ERROR_NO_EFS
+
+
+The required encryption driver is not loaded for this system.
+
+0x00001775
+
+ERROR_WRONG_EFS
+
+
+The file was encrypted with a different encryption driver than is currently loaded.
+
+0x00001776
+
+ERROR_NO_USER_KEYS
+
+
+There are no Encrypting File System (EFS) keys defined for the user.
+
+0x00001777
+
+ERROR_FILE_NOT_ENCRYPTED
+
+
+The specified file is not encrypted.
+
+0x00001778
+
+ERROR_NOT_EXPORT_FORMAT
+
+
+The specified file is not in the defined EFS export format.
+
+0x00001779
+
+ERROR_FILE_READ_ONLY
+
+
+The specified file is read-only.
+
+0x0000177A
+
+ERROR_DIR_EFS_DISALLOWED
+
+
+The directory has been disabled for encryption.
+
+0x0000177B
+
+ERROR_EFS_SERVER_NOT_TRUSTED
+
+
+The server is not trusted for remote encryption operation.
+
+0x0000177C
+
+ERROR_BAD_RECOVERY_POLICY
+
+
+Recovery policy configured for this system contains invalid recovery certificate.
+
+0x0000177D
+
+ERROR_EFS_ALG_BLOB_TOO_BIG
+
+
+The encryption algorithm used on the source file needs a bigger key buffer than the one on the destination file.
+
+0x0000177E
+
+ERROR_VOLUME_NOT_SUPPORT_EFS
+
+
+The disk partition does not support file encryption.
+
+0x0000177F
+
+ERROR_EFS_DISABLED
+
+
+This machine is disabled for file encryption.
+
+0x00001780
+
+ERROR_EFS_VERSION_NOT_SUPPORT
+
+
+A newer system is required to decrypt this encrypted file.
+
+0x00001781
+
+ERROR_CS_ENCRYPTION_INVALID_SERVER_RESPONSE
+
+
+The remote server sent an invalid response for a file being opened with client-side encryption.
+
+0x00001782
+
+ERROR_CS_ENCRYPTION_UNSUPPORTED_SERVER
+
+
+Client-side encryption is not supported by the remote server even though it claims to support it.
+
+0x00001783
+
+ERROR_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE
+
+
+File is encrypted and should be opened in client-side encryption mode.
+
+0x00001784
+
+ERROR_CS_ENCRYPTION_NEW_ENCRYPTED_FILE
+
+
+A new encrypted file is being created and a $EFS needs to be provided.
+
+0x00001785
+
+ERROR_CS_ENCRYPTION_FILE_NOT_CSE
+
+
+The SMB client requested a client-side extension (CSE) file system control (FSCTL) on a non-CSE file.
+
+0x000017E6
+
+ERROR_NO_BROWSER_SERVERS_FOUND
+
+
+The list of servers for this workgroup is not currently available
+
+0x00001838
+
+SCHED_E_SERVICE_NOT_LOCALSYSTEM
+
+
+The Task Scheduler service must be configured to run in the System account to function properly. Individual tasks can be configured to run in other accounts.
+
+0x000019C8
+
+ERROR_LOG_SECTOR_INVALID
+
+
+The log service encountered an invalid log sector.
+
+0x000019C9
+
+ERROR_LOG_SECTOR_PARITY_INVALID
+
+
+The log service encountered a log sector with invalid block parity.
+
+0x000019CA
+
+ERROR_LOG_SECTOR_REMAPPED
+
+
+The log service encountered a remapped log sector.
+
+0x000019CB
+
+ERROR_LOG_BLOCK_INCOMPLETE
+
+
+The log service encountered a partial or incomplete log block.
+
+0x000019CC
+
+ERROR_LOG_INVALID_RANGE
+
+
+The log service encountered an attempt to access data outside the active log range.
+
+0x000019CD
+
+ERROR_LOG_BLOCKS_EXHAUSTED
+
+
+The log service user marshaling buffers are exhausted.
+
+0x000019CE
+
+ERROR_LOG_READ_CONTEXT_INVALID
+
+
+The log service encountered an attempt to read from a marshaling area with an invalid read context.
+
+0x000019CF
+
+ERROR_LOG_RESTART_INVALID
+
+
+The log service encountered an invalid log restart area.
+
+0x000019D0
+
+ERROR_LOG_BLOCK_VERSION
+
+
+The log service encountered an invalid log block version.
+
+0x000019D1
+
+ERROR_LOG_BLOCK_INVALID
+
+
+The log service encountered an invalid log block.
+
+0x000019D2
+
+ERROR_LOG_READ_MODE_INVALID
+
+
+The log service encountered an attempt to read the log with an invalid read mode.
+
+0x000019D3
+
+ERROR_LOG_NO_RESTART
+
+
+The log service encountered a log stream with no restart area.
+
+0x000019D4
+
+ERROR_LOG_METADATA_CORRUPT
+
+
+The log service encountered a corrupted metadata file.
+
+0x000019D5
+
+ERROR_LOG_METADATA_INVALID
+
+
+The log service encountered a metadata file that could not be created by the log file system.
+
+0x000019D6
+
+ERROR_LOG_METADATA_INCONSISTENT
+
+
+The log service encountered a metadata file with inconsistent data.
+
+0x000019D7
+
+ERROR_LOG_RESERVATION_INVALID
+
+
+The log service encountered an attempt to erroneous allocate or dispose reservation space.
+
+0x000019D8
+
+ERROR_LOG_CANT_DELETE
+
+
+The log service cannot delete a log file or file system container.
+
+0x000019D9
+
+ERROR_LOG_CONTAINER_LIMIT_EXCEEDED
+
+
+The log service has reached the maximum allowable containers allocated to a log file.
+
+0x000019DA
+
+ERROR_LOG_START_OF_LOG
+
+
+The log service has attempted to read or write backward past the start of the log.
+
+0x000019DB
+
+ERROR_LOG_POLICY_ALREADY_INSTALLED
+
+
+The log policy could not be installed because a policy of the same type is already present.
+
+0x000019DC
+
+ERROR_LOG_POLICY_NOT_INSTALLED
+
+
+The log policy in question was not installed at the time of the request.
+
+0x000019DD
+
+ERROR_LOG_POLICY_INVALID
+
+
+The installed set of policies on the log is invalid.
+
+0x000019DE
+
+ERROR_LOG_POLICY_CONFLICT
+
+
+A policy on the log in question prevented the operation from completing.
+
+0x000019DF
+
+ERROR_LOG_PINNED_ARCHIVE_TAIL
+
+
+Log space cannot be reclaimed because the log is pinned by the archive tail.
+
+0x000019E0
+
+ERROR_LOG_RECORD_NONEXISTENT
+
+
+The log record is not a record in the log file.
+
+0x000019E1
+
+ERROR_LOG_RECORDS_RESERVED_INVALID
+
+
+The number of reserved log records or the adjustment of the number of reserved log records is invalid.
+
+0x000019E2
+
+ERROR_LOG_SPACE_RESERVED_INVALID
+
+
+The reserved log space or the adjustment of the log space is invalid.
+
+0x000019E3
+
+ERROR_LOG_TAIL_INVALID
+
+
+A new or existing archive tail or base of the active log is invalid.
+
+0x000019E4
+
+ERROR_LOG_FULL
+
+
+The log space is exhausted.
+
+0x000019E5
+
+ERROR_COULD_NOT_RESIZE_LOG
+
+
+The log could not be set to the requested size.
+
+0x000019E6
+
+ERROR_LOG_MULTIPLEXED
+
+
+The log is multiplexed; no direct writes to the physical log are allowed.
+
+0x000019E7
+
+ERROR_LOG_DEDICATED
+
+
+The operation failed because the log is a dedicated log.
+
+0x000019E8
+
+ERROR_LOG_ARCHIVE_NOT_IN_PROGRESS
+
+
+The operation requires an archive context.
+
+0x000019E9
+
+ERROR_LOG_ARCHIVE_IN_PROGRESS
+
+
+Log archival is in progress.
+
+0x000019EA
+
+ERROR_LOG_EPHEMERAL
+
+
+The operation requires a non-ephemeral log, but the log is ephemeral.
+
+0x000019EB
+
+ERROR_LOG_NOT_ENOUGH_CONTAINERS
+
+
+The log must have at least two containers before it can be read from or written to.
+
+0x000019EC
+
+ERROR_LOG_CLIENT_ALREADY_REGISTERED
+
+
+A log client has already registered on the stream.
+
+0x000019ED
+
+ERROR_LOG_CLIENT_NOT_REGISTERED
+
+
+A log client has not been registered on the stream.
+
+0x000019EE
+
+ERROR_LOG_FULL_HANDLER_IN_PROGRESS
+
+
+A request has already been made to handle the log full condition.
+
+0x000019EF
+
+ERROR_LOG_CONTAINER_READ_FAILED
+
+
+The log service encountered an error when attempting to read from a log container.
+
+0x000019F0
+
+ERROR_LOG_CONTAINER_WRITE_FAILED
+
+
+The log service encountered an error when attempting to write to a log container.
+
+0x000019F1
+
+ERROR_LOG_CONTAINER_OPEN_FAILED
+
+
+The log service encountered an error when attempting to open a log container.
+
+0x000019F2
+
+ERROR_LOG_CONTAINER_STATE_INVALID
+
+
+The log service encountered an invalid container state when attempting a requested action.
+
+0x000019F3
+
+ERROR_LOG_STATE_INVALID
+
+
+The log service is not in the correct state to perform a requested action.
+
+0x000019F4
+
+ERROR_LOG_PINNED
+
+
+The log space cannot be reclaimed because the log is pinned.
+
+0x000019F5
+
+ERROR_LOG_METADATA_FLUSH_FAILED
+
+
+The log metadata flush failed.
+
+0x000019F6
+
+ERROR_LOG_INCONSISTENT_SECURITY
+
+
+Security on the log and its containers is inconsistent.
+
+0x000019F7
+
+ERROR_LOG_APPENDED_FLUSH_FAILED
+
+
+Records were appended to the log or reservation changes were made, but the log could not be flushed.
+
+0x000019F8
+
+ERROR_LOG_PINNED_RESERVATION
+
+
+The log is pinned due to reservation consuming most of the log space. Free some reserved records to make space available.
+
+0x00001A2C
+
+ERROR_INVALID_TRANSACTION
+
+
+The transaction handle associated with this operation is not valid.
+
+0x00001A2D
+
+ERROR_TRANSACTION_NOT_ACTIVE
+
+
+The requested operation was made in the context of a transaction that is no longer active.
+
+0x00001A2E
+
+ERROR_TRANSACTION_REQUEST_NOT_VALID
+
+
+The requested operation is not valid on the transaction object in its current state.
+
+0x00001A2F
+
+ERROR_TRANSACTION_NOT_REQUESTED
+
+
+The caller has called a response API, but the response is not expected because the transaction manager did not issue the corresponding request to the caller.
+
+0x00001A30
+
+ERROR_TRANSACTION_ALREADY_ABORTED
+
+
+It is too late to perform the requested operation because the transaction has already been aborted.
+
+0x00001A31
+
+ERROR_TRANSACTION_ALREADY_COMMITTED
+
+
+It is too late to perform the requested operation because the transaction has already been committed.
+
+0x00001A32
+
+ERROR_TM_INITIALIZATION_FAILED
+
+
+The transaction manager was unable to be successfully initialized. Transacted operations are not supported.
+
+0x00001A33
+
+ERROR_RESOURCEMANAGER_READ_ONLY
+
+
+The specified resource manager made no changes or updates to the resource under this transaction.
+
+0x00001A34
+
+ERROR_TRANSACTION_NOT_JOINED
+
+
+The resource manager has attempted to prepare a transaction that it has not successfully joined.
+
+0x00001A35
+
+ERROR_TRANSACTION_SUPERIOR_EXISTS
+
+
+The transaction object already has a superior enlistment, and the caller attempted an operation that would have created a new superior. Only a single superior enlistment is allowed.
+
+0x00001A36
+
+ERROR_CRM_PROTOCOL_ALREADY_EXISTS
+
+
+The resource manager tried to register a protocol that already exists.
+
+0x00001A37
+
+ERROR_TRANSACTION_PROPAGATION_FAILED
+
+
+The attempt to propagate the transaction failed.
+
+0x00001A38
+
+ERROR_CRM_PROTOCOL_NOT_FOUND
+
+
+The requested propagation protocol was not registered as a CRM.
+
+0x00001A39
+
+ERROR_TRANSACTION_INVALID_MARSHALL_BUFFER
+
+
+The buffer passed in to PushTransaction or PullTransaction is not in a valid format.
+
+0x00001A3A
+
+ERROR_CURRENT_TRANSACTION_NOT_VALID
+
+
+The current transaction context associated with the thread is not a valid handle to a transaction object.
+
+0x00001A3B
+
+ERROR_TRANSACTION_NOT_FOUND
+
+
+The specified transaction object could not be opened because it was not found.
+
+0x00001A3C
+
+ERROR_RESOURCEMANAGER_NOT_FOUND
+
+
+The specified resource manager object could not be opened because it was not found.
+
+0x00001A3D
+
+ERROR_ENLISTMENT_NOT_FOUND
+
+
+The specified enlistment object could not be opened because it was not found.
+
+0x00001A3E
+
+ERROR_TRANSACTIONMANAGER_NOT_FOUND
+
+
+The specified transaction manager object could not be opened because it was not found.
+
+0x00001A3F
+
+ERROR_TRANSACTIONMANAGER_NOT_ONLINE
+
+
+The specified resource manager was unable to create an enlistment because its associated transaction manager is not online.
+
+0x00001A40
+
+ERROR_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION
+
+
+The specified transaction manager was unable to create the objects contained in its log file in the ObjectB namespace. Therefore, the transaction manager was unable to recover.
+
+0x00001A90
+
+ERROR_TRANSACTIONAL_CONFLICT
+
+
+The function attempted to use a name that is reserved for use by another transaction.
+
+0x00001A91
+
+ERROR_RM_NOT_ACTIVE
+
+
+Transaction support within the specified file system resource manager is not started or was shut down due to an error.
+
+0x00001A92
+
+ERROR_RM_METADATA_CORRUPT
+
+
+The metadata of the resource manager has been corrupted. The resource manager will not function.
+
+0x00001A93
+
+ERROR_DIRECTORY_NOT_RM
+
+
+The specified directory does not contain a resource manager.
+
+0x00001A95
+
+ERROR_TRANSACTIONS_UNSUPPORTED_REMOTE
+
+
+The remote server or share does not support transacted file operations.
+
+0x00001A96
+
+ERROR_LOG_RESIZE_INVALID_SIZE
+
+
+The requested log size is invalid.
+
+0x00001A97
+
+ERROR_OBJECT_NO_LONGER_EXISTS
+
+
+The object (file, stream, link) corresponding to the handle has been deleted by a transaction savepoint rollback.
+
+0x00001A98
+
+ERROR_STREAM_MINIVERSION_NOT_FOUND
+
+
+The specified file miniversion was not found for this transacted file open.
+
+0x00001A99
+
+ERROR_STREAM_MINIVERSION_NOT_VALID
+
+
+The specified file miniversion was found but has been invalidated. The most likely cause is a transaction savepoint rollback.
+
+0x00001A9A
+
+ERROR_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION
+
+
+A miniversion can only be opened in the context of the transaction that created it.
+
+0x00001A9B
+
+ERROR_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT
+
+
+It is not possible to open a miniversion with modify access.
+
+0x00001A9C
+
+ERROR_CANT_CREATE_MORE_STREAM_MINIVERSIONS
+
+
+It is not possible to create any more miniversions for this stream.
+
+0x00001A9E
+
+ERROR_REMOTE_FILE_VERSION_MISMATCH
+
+
+The remote server sent mismatching version numbers or FID for a file opened with transactions.
+
+0x00001A9F
+
+ERROR_HANDLE_NO_LONGER_VALID
+
+
+The handle has been invalidated by a transaction. The most likely cause is the presence of memory mapping on a file, or an open handle when the transaction ended or rolled back to savepoint.
+
+0x00001AA0
+
+ERROR_NO_TXF_METADATA
+
+
+There is no transaction metadata on the file.
+
+0x00001AA1
+
+ERROR_LOG_CORRUPTION_DETECTED
+
+
+The log data is corrupt.
+
+0x00001AA2
+
+ERROR_CANT_RECOVER_WITH_HANDLE_OPEN
+
+
+The file cannot be recovered because a handle is still open on it.
+
+0x00001AA3
+
+ERROR_RM_DISCONNECTED
+
+
+The transaction outcome is unavailable because the resource manager responsible for it is disconnected.
+
+0x00001AA4
+
+ERROR_ENLISTMENT_NOT_SUPERIOR
+
+
+The request was rejected because the enlistment in question is not a superior enlistment.
+
+0x00001AA5
+
+ERROR_RECOVERY_NOT_NEEDED
+
+
+The transactional resource manager is already consistent. Recovery is not needed.
+
+0x00001AA6
+
+ERROR_RM_ALREADY_STARTED
+
+
+The transactional resource manager has already been started.
+
+0x00001AA7
+
+ERROR_FILE_IDENTITY_NOT_PERSISTENT
+
+
+The file cannot be opened in a transaction because its identity depends on the outcome of an unresolved transaction.
+
+0x00001AA8
+
+ERROR_CANT_BREAK_TRANSACTIONAL_DEPENDENCY
+
+
+The operation cannot be performed because another transaction is depending on the fact that this property will not change.
+
+0x00001AA9
+
+ERROR_CANT_CROSS_RM_BOUNDARY
+
+
+The operation would involve a single file with two transactional resource managers and is therefore not allowed.
+
+0x00001AAA
+
+ERROR_TXF_DIR_NOT_EMPTY
+
+
+The $Txf directory must be empty for this operation to succeed.
+
+0x00001AAB
+
+ERROR_INDOUBT_TRANSACTIONS_EXIST
+
+
+The operation would leave a transactional resource manager in an inconsistent state and is, therefore, not allowed.
+
+0x00001AAC
+
+ERROR_TM_VOLATILE
+
+
+The operation could not be completed because the transaction manager does not have a log.
+
+0x00001AAD
+
+ERROR_ROLLBACK_TIMER_EXPIRED
+
+
+A rollback could not be scheduled because a previously scheduled rollback has already been executed or is queued for execution.
+
+0x00001AAE
+
+ERROR_TXF_ATTRIBUTE_CORRUPT
+
+
+The transactional metadata attribute on the file or directory is corrupt and unreadable.
+
+0x00001AAF
+
+ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION
+
+
+The encryption operation could not be completed because a transaction is active.
+
+0x00001AB0
+
+ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED
+
+
+This object is not allowed to be opened in a transaction.
+
+0x00001AB1
+
+ERROR_LOG_GROWTH_FAILED
+
+
+An attempt to create space in the transactional resource manager's log failed. The failure status has been recorded in the event log.
+
+0x00001AB2
+
+ERROR_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE
+
+
+Memory mapping (creating a mapped section) to a remote file under a transaction is not supported.
+
+0x00001AB3
+
+ERROR_TXF_METADATA_ALREADY_PRESENT
+
+
+Transaction metadata is already present on this file and cannot be superseded.
+
+0x00001AB4
+
+ERROR_TRANSACTION_SCOPE_CALLBACKS_NOT_SET
+
+
+A transaction scope could not be entered because the scope handler has not been initialized.
+
+0x00001AB5
+
+ERROR_TRANSACTION_REQUIRED_PROMOTION
+
+
+Promotion was required to allow the resource manager to enlist, but the transaction was set to disallow it.
+
+0x00001AB6
+
+ERROR_CANNOT_EXECUTE_FILE_IN_TRANSACTION
+
+
+This file is open for modification in an unresolved transaction and can be opened for execution only by a transacted reader.
+
+0x00001AB7
+
+ERROR_TRANSACTIONS_NOT_FROZEN
+
+
+The request to thaw frozen transactions was ignored because transactions were not previously frozen.
+
+0x00001AB8
+
+ERROR_TRANSACTION_FREEZE_IN_PROGRESS
+
+
+Transactions cannot be frozen because a freeze is already in progress.
+
+0x00001AB9
+
+ERROR_NOT_SNAPSHOT_VOLUME
+
+
+The target volume is not a snapshot volume. This operation is only valid on a volume mounted as a snapshot.
+
+0x00001ABA
+
+ERROR_NO_SAVEPOINT_WITH_OPEN_FILES
+
+
+The savepoint operation failed because files are open on the transaction. This is not permitted.
+
+0x00001ABB
+
+ERROR_DATA_LOST_REPAIR
+
+
+Windows has discovered corruption in a file, and that file has since been repaired. Data loss might have occurred.
+
+0x00001ABC
+
+ERROR_SPARSE_NOT_ALLOWED_IN_TRANSACTION
+
+
+The sparse operation could not be completed because a transaction is active on the file.
+
+0x00001ABD
+
+ERROR_TM_IDENTITY_MISMATCH
+
+
+The call to create a transaction manager object failed because the Tm Identity stored in the logfile does not match the Tm Identity that was passed in as an argument.
+
+0x00001ABE
+
+ERROR_FLOATED_SECTION
+
+
+I/O was attempted on a section object that has been floated as a result of a transaction ending. There is no valid data.
+
+0x00001ABF
+
+ERROR_CANNOT_ACCEPT_TRANSACTED_WORK
+
+
+The transactional resource manager cannot currently accept transacted work due to a transient condition, such as low resources.
+
+0x00001AC0
+
+ERROR_CANNOT_ABORT_TRANSACTIONS
+
+
+The transactional resource manager had too many transactions outstanding that could not be aborted. The transactional resource manager has been shut down.
+
+0x00001B59
+
+ERROR_CTX_WINSTATION_NAME_INVALID
+
+
+The specified session name is invalid.
+
+0x00001B5A
+
+ERROR_CTX_INVALID_PD
+
+
+The specified protocol driver is invalid.
+
+0x00001B5B
+
+ERROR_CTX_PD_NOT_FOUND
+
+
+The specified protocol driver was not found in the system path.
+
+0x00001B5C
+
+ERROR_CTX_WD_NOT_FOUND
+
+
+The specified terminal connection driver was not found in the system path.
+
+0x00001B5D
+
+ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY
+
+
+A registry key for event logging could not be created for this session.
+
+0x00001B5E
+
+ERROR_CTX_SERVICE_NAME_COLLISION
+
+
+A service with the same name already exists on the system.
+
+0x00001B5F
+
+ERROR_CTX_CLOSE_PENDING
+
+
+A close operation is pending on the session.
+
+0x00001B60
+
+ERROR_CTX_NO_OUTBUF
+
+
+There are no free output buffers available.
+
+0x00001B61
+
+ERROR_CTX_MODEM_INF_NOT_FOUND
+
+
+The MODEM.INF file was not found.
+
+0x00001B62
+
+ERROR_CTX_INVALID_MODEMNAME
+
+
+The modem name was not found in the MODEM.INF file.
+
+0x00001B63
+
+ERROR_CTX_MODEM_RESPONSE_ERROR
+
+
+The modem did not accept the command sent to it. Verify that the configured modem name matches the attached modem.
+
+0x00001B64
+
+ERROR_CTX_MODEM_RESPONSE_TIMEOUT
+
+
+The modem did not respond to the command sent to it. Verify that the modem is properly cabled and turned on.
+
+0x00001B65
+
+ERROR_CTX_MODEM_RESPONSE_NO_CARRIER
+
+
+Carrier detect has failed or carrier has been dropped due to disconnect.
+
+0x00001B66
+
+ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE
+
+
+Dial tone not detected within the required time. Verify that the phone cable is properly attached and functional.
+
+0x00001B67
+
+ERROR_CTX_MODEM_RESPONSE_BUSY
+
+
+Busy signal detected at remote site on callback.
+
+0x00001B68
+
+ERROR_CTX_MODEM_RESPONSE_VOICE
+
+
+Voice detected at remote site on callback.
+
+0x00001B69
+
+ERROR_CTX_TD_ERROR
+
+
+Transport driver error.
+
+0x00001B6E
+
+ERROR_CTX_WINSTATION_NOT_FOUND
+
+
+The specified session cannot be found.
+
+0x00001B6F
+
+ERROR_CTX_WINSTATION_ALREADY_EXISTS
+
+
+The specified session name is already in use.
+
+0x00001B70
+
+ERROR_CTX_WINSTATION_BUSY
+
+
+The requested operation cannot be completed because the terminal connection is currently busy processing a connect, disconnect, reset, or delete operation.
+
+0x00001B71
+
+ERROR_CTX_BAD_VIDEO_MODE
+
+
+An attempt has been made to connect to a session whose video mode is not supported by the current client.
+
+0x00001B7B
+
+ERROR_CTX_GRAPHICS_INVALID
+
+
+The application attempted to enable DOS graphics mode. DOS graphics mode is not supported.
+
+0x00001B7D
+
+ERROR_CTX_LOGON_DISABLED
+
+
+Your interactive logon privilege has been disabled. Contact your administrator.
+
+0x00001B7E
+
+ERROR_CTX_NOT_CONSOLE
+
+
+The requested operation can be performed only on the system console. This is most often the result of a driver or system DLL requiring direct console access.
+
+0x00001B80
+
+ERROR_CTX_CLIENT_QUERY_TIMEOUT
+
+
+The client failed to respond to the server connect message.
+
+0x00001B81
+
+ERROR_CTX_CONSOLE_DISCONNECT
+
+
+Disconnecting the console session is not supported.
+
+0x00001B82
+
+ERROR_CTX_CONSOLE_CONNECT
+
+
+Reconnecting a disconnected session to the console is not supported.
+
+0x00001B84
+
+ERROR_CTX_SHADOW_DENIED
+
+
+The request to control another session remotely was denied.
+
+0x00001B85
+
+ERROR_CTX_WINSTATION_ACCESS_DENIED
+
+
+The requested session access is denied.
+
+0x00001B89
+
+ERROR_CTX_INVALID_WD
+
+
+The specified terminal connection driver is invalid.
+
+0x00001B8A
+
+ERROR_CTX_SHADOW_INVALID
+
+
+The requested session cannot be controlled remotely. This might be because the session is disconnected or does not currently have a user logged on.
+
+0x00001B8B
+
+ERROR_CTX_SHADOW_DISABLED
+
+
+The requested session is not configured to allow remote control.
+
+0x00001B8C
+
+ERROR_CTX_CLIENT_LICENSE_IN_USE
+
+
+Your request to connect to this terminal server has been rejected. Your terminal server client license number is currently being used by another user. Call your system administrator to obtain a unique license number.
+
+0x00001B8D
+
+ERROR_CTX_CLIENT_LICENSE_NOT_SET
+
+
+Your request to connect to this terminal server has been rejected. Your terminal server client license number has not been entered for this copy of the terminal server client. Contact your system administrator.
+
+0x00001B8E
+
+ERROR_CTX_LICENSE_NOT_AVAILABLE
+
+
+The number of connections to this computer is limited and all connections are in use right now. Try connecting later or contact your system administrator.
+
+0x00001B8F
+
+ERROR_CTX_LICENSE_CLIENT_INVALID
+
+
+The client you are using is not licensed to use this system. Your logon request is denied.
+
+0x00001B90
+
+ERROR_CTX_LICENSE_EXPIRED
+
+
+The system license has expired. Your logon request is denied.
+
+0x00001B91
+
+ERROR_CTX_SHADOW_NOT_RUNNING
+
+
+Remote control could not be terminated because the specified session is not currently being remotely controlled.
+
+0x00001B92
+
+ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE
+
+
+The remote control of the console was terminated because the display mode was changed. Changing the display mode in a remote control session is not supported.
+
+0x00001B93
+
+ERROR_ACTIVATION_COUNT_EXCEEDED
+
+
+Activation has already been reset the maximum number of times for this installation. Your activation timer will not be cleared.
+
+0x00001B94
+
+ERROR_CTX_WINSTATIONS_DISABLED
+
+
+Remote logons are currently disabled.
+
+0x00001B95
+
+ERROR_CTX_ENCRYPTION_LEVEL_REQUIRED
+
+
+You do not have the proper encryption level to access this session.
+
+0x00001B96
+
+ERROR_CTX_SESSION_IN_USE
+
+
+The user %s\\%s is currently logged on to this computer. Only the current user or an administrator can log on to this computer.
+
+0x00001B97
+
+ERROR_CTX_NO_FORCE_LOGOFF
+
+
+The user %s\\%s is already logged on to the console of this computer. You do not have permission to log in at this time. To resolve this issue, contact %s\\%s and have them log off.
+
+0x00001B98
+
+ERROR_CTX_ACCOUNT_RESTRICTION
+
+
+Unable to log you on because of an account restriction.
+
+0x00001B99
+
+ERROR_RDP_PROTOCOL_ERROR
+
+
+The RDP component %2 detected an error in the protocol stream and has disconnected the client.
+
+0x00001B9A
+
+ERROR_CTX_CDM_CONNECT
+
+
+The Client Drive Mapping Service has connected on terminal connection.
+
+0x00001B9B
+
+ERROR_CTX_CDM_DISCONNECT
+
+
+The Client Drive Mapping Service has disconnected on terminal connection.
+
+0x00001B9C
+
+ERROR_CTX_SECURITY_LAYER_ERROR
+
+
+The terminal server security layer detected an error in the protocol stream and has disconnected the client.
+
+0x00001B9D
+
+ERROR_TS_INCOMPATIBLE_SESSIONS
+
+
+The target session is incompatible with the current session.
+
+0x00001F41
+
+FRS_ERR_INVALID_API_SEQUENCE
+
+
+The file replication service API was called incorrectly.
+
+0x00001F42
+
+FRS_ERR_STARTING_SERVICE
+
+
+The file replication service cannot be started.
+
+0x00001F43
+
+FRS_ERR_STOPPING_SERVICE
+
+
+The file replication service cannot be stopped.
+
+0x00001F44
+
+FRS_ERR_INTERNAL_API
+
+
+The file replication service API terminated the request. The event log might contain more information.
+
+0x00001F45
+
+FRS_ERR_INTERNAL
+
+
+The file replication service terminated the request. The event log might contain more information.
+
+0x00001F46
+
+FRS_ERR_SERVICE_COMM
+
+
+The file replication service cannot be contacted. The event log might contain more information.
+
+0x00001F47
+
+FRS_ERR_INSUFFICIENT_PRIV
+
+
+The file replication service cannot satisfy the request because the user has insufficient privileges. The event log might contain more information.
+
+0x00001F48
+
+FRS_ERR_AUTHENTICATION
+
+
+The file replication service cannot satisfy the request because authenticated RPC is not available. The event log might contain more information.
+
+0x00001F49
+
+FRS_ERR_PARENT_INSUFFICIENT_PRIV
+
+
+The file replication service cannot satisfy the request because the user has insufficient privileges on the domain controller. The event log might contain more information.
+
+0x00001F4A
+
+FRS_ERR_PARENT_AUTHENTICATION
+
+
+The file replication service cannot satisfy the request because authenticated RPC is not available on the domain controller. The event log might contain more information.
+
+0x00001F4B
+
+FRS_ERR_CHILD_TO_PARENT_COMM
+
+
+The file replication service cannot communicate with the file replication service on the domain controller. The event log might contain more information.
+
+0x00001F4C
+
+FRS_ERR_PARENT_TO_CHILD_COMM
+
+
+The file replication service on the domain controller cannot communicate with the file replication service on this computer. The event log might contain more information.
+
+0x00001F4D
+
+FRS_ERR_SYSVOL_POPULATE
+
+
+The file replication service cannot populate the system volume because of an internal error. The event log might contain more information.
+
+0x00001F4E
+
+FRS_ERR_SYSVOL_POPULATE_TIMEOUT
+
+
+The file replication service cannot populate the system volume because of an internal time-out. The event log might contain more information.
+
+0x00001F4F
+
+FRS_ERR_SYSVOL_IS_BUSY
+
+
+The file replication service cannot process the request. The system volume is busy with a previous request.
+
+0x00001F50
+
+FRS_ERR_SYSVOL_DEMOTE
+
+
+The file replication service cannot stop replicating the system volume because of an internal error. The event log might contain more information.
+
+0x00001F51
+
+FRS_ERR_INVALID_SERVICE_PARAMETER
+
+
+The file replication service detected an invalid parameter.
+
+0x00002008
+
+ERROR_DS_NOT_INSTALLED
+
+
+An error occurred while installing the directory service. For more information, see the event log.
+
+0x00002009
+
+ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY
+
+
+The directory service evaluated group memberships locally.
+
+0x0000200A
+
+ERROR_DS_NO_ATTRIBUTE_OR_VALUE
+
+
+The specified directory service attribute or value does not exist.
+
+0x0000200B
+
+ERROR_DS_INVALID_ATTRIBUTE_SYNTAX
+
+
+The attribute syntax specified to the directory service is invalid.
+
+0x0000200C
+
+ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED
+
+
+The attribute type specified to the directory service is not defined.
+
+0x0000200D
+
+ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS
+
+
+The specified directory service attribute or value already exists.
+
+0x0000200E
+
+ERROR_DS_BUSY
+
+
+The directory service is busy.
+
+0x0000200F
+
+ERROR_DS_UNAVAILABLE
+
+
+The directory service is unavailable.
+
+0x00002010
+
+ERROR_DS_NO_RIDS_ALLOCATED
+
+
+The directory service was unable to allocate a relative identifier.
+
+0x00002011
+
+ERROR_DS_NO_MORE_RIDS
+
+
+The directory service has exhausted the pool of relative identifiers.
+
+0x00002012
+
+ERROR_DS_INCORRECT_ROLE_OWNER
+
+
+The requested operation could not be performed because the directory service is not the master for that type of operation.
+
+0x00002013
+
+ERROR_DS_RIDMGR_INIT_ERROR
+
+
+The directory service was unable to initialize the subsystem that allocates relative identifiers.
+
+0x00002014
+
+ERROR_DS_OBJ_CLASS_VIOLATION
+
+
+The requested operation did not satisfy one or more constraints associated with the class of the object.
+
+0x00002015
+
+ERROR_DS_CANT_ON_NON_LEAF
+
+
+The directory service can perform the requested operation only on a leaf object.
+
+0x00002016
+
+ERROR_DS_CANT_ON_RDN
+
+
+The directory service cannot perform the requested operation on the relative distinguished name (RDN) attribute of an object.
+
+0x00002017
+
+ERROR_DS_CANT_MOD_OBJ_CLASS
+
+
+The directory service detected an attempt to modify the object class of an object.
+
+0x00002018
+
+ERROR_DS_CROSS_DOM_MOVE_ERROR
+
+
+The requested cross-domain move operation could not be performed.
+
+0x00002019
+
+ERROR_DS_GC_NOT_AVAILABLE
+
+
+Unable to contact the global catalog (GC) server.
+
+0x0000201A
+
+ERROR_SHARED_POLICY
+
+
+The policy object is shared and can only be modified at the root.
+
+0x0000201B
+
+ERROR_POLICY_OBJECT_NOT_FOUND
+
+
+The policy object does not exist.
+
+0x0000201C
+
+ERROR_POLICY_ONLY_IN_DS
+
+
+The requested policy information is only in the directory service.
+
+0x0000201D
+
+ERROR_PROMOTION_ACTIVE
+
+
+A domain controller promotion is currently active.
+
+0x0000201E
+
+ERROR_NO_PROMOTION_ACTIVE
+
+
+A domain controller promotion is not currently active.
+
+0x00002020
+
+ERROR_DS_OPERATIONS_ERROR
+
+
+An operations error occurred.
+
+0x00002021
+
+ERROR_DS_PROTOCOL_ERROR
+
+
+A protocol error occurred.
+
+0x00002022
+
+ERROR_DS_TIMELIMIT_EXCEEDED
+
+
+The time limit for this request was exceeded.
+
+0x00002023
+
+ERROR_DS_SIZELIMIT_EXCEEDED
+
+
+The size limit for this request was exceeded.
+
+0x00002024
+
+ERROR_DS_ADMIN_LIMIT_EXCEEDED
+
+
+The administrative limit for this request was exceeded.
+
+0x00002025
+
+ERROR_DS_COMPARE_FALSE
+
+
+The compare response was false.
+
+0x00002026
+
+ERROR_DS_COMPARE_TRUE
+
+
+The compare response was true.
+
+0x00002027
+
+ERROR_DS_AUTH_METHOD_NOT_SUPPORTED
+
+
+The requested authentication method is not supported by the server.
+
+0x00002028
+
+ERROR_DS_STRONG_AUTH_REQUIRED
+
+
+A more secure authentication method is required for this server.
+
+0x00002029
+
+ERROR_DS_INAPPROPRIATE_AUTH
+
+
+Inappropriate authentication.
+
+0x0000202A
+
+ERROR_DS_AUTH_UNKNOWN
+
+
+The authentication mechanism is unknown.
+
+0x0000202B
+
+ERROR_DS_REFERRAL
+
+
+A referral was returned from the server.
+
+0x0000202C
+
+ERROR_DS_UNAVAILABLE_CRIT_EXTENSION
+
+
+The server does not support the requested critical extension.
+
+0x0000202D
+
+ERROR_DS_CONFIDENTIALITY_REQUIRED
+
+
+This request requires a secure connection.
+
+0x0000202E
+
+ERROR_DS_INAPPROPRIATE_MATCHING
+
+
+Inappropriate matching.
+
+0x0000202F
+
+ERROR_DS_CONSTRAINT_VIOLATION
+
+
+A constraint violation occurred.
+
+0x00002030
+
+ERROR_DS_NO_SUCH_OBJECT
+
+
+There is no such object on the server.
+
+0x00002031
+
+ERROR_DS_ALIAS_PROBLEM
+
+
+There is an alias problem.
+
+0x00002032
+
+ERROR_DS_INVALID_DN_SYNTAX
+
+
+An invalid dn syntax has been specified.
+
+0x00002033
+
+ERROR_DS_IS_LEAF
+
+
+The object is a leaf object.
+
+0x00002034
+
+ERROR_DS_ALIAS_DEREF_PROBLEM
+
+
+There is an alias dereferencing problem.
+
+0x00002035
+
+ERROR_DS_UNWILLING_TO_PERFORM
+
+
+The server is unwilling to process the request.
+
+0x00002036
+
+ERROR_DS_LOOP_DETECT
+
+
+A loop has been detected.
+
+0x00002037
+
+ERROR_DS_NAMING_VIOLATION
+
+
+There is a naming violation.
+
+0x00002038
+
+ERROR_DS_OBJECT_RESULTS_TOO_LARGE
+
+
+The result set is too large.
+
+0x00002039
+
+ERROR_DS_AFFECTS_MULTIPLE_DSAS
+
+
+The operation affects multiple DSAs.
+
+0x0000203A
+
+ERROR_DS_SERVER_DOWN
+
+
+The server is not operational.
+
+0x0000203B
+
+ERROR_DS_LOCAL_ERROR
+
+
+A local error has occurred.
+
+0x0000203C
+
+ERROR_DS_ENCODING_ERROR
+
+
+An encoding error has occurred.
+
+0x0000203D
+
+ERROR_DS_DECODING_ERROR
+
+
+A decoding error has occurred.
+
+0x0000203E
+
+ERROR_DS_FILTER_UNKNOWN
+
+
+The search filter cannot be recognized.
+
+0x0000203F
+
+ERROR_DS_PARAM_ERROR
+
+
+One or more parameters are illegal.
+
+0x00002040
+
+ERROR_DS_NOT_SUPPORTED
+
+
+The specified method is not supported.
+
+0x00002041
+
+ERROR_DS_NO_RESULTS_RETURNED
+
+
+No results were returned.
+
+0x00002042
+
+ERROR_DS_CONTROL_NOT_FOUND
+
+
+The specified control is not supported by the server.
+
+0x00002043
+
+ERROR_DS_CLIENT_LOOP
+
+
+A referral loop was detected by the client.
+
+0x00002044
+
+ERROR_DS_REFERRAL_LIMIT_EXCEEDED
+
+
+The preset referral limit was exceeded.
+
+0x00002045
+
+ERROR_DS_SORT_CONTROL_MISSING
+
+
+The search requires a SORT control.
+
+0x00002046
+
+ERROR_DS_OFFSET_RANGE_ERROR
+
+
+The search results exceed the offset range specified.
+
+0x0000206D
+
+ERROR_DS_ROOT_MUST_BE_NC
+
+
+The root object must be the head of a naming context. The root object cannot have an instantiated parent.
+
+0x0000206E
+
+ERROR_DS_ADD_REPLICA_INHIBITED
+
+
+The add replica operation cannot be performed. The naming context must be writable to create the replica.
+
+0x0000206F
+
+ERROR_DS_ATT_NOT_DEF_IN_SCHEMA
+
+
+A reference to an attribute that is not defined in the schema occurred.
+
+0x00002070
+
+ERROR_DS_MAX_OBJ_SIZE_EXCEEDED
+
+
+The maximum size of an object has been exceeded.
+
+0x00002071
+
+ERROR_DS_OBJ_STRING_NAME_EXISTS
+
+
+An attempt was made to add an object to the directory with a name that is already in use.
+
+0x00002072
+
+ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA
+
+
+An attempt was made to add an object of a class that does not have an RDN defined in the schema.
+
+0x00002073
+
+ERROR_DS_RDN_DOESNT_MATCH_SCHEMA
+
+
+An attempt was made to add an object using an RDN that is not the RDN defined in the schema.
+
+0x00002074
+
+ERROR_DS_NO_REQUESTED_ATTS_FOUND
+
+
+None of the requested attributes were found on the objects.
+
+0x00002075
+
+ERROR_DS_USER_BUFFER_TO_SMALL
+
+
+The user buffer is too small.
+
+0x00002076
+
+ERROR_DS_ATT_IS_NOT_ON_OBJ
+
+
+The attribute specified in the operation is not present on the object.
+
+0x00002077
+
+ERROR_DS_ILLEGAL_MOD_OPERATION
+
+
+Illegal modify operation. Some aspect of the modification is not permitted.
+
+0x00002078
+
+ERROR_DS_OBJ_TOO_LARGE
+
+
+The specified object is too large.
+
+0x00002079
+
+ERROR_DS_BAD_INSTANCE_TYPE
+
+
+The specified instance type is not valid.
+
+0x0000207A
+
+ERROR_DS_MASTERDSA_REQUIRED
+
+
+The operation must be performed at a master DSA.
+
+0x0000207B
+
+ERROR_DS_OBJECT_CLASS_REQUIRED
+
+
+The object class attribute must be specified.
+
+0x0000207C
+
+ERROR_DS_MISSING_REQUIRED_ATT
+
+
+A required attribute is missing.
+
+0x0000207D
+
+ERROR_DS_ATT_NOT_DEF_FOR_CLASS
+
+
+An attempt was made to modify an object to include an attribute that is not legal for its class.
+
+0x0000207E
+
+ERROR_DS_ATT_ALREADY_EXISTS
+
+
+The specified attribute is already present on the object.
+
+0x00002080
+
+ERROR_DS_CANT_ADD_ATT_VALUES
+
+
+The specified attribute is not present, or has no values.
+
+0x00002081
+
+ERROR_DS_SINGLE_VALUE_CONSTRAINT
+
+
+Multiple values were specified for an attribute that can have only one value.
+
+0x00002082
+
+ERROR_DS_RANGE_CONSTRAINT
+
+
+A value for the attribute was not in the acceptable range of values.
+
+0x00002083
+
+ERROR_DS_ATT_VAL_ALREADY_EXISTS
+
+
+The specified value already exists.
+
+0x00002084
+
+ERROR_DS_CANT_REM_MISSING_ATT
+
+
+The attribute cannot be removed because it is not present on the object.
+
+0x00002085
+
+ERROR_DS_CANT_REM_MISSING_ATT_VAL
+
+
+The attribute value cannot be removed because it is not present on the object.
+
+0x00002086
+
+ERROR_DS_ROOT_CANT_BE_SUBREF
+
+
+The specified root object cannot be a subreference.
+
+0x00002087
+
+ERROR_DS_NO_CHAINING
+
+
+Chaining is not permitted.
+
+0x00002088
+
+ERROR_DS_NO_CHAINED_EVAL
+
+
+Chained evaluation is not permitted.
+
+0x00002089
+
+ERROR_DS_NO_PARENT_OBJECT
+
+
+The operation could not be performed because the object's parent is either uninstantiated or deleted.
+
+0x0000208A
+
+ERROR_DS_PARENT_IS_AN_ALIAS
+
+
+Having a parent that is an alias is not permitted. Aliases are leaf objects.
+
+0x0000208B
+
+ERROR_DS_CANT_MIX_MASTER_AND_REPS
+
+
+The object and parent must be of the same type, either both masters or both replicas.
+
+0x0000208C
+
+ERROR_DS_CHILDREN_EXIST
+
+
+The operation cannot be performed because child objects exist. This operation can only be performed on a leaf object.
+
+0x0000208D
+
+ERROR_DS_OBJ_NOT_FOUND
+
+
+Directory object not found.
+
+0x0000208E
+
+ERROR_DS_ALIASED_OBJ_MISSING
+
+
+The aliased object is missing.
+
+0x0000208F
+
+ERROR_DS_BAD_NAME_SYNTAX
+
+
+The object name has bad syntax.
+
+0x00002090
+
+ERROR_DS_ALIAS_POINTS_TO_ALIAS
+
+
+An alias is not permitted to refer to another alias.
+
+0x00002091
+
+ERROR_DS_CANT_DEREF_ALIAS
+
+
+The alias cannot be dereferenced.
+
+0x00002092
+
+ERROR_DS_OUT_OF_SCOPE
+
+
+The operation is out of scope.
+
+0x00002093
+
+ERROR_DS_OBJECT_BEING_REMOVED
+
+
+The operation cannot continue because the object is in the process of being removed.
+
+0x00002094
+
+ERROR_DS_CANT_DELETE_DSA_OBJ
+
+
+The DSA object cannot be deleted.
+
+0x00002095
+
+ERROR_DS_GENERIC_ERROR
+
+
+A directory service error has occurred.
+
+0x00002096
+
+ERROR_DS_DSA_MUST_BE_INT_MASTER
+
+
+The operation can only be performed on an internal master DSA object.
+
+0x00002097
+
+ERROR_DS_CLASS_NOT_DSA
+
+
+The object must be of class DSA.
+
+0x00002098
+
+ERROR_DS_INSUFF_ACCESS_RIGHTS
+
+
+Insufficient access rights to perform the operation.
+
+0x00002099
+
+ERROR_DS_ILLEGAL_SUPERIOR
+
+
+The object cannot be added because the parent is not on the list of possible superiors.
+
+0x0000209A
+
+ERROR_DS_ATTRIBUTE_OWNED_BY_SAM
+
+
+Access to the attribute is not permitted because the attribute is owned by the SAM.
+
+0x0000209B
+
+ERROR_DS_NAME_TOO_MANY_PARTS
+
+
+The name has too many parts.
+
+0x0000209C
+
+ERROR_DS_NAME_TOO_LONG
+
+
+The name is too long.
+
+0x0000209D
+
+ERROR_DS_NAME_VALUE_TOO_LONG
+
+
+The name value is too long.
+
+0x0000209E
+
+ERROR_DS_NAME_UNPARSEABLE
+
+
+The directory service encountered an error parsing a name.
+
+0x0000209F
+
+ERROR_DS_NAME_TYPE_UNKNOWN
+
+
+The directory service cannot get the attribute type for a name.
+
+0x000020A0
+
+ERROR_DS_NOT_AN_OBJECT
+
+
+The name does not identify an object; the name identifies a phantom.
+
+0x000020A1
+
+ERROR_DS_SEC_DESC_TOO_SHORT
+
+
+The security descriptor is too short.
+
+0x000020A2
+
+ERROR_DS_SEC_DESC_INVALID
+
+
+The security descriptor is invalid.
+
+0x000020A3
+
+ERROR_DS_NO_DELETED_NAME
+
+
+Failed to create name for deleted object.
+
+0x000020A4
+
+ERROR_DS_SUBREF_MUST_HAVE_PARENT
+
+
+The parent of a new subreference must exist.
+
+0x000020A5
+
+ERROR_DS_NCNAME_MUST_BE_NC
+
+
+The object must be a naming context.
+
+0x000020A6
+
+ERROR_DS_CANT_ADD_SYSTEM_ONLY
+
+
+It is not permitted to add an attribute that is owned by the system.
+
+0x000020A7
+
+ERROR_DS_CLASS_MUST_BE_CONCRETE
+
+
+The class of the object must be structural; you cannot instantiate an abstract class.
+
+0x000020A8
+
+ERROR_DS_INVALID_DMD
+
+
+The schema object could not be found.
+
+0x000020A9
+
+ERROR_DS_OBJ_GUID_EXISTS
+
+
+A local object with this GUID (dead or alive) already exists.
+
+0x000020AA
+
+ERROR_DS_NOT_ON_BACKLINK
+
+
+The operation cannot be performed on a back link.
+
+0x000020AB
+
+ERROR_DS_NO_CROSSREF_FOR_NC
+
+
+The cross-reference for the specified naming context could not be found.
+
+0x000020AC
+
+ERROR_DS_SHUTTING_DOWN
+
+
+The operation could not be performed because the directory service is shutting down.
+
+0x000020AD
+
+ERROR_DS_UNKNOWN_OPERATION
+
+
+The directory service request is invalid.
+
+0x000020AE
+
+ERROR_DS_INVALID_ROLE_OWNER
+
+
+The role owner attribute could not be read.
+
+0x000020AF
+
+ERROR_DS_COULDNT_CONTACT_FSMO
+
+
+The requested Flexible Single Master Operations (FSMO) operation failed. The current FSMO holder could not be contacted.
+
+0x000020B0
+
+ERROR_DS_CROSS_NC_DN_RENAME
+
+
+Modification of a distinguished name across a naming context is not permitted.
+
+0x000020B1
+
+ERROR_DS_CANT_MOD_SYSTEM_ONLY
+
+
+The attribute cannot be modified because it is owned by the system.
+
+0x000020B2
+
+ERROR_DS_REPLICATOR_ONLY
+
+
+Only the replicator can perform this function.
+
+0x000020B3
+
+ERROR_DS_OBJ_CLASS_NOT_DEFINED
+
+
+The specified class is not defined.
+
+0x000020B4
+
+ERROR_DS_OBJ_CLASS_NOT_SUBCLASS
+
+
+The specified class is not a subclass.
+
+0x000020B5
+
+ERROR_DS_NAME_REFERENCE_INVALID
+
+
+The name reference is invalid.
+
+0x000020B6
+
+ERROR_DS_CROSS_REF_EXISTS
+
+
+A cross-reference already exists.
+
+0x000020B7
+
+ERROR_DS_CANT_DEL_MASTER_CROSSREF
+
+
+It is not permitted to delete a master cross-reference.
+
+0x000020B8
+
+ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD
+
+
+Subtree notifications are only supported on naming context (NC) heads.
+
+0x000020B9
+
+ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX
+
+
+Notification filter is too complex.
+
+0x000020BA
+
+ERROR_DS_DUP_RDN
+
+
+Schema update failed: Duplicate RDN.
+
+0x000020BB
+
+ERROR_DS_DUP_OID
+
+
+Schema update failed: Duplicate OID.
+
+0x000020BC
+
+ERROR_DS_DUP_MAPI_ID
+
+
+Schema update failed: Duplicate Message Application Programming Interface (MAPI) identifier.
+
+0x000020BD
+
+ERROR_DS_DUP_SCHEMA_ID_GUID
+
+
+Schema update failed: Duplicate schema ID GUID.
+
+0x000020BE
+
+ERROR_DS_DUP_LDAP_DISPLAY_NAME
+
+
+Schema update failed: Duplicate LDAP display name.
+
+0x000020BF
+
+ERROR_DS_SEMANTIC_ATT_TEST
+
+
+Schema update failed: Range-Lower less than Range-Upper.
+
+0x000020C0
+
+ERROR_DS_SYNTAX_MISMATCH
+
+
+Schema update failed: Syntax mismatch.
+
+0x000020C1
+
+ERROR_DS_EXISTS_IN_MUST_HAVE
+
+
+Schema deletion failed: Attribute is used in the Must-Contain list.
+
+0x000020C2
+
+ERROR_DS_EXISTS_IN_MAY_HAVE
+
+
+Schema deletion failed: Attribute is used in the May-Contain list.
+
+0x000020C3
+
+ERROR_DS_NONEXISTENT_MAY_HAVE
+
+
+Schema update failed: Attribute in May-Contain list does not exist.
+
+0x000020C4
+
+ERROR_DS_NONEXISTENT_MUST_HAVE
+
+
+Schema update failed: Attribute in the Must-Contain list does not exist.
+
+0x000020C5
+
+ERROR_DS_AUX_CLS_TEST_FAIL
+
+
+Schema update failed: Class in the Aux Class list does not exist or is not an auxiliary class.
+
+0x000020C6
+
+ERROR_DS_NONEXISTENT_POSS_SUP
+
+
+Schema update failed: Class in the Poss-Superiors list does not exist.
+
+0x000020C7
+
+ERROR_DS_SUB_CLS_TEST_FAIL
+
+
+Schema update failed: Class in the subclass of the list does not exist or does not satisfy hierarchy rules.
+
+0x000020C8
+
+ERROR_DS_BAD_RDN_ATT_ID_SYNTAX
+
+
+Schema update failed: Rdn-Att-Id has wrong syntax.
+
+0x000020C9
+
+ERROR_DS_EXISTS_IN_AUX_CLS
+
+
+Schema deletion failed: Class is used as an auxiliary class.
+
+0x000020CA
+
+ERROR_DS_EXISTS_IN_SUB_CLS
+
+
+Schema deletion failed: Class is used as a subclass.
+
+0x000020CB
+
+ERROR_DS_EXISTS_IN_POSS_SUP
+
+
+Schema deletion failed: Class is used as a Poss-Superior.
+
+0x000020CC
+
+ERROR_DS_RECALCSCHEMA_FAILED
+
+
+Schema update failed in recalculating validation cache.
+
+0x000020CD
+
+ERROR_DS_TREE_DELETE_NOT_FINISHED
+
+
+The tree deletion is not finished. The request must be made again to continue deleting the tree.
+
+0x000020CE
+
+ERROR_DS_CANT_DELETE
+
+
+The requested delete operation could not be performed.
+
+0x000020CF
+
+ERROR_DS_ATT_SCHEMA_REQ_ID
+
+
+Cannot read the governs class identifier for the schema record.
+
+0x000020D0
+
+ERROR_DS_BAD_ATT_SCHEMA_SYNTAX
+
+
+The attribute schema has bad syntax.
+
+0x000020D1
+
+ERROR_DS_CANT_CACHE_ATT
+
+
+The attribute could not be cached.
+
+0x000020D2
+
+ERROR_DS_CANT_CACHE_CLASS
+
+
+The class could not be cached.
+
+0x000020D3
+
+ERROR_DS_CANT_REMOVE_ATT_CACHE
+
+
+The attribute could not be removed from the cache.
+
+0x000020D4
+
+ERROR_DS_CANT_REMOVE_CLASS_CACHE
+
+
+The class could not be removed from the cache.
+
+0x000020D5
+
+ERROR_DS_CANT_RETRIEVE_DN
+
+
+The distinguished name attribute could not be read.
+
+0x000020D6
+
+ERROR_DS_MISSING_SUPREF
+
+
+No superior reference has been configured for the directory service. The directory service is, therefore, unable to issue referrals to objects outside this forest.
+
+0x000020D7
+
+ERROR_DS_CANT_RETRIEVE_INSTANCE
+
+
+The instance type attribute could not be retrieved.
+
+0x000020D8
+
+ERROR_DS_CODE_INCONSISTENCY
+
+
+An internal error has occurred.
+
+0x000020D9
+
+ERROR_DS_DATABASE_ERROR
+
+
+A database error has occurred.
+
+0x000020DA
+
+ERROR_DS_GOVERNSID_MISSING
+
+
+The governsID attribute is missing.
+
+0x000020DB
+
+ERROR_DS_MISSING_EXPECTED_ATT
+
+
+An expected attribute is missing.
+
+0x000020DC
+
+ERROR_DS_NCNAME_MISSING_CR_REF
+
+
+The specified naming context is missing a cross-reference.
+
+0x000020DD
+
+ERROR_DS_SECURITY_CHECKING_ERROR
+
+
+A security checking error has occurred.
+
+0x000020DE
+
+ERROR_DS_SCHEMA_NOT_LOADED
+
+
+The schema is not loaded.
+
+0x000020DF
+
+ERROR_DS_SCHEMA_ALLOC_FAILED
+
+
+Schema allocation failed. Check if the machine is running low on memory.
+
+0x000020E0
+
+ERROR_DS_ATT_SCHEMA_REQ_SYNTAX
+
+
+Failed to obtain the required syntax for the attribute schema.
+
+0x000020E1
+
+ERROR_DS_GCVERIFY_ERROR
+
+
+The GC verification failed. The GC is not available or does not support the operation. Some part of the directory is currently not available.
+
+0x000020E2
+
+ERROR_DS_DRA_SCHEMA_MISMATCH
+
+
+The replication operation failed because of a schema mismatch between the servers involved.
+
+0x000020E3
+
+ERROR_DS_CANT_FIND_DSA_OBJ
+
+
+The DSA object could not be found.
+
+0x000020E4
+
+ERROR_DS_CANT_FIND_EXPECTED_NC
+
+
+The naming context could not be found.
+
+0x000020E5
+
+ERROR_DS_CANT_FIND_NC_IN_CACHE
+
+
+The naming context could not be found in the cache.
+
+0x000020E6
+
+ERROR_DS_CANT_RETRIEVE_CHILD
+
+
+The child object could not be retrieved.
+
+0x000020E7
+
+ERROR_DS_SECURITY_ILLEGAL_MODIFY
+
+
+The modification was not permitted for security reasons.
+
+0x000020E8
+
+ERROR_DS_CANT_REPLACE_HIDDEN_REC
+
+
+The operation cannot replace the hidden record.
+
+0x000020E9
+
+ERROR_DS_BAD_HIERARCHY_FILE
+
+
+The hierarchy file is invalid.
+
+0x000020EA
+
+ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED
+
+
+The attempt to build the hierarchy table failed.
+
+0x000020EB
+
+ERROR_DS_CONFIG_PARAM_MISSING
+
+
+The directory configuration parameter is missing from the registry.
+
+0x000020EC
+
+ERROR_DS_COUNTING_AB_INDICES_FAILED
+
+
+The attempt to count the address book indices failed.
+
+0x000020ED
+
+ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED
+
+
+The allocation of the hierarchy table failed.
+
+0x000020EE
+
+ERROR_DS_INTERNAL_FAILURE
+
+
+The directory service encountered an internal failure.
+
+0x000020EF
+
+ERROR_DS_UNKNOWN_ERROR
+
+
+The directory service encountered an unknown failure.
+
+0x000020F0
+
+ERROR_DS_ROOT_REQUIRES_CLASS_TOP
+
+
+A root object requires a class of "top".
+
+0x000020F1
+
+ERROR_DS_REFUSING_FSMO_ROLES
+
+
+This directory server is shutting down, and cannot take ownership of new floating single-master operation roles.
+
+0x000020F2
+
+ERROR_DS_MISSING_FSMO_SETTINGS
+
+
+The directory service is missing mandatory configuration information and is unable to determine the ownership of floating single-master operation roles.
+
+0x000020F3
+
+ERROR_DS_UNABLE_TO_SURRENDER_ROLES
+
+
+The directory service was unable to transfer ownership of one or more floating single-master operation roles to other servers.
+
+0x000020F4
+
+ERROR_DS_DRA_GENERIC
+
+
+The replication operation failed.
+
+0x000020F5
+
+ERROR_DS_DRA_INVALID_PARAMETER
+
+
+An invalid parameter was specified for this replication operation.
+
+0x000020F6
+
+ERROR_DS_DRA_BUSY
+
+
+The directory service is too busy to complete the replication operation at this time.
+
+0x000020F7
+
+ERROR_DS_DRA_BAD_DN
+
+
+The DN specified for this replication operation is invalid.
+
+0x000020F8
+
+ERROR_DS_DRA_BAD_NC
+
+
+The naming context specified for this replication operation is invalid.
+
+0x000020F9
+
+ERROR_DS_DRA_DN_EXISTS
+
+
+The DN specified for this replication operation already exists.
+
+0x000020FA
+
+ERROR_DS_DRA_INTERNAL_ERROR
+
+
+The replication system encountered an internal error.
+
+0x000020FB
+
+ERROR_DS_DRA_INCONSISTENT_DIT
+
+
+The replication operation encountered a database inconsistency.
+
+0x000020FC
+
+ERROR_DS_DRA_CONNECTION_FAILED
+
+
+The server specified for this replication operation could not be contacted.
+
+0x000020FD
+
+ERROR_DS_DRA_BAD_INSTANCE_TYPE
+
+
+The replication operation encountered an object with an invalid instance type.
+
+0x000020FE
+
+ERROR_DS_DRA_OUT_OF_MEM
+
+
+The replication operation failed to allocate memory.
+
+0x000020FF
+
+ERROR_DS_DRA_MAIL_PROBLEM
+
+
+The replication operation encountered an error with the mail system.
+
+0x00002100
+
+ERROR_DS_DRA_REF_ALREADY_EXISTS
+
+
+The replication reference information for the target server already exists.
+
+0x00002101
+
+ERROR_DS_DRA_REF_NOT_FOUND
+
+
+The replication reference information for the target server does not exist.
+
+0x00002102
+
+ERROR_DS_DRA_OBJ_IS_REP_SOURCE
+
+
+The naming context cannot be removed because it is replicated to another server.
+
+0x00002103
+
+ERROR_DS_DRA_DB_ERROR
+
+
+The replication operation encountered a database error.
+
+0x00002104
+
+ERROR_DS_DRA_NO_REPLICA
+
+
+The naming context is in the process of being removed or is not replicated from the specified server.
+
+0x00002105
+
+ERROR_DS_DRA_ACCESS_DENIED
+
+
+Replication access was denied.
+
+0x00002106
+
+ERROR_DS_DRA_NOT_SUPPORTED
+
+
+The requested operation is not supported by this version of the directory service.
+
+0x00002107
+
+ERROR_DS_DRA_RPC_CANCELLED
+
+
+The replication RPC was canceled.
+
+0x00002108
+
+ERROR_DS_DRA_SOURCE_DISABLED
+
+
+The source server is currently rejecting replication requests.
+
+0x00002109
+
+ERROR_DS_DRA_SINK_DISABLED
+
+
+The destination server is currently rejecting replication requests.
+
+0x0000210A
+
+ERROR_DS_DRA_NAME_COLLISION
+
+
+The replication operation failed due to a collision of object names.
+
+0x0000210B
+
+ERROR_DS_DRA_SOURCE_REINSTALLED
+
+
+The replication source has been reinstalled.
+
+0x0000210C
+
+ERROR_DS_DRA_MISSING_PARENT
+
+
+The replication operation failed because a required parent object is missing.
+
+0x0000210D
+
+ERROR_DS_DRA_PREEMPTED
+
+
+The replication operation was preempted.
+
+0x0000210E
+
+ERROR_DS_DRA_ABANDON_SYNC
+
+
+The replication synchronization attempt was abandoned because of a lack of updates.
+
+0x0000210F
+
+ERROR_DS_DRA_SHUTDOWN
+
+
+The replication operation was terminated because the system is shutting down.
+
+0x00002110
+
+ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET
+
+
+A synchronization attempt failed because the destination DC is currently waiting to synchronize new partial attributes from the source. This condition is normal if a recent schema change modified the partial attribute set. The destination partial attribute set is not a subset of the source partial attribute set.
+
+0x00002111
+
+ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA
+
+
+The replication synchronization attempt failed because a master replica attempted to sync from a partial replica.
+
+0x00002112
+
+ERROR_DS_DRA_EXTN_CONNECTION_FAILED
+
+
+The server specified for this replication operation was contacted, but that server was unable to contact an additional server needed to complete the operation.
+
+0x00002113
+
+ERROR_DS_INSTALL_SCHEMA_MISMATCH
+
+
+The version of the directory service schema of the source forest is not compatible with the version of the directory service on this computer.
+
+0x00002114
+
+ERROR_DS_DUP_LINK_ID
+
+
+Schema update failed: An attribute with the same link identifier already exists.
+
+0x00002115
+
+ERROR_DS_NAME_ERROR_RESOLVING
+
+
+Name translation: Generic processing error.
+
+0x00002116
+
+ERROR_DS_NAME_ERROR_NOT_FOUND
+
+
+Name translation: Could not find the name or insufficient right to see name.
+
+0x00002117
+
+ERROR_DS_NAME_ERROR_NOT_UNIQUE
+
+
+Name translation: Input name mapped to more than one output name.
+
+0x00002118
+
+ERROR_DS_NAME_ERROR_NO_MAPPING
+
+
+Name translation: The input name was found but not the associated output format.
+
+0x00002119
+
+ERROR_DS_NAME_ERROR_DOMAIN_ONLY
+
+
+Name translation: Unable to resolve completely, only the domain was found.
+
+0x0000211A
+
+ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING
+
+
+Name translation: Unable to perform purely syntactical mapping at the client without going out to the wire.
+
+0x0000211B
+
+ERROR_DS_CONSTRUCTED_ATT_MOD
+
+
+Modification of a constructed attribute is not allowed.
+
+0x0000211C
+
+ERROR_DS_WRONG_OM_OBJ_CLASS
+
+
+The OM-Object-Class specified is incorrect for an attribute with the specified syntax.
+
+0x0000211D
+
+ERROR_DS_DRA_REPL_PENDING
+
+
+The replication request has been posted; waiting for a reply.
+
+0x0000211E
+
+ERROR_DS_DS_REQUIRED
+
+
+The requested operation requires a directory service, and none was available.
+
+0x0000211F
+
+ERROR_DS_INVALID_LDAP_DISPLAY_NAME
+
+
+The LDAP display name of the class or attribute contains non-ASCII characters.
+
+0x00002120
+
+ERROR_DS_NON_BASE_SEARCH
+
+
+The requested search operation is only supported for base searches.
+
+0x00002121
+
+ERROR_DS_CANT_RETRIEVE_ATTS
+
+
+The search failed to retrieve attributes from the database.
+
+0x00002122
+
+ERROR_DS_BACKLINK_WITHOUT_LINK
+
+
+The schema update operation tried to add a backward link attribute that has no corresponding forward link.
+
+0x00002123
+
+ERROR_DS_EPOCH_MISMATCH
+
+
+The source and destination of a cross-domain move do not agree on the object's epoch number. Either the source or the destination does not have the latest version of the object.
+
+0x00002124
+
+ERROR_DS_SRC_NAME_MISMATCH
+
+
+The source and destination of a cross-domain move do not agree on the object's current name. Either the source or the destination does not have the latest version of the object.
+
+0x00002125
+
+ERROR_DS_SRC_AND_DST_NC_IDENTICAL
+
+
+The source and destination for the cross-domain move operation are identical. The caller should use a local move operation instead of a cross-domain move operation.
+
+0x00002126
+
+ERROR_DS_DST_NC_MISMATCH
+
+
+The source and destination for a cross-domain move do not agree on the naming contexts in the forest. Either the source or the destination does not have the latest version of the Partitions container.
+
+0x00002127
+
+ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC
+
+
+The destination of a cross-domain move is not authoritative for the destination naming context.
+
+0x00002128
+
+ERROR_DS_SRC_GUID_MISMATCH
+
+
+The source and destination of a cross-domain move do not agree on the identity of the source object. Either the source or the destination does not have the latest version of the source object.
+
+0x00002129
+
+ERROR_DS_CANT_MOVE_DELETED_OBJECT
+
+
+The object being moved across domains is already known to be deleted by the destination server. The source server does not have the latest version of the source object.
+
+0x0000212A
+
+ERROR_DS_PDC_OPERATION_IN_PROGRESS
+
+
+Another operation that requires exclusive access to the PDC FSMO is already in progress.
+
+0x0000212B
+
+ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD
+
+
+A cross-domain move operation failed because two versions of the moved object exist—one each in the source and destination domains. The destination object needs to be removed to restore the system to a consistent state.
+
+0x0000212C
+
+ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION
+
+
+This object cannot be moved across domain boundaries either because cross-domain moves for this class are not allowed, or the object has some special characteristics, for example, a trust account or a restricted relative identifier (RID), that prevent its move.
+
+0x0000212D
+
+ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS
+
+
+Cannot move objects with memberships across domain boundaries because, once moved, this violates the membership conditions of the account group. Remove the object from any account group memberships and retry.
+
+0x0000212E
+
+ERROR_DS_NC_MUST_HAVE_NC_PARENT
+
+
+A naming context head must be the immediate child of another naming context head, not of an interior node.
+
+0x0000212F
+
+ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE
+
+
+The directory cannot validate the proposed naming context name because it does not hold a replica of the naming context above the proposed naming context. Ensure that the domain naming master role is held by a server that is configured as a GC server, and that the server is up-to-date with its replication partners. (Applies only to Windows 2000 operating system domain naming masters.)
+
+0x00002130
+
+ERROR_DS_DST_DOMAIN_NOT_NATIVE
+
+
+Destination domain must be in native mode.
+
+0x00002131
+
+ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER
+
+
+The operation cannot be performed because the server does not have an infrastructure container in the domain of interest.
+
+0x00002132
+
+ERROR_DS_CANT_MOVE_ACCOUNT_GROUP
+
+
+Cross-domain moves of nonempty account groups is not allowed.
+
+0x00002133
+
+ERROR_DS_CANT_MOVE_RESOURCE_GROUP
+
+
+Cross-domain moves of nonempty resource groups is not allowed.
+
+0x00002134
+
+ERROR_DS_INVALID_SEARCH_FLAG
+
+
+The search flags for the attribute are invalid. The ambiguous name resolution (ANR) bit is valid only on attributes of Unicode or Teletex strings.
+
+0x00002135
+
+ERROR_DS_NO_TREE_DELETE_ABOVE_NC
+
+
+Tree deletions starting at an object that has an NC head as a descendant are not allowed.
+
+0x00002136
+
+ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE
+
+
+The directory service failed to lock a tree in preparation for a tree deletion because the tree was in use.
+
+0x00002137
+
+ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE
+
+
+The directory service failed to identify the list of objects to delete while attempting a tree deletion.
+
+0x00002138
+
+ERROR_DS_SAM_INIT_FAILURE
+
+
+SAM initialization failed because of the following error: %1. Error Status: 0x%2. Click OK to shut down the system and reboot into Directory Services Restore Mode. Check the event log for detailed information.
+
+0x00002139
+
+ERROR_DS_SENSITIVE_GROUP_VIOLATION
+
+
+Only an administrator can modify the membership list of an administrative group.
+
+0x0000213A
+
+ERROR_DS_CANT_MOD_PRIMARYGROUPID
+
+
+Cannot change the primary group ID of a domain controller account.
+
+0x0000213B
+
+ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD
+
+
+An attempt was made to modify the base schema.
+
+0x0000213C
+
+ERROR_DS_NONSAFE_SCHEMA_CHANGE
+
+
+Adding a new mandatory attribute to an existing class, deleting a mandatory attribute from an existing class, or adding an optional attribute to the special class Top that is not a backlink attribute (directly or through inheritance, for example, by adding or deleting an auxiliary class) is not allowed.
+
+0x0000213D
+
+ERROR_DS_SCHEMA_UPDATE_DISALLOWED
+
+
+Schema update is not allowed on this DC because the DC is not the schema FSMO role owner.
+
+0x0000213E
+
+ERROR_DS_CANT_CREATE_UNDER_SCHEMA
+
+
+An object of this class cannot be created under the schema container. You can only create Attribute-Schema and Class-Schema objects under the schema container.
+
+0x0000213F
+
+ERROR_DS_INSTALL_NO_SRC_SCH_VERSION
+
+
+The replica or child install failed to get the objectVersion attribute on the schema container on the source DC. Either the attribute is missing on the schema container or the credentials supplied do not have permission to read it.
+
+0x00002140
+
+ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE
+
+
+The replica or child install failed to read the objectVersion attribute in the SCHEMA section of the file schema.ini in the System32 directory.
+
+0x00002141
+
+ERROR_DS_INVALID_GROUP_TYPE
+
+
+The specified group type is invalid.
+
+0x00002142
+
+ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN
+
+
+You cannot nest global groups in a mixed domain if the group is security-enabled.
+
+0x00002143
+
+ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN
+
+
+You cannot nest local groups in a mixed domain if the group is security-enabled.
+
+0x00002144
+
+ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER
+
+
+A global group cannot have a local group as a member.
+
+0x00002145
+
+ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER
+
+
+A global group cannot have a universal group as a member.
+
+0x00002146
+
+ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER
+
+
+A universal group cannot have a local group as a member.
+
+0x00002147
+
+ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER
+
+
+A global group cannot have a cross-domain member.
+
+0x00002148
+
+ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER
+
+
+A local group cannot have another cross domain local group as a member.
+
+0x00002149
+
+ERROR_DS_HAVE_PRIMARY_MEMBERS
+
+
+A group with primary members cannot change to a security-disabled group.
+
+0x0000214A
+
+ERROR_DS_STRING_SD_CONVERSION_FAILED
+
+
+The schema cache load failed to convert the string default security descriptor (SD) on a class-schema object.
+
+0x0000214B
+
+ERROR_DS_NAMING_MASTER_GC
+
+
+Only DSAs configured to be GC servers should be allowed to hold the domain naming master FSMO role. (Applies only to Windows 2000 servers.)
+
+0x0000214C
+
+ERROR_DS_DNS_LOOKUP_FAILURE
+
+
+The DSA operation is unable to proceed because of a DNS lookup failure.
+
+0x0000214D
+
+ERROR_DS_COULDNT_UPDATE_SPNS
+
+
+While processing a change to the DNS host name for an object, the SPN values could not be kept in sync.
+
+0x0000214E
+
+ERROR_DS_CANT_RETRIEVE_SD
+
+
+The Security Descriptor attribute could not be read.
+
+0x0000214F
+
+ERROR_DS_KEY_NOT_UNIQUE
+
+
+The object requested was not found, but an object with that key was found.
+
+0x00002150
+
+ERROR_DS_WRONG_LINKED_ATT_SYNTAX
+
+
+The syntax of the linked attribute being added is incorrect. Forward links can only have syntax 2.5.5.1, 2.5.5.7, and 2.5.5.14, and backlinks can only have syntax 2.5.5.1.
+
+0x00002151
+
+ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD
+
+
+SAM needs to get the boot password.
+
+0x00002152
+
+ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY
+
+
+SAM needs to get the boot key from the floppy disk.
+
+0x00002153
+
+ERROR_DS_CANT_START
+
+
+Directory Service cannot start.
+
+0x00002154
+
+ERROR_DS_INIT_FAILURE
+
+
+Directory Services could not start.
+
+0x00002155
+
+ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION
+
+
+The connection between client and server requires packet privacy or better.
+
+0x00002156
+
+ERROR_DS_SOURCE_DOMAIN_IN_FOREST
+
+
+The source domain cannot be in the same forest as the destination.
+
+0x00002157
+
+ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST
+
+
+The destination domain MUST be in the forest.
+
+0x00002158
+
+ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED
+
+
+The operation requires that destination domain auditing be enabled.
+
+0x00002159
+
+ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN
+
+
+The operation could not locate a DC for the source domain.
+
+0x0000215A
+
+ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER
+
+
+The source object must be a group or user.
+
+0x0000215B
+
+ERROR_DS_SRC_SID_EXISTS_IN_FOREST
+
+
+The source object's SID already exists in the destination forest.
+
+0x0000215C
+
+ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH
+
+
+The source and destination object must be of the same type.
+
+0x0000215D
+
+ERROR_SAM_INIT_FAILURE
+
+
+SAM initialization failed because of the following error: %1. Error Status: 0x%2. Click OK to shut down the system and reboot into Safe Mode. Check the event log for detailed information.
+
+0x0000215E
+
+ERROR_DS_DRA_SCHEMA_INFO_SHIP
+
+
+Schema information could not be included in the replication request.
+
+0x0000215F
+
+ERROR_DS_DRA_SCHEMA_CONFLICT
+
+
+The replication operation could not be completed due to a schema incompatibility.
+
+0x00002160
+
+ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT
+
+
+The replication operation could not be completed due to a previous schema incompatibility.
+
+0x00002161
+
+ERROR_DS_DRA_OBJ_NC_MISMATCH
+
+
+The replication update could not be applied because either the source or the destination has not yet received information regarding a recent cross-domain move operation.
+
+0x00002162
+
+ERROR_DS_NC_STILL_HAS_DSAS
+
+
+The requested domain could not be deleted because there exist domain controllers that still host this domain.
+
+0x00002163
+
+ERROR_DS_GC_REQUIRED
+
+
+The requested operation can be performed only on a GC server.
+
+0x00002164
+
+ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY
+
+
+A local group can only be a member of other local groups in the same domain.
+
+0x00002165
+
+ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS
+
+
+Foreign security principals cannot be members of universal groups.
+
+0x00002166
+
+ERROR_DS_CANT_ADD_TO_GC
+
+
+The attribute is not allowed to be replicated to the GC because of security reasons.
+
+0x00002167
+
+ERROR_DS_NO_CHECKPOINT_WITH_PDC
+
+
+The checkpoint with the PDC could not be taken because too many modifications are currently being processed.
+
+0x00002168
+
+ERROR_DS_SOURCE_AUDITING_NOT_ENABLED
+
+
+The operation requires that source domain auditing be enabled.
+
+0x00002169
+
+ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC
+
+
+Security principal objects can only be created inside domain naming contexts.
+
+0x0000216A
+
+ERROR_DS_INVALID_NAME_FOR_SPN
+
+
+An SPN could not be constructed because the provided host name is not in the necessary format.
+
+0x0000216B
+
+ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS
+
+
+A filter was passed that uses constructed attributes.
+
+0x0000216C
+
+ERROR_DS_UNICODEPWD_NOT_IN_QUOTES
+
+
+The unicodePwd attribute value must be enclosed in quotation marks.
+
+0x0000216D
+
+ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED
+
+
+Your computer could not be joined to the domain. You have exceeded the maximum number of computer accounts you are allowed to create in this domain. Contact your system administrator to have this limit reset or increased.
+
+0x0000216E
+
+ERROR_DS_MUST_BE_RUN_ON_DST_DC
+
+
+For security reasons, the operation must be run on the destination DC.
+
+0x0000216F
+
+ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER
+
+
+For security reasons, the source DC must be NT4SP4 or greater.
+
+0x00002170
+
+ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ
+
+
+Critical directory service system objects cannot be deleted during tree deletion operations. The tree deletion might have been partially performed.
+
+0x00002171
+
+ERROR_DS_INIT_FAILURE_CONSOLE
+
+
+Directory Services could not start because of the following error: %1. Error Status: 0x%2. Click OK to shut down the system. You can use the Recovery Console to further diagnose the system.
+
+0x00002172
+
+ERROR_DS_SAM_INIT_FAILURE_CONSOLE
+
+
+SAM initialization failed because of the following error: %1. Error Status: 0x%2. Click OK to shut down the system. You can use the Recovery Console to further diagnose the system.
+
+0x00002173
+
+ERROR_DS_FOREST_VERSION_TOO_HIGH
+
+
+The version of the operating system installed is incompatible with the current forest functional level. You must upgrade to a new version of the operating system before this server can become a domain controller in this forest.
+
+0x00002174
+
+ERROR_DS_DOMAIN_VERSION_TOO_HIGH
+
+
+The version of the operating system installed is incompatible with the current domain functional level. You must upgrade to a new version of the operating system before this server can become a domain controller in this domain.
+
+0x00002175
+
+ERROR_DS_FOREST_VERSION_TOO_LOW
+
+
+The version of the operating system installed on this server no longer supports the current forest functional level. You must raise the forest functional level before this server can become a domain controller in this forest.
+
+0x00002176
+
+ERROR_DS_DOMAIN_VERSION_TOO_LOW
+
+
+The version of the operating system installed on this server no longer supports the current domain functional level. You must raise the domain functional level before this server can become a domain controller in this domain.
+
+0x00002177
+
+ERROR_DS_INCOMPATIBLE_VERSION
+
+
+The version of the operating system installed on this server is incompatible with the functional level of the domain or forest.
+
+0x00002178
+
+ERROR_DS_LOW_DSA_VERSION
+
+
+The functional level of the domain (or forest) cannot be raised to the requested value because one or more domain controllers in the domain (or forest) are at a lower, incompatible functional level.
+
+0x00002179
+
+ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN
+
+
+The forest functional level cannot be raised to the requested value because one or more domains are still in mixed-domain mode. All domains in the forest must be in native mode for you to raise the forest functional level.
+
+0x0000217A
+
+ERROR_DS_NOT_SUPPORTED_SORT_ORDER
+
+
+The sort order requested is not supported.
+
+0x0000217B
+
+ERROR_DS_NAME_NOT_UNIQUE
+
+
+The requested name already exists as a unique identifier.
+
+0x0000217C
+
+ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4
+
+
+The machine account was created before Windows NT 4.0. The account needs to be re-created.
+
+0x0000217D
+
+ERROR_DS_OUT_OF_VERSION_STORE
+
+
+The database is out of version store.
+
+0x0000217E
+
+ERROR_DS_INCOMPATIBLE_CONTROLS_USED
+
+
+Unable to continue operation because multiple conflicting controls were used.
+
+0x0000217F
+
+ERROR_DS_NO_REF_DOMAIN
+
+
+Unable to find a valid security descriptor reference domain for this partition.
+
+0x00002180
+
+ERROR_DS_RESERVED_LINK_ID
+
+
+Schema update failed: The link identifier is reserved.
+
+0x00002181
+
+ERROR_DS_LINK_ID_NOT_AVAILABLE
+
+
+Schema update failed: There are no link identifiers available.
+
+0x00002182
+
+ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER
+
+
+An account group cannot have a universal group as a member.
+
+0x00002183
+
+ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE
+
+
+Rename or move operations on naming context heads or read-only objects are not allowed.
+
+0x00002184
+
+ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC
+
+
+Move operations on objects in the schema naming context are not allowed.
+
+0x00002185
+
+ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG
+
+
+A system flag has been set on the object that does not allow the object to be moved or renamed.
+
+0x00002186
+
+ERROR_DS_MODIFYDN_WRONG_GRANDPARENT
+
+
+This object is not allowed to change its grandparent container. Moves are not forbidden on this object, but are restricted to sibling containers.
+
+0x00002187
+
+ERROR_DS_NAME_ERROR_TRUST_REFERRAL
+
+
+Unable to resolve completely; a referral to another forest was generated.
+
+0x00002188
+
+ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER
+
+
+The requested action is not supported on a standard server.
+
+0x00002189
+
+ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD
+
+
+Could not access a partition of the directory service located on a remote server. Make sure at least one server is running for the partition in question.
+
+0x0000218A
+
+ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2
+
+
+The directory cannot validate the proposed naming context (or partition) name because it does not hold a replica, nor can it contact a replica of the naming context above the proposed naming context. Ensure that the parent naming context is properly registered in the DNS, and at least one replica of this naming context is reachable by the domain naming master.
+
+0x0000218B
+
+ERROR_DS_THREAD_LIMIT_EXCEEDED
+
+
+The thread limit for this request was exceeded.
+
+0x0000218C
+
+ERROR_DS_NOT_CLOSEST
+
+
+The GC server is not in the closest site.
+
+0x0000218D
+
+ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF
+
+
+The directory service cannot derive an SPN with which to mutually authenticate the target server because the corresponding server object in the local DS database has no serverReference attribute.
+
+0x0000218E
+
+ERROR_DS_SINGLE_USER_MODE_FAILED
+
+
+The directory service failed to enter single-user mode.
+
+0x0000218F
+
+ERROR_DS_NTDSCRIPT_SYNTAX_ERROR
+
+
+The directory service cannot parse the script because of a syntax error.
+
+0x00002190
+
+ERROR_DS_NTDSCRIPT_PROCESS_ERROR
+
+
+The directory service cannot process the script because of an error.
+
+0x00002191
+
+ERROR_DS_DIFFERENT_REPL_EPOCHS
+
+
+The directory service cannot perform the requested operation because the servers involved are of different replication epochs (which is usually related to a domain rename that is in progress).
+
+0x00002192
+
+ERROR_DS_DRS_EXTENSIONS_CHANGED
+
+
+The directory service binding must be renegotiated due to a change in the server extensions information.
+
+0x00002193
+
+ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR
+
+
+The operation is not allowed on a disabled cross-reference.
+
+0x00002194
+
+ERROR_DS_NO_MSDS_INTID
+
+
+Schema update failed: No values for msDS-IntId are available.
+
+0x00002195
+
+ERROR_DS_DUP_MSDS_INTID
+
+
+Schema update failed: Duplicate msDS-IntId. Retry the operation.
+
+0x00002196
+
+ERROR_DS_EXISTS_IN_RDNATTID
+
+
+Schema deletion failed: Attribute is used in rDNAttID.
+
+0x00002197
+
+ERROR_DS_AUTHORIZATION_FAILED
+
+
+The directory service failed to authorize the request.
+
+0x00002198
+
+ERROR_DS_INVALID_SCRIPT
+
+
+The directory service cannot process the script because it is invalid.
+
+0x00002199
+
+ERROR_DS_REMOTE_CROSSREF_OP_FAILED
+
+
+The remote create cross-reference operation failed on the domain naming master FSMO. The operation's error is in the extended data.
+
+0x0000219A
+
+ERROR_DS_CROSS_REF_BUSY
+
+
+A cross-reference is in use locally with the same name.
+
+0x0000219B
+
+ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN
+
+
+The directory service cannot derive an SPN with which to mutually authenticate the target server because the server's domain has been deleted from the forest.
+
+0x0000219C
+
+ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC
+
+
+Writable NCs prevent this DC from demoting.
+
+0x0000219D
+
+ERROR_DS_DUPLICATE_ID_FOUND
+
+
+The requested object has a nonunique identifier and cannot be retrieved.
+
+0x0000219E
+
+ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT
+
+
+Insufficient attributes were given to create an object. This object might not exist because it might have been deleted and the garbage already collected.
+
+0x0000219F
+
+ERROR_DS_GROUP_CONVERSION_ERROR
+
+
+The group cannot be converted due to attribute restrictions on the requested group type.
+
+0x000021A0
+
+ERROR_DS_CANT_MOVE_APP_BASIC_GROUP
+
+
+Cross-domain moves of nonempty basic application groups is not allowed.
+
+0x000021A1
+
+ERROR_DS_CANT_MOVE_APP_QUERY_GROUP
+
+
+Cross-domain moves of nonempty query-based application groups is not allowed.
+
+0x000021A2
+
+ERROR_DS_ROLE_NOT_VERIFIED
+
+
+The FSMO role ownership could not be verified because its directory partition did not replicate successfully with at least one replication partner.
+
+0x000021A3
+
+ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL
+
+
+The target container for a redirection of a well-known object container cannot already be a special container.
+
+0x000021A4
+
+ERROR_DS_DOMAIN_RENAME_IN_PROGRESS
+
+
+The directory service cannot perform the requested operation because a domain rename operation is in progress.
+
+0x000021A5
+
+ERROR_DS_EXISTING_AD_CHILD_NC
+
+
+The directory service detected a child partition below the requested partition name. The partition hierarchy must be created in a top down method.
+
+0x000021A6
+
+ERROR_DS_REPL_LIFETIME_EXCEEDED
+
+
+The directory service cannot replicate with this server because the time since the last replication with this server has exceeded the tombstone lifetime.
+
+0x000021A7
+
+ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER
+
+
+The requested operation is not allowed on an object under the system container.
+
+0x000021A8
+
+ERROR_DS_LDAP_SEND_QUEUE_FULL
+
+
+The LDAP server's network send queue has filled up because the client is not processing the results of its requests fast enough. No more requests will be processed until the client catches up. If the client does not catch up then it will be disconnected.
+
+0x000021A9
+
+ERROR_DS_DRA_OUT_SCHEDULE_WINDOW
+
+
+The scheduled replication did not take place because the system was too busy to execute the request within the schedule window. The replication queue is overloaded. Consider reducing the number of partners or decreasing the scheduled replication frequency.
+
+0x000021AA
+
+ERROR_DS_POLICY_NOT_KNOWN
+
+
+At this time, it cannot be determined if the branch replication policy is available on the hub domain controller. Retry at a later time to account for replication latencies.
+
+0x000021AB
+
+ERROR_NO_SITE_SETTINGS_OBJECT
+
+
+The site settings object for the specified site does not exist.
+
+0x000021AC
+
+ERROR_NO_SECRETS
+
+
+The local account store does not contain secret material for the specified account.
+
+0x000021AD
+
+ERROR_NO_WRITABLE_DC_FOUND
+
+
+Could not find a writable domain controller in the domain.
+
+0x000021AE
+
+ERROR_DS_NO_SERVER_OBJECT
+
+
+The server object for the domain controller does not exist.
+
+0x000021AF
+
+ERROR_DS_NO_NTDSA_OBJECT
+
+
+The NTDS Settings object for the domain controller does not exist.
+
+0x000021B0
+
+ERROR_DS_NON_ASQ_SEARCH
+
+
+The requested search operation is not supported for attribute scoped query (ASQ) searches.
+
+0x000021B1
+
+ERROR_DS_AUDIT_FAILURE
+
+
+A required audit event could not be generated for the operation.
+
+0x000021B2
+
+ERROR_DS_INVALID_SEARCH_FLAG_SUBTREE
+
+
+The search flags for the attribute are invalid. The subtree index bit is valid only on single-valued attributes.
+
+0x000021B3
+
+ERROR_DS_INVALID_SEARCH_FLAG_TUPLE
+
+
+The search flags for the attribute are invalid. The tuple index bit is valid only on attributes of Unicode strings.
+
+0x000021BF
+
+ERROR_DS_DRA_RECYCLED_TARGET
+
+
+The replication operation failed because the target object referenced by a link value is recycled.
+
+0x000021C2
+
+ERROR_DS_HIGH_DSA_VERSION
+
+
+The functional level of the domain (or forest) cannot be lowered to the requested value.
+
+0x000021C7
+
+ERROR_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST
+
+
+The operation failed because the SPN value provided for addition/modification is not unique forest-wide.
+
+0x000021C8
+
+ERROR_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST
+
+
+The operation failed because the UPN value provided for addition/modification is not unique forest-wide.
+
+0x00002329
+
+DNS_ERROR_RCODE_FORMAT_ERROR
+
+
+DNS server unable to interpret format.
+
+0x0000232A
+
+DNS_ERROR_RCODE_SERVER_FAILURE
+
+
+DNS server failure.
+
+0x0000232B
+
+DNS_ERROR_RCODE_NAME_ERROR
+
+
+DNS name does not exist.
+
+0x0000232C
+
+DNS_ERROR_RCODE_NOT_IMPLEMENTED
+
+
+DNS request not supported by name server.
+
+0x0000232D
+
+DNS_ERROR_RCODE_REFUSED
+
+
+DNS operation refused.
+
+0x0000232E
+
+DNS_ERROR_RCODE_YXDOMAIN
+
+
+DNS name that should not exist, does exist.
+
+0x0000232F
+
+DNS_ERROR_RCODE_YXRRSET
+
+
+DNS resource record (RR) set that should not exist, does exist.
+
+0x00002330
+
+DNS_ERROR_RCODE_NXRRSET
+
+
+DNS RR set that should to exist, does not exist.
+
+0x00002331
+
+DNS_ERROR_RCODE_NOTAUTH
+
+
+DNS server not authoritative for zone.
+
+0x00002332
+
+DNS_ERROR_RCODE_NOTZONE
+
+
+DNS name in update or prereq is not in zone.
+
+0x00002338
+
+DNS_ERROR_RCODE_BADSIG
+
+
+DNS signature failed to verify.
+
+0x00002339
+
+DNS_ERROR_RCODE_BADKEY
+
+
+DNS bad key.
+
+0x0000233A
+
+DNS_ERROR_RCODE_BADTIME
+
+
+DNS signature validity expired.
+
+0x0000251D
+
+DNS_INFO_NO_RECORDS
+
+
+No records found for given DNS query.
+
+0x0000251E
+
+DNS_ERROR_BAD_PACKET
+
+
+Bad DNS packet.
+
+0x0000251F
+
+DNS_ERROR_NO_PACKET
+
+
+No DNS packet.
+
+0x00002520
+
+DNS_ERROR_RCODE
+
+
+DNS error, check rcode.
+
+0x00002521
+
+DNS_ERROR_UNSECURE_PACKET
+
+
+Unsecured DNS packet.
+
+0x0000254F
+
+DNS_ERROR_INVALID_TYPE
+
+
+Invalid DNS type.
+
+0x00002550
+
+DNS_ERROR_INVALID_IP_ADDRESS
+
+
+Invalid IP address.
+
+0x00002551
+
+DNS_ERROR_INVALID_PROPERTY
+
+
+Invalid property.
+
+0x00002552
+
+DNS_ERROR_TRY_AGAIN_LATER
+
+
+Try DNS operation again later.
+
+0x00002553
+
+DNS_ERROR_NOT_UNIQUE
+
+
+Record for given name and type is not unique.
+
+0x00002554
+
+DNS_ERROR_NON_RFC_NAME
+
+
+DNS name does not comply with RFC specifications.
+
+0x00002555
+
+DNS_STATUS_FQDN
+
+
+DNS name is a fully qualified DNS name.
+
+0x00002556
+
+DNS_STATUS_DOTTED_NAME
+
+
+DNS name is dotted (multilabel).
+
+0x00002557
+
+DNS_STATUS_SINGLE_PART_NAME
+
+
+DNS name is a single-part name.
+
+0x00002558
+
+DNS_ERROR_INVALID_NAME_CHAR
+
+
+DNS name contains an invalid character.
+
+0x00002559
+
+DNS_ERROR_NUMERIC_NAME
+
+
+DNS name is entirely numeric.
+
+0x0000255A
+
+DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER
+
+
+The operation requested is not permitted on a DNS root server.
+
+0x0000255B
+
+DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION
+
+
+The record could not be created because this part of the DNS namespace has been delegated to another server.
+
+0x0000255C
+
+DNS_ERROR_CANNOT_FIND_ROOT_HINTS
+
+
+The DNS server could not find a set of root hints.
+
+0x0000255D
+
+DNS_ERROR_INCONSISTENT_ROOT_HINTS
+
+
+The DNS server found root hints but they were not consistent across all adapters.
+
+0x0000255E
+
+DNS_ERROR_DWORD_VALUE_TOO_SMALL
+
+
+The specified value is too small for this parameter.
+
+0x0000255F
+
+DNS_ERROR_DWORD_VALUE_TOO_LARGE
+
+
+The specified value is too large for this parameter.
+
+0x00002560
+
+DNS_ERROR_BACKGROUND_LOADING
+
+
+This operation is not allowed while the DNS server is loading zones in the background. Try again later.
+
+0x00002561
+
+DNS_ERROR_NOT_ALLOWED_ON_RODC
+
+
+The operation requested is not permitted on against a DNS server running on a read-only DC.
+
+0x00002581
+
+DNS_ERROR_ZONE_DOES_NOT_EXIST
+
+
+DNS zone does not exist.
+
+0x00002582
+
+DNS_ERROR_NO_ZONE_INFO
+
+
+DNS zone information not available.
+
+0x00002583
+
+DNS_ERROR_INVALID_ZONE_OPERATION
+
+
+Invalid operation for DNS zone.
+
+0x00002584
+
+DNS_ERROR_ZONE_CONFIGURATION_ERROR
+
+
+Invalid DNS zone configuration.
+
+0x00002585
+
+DNS_ERROR_ZONE_HAS_NO_SOA_RECORD
+
+
+DNS zone has no start of authority (SOA) record.
+
+0x00002586
+
+DNS_ERROR_ZONE_HAS_NO_NS_RECORDS
+
+
+DNS zone has no Name Server (NS) record.
+
+0x00002587
+
+DNS_ERROR_ZONE_LOCKED
+
+
+DNS zone is locked.
+
+0x00002588
+
+DNS_ERROR_ZONE_CREATION_FAILED
+
+
+DNS zone creation failed.
+
+0x00002589
+
+DNS_ERROR_ZONE_ALREADY_EXISTS
+
+
+DNS zone already exists.
+
+0x0000258A
+
+DNS_ERROR_AUTOZONE_ALREADY_EXISTS
+
+
+DNS automatic zone already exists.
+
+0x0000258B
+
+DNS_ERROR_INVALID_ZONE_TYPE
+
+
+Invalid DNS zone type.
+
+0x0000258C
+
+DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP
+
+
+Secondary DNS zone requires master IP address.
+
+0x0000258D
+
+DNS_ERROR_ZONE_NOT_SECONDARY
+
+
+DNS zone not secondary.
+
+0x0000258E
+
+DNS_ERROR_NEED_SECONDARY_ADDRESSES
+
+
+Need secondary IP address.
+
+0x0000258F
+
+DNS_ERROR_WINS_INIT_FAILED
+
+
+WINS initialization failed.
+
+0x00002590
+
+DNS_ERROR_NEED_WINS_SERVERS
+
+
+Need WINS servers.
+
+0x00002591
+
+DNS_ERROR_NBSTAT_INIT_FAILED
+
+
+NBTSTAT initialization call failed.
+
+0x00002592
+
+DNS_ERROR_SOA_DELETE_INVALID
+
+
+Invalid delete of SOA.
+
+0x00002593
+
+DNS_ERROR_FORWARDER_ALREADY_EXISTS
+
+
+A conditional forwarding zone already exists for that name.
+
+0x00002594
+
+DNS_ERROR_ZONE_REQUIRES_MASTER_IP
+
+
+This zone must be configured with one or more master DNS server IP addresses.
+
+0x00002595
+
+DNS_ERROR_ZONE_IS_SHUTDOWN
+
+
+The operation cannot be performed because this zone is shut down.
+
+0x000025B3
+
+DNS_ERROR_PRIMARY_REQUIRES_DATAFILE
+
+
+The primary DNS zone requires a data file.
+
+0x000025B4
+
+DNS_ERROR_INVALID_DATAFILE_NAME
+
+
+Invalid data file name for the DNS zone.
+
+0x000025B5
+
+DNS_ERROR_DATAFILE_OPEN_FAILURE
+
+
+Failed to open the data file for the DNS zone.
+
+0x000025B6
+
+DNS_ERROR_FILE_WRITEBACK_FAILED
+
+
+Failed to write the data file for the DNS zone.
+
+0x000025B7
+
+DNS_ERROR_DATAFILE_PARSING
+
+
+Failure while reading datafile for DNS zone.
+
+0x000025E5
+
+DNS_ERROR_RECORD_DOES_NOT_EXIST
+
+
+DNS record does not exist.
+
+0x000025E6
+
+DNS_ERROR_RECORD_FORMAT
+
+
+DNS record format error.
+
+0x000025E7
+
+DNS_ERROR_NODE_CREATION_FAILED
+
+
+Node creation failure in DNS.
+
+0x000025E8
+
+DNS_ERROR_UNKNOWN_RECORD_TYPE
+
+
+Unknown DNS record type.
+
+0x000025E9
+
+DNS_ERROR_RECORD_TIMED_OUT
+
+
+DNS record timed out.
+
+0x000025EA
+
+DNS_ERROR_NAME_NOT_IN_ZONE
+
+
+Name not in DNS zone.
+
+0x000025EB
+
+DNS_ERROR_CNAME_LOOP
+
+
+CNAME loop detected.
+
+0x000025EC
+
+DNS_ERROR_NODE_IS_CNAME
+
+
+Node is a CNAME DNS record.
+
+0x000025ED
+
+DNS_ERROR_CNAME_COLLISION
+
+
+A CNAME record already exists for the given name.
+
+0x000025EE
+
+DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT
+
+
+Record is only at DNS zone root.
+
+0x000025EF
+
+DNS_ERROR_RECORD_ALREADY_EXISTS
+
+
+DNS record already exists.
+
+0x000025F0
+
+DNS_ERROR_SECONDARY_DATA
+
+
+Secondary DNS zone data error.
+
+0x000025F1
+
+DNS_ERROR_NO_CREATE_CACHE_DATA
+
+
+Could not create DNS cache data.
+
+0x000025F2
+
+DNS_ERROR_NAME_DOES_NOT_EXIST
+
+
+DNS name does not exist.
+
+0x000025F3
+
+DNS_WARNING_PTR_CREATE_FAILED
+
+
+Could not create pointer (PTR) record.
+
+0x000025F4
+
+DNS_WARNING_DOMAIN_UNDELETED
+
+
+DNS domain was undeleted.
+
+0x000025F5
+
+DNS_ERROR_DS_UNAVAILABLE
+
+
+The directory service is unavailable.
+
+0x000025F6
+
+DNS_ERROR_DS_ZONE_ALREADY_EXISTS
+
+
+DNS zone already exists in the directory service.
+
+0x000025F7
+
+DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE
+
+
+DNS server not creating or reading the boot file for the directory service integrated DNS zone.
+
+0x00002617
+
+DNS_INFO_AXFR_COMPLETE
+
+
+DNS AXFR (zone transfer) complete.
+
+0x00002618
+
+DNS_ERROR_AXFR
+
+
+DNS zone transfer failed.
+
+0x00002619
+
+DNS_INFO_ADDED_LOCAL_WINS
+
+
+Added local WINS server.
+
+0x00002649
+
+DNS_STATUS_CONTINUE_NEEDED
+
+
+Secure update call needs to continue update request.
+
+0x0000267B
+
+DNS_ERROR_NO_TCPIP
+
+
+TCP/IP network protocol not installed.
+
+0x0000267C
+
+DNS_ERROR_NO_DNS_SERVERS
+
+
+No DNS servers configured for local system.
+
+0x000026AD
+
+DNS_ERROR_DP_DOES_NOT_EXIST
+
+
+The specified directory partition does not exist.
+
+0x000026AE
+
+DNS_ERROR_DP_ALREADY_EXISTS
+
+
+The specified directory partition already exists.
+
+0x000026AF
+
+DNS_ERROR_DP_NOT_ENLISTED
+
+
+This DNS server is not enlisted in the specified directory partition.
+
+0x000026B0
+
+DNS_ERROR_DP_ALREADY_ENLISTED
+
+
+This DNS server is already enlisted in the specified directory partition.
+
+0x000026B1
+
+DNS_ERROR_DP_NOT_AVAILABLE
+
+
+The directory partition is not available at this time. Wait a few minutes and try again.
+
+0x000026B2
+
+DNS_ERROR_DP_FSMO_ERROR
+
+
+The application directory partition operation failed. The domain controller holding the domain naming master role is down or unable to service the request or is not running Windows Server 2003.
+
+0x00002714
+
+WSAEINTR
+
+
+A blocking operation was interrupted by a call to WSACancelBlockingCall.
+
+0x00002719
+
+WSAEBADF
+
+
+The file handle supplied is not valid.
+
+0x0000271D
+
+WSAEACCES
+
+
+An attempt was made to access a socket in a way forbidden by its access permissions.
+
+0x0000271E
+
+WSAEFAULT
+
+
+The system detected an invalid pointer address in attempting to use a pointer argument in a call.
+
+0x00002726
+
+WSAEINVAL
+
+
+An invalid argument was supplied.
+
+0x00002728
+
+WSAEMFILE
+
+
+Too many open sockets.
+
+0x00002733
+
+WSAEWOULDBLOCK
+
+
+A nonblocking socket operation could not be completed immediately.
+
+0x00002734
+
+WSAEINPROGRESS
+
+
+A blocking operation is currently executing.
+
+0x00002735
+
+WSAEALREADY
+
+
+An operation was attempted on a nonblocking socket that already had an operation in progress.
+
+0x00002736
+
+WSAENOTSOCK
+
+
+An operation was attempted on something that is not a socket.
+
+0x00002737
+
+WSAEDESTADDRREQ
+
+
+A required address was omitted from an operation on a socket.
+
+0x00002738
+
+WSAEMSGSIZE
+
+
+A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.
+
+0x00002739
+
+WSAEPROTOTYPE
+
+
+A protocol was specified in the socket function call that does not support the semantics of the socket type requested.
+
+0x0000273A
+
+WSAENOPROTOOPT
+
+
+An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call.
+
+0x0000273B
+
+WSAEPROTONOSUPPORT
+
+
+The requested protocol has not been configured into the system, or no implementation for it exists.
+
+0x0000273C
+
+WSAESOCKTNOSUPPORT
+
+
+The support for the specified socket type does not exist in this address family.
+
+0x0000273D
+
+WSAEOPNOTSUPP
+
+
+The attempted operation is not supported for the type of object referenced.
+
+0x0000273E
+
+WSAEPFNOSUPPORT
+
+
+The protocol family has not been configured into the system or no implementation for it exists.
+
+0x0000273F
+
+WSAEAFNOSUPPORT
+
+
+An address incompatible with the requested protocol was used.
+
+0x00002740
+
+WSAEADDRINUSE
+
+
+Only one usage of each socket address (protocol/network address/port) is normally permitted.
+
+0x00002741
+
+WSAEADDRNOTAVAIL
+
+
+The requested address is not valid in its context.
+
+0x00002742
+
+WSAENETDOWN
+
+
+A socket operation encountered a dead network.
+
+0x00002743
+
+WSAENETUNREACH
+
+
+A socket operation was attempted to an unreachable network.
+
+0x00002744
+
+WSAENETRESET
+
+
+The connection has been broken due to keep-alive activity detecting a failure while the operation was in progress.
+
+0x00002745
+
+WSAECONNABORTED
+
+
+An established connection was aborted by the software in your host machine.
+
+0x00002746
+
+WSAECONNRESET
+
+
+An existing connection was forcibly closed by the remote host.
+
+0x00002747
+
+WSAENOBUFS
+
+
+An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
+
+0x00002748
+
+WSAEISCONN
+
+
+A connect request was made on an already connected socket.
+
+0x00002749
+
+WSAENOTCONN
+
+
+A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.
+
+0x0000274A
+
+WSAESHUTDOWN
+
+
+A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call.
+
+0x0000274B
+
+WSAETOOMANYREFS
+
+
+Too many references to a kernel object.
+
+0x0000274C
+
+WSAETIMEDOUT
+
+
+A connection attempt failed because the connected party did not properly respond after a period of time, or the established connection failed because the connected host failed to respond.
+
+0x0000274D
+
+WSAECONNREFUSED
+
+
+No connection could be made because the target machine actively refused it.
+
+0x0000274E
+
+WSAELOOP
+
+
+Cannot translate name.
+
+0x0000274F
+
+WSAENAMETOOLONG
+
+
+Name or name component was too long.
+
+0x00002750
+
+WSAEHOSTDOWN
+
+
+A socket operation failed because the destination host was down.
+
+0x00002751
+
+WSAEHOSTUNREACH
+
+
+A socket operation was attempted to an unreachable host.
+
+0x00002752
+
+WSAENOTEMPTY
+
+
+Cannot remove a directory that is not empty.
+
+0x00002753
+
+WSAEPROCLIM
+
+
+A Windows Sockets implementation might have a limit on the number of applications that can use it simultaneously.
+
+0x00002754
+
+WSAEUSERS
+
+
+Ran out of quota.
+
+0x00002755
+
+WSAEDQUOT
+
+
+Ran out of disk quota.
+
+0x00002756
+
+WSAESTALE
+
+
+File handle reference is no longer available.
+
+0x00002757
+
+WSAEREMOTE
+
+
+Item is not available locally.
+
+0x0000276B
+
+WSASYSNOTREADY
+
+
+WSAStartup cannot function at this time because the underlying system it uses to provide network services is currently unavailable.
+
+0x0000276C
+
+WSAVERNOTSUPPORTED
+
+
+The Windows Sockets version requested is not supported.
+
+0x0000276D
+
+WSANOTINITIALISED
+
+
+Either the application has not called WSAStartup, or WSAStartup failed.
+
+0x00002775
+
+WSAEDISCON
+
+
+Returned by WSARecv or WSARecvFrom to indicate that the remote party has initiated a graceful shutdown sequence.
+
+0x00002776
+
+WSAENOMORE
+
+
+No more results can be returned by WSALookupServiceNext.
+
+0x00002777
+
+WSAECANCELLED
+
+
+A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled.
+
+0x00002778
+
+WSAEINVALIDPROCTABLE
+
+
+The procedure call table is invalid.
+
+0x00002779
+
+WSAEINVALIDPROVIDER
+
+
+The requested service provider is invalid.
+
+0x0000277A
+
+WSAEPROVIDERFAILEDINIT
+
+
+The requested service provider could not be loaded or initialized.
+
+0x0000277B
+
+WSASYSCALLFAILURE
+
+
+A system call that should never fail has failed.
+
+0x0000277C
+
+WSASERVICE_NOT_FOUND
+
+
+No such service is known. The service cannot be found in the specified namespace.
+
+0x0000277D
+
+WSATYPE_NOT_FOUND
+
+
+The specified class was not found.
+
+0x0000277E
+
+WSA_E_NO_MORE
+
+
+No more results can be returned by WSALookupServiceNext.
+
+0x0000277F
+
+WSA_E_CANCELLED
+
+
+A call to WSALookupServiceEnd was made while this call was still processing. The call has been canceled.
+
+0x00002780
+
+WSAEREFUSED
+
+
+A database query failed because it was actively refused.
+
+0x00002AF9
+
+WSAHOST_NOT_FOUND
+
+
+No such host is known.
+
+0x00002AFA
+
+WSATRY_AGAIN
+
+
+This is usually a temporary error during host name resolution and means that the local server did not receive a response from an authoritative server.
+
+0x00002AFB
+
+WSANO_RECOVERY
+
+
+A nonrecoverable error occurred during a database lookup.
+
+0x00002AFC
+
+WSANO_DATA
+
+
+The requested name is valid, but no data of the requested type was found.
+
+0x00002AFD
+
+WSA_QOS_RECEIVERS
+
+
+At least one reserve has arrived.
+
+0x00002AFE
+
+WSA_QOS_SENDERS
+
+
+At least one path has arrived.
+
+0x00002AFF
+
+WSA_QOS_NO_SENDERS
+
+
+There are no senders.
+
+0x00002B00
+
+WSA_QOS_NO_RECEIVERS
+
+
+There are no receivers.
+
+0x00002B01
+
+WSA_QOS_REQUEST_CONFIRMED
+
+
+Reserve has been confirmed.
+
+0x00002B02
+
+WSA_QOS_ADMISSION_FAILURE
+
+
+Error due to lack of resources.
+
+0x00002B03
+
+WSA_QOS_POLICY_FAILURE
+
+
+Rejected for administrative reasons—bad credentials.
+
+0x00002B04
+
+WSA_QOS_BAD_STYLE
+
+
+Unknown or conflicting style.
+
+0x00002B05
+
+WSA_QOS_BAD_OBJECT
+
+
+There is a problem with some part of the filterspec or provider-specific buffer in general.
+
+0x00002B06
+
+WSA_QOS_TRAFFIC_CTRL_ERROR
+
+
+There is a problem with some part of the flowspec.
+
+0x00002B07
+
+WSA_QOS_GENERIC_ERROR
+
+
+General quality of serve (QOS) error.
+
+0x00002B08
+
+WSA_QOS_ESERVICETYPE
+
+
+An invalid or unrecognized service type was found in the flowspec.
+
+0x00002B09
+
+WSA_QOS_EFLOWSPEC
+
+
+An invalid or inconsistent flowspec was found in the QOS structure.
+
+0x00002B0A
+
+WSA_QOS_EPROVSPECBUF
+
+
+Invalid QOS provider-specific buffer.
+
+0x00002B0B
+
+WSA_QOS_EFILTERSTYLE
+
+
+An invalid QOS filter style was used.
+
+0x00002B0C
+
+WSA_QOS_EFILTERTYPE
+
+
+An invalid QOS filter type was used.
+
+0x00002B0D
+
+WSA_QOS_EFILTERCOUNT
+
+
+An incorrect number of QOS FILTERSPECs were specified in the FLOWDESCRIPTOR.
+
+0x00002B0E
+
+WSA_QOS_EOBJLENGTH
+
+
+An object with an invalid ObjectLength field was specified in the QOS provider-specific buffer.
+
+0x00002B0F
+
+WSA_QOS_EFLOWCOUNT
+
+
+An incorrect number of flow descriptors was specified in the QOS structure.
+
+0x00002B10
+
+WSA_QOS_EUNKOWNPSOBJ
+
+
+An unrecognized object was found in the QOS provider-specific buffer.
+
+0x00002B11
+
+WSA_QOS_EPOLICYOBJ
+
+
+An invalid policy object was found in the QOS provider-specific buffer.
+
+0x00002B12
+
+WSA_QOS_EFLOWDESC
+
+
+An invalid QOS flow descriptor was found in the flow descriptor list.
+
+0x00002B13
+
+WSA_QOS_EPSFLOWSPEC
+
+
+An invalid or inconsistent flowspec was found in the QOS provider-specific buffer.
+
+0x00002B14
+
+WSA_QOS_EPSFILTERSPEC
+
+
+An invalid FILTERSPEC was found in the QOS provider-specific buffer.
+
+0x00002B15
+
+WSA_QOS_ESDMODEOBJ
+
+
+An invalid shape discard mode object was found in the QOS provider-specific buffer.
+
+0x00002B16
+
+WSA_QOS_ESHAPERATEOBJ
+
+
+An invalid shaping rate object was found in the QOS provider-specific buffer.
+
+0x00002B17
+
+WSA_QOS_RESERVED_PETYPE
+
+
+A reserved policy element was found in the QOS provider-specific buffer.
+
+0x000032C8
+
+ERROR_IPSEC_QM_POLICY_EXISTS
+
+
+The specified quick mode policy already exists.
+
+0x000032C9
+
+ERROR_IPSEC_QM_POLICY_NOT_FOUND
+
+
+The specified quick mode policy was not found.
+
+0x000032CA
+
+ERROR_IPSEC_QM_POLICY_IN_USE
+
+
+The specified quick mode policy is being used.
+
+0x000032CB
+
+ERROR_IPSEC_MM_POLICY_EXISTS
+
+
+The specified main mode policy already exists.
+
+0x000032CC
+
+ERROR_IPSEC_MM_POLICY_NOT_FOUND
+
+
+The specified main mode policy was not found.
+
+0x000032CD
+
+ERROR_IPSEC_MM_POLICY_IN_USE
+
+
+The specified main mode policy is being used.
+
+0x000032CE
+
+ERROR_IPSEC_MM_FILTER_EXISTS
+
+
+The specified main mode filter already exists.
+
+0x000032CF
+
+ERROR_IPSEC_MM_FILTER_NOT_FOUND
+
+
+The specified main mode filter was not found.
+
+0x000032D0
+
+ERROR_IPSEC_TRANSPORT_FILTER_EXISTS
+
+
+The specified transport mode filter already exists.
+
+0x000032D1
+
+ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND
+
+
+The specified transport mode filter does not exist.
+
+0x000032D2
+
+ERROR_IPSEC_MM_AUTH_EXISTS
+
+
+The specified main mode authentication list exists.
+
+0x000032D3
+
+ERROR_IPSEC_MM_AUTH_NOT_FOUND
+
+
+The specified main mode authentication list was not found.
+
+0x000032D4
+
+ERROR_IPSEC_MM_AUTH_IN_USE
+
+
+The specified main mode authentication list is being used.
+
+0x000032D5
+
+ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND
+
+
+The specified default main mode policy was not found.
+
+0x000032D6
+
+ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND
+
+
+The specified default main mode authentication list was not found.
+
+0x000032D7
+
+ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND
+
+
+The specified default quick mode policy was not found.
+
+0x000032D8
+
+ERROR_IPSEC_TUNNEL_FILTER_EXISTS
+
+
+The specified tunnel mode filter exists.
+
+0x000032D9
+
+ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND
+
+
+The specified tunnel mode filter was not found.
+
+0x000032DA
+
+ERROR_IPSEC_MM_FILTER_PENDING_DELETION
+
+
+The main mode filter is pending deletion.
+
+0x000032DB
+
+ERROR_IPSEC_TRANSPORT_FILTER_ENDING_DELETION
+
+
+The transport filter is pending deletion.
+
+0x000032DC
+
+ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION
+
+
+The tunnel filter is pending deletion.
+
+0x000032DD
+
+ERROR_IPSEC_MM_POLICY_PENDING_ELETION
+
+
+The main mode policy is pending deletion.
+
+0x000032DE
+
+ERROR_IPSEC_MM_AUTH_PENDING_DELETION
+
+
+The main mode authentication bundle is pending deletion.
+
+0x000032DF
+
+ERROR_IPSEC_QM_POLICY_PENDING_DELETION
+
+
+The quick mode policy is pending deletion.
+
+0x000032E0
+
+WARNING_IPSEC_MM_POLICY_PRUNED
+
+
+The main mode policy was successfully added, but some of the requested offers are not supported.
+
+0x000032E1
+
+WARNING_IPSEC_QM_POLICY_PRUNED
+
+
+The quick mode policy was successfully added, but some of the requested offers are not supported.
+
+0x000035E8
+
+ERROR_IPSEC_IKE_NEG_STATUS_BEGIN
+
+
+Starts the list of frequencies of various IKE Win32 error codes encountered during negotiations.
+
+0x000035E9
+
+ERROR_IPSEC_IKE_AUTH_FAIL
+
+
+The IKE authentication credentials are unacceptable.
+
+0x000035EA
+
+ERROR_IPSEC_IKE_ATTRIB_FAIL
+
+
+The IKE security attributes are unacceptable.
+
+0x000035EB
+
+ERROR_IPSEC_IKE_NEGOTIATION_PENDING
+
+
+The IKE negotiation is in progress.
+
+0x000035EC
+
+ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR
+
+
+General processing error.
+
+0x000035ED
+
+ERROR_IPSEC_IKE_TIMED_OUT
+
+
+Negotiation timed out.
+
+0x000035EE
+
+ERROR_IPSEC_IKE_NO_CERT
+
+
+The IKE failed to find a valid machine certificate. Contact your network security administrator about installing a valid certificate in the appropriate certificate store.
+
+0x000035EF
+
+ERROR_IPSEC_IKE_SA_DELETED
+
+
+The IKE security association (SA) was deleted by a peer before it was completely established.
+
+0x000035F0
+
+ERROR_IPSEC_IKE_SA_REAPED
+
+
+The IKE SA was deleted before it was completely established.
+
+0x000035F1
+
+ERROR_IPSEC_IKE_MM_ACQUIRE_DROP
+
+
+The negotiation request sat in the queue too long.
+
+0x000035F2
+
+ERROR_IPSEC_IKE_QM_ACQUIRE_DROP
+
+
+The negotiation request sat in the queue too long.
+
+0x000035F3
+
+ERROR_IPSEC_IKE_QUEUE_DROP_MM
+
+
+The negotiation request sat in the queue too long.
+
+0x000035F4
+
+ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM
+
+
+The negotiation request sat in the queue too long.
+
+0x000035F5
+
+ERROR_IPSEC_IKE_DROP_NO_RESPONSE
+
+
+There was no response from a peer.
+
+0x000035F6
+
+ERROR_IPSEC_IKE_MM_DELAY_DROP
+
+
+The negotiation took too long.
+
+0x000035F7
+
+ERROR_IPSEC_IKE_QM_DELAY_DROP
+
+
+The negotiation took too long.
+
+0x000035F8
+
+ERROR_IPSEC_IKE_ERROR
+
+
+An unknown error occurred.
+
+0x000035F9
+
+ERROR_IPSEC_IKE_CRL_FAILED
+
+
+The certificate revocation check failed.
+
+0x000035FA
+
+ERROR_IPSEC_IKE_INVALID_KEY_USAGE
+
+
+Invalid certificate key usage.
+
+0x000035FB
+
+ERROR_IPSEC_IKE_INVALID_CERT_TYPE
+
+
+Invalid certificate type.
+
+0x000035FC
+
+ERROR_IPSEC_IKE_NO_PRIVATE_KEY
+
+
+The IKE negotiation failed because the machine certificate used does not have a private key. IPsec certificates require a private key. Contact your network security administrator about a certificate that has a private key.
+
+0x000035FE
+
+ERROR_IPSEC_IKE_DH_FAIL
+
+
+There was a failure in the Diffie-Hellman computation.
+
+0x00003600
+
+ERROR_IPSEC_IKE_INVALID_HEADER
+
+
+Invalid header.
+
+0x00003601
+
+ERROR_IPSEC_IKE_NO_POLICY
+
+
+No policy configured.
+
+0x00003602
+
+ERROR_IPSEC_IKE_INVALID_SIGNATURE
+
+
+Failed to verify signature.
+
+0x00003603
+
+ERROR_IPSEC_IKE_KERBEROS_ERROR
+
+
+Failed to authenticate using Kerberos.
+
+0x00003604
+
+ERROR_IPSEC_IKE_NO_PUBLIC_KEY
+
+
+The peer's certificate did not have a public key.
+
+0x00003605
+
+ERROR_IPSEC_IKE_PROCESS_ERR
+
+
+Error processing the error payload.
+
+0x00003606
+
+ERROR_IPSEC_IKE_PROCESS_ERR_SA
+
+
+Error processing the SA payload.
+
+0x00003607
+
+ERROR_IPSEC_IKE_PROCESS_ERR_PROP
+
+
+Error processing the proposal payload.
+
+0x00003608
+
+ERROR_IPSEC_IKE_PROCESS_ERR_TRANS
+
+
+Error processing the transform payload.
+
+0x00003609
+
+ERROR_IPSEC_IKE_PROCESS_ERR_KE
+
+
+Error processing the key exchange payload.
+
+0x0000360A
+
+ERROR_IPSEC_IKE_PROCESS_ERR_ID
+
+
+Error processing the ID payload.
+
+0x0000360B
+
+ERROR_IPSEC_IKE_PROCESS_ERR_CERT
+
+
+Error processing the certification payload.
+
+0x0000360C
+
+ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ
+
+
+Error processing the certificate request payload.
+
+0x0000360D
+
+ERROR_IPSEC_IKE_PROCESS_ERR_HASH
+
+
+Error processing the hash payload.
+
+0x0000360E
+
+ERROR_IPSEC_IKE_PROCESS_ERR_SIG
+
+
+Error processing the signature payload.
+
+0x0000360F
+
+ERROR_IPSEC_IKE_PROCESS_ERR_NONCE
+
+
+Error processing the nonce payload.
+
+0x00003610
+
+ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY
+
+
+Error processing the notify payload.
+
+0x00003611
+
+ERROR_IPSEC_IKE_PROCESS_ERR_DELETE
+
+
+Error processing the delete payload.
+
+0x00003612
+
+ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR
+
+
+Error processing the VendorId payload.
+
+0x00003613
+
+ERROR_IPSEC_IKE_INVALID_PAYLOAD
+
+
+Invalid payload received.
+
+0x00003614
+
+ERROR_IPSEC_IKE_LOAD_SOFT_SA
+
+
+Soft SA loaded.
+
+0x00003615
+
+ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN
+
+
+Soft SA torn down.
+
+0x00003616
+
+ERROR_IPSEC_IKE_INVALID_COOKIE
+
+
+Invalid cookie received.
+
+0x00003617
+
+ERROR_IPSEC_IKE_NO_PEER_CERT
+
+
+Peer failed to send valid machine certificate.
+
+0x00003618
+
+ERROR_IPSEC_IKE_PEER_CRL_FAILED
+
+
+Certification revocation check of peer's certificate failed.
+
+0x00003619
+
+ERROR_IPSEC_IKE_POLICY_CHANGE
+
+
+New policy invalidated SAs formed with the old policy.
+
+0x0000361A
+
+ERROR_IPSEC_IKE_NO_MM_POLICY
+
+
+There is no available main mode IKE policy.
+
+0x0000361B
+
+ERROR_IPSEC_IKE_NOTCBPRIV
+
+
+Failed to enabled trusted computer base (TCB) privilege.
+
+0x0000361C
+
+ERROR_IPSEC_IKE_SECLOADFAIL
+
+
+Failed to load SECURITY.DLL.
+
+0x0000361D
+
+ERROR_IPSEC_IKE_FAILSSPINIT
+
+
+Failed to obtain the security function table dispatch address from the SSPI.
+
+0x0000361E
+
+ERROR_IPSEC_IKE_FAILQUERYSSP
+
+
+Failed to query the Kerberos package to obtain the max token size.
+
+0x0000361F
+
+ERROR_IPSEC_IKE_SRVACQFAIL
+
+
+Failed to obtain the Kerberos server credentials for the Internet Security Association and Key Management Protocol (ISAKMP)/ERROR_IPSEC_IKE service. Kerberos authentication will not function. The most likely reason for this is lack of domain membership. This is normal if your computer is a member of a workgroup.
+
+0x00003620
+
+ERROR_IPSEC_IKE_SRVQUERYCRED
+
+
+Failed to determine the SSPI principal name for ISAKMP/ERROR_IPSEC_IKE service (QueryCredentialsAttributes).
+
+0x00003621
+
+ERROR_IPSEC_IKE_GETSPIFAIL
+
+
+Failed to obtain a new service provider interface (SPI) for the inbound SA from the IPsec driver. The most common cause for this is that the driver does not have the correct filter. Check your policy to verify the filters.
+
+0x00003622
+
+ERROR_IPSEC_IKE_INVALID_FILTER
+
+
+Given filter is invalid.
+
+0x00003623
+
+ERROR_IPSEC_IKE_OUT_OF_MEMORY
+
+
+Memory allocation failed.
+
+0x00003624
+
+ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED
+
+
+Failed to add an SA to the IPSec driver. The most common cause for this is if the IKE negotiation took too long to complete. If the problem persists, reduce the load on the faulting machine.
+
+0x00003625
+
+ERROR_IPSEC_IKE_INVALID_POLICY
+
+
+Invalid policy.
+
+0x00003626
+
+ERROR_IPSEC_IKE_UNKNOWN_DOI
+
+
+Invalid digital object identifier (DOI).
+
+0x00003627
+
+ERROR_IPSEC_IKE_INVALID_SITUATION
+
+
+Invalid situation.
+
+0x00003628
+
+ERROR_IPSEC_IKE_DH_FAILURE
+
+
+Diffie-Hellman failure.
+
+0x00003629
+
+ERROR_IPSEC_IKE_INVALID_GROUP
+
+
+Invalid Diffie-Hellman group.
+
+0x0000362A
+
+ERROR_IPSEC_IKE_ENCRYPT
+
+
+Error encrypting payload.
+
+0x0000362B
+
+ERROR_IPSEC_IKE_DECRYPT
+
+
+Error decrypting payload.
+
+0x0000362C
+
+ERROR_IPSEC_IKE_POLICY_MATCH
+
+
+Policy match error.
+
+0x0000362D
+
+ERROR_IPSEC_IKE_UNSUPPORTED_ID
+
+
+Unsupported ID.
+
+0x0000362E
+
+ERROR_IPSEC_IKE_INVALID_HASH
+
+
+Hash verification failed.
+
+0x0000362F
+
+ERROR_IPSEC_IKE_INVALID_HASH_ALG
+
+
+Invalid hash algorithm.
+
+0x00003630
+
+ERROR_IPSEC_IKE_INVALID_HASH_SIZE
+
+
+Invalid hash size.
+
+0x00003631
+
+ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG
+
+
+Invalid encryption algorithm.
+
+0x00003632
+
+ERROR_IPSEC_IKE_INVALID_AUTH_ALG
+
+
+Invalid authentication algorithm.
+
+0x00003633
+
+ERROR_IPSEC_IKE_INVALID_SIG
+
+
+Invalid certificate signature.
+
+0x00003634
+
+ERROR_IPSEC_IKE_LOAD_FAILED
+
+
+Load failed.
+
+0x00003635
+
+ERROR_IPSEC_IKE_RPC_DELETE
+
+
+Deleted by using an RPC call.
+
+0x00003636
+
+ERROR_IPSEC_IKE_BENIGN_REINIT
+
+
+A temporary state was created to perform reinitialization. This is not a real failure.
+
+0x00003637
+
+ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY
+
+
+The lifetime value received in the Responder Lifetime Notify is below the Windows 2000 configured minimum value. Fix the policy on the peer machine.
+
+0x00003639
+
+ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN
+
+
+Key length in the certificate is too small for configured security requirements.
+
+0x0000363A
+
+ERROR_IPSEC_IKE_MM_LIMIT
+
+
+Maximum number of established MM SAs to peer exceeded.
+
+0x0000363B
+
+ERROR_IPSEC_IKE_NEGOTIATION_DISABLED
+
+
+The IKE received a policy that disables negotiation.
+
+0x0000363C
+
+ERROR_IPSEC_IKE_QM_LIMIT
+
+
+Reached maximum quick mode limit for the main mode. New main mode will be started.
+
+0x0000363D
+
+ERROR_IPSEC_IKE_MM_EXPIRED
+
+
+Main mode SA lifetime expired or the peer sent a main mode delete.
+
+0x0000363E
+
+ERROR_IPSEC_IKE_PEER_MM_ASSUMED_INVALID
+
+
+Main mode SA assumed to be invalid because peer stopped responding.
+
+0x0000363F
+
+ERROR_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH
+
+
+Certificate does not chain to a trusted root in IPsec policy.
+
+0x00003640
+
+ERROR_IPSEC_IKE_UNEXPECTED_MESSAGE_ID
+
+
+Received unexpected message ID.
+
+0x00003641
+
+ERROR_IPSEC_IKE_INVALID_UMATTS
+
+
+Received invalid AuthIP user mode attributes.
+
+0x00003642
+
+ERROR_IPSEC_IKE_DOS_COOKIE_SENT
+
+
+Sent DOS cookie notify to initiator.
+
+0x00003643
+
+ERROR_IPSEC_IKE_SHUTTING_DOWN
+
+
+The IKE service is shutting down.
+
+0x00003644
+
+ERROR_IPSEC_IKE_CGA_AUTH_FAILED
+
+
+Could not verify the binding between the color graphics adapter (CGA) address and the certificate.
+
+0x00003645
+
+ERROR_IPSEC_IKE_PROCESS_ERR_NATOA
+
+
+Error processing the NatOA payload.
+
+0x00003646
+
+ERROR_IPSEC_IKE_INVALID_MM_FOR_QM
+
+
+The parameters of the main mode are invalid for this quick mode.
+
+0x00003647
+
+ERROR_IPSEC_IKE_QM_EXPIRED
+
+
+The quick mode SA was expired by the IPsec driver.
+
+0x00003648
+
+ERROR_IPSEC_IKE_TOO_MANY_FILTERS
+
+
+Too many dynamically added IKEEXT filters were detected.
+
+0x00003649
+
+ERROR_IPSEC_IKE_NEG_STATUS_END
+
+
+Ends the list of frequencies of various IKE Win32 error codes encountered during negotiations.
+
+0x000036B0
+
+ERROR_SXS_SECTION_NOT_FOUND
+
+
+The requested section was not present in the activation context.
+
+0x000036B1
+
+ERROR_SXS_CANT_GEN_ACTCTX
+
+
+The application has failed to start because its side-by-side configuration is incorrect. See the application event log for more detail.
+
+0x000036B2
+
+ERROR_SXS_INVALID_ACTCTXDATA_FORMAT
+
+
+The application binding data format is invalid.
+
+0x000036B3
+
+ERROR_SXS_ASSEMBLY_NOT_FOUND
+
+
+The referenced assembly is not installed on your system.
+
+0x000036B4
+
+ERROR_SXS_MANIFEST_FORMAT_ERROR
+
+
+The manifest file does not begin with the required tag and format information.
+
+0x000036B5
+
+ERROR_SXS_MANIFEST_PARSE_ERROR
+
+
+The manifest file contains one or more syntax errors.
+
+0x000036B6
+
+ERROR_SXS_ACTIVATION_CONTEXT_DISABLED
+
+
+The application attempted to activate a disabled activation context.
+
+0x000036B7
+
+ERROR_SXS_KEY_NOT_FOUND
+
+
+The requested lookup key was not found in any active activation context.
+
+0x000036B8
+
+ERROR_SXS_VERSION_CONFLICT
+
+
+A component version required by the application conflicts with another active component version.
+
+0x000036B9
+
+ERROR_SXS_WRONG_SECTION_TYPE
+
+
+The type requested activation context section does not match the query API used.
+
+0x000036BA
+
+ERROR_SXS_THREAD_QUERIES_DISABLED
+
+
+Lack of system resources has required isolated activation to be disabled for the current thread of execution.
+
+0x000036BB
+
+ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET
+
+
+An attempt to set the process default activation context failed because the process default activation context was already set.
+
+0x000036BC
+
+ERROR_SXS_UNKNOWN_ENCODING_GROUP
+
+
+The encoding group identifier specified is not recognized.
+
+0x000036BD
+
+ERROR_SXS_UNKNOWN_ENCODING
+
+
+The encoding requested is not recognized.
+
+0x000036BE
+
+ERROR_SXS_INVALID_XML_NAMESPACE_URI
+
+
+The manifest contains a reference to an invalid URI.
+
+0x000036BF
+
+ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_OT_INSTALLED
+
+
+The application manifest contains a reference to a dependent assembly that is not installed.
+
+0x000036C0
+
+ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED
+
+
+The manifest for an assembly used by the application has a reference to a dependent assembly that is not installed.
+
+0x000036C1
+
+ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE
+
+
+The manifest contains an attribute for the assembly identity that is not valid.
+
+0x000036C2
+
+ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE
+
+
+The manifest is missing the required default namespace specification on the assembly element.
+
+0x000036C3
+
+ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE
+
+
+The manifest has a default namespace specified on the assembly element but its value is not urn:schemas-microsoft-com:asm.v1"."
+
+0x000036C4
+
+ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT
+
+
+The private manifest probed has crossed the reparse-point-associated path.
+
+0x000036C5
+
+ERROR_SXS_DUPLICATE_DLL_NAME
+
+
+Two or more components referenced directly or indirectly by the application manifest have files by the same name.
+
+0x000036C6
+
+ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME
+
+
+Two or more components referenced directly or indirectly by the application manifest have window classes with the same name.
+
+0x000036C7
+
+ERROR_SXS_DUPLICATE_CLSID
+
+
+Two or more components referenced directly or indirectly by the application manifest have the same COM server CLSIDs.
+
+0x000036C8
+
+ERROR_SXS_DUPLICATE_IID
+
+
+Two or more components referenced directly or indirectly by the application manifest have proxies for the same COM interface IIDs.
+
+0x000036C9
+
+ERROR_SXS_DUPLICATE_TLBID
+
+
+Two or more components referenced directly or indirectly by the application manifest have the same COM type library TLBIDs.
+
+0x000036CA
+
+ERROR_SXS_DUPLICATE_PROGID
+
+
+Two or more components referenced directly or indirectly by the application manifest have the same COM ProgIDs.
+
+0x000036CB
+
+ERROR_SXS_DUPLICATE_ASSEMBLY_NAME
+
+
+Two or more components referenced directly or indirectly by the application manifest are different versions of the same component, which is not permitted.
+
+0x000036CC
+
+ERROR_SXS_FILE_HASH_MISMATCH
+
+
+A component's file does not match the verification information present in the component manifest.
+
+0x000036CD
+
+ERROR_SXS_POLICY_PARSE_ERROR
+
+
+The policy manifest contains one or more syntax errors.
+
+0x000036CE
+
+ERROR_SXS_XML_E_MISSINGQUOTE
+
+
+Manifest Parse Error: A string literal was expected, but no opening quotation mark was found.
+
+0x000036CF
+
+ERROR_SXS_XML_E_COMMENTSYNTAX
+
+
+Manifest Parse Error: Incorrect syntax was used in a comment.
+
+0x000036D0
+
+ERROR_SXS_XML_E_BADSTARTNAMECHAR
+
+
+Manifest Parse Error: A name started with an invalid character.
+
+0x000036D1
+
+ERROR_SXS_XML_E_BADNAMECHAR
+
+
+Manifest Parse Error: A name contained an invalid character.
+
+0x000036D2
+
+ERROR_SXS_XML_E_BADCHARINSTRING
+
+
+Manifest Parse Error: A string literal contained an invalid character.
+
+0x000036D3
+
+ERROR_SXS_XML_E_XMLDECLSYNTAX
+
+
+Manifest Parse Error: Invalid syntax for an XML declaration.
+
+0x000036D4
+
+ERROR_SXS_XML_E_BADCHARDATA
+
+
+Manifest Parse Error: An Invalid character was found in text content.
+
+0x000036D5
+
+ERROR_SXS_XML_E_MISSINGWHITESPACE
+
+
+Manifest Parse Error: Required white space was missing.
+
+0x000036D6
+
+ERROR_SXS_XML_E_EXPECTINGTAGEND
+
+
+Manifest Parse Error: The angle bracket (>) character was expected.
+
+0x000036D7
+
+ERROR_SXS_XML_E_MISSINGSEMICOLON
+
+
+Manifest Parse Error: A semicolon (;) was expected.
+
+0x000036D8
+
+ERROR_SXS_XML_E_UNBALANCEDPAREN
+
+
+Manifest Parse Error: Unbalanced parentheses.
+
+0x000036D9
+
+ERROR_SXS_XML_E_INTERNALERROR
+
+
+Manifest Parse Error: Internal error.
+
+0x000036DA
+
+ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE
+
+
+Manifest Parse Error: Whitespace is not allowed at this location.
+
+0x000036DB
+
+ERROR_SXS_XML_E_INCOMPLETE_ENCODING
+
+
+Manifest Parse Error: End of file reached in invalid state for current encoding.
+
+0x000036DC
+
+ERROR_SXS_XML_E_MISSING_PAREN
+
+
+Manifest Parse Error: Missing parenthesis.
+
+0x000036DD
+
+ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE
+
+
+Manifest Parse Error: A single (') or double (") quotation mark is missing.
+
+0x000036DE
+
+ERROR_SXS_XML_E_MULTIPLE_COLONS
+
+
+Manifest Parse Error: Multiple colons are not allowed in a name.
+
+0x000036DF
+
+ERROR_SXS_XML_E_INVALID_DECIMAL
+
+
+Manifest Parse Error: Invalid character for decimal digit.
+
+0x000036E0
+
+ERROR_SXS_XML_E_INVALID_HEXIDECIMAL
+
+
+Manifest Parse Error: Invalid character for hexadecimal digit.
+
+0x000036E1
+
+ERROR_SXS_XML_E_INVALID_UNICODE
+
+
+Manifest Parse Error: Invalid Unicode character value for this platform.
+
+0x000036E2
+
+ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK
+
+
+Manifest Parse Error: Expecting whitespace or question mark (?).
+
+0x000036E3
+
+ERROR_SXS_XML_E_UNEXPECTEDENDTAG
+
+
+Manifest Parse Error: End tag was not expected at this location.
+
+0x000036E4
+
+ERROR_SXS_XML_E_UNCLOSEDTAG
+
+
+Manifest Parse Error: The following tags were not closed: %1.
+
+0x000036E5
+
+ERROR_SXS_XML_E_DUPLICATEATTRIBUTE
+
+
+Manifest Parse Error: Duplicate attribute.
+
+0x000036E6
+
+ERROR_SXS_XML_E_MULTIPLEROOTS
+
+
+Manifest Parse Error: Only one top-level element is allowed in an XML document.
+
+0x000036E7
+
+ERROR_SXS_XML_E_INVALIDATROOTLEVEL
+
+
+Manifest Parse Error: Invalid at the top level of the document.
+
+0x000036E8
+
+ERROR_SXS_XML_E_BADXMLDECL
+
+
+Manifest Parse Error: Invalid XML declaration.
+
+0x000036E9
+
+ERROR_SXS_XML_E_MISSINGROOT
+
+
+Manifest Parse Error: XML document must have a top-level element.
+
+0x000036EA
+
+ERROR_SXS_XML_E_UNEXPECTEDEOF
+
+
+Manifest Parse Error: Unexpected end of file.
+
+0x000036EB
+
+ERROR_SXS_XML_E_BADPEREFINSUBSET
+
+
+Manifest Parse Error: Parameter entities cannot be used inside markup declarations in an internal subset.
+
+0x000036EC
+
+ERROR_SXS_XML_E_UNCLOSEDSTARTTAG
+
+
+Manifest Parse Error: Element was not closed.
+
+0x000036ED
+
+ERROR_SXS_XML_E_UNCLOSEDENDTAG
+
+
+Manifest Parse Error: End element was missing the angle bracket (>) character.
+
+0x000036EE
+
+ERROR_SXS_XML_E_UNCLOSEDSTRING
+
+
+Manifest Parse Error: A string literal was not closed.
+
+0x000036EF
+
+ERROR_SXS_XML_E_UNCLOSEDCOMMENT
+
+
+Manifest Parse Error: A comment was not closed.
+
+0x000036F0
+
+ERROR_SXS_XML_E_UNCLOSEDDECL
+
+
+Manifest Parse Error: A declaration was not closed.
+
+0x000036F1
+
+ERROR_SXS_XML_E_UNCLOSEDCDATA
+
+
+Manifest Parse Error: A CDATA section was not closed.
+
+0x000036F2
+
+ERROR_SXS_XML_E_RESERVEDNAMESPACE
+
+
+Manifest Parse Error: The namespace prefix is not allowed to start with the reserved string xml"."
+
+0x000036F3
+
+ERROR_SXS_XML_E_INVALIDENCODING
+
+
+Manifest Parse Error: System does not support the specified encoding.
+
+0x000036F4
+
+ERROR_SXS_XML_E_INVALIDSWITCH
+
+
+Manifest Parse Error: Switch from current encoding to specified encoding not supported.
+
+0x000036F5
+
+ERROR_SXS_XML_E_BADXMLCASE
+
+
+Manifest Parse Error: The name "xml" is reserved and must be lowercase.
+
+0x000036F6
+
+ERROR_SXS_XML_E_INVALID_STANDALONE
+
+
+Manifest Parse Error: The stand-alone attribute must have the value "yes" or "no".
+
+0x000036F7
+
+ERROR_SXS_XML_E_UNEXPECTED_STANDALONE
+
+
+Manifest Parse Error: The stand-alone attribute cannot be used in external entities.
+
+0x000036F8
+
+ERROR_SXS_XML_E_INVALID_VERSION
+
+
+Manifest Parse Error: Invalid version number.
+
+0x000036F9
+
+ERROR_SXS_XML_E_MISSINGEQUALS
+
+
+Manifest Parse Error: Missing equal sign (=) between the attribute and the attribute value.
+
+0x000036FA
+
+ERROR_SXS_PROTECTION_RECOVERY_FAILED
+
+
+Assembly Protection Error: Unable to recover the specified assembly.
+
+0x000036FB
+
+ERROR_SXS_PROTECTION_PUBLIC_KEY_OO_SHORT
+
+
+Assembly Protection Error: The public key for an assembly was too short to be allowed.
+
+0x000036FC
+
+ERROR_SXS_PROTECTION_CATALOG_NOT_VALID
+
+
+Assembly Protection Error: The catalog for an assembly is not valid, or does not match the assembly's manifest.
+
+0x000036FD
+
+ERROR_SXS_UNTRANSLATABLE_HRESULT
+
+
+An HRESULT could not be translated to a corresponding Win32 error code.
+
+0x000036FE
+
+ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING
+
+
+Assembly Protection Error: The catalog for an assembly is missing.
+
+0x000036FF
+
+ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE
+
+
+The supplied assembly identity is missing one or more attributes that must be present in this context.
+
+0x00003700
+
+ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME
+
+
+The supplied assembly identity has one or more attribute names that contain characters not permitted in XML names.
+
+0x00003701
+
+ERROR_SXS_ASSEMBLY_MISSING
+
+
+The referenced assembly could not be found.
+
+0x00003702
+
+ERROR_SXS_CORRUPT_ACTIVATION_STACK
+
+
+The activation context activation stack for the running thread of execution is corrupt.
+
+0x00003703
+
+ERROR_SXS_CORRUPTION
+
+
+The application isolation metadata for this process or thread has become corrupt.
+
+0x00003704
+
+ERROR_SXS_EARLY_DEACTIVATION
+
+
+The activation context being deactivated is not the most recently activated one.
+
+0x00003705
+
+ERROR_SXS_INVALID_DEACTIVATION
+
+
+The activation context being deactivated is not active for the current thread of execution.
+
+0x00003706
+
+ERROR_SXS_MULTIPLE_DEACTIVATION
+
+
+The activation context being deactivated has already been deactivated.
+
+0x00003707
+
+ERROR_SXS_PROCESS_TERMINATION_REQUESTED
+
+
+A component used by the isolation facility has requested to terminate the process.
+
+0x00003708
+
+ERROR_SXS_RELEASE_ACTIVATION_ONTEXT
+
+
+A kernel mode component is releasing a reference on an activation context.
+
+0x00003709
+
+ERROR_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY
+
+
+The activation context of the system default assembly could not be generated.
+
+0x0000370A
+
+ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE
+
+
+The value of an attribute in an identity is not within the legal range.
+
+0x0000370B
+
+ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME
+
+
+The name of an attribute in an identity is not within the legal range.
+
+0x0000370C
+
+ERROR_SXS_IDENTITY_DUPLICATE_ATTRIBUTE
+
+
+An identity contains two definitions for the same attribute.
+
+0x0000370D
+
+ERROR_SXS_IDENTITY_PARSE_ERROR
+
+
+The identity string is malformed. This might be due to a trailing comma, more than two unnamed attributes, a missing attribute name, or a missing attribute value.
+
+0x0000370E
+
+ERROR_MALFORMED_SUBSTITUTION_STRING
+
+
+A string containing localized substitutable content was malformed. Either a dollar sign ($) was followed by something other than a left parenthesis or another dollar sign, or a substitution's right parenthesis was not found.
+
+0x0000370F
+
+ERROR_SXS_INCORRECT_PUBLIC_KEY_OKEN
+
+
+The public key token does not correspond to the public key specified.
+
+0x00003710
+
+ERROR_UNMAPPED_SUBSTITUTION_STRING
+
+
+A substitution string had no mapping.
+
+0x00003711
+
+ERROR_SXS_ASSEMBLY_NOT_LOCKED
+
+
+The component must be locked before making the request.
+
+0x00003712
+
+ERROR_SXS_COMPONENT_STORE_CORRUPT
+
+
+The component store has been corrupted.
+
+0x00003713
+
+ERROR_ADVANCED_INSTALLER_FAILED
+
+
+An advanced installer failed during setup or servicing.
+
+0x00003714
+
+ERROR_XML_ENCODING_MISMATCH
+
+
+The character encoding in the XML declaration did not match the encoding used in the document.
+
+0x00003715
+
+ERROR_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT
+
+
+The identities of the manifests are identical, but the contents are different.
+
+0x00003716
+
+ERROR_SXS_IDENTITIES_DIFFERENT
+
+
+The component identities are different.
+
+0x00003717
+
+ERROR_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT
+
+
+The assembly is not a deployment.
+
+0x00003718
+
+ERROR_SXS_FILE_NOT_PART_OF_ASSEMBLY
+
+
+The file is not a part of the assembly.
+
+0x00003719
+
+ERROR_SXS_MANIFEST_TOO_BIG
+
+
+The size of the manifest exceeds the maximum allowed.
+
+0x0000371A
+
+ERROR_SXS_SETTING_NOT_REGISTERED
+
+
+The setting is not registered.
+
+0x0000371B
+
+ERROR_SXS_TRANSACTION_CLOSURE_INCOMPLETE
+
+
+One or more required members of the transaction are not present.
+
+0x00003A98
+
+ERROR_EVT_INVALID_CHANNEL_PATH
+
+
+The specified channel path is invalid.
+
+0x00003A99
+
+ERROR_EVT_INVALID_QUERY
+
+
+The specified query is invalid.
+
+0x00003A9A
+
+ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND
+
+
+The publisher metadata cannot be found in the resource.
+
+0x00003A9B
+
+ERROR_EVT_EVENT_TEMPLATE_NOT_FOUND
+
+
+The template for an event definition cannot be found in the resource (error = %1).
+
+0x00003A9C
+
+ERROR_EVT_INVALID_PUBLISHER_NAME
+
+
+The specified publisher name is invalid.
+
+0x00003A9D
+
+ERROR_EVT_INVALID_EVENT_DATA
+
+
+The event data raised by the publisher is not compatible with the event template definition in the publisher's manifest.
+
+0x00003A9F
+
+ERROR_EVT_CHANNEL_NOT_FOUND
+
+
+The specified channel could not be found. Check channel configuration.
+
+0x00003AA0
+
+ERROR_EVT_MALFORMED_XML_TEXT
+
+
+The specified XML text was not well-formed. See extended error for more details.
+
+0x00003AA1
+
+ERROR_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL
+
+
+The caller is trying to subscribe to a direct channel which is not allowed. The events for a direct channel go directly to a log file and cannot be subscribed to.
+
+0x00003AA2
+
+ERROR_EVT_CONFIGURATION_ERROR
+
+
+Configuration error.
+
+0x00003AA3
+
+ERROR_EVT_QUERY_RESULT_STALE
+
+
+The query result is stale or invalid. This might be due to the log being cleared or rolling over after the query result was created. Users should handle this code by releasing the query result object and reissuing the query.
+
+0x00003AA4
+
+ERROR_EVT_QUERY_RESULT_INVALID_POSITION
+
+
+Query result is currently at an invalid position.
+
+0x00003AA5
+
+ERROR_EVT_NON_VALIDATING_MSXML
+
+
+Registered Microsoft XML (MSXML) does not support validation.
+
+0x00003AA6
+
+ERROR_EVT_FILTER_ALREADYSCOPED
+
+
+An expression can only be followed by a change-of-scope operation if it itself evaluates to a node set and is not already part of some other change-of-scope operation.
+
+0x00003AA7
+
+ERROR_EVT_FILTER_NOTELTSET
+
+
+Cannot perform a step operation from a term that does not represent an element set.
+
+0x00003AA8
+
+ERROR_EVT_FILTER_INVARG
+
+
+Left side arguments to binary operators must be either attributes, nodes, or variables and right side arguments must be constants.
+
+0x00003AA9
+
+ERROR_EVT_FILTER_INVTEST
+
+
+A step operation must involve either a node test or, in the case of a predicate, an algebraic expression against which to test each node in the node set identified by the preceding node set can be evaluated.
+
+0x00003AAA
+
+ERROR_EVT_FILTER_INVTYPE
+
+
+This data type is currently unsupported.
+
+0x00003AAB
+
+ERROR_EVT_FILTER_PARSEERR
+
+
+A syntax error occurred at position %1!d!
+
+0x00003AAC
+
+ERROR_EVT_FILTER_UNSUPPORTEDOP
+
+
+This operator is unsupported by this implementation of the filter.
+
+0x00003AAD
+
+ERROR_EVT_FILTER_UNEXPECTEDTOKEN
+
+
+The token encountered was unexpected.
+
+0x00003AAE
+
+ERROR_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL
+
+
+The requested operation cannot be performed over an enabled direct channel. The channel must first be disabled before performing the requested operation.
+
+0x00003AAF
+
+ERROR_EVT_INVALID_CHANNEL_PROPERTY_VALUE
+
+
+Channel property %1!s! contains an invalid value. The value has an invalid type, is outside the valid range, cannot be updated, or is not supported by this type of channel.
+
+0x00003AB0
+
+ERROR_EVT_INVALID_PUBLISHER_PROPERTY_VALUE
+
+
+Publisher property %1!s! contains an invalid value. The value has an invalid type, is outside the valid range, cannot be updated, or is not supported by this type of publisher.
+
+0x00003AB1
+
+ERROR_EVT_CHANNEL_CANNOT_ACTIVATE
+
+
+The channel fails to activate.
+
+0x00003AB2
+
+ERROR_EVT_FILTER_TOO_COMPLEX
+
+
+The xpath expression exceeded supported complexity. Simplify it or split it into two or more simple expressions.
+
+0x00003AB3
+
+ERROR_EVT_MESSAGE_NOT_FOUND
+
+
+The message resource is present but the message is not found in the string or message table.
+
+0x00003AB4
+
+ERROR_EVT_MESSAGE_ID_NOT_FOUND
+
+
+The message ID for the desired message could not be found.
+
+0x00003AB5
+
+ERROR_EVT_UNRESOLVED_VALUE_INSERT
+
+
+The substitution string for the insert index (%1) could not be found.
+
+0x00003AB6
+
+ERROR_EVT_UNRESOLVED_PARAMETER_INSERT
+
+
+The description string for the parameter reference (%1) could not be found.
+
+0x00003AB7
+
+ERROR_EVT_MAX_INSERTS_REACHED
+
+
+The maximum number of replacements has been reached.
+
+0x00003AB8
+
+ERROR_EVT_EVENT_DEFINITION_NOT_OUND
+
+
+The event definition could not be found for the event ID (%1).
+
+0x00003AB9
+
+ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND
+
+
+The locale-specific resource for the desired message is not present.
+
+0x00003ABA
+
+ERROR_EVT_VERSION_TOO_OLD
+
+
+The resource is too old to be compatible.
+
+0x00003ABB
+
+ERROR_EVT_VERSION_TOO_NEW
+
+
+The resource is too new to be compatible.
+
+0x00003ABC
+
+ERROR_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY
+
+
+The channel at index %1 of the query cannot be opened.
+
+0x00003ABD
+
+ERROR_EVT_PUBLISHER_DISABLED
+
+
+The publisher has been disabled and its resource is not available. This usually occurs when the publisher is in the process of being uninstalled or upgraded.
+
+0x00003AE8
+
+ERROR_EC_SUBSCRIPTION_CANNOT_ACTIVATE
+
+
+The subscription fails to activate.
+
+0x00003AE9
+
+ERROR_EC_LOG_DISABLED
+
+
+The log of the subscription is in a disabled state and events cannot be forwarded to it. The log must first be enabled before the subscription can be activated.
+
+0x00003AFC
+
+ERROR_MUI_FILE_NOT_FOUND
+
+
+The resource loader failed to find the Multilingual User Interface (MUI) file.
+
+0x00003AFD
+
+ERROR_MUI_INVALID_FILE
+
+
+The resource loader failed to load the MUI file because the file failed to pass validation.
+
+0x00003AFE
+
+ERROR_MUI_INVALID_RC_CONFIG
+
+
+The release candidate (RC) manifest is corrupted with garbage data, is an unsupported version, or is missing a required item.
+
+0x00003AFF
+
+ERROR_MUI_INVALID_LOCALE_NAME
+
+
+The RC manifest has an invalid culture name.
+
+0x00003B00
+
+ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME
+
+
+The RC Manifest has an invalid ultimate fallback name.
+
+0x00003B01
+
+ERROR_MUI_FILE_NOT_LOADED
+
+
+The resource loader cache does not have a loaded MUI entry.
+
+0x00003B02
+
+ERROR_RESOURCE_ENUM_USER_STOP
+
+
+The user stopped resource enumeration.
+
+0x00003B03
+
+ERROR_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED
+
+
+User interface language installation failed.
+
+0x00003B04
+
+ERROR_MUI_INTLSETTINGS_INVALID_LOCALE_NAME
+
+
+Locale installation failed.
+
+0x00003B60
+
+ERROR_MCA_INVALID_CAPABILITIES_STRING
+
+
+The monitor returned a DDC/CI capabilities string that did not comply with the ACCESS.bus 3.0, DDC/CI 1.1, or MCCS 2 Revision 1 specification.
+
+0x00003B61
+
+ERROR_MCA_INVALID_VCP_VERSION
+
+
+The monitor's VCP version (0xDF) VCP code returned an invalid version value.
+
+0x00003B62
+
+ERROR_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION
+
+
+The monitor does not comply with the MCCS specification it claims to support.
+
+0x00003B63
+
+ERROR_MCA_MCCS_VERSION_MISMATCH
+
+
+The MCCS version in a monitor's mccs_ver capability does not match the MCCS version the monitor reports when the VCP version (0xDF) VCP code is used.
+
+0x00003B64
+
+ERROR_MCA_UNSUPPORTED_MCCS_VERSION
+
+
+The monitor configuration API works only with monitors that support the MCCS 1.0, MCCS 2.0, or MCCS 2.0 Revision 1 specifications.
+
+0x00003B65
+
+ERROR_MCA_INTERNAL_ERROR
+
+
+An internal monitor configuration API error occurred.
+
+0x00003B66
+
+ERROR_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED
+
+
+The monitor returned an invalid monitor technology type. CRT, plasma, and LCD (TFT) are examples of monitor technology types. This error implies that the monitor violated the MCCS 2.0 or MCCS 2.0 Revision 1 specification.
+
+0x00003B67
+
+ERROR_MCA_UNSUPPORTED_COLOR_TEMPERATURE
+
+
+The SetMonitorColorTemperature() caller passed a color temperature to it that the current monitor did not support. CRT, plasma, and LCD (TFT) are examples of monitor technology types. This error implies that the monitor violated the MCCS 2.0 or MCCS 2.0 Revision 1 specification.
+
+0x00003B92
+
+ERROR_AMBIGUOUS_SYSTEM_DEVICE
+
+
+The requested system device cannot be identified due to multiple indistinguishable devices potentially matching the identification criteria.
+
+0x00003BC3
+
+ERROR_SYSTEM_DEVICE_NOT_FOUND
+
+
+The requested system device cannot be found.
diff --git a/libcli/util/wscript_build b/libcli/util/wscript_build
new file mode 100644
index 0000000..340ea42
--- /dev/null
+++ b/libcli/util/wscript_build
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+
+bld.SAMBA_LIBRARY('samba-errors',
+ public_headers='error.h ntstatus.h ntstatus_gen.h doserr.h werror.h werror_gen.h hresult.h',
+ private_headers='nterr_private.h',
+ header_path='core',
+ source='doserr.c errormap.c nterr.c errmap_unix.c hresult.c',
+ public_deps='talloc samba-debug',
+ deps='gnutls',
+ # private_library=True,
+ pc_files=[],
+ vnum='1.0.0',
+ )
+
+bld.SAMBA_GENERATOR('hresult_generated',
+ source='../../source4/scripting/bin/gen_hresult.py hresult_err_table.txt ../../source4/scripting/bin/gen_error_common.py',
+ target='hresult.h hresult.c py_hresult.c',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} ${SRC[1].abspath(env)} ${TGT[0].abspath(env)} ${TGT[1].abspath(env)} ${TGT[2].abspath(env)}'
+ )
+
+bld.SAMBA_GENERATOR('ntstatus_generated',
+ source='../../source4/scripting/bin/gen_ntstatus.py ntstatus_err_table.txt ../../source4/scripting/bin/gen_error_common.py',
+ target='ntstatus_gen.h nterr_gen.c py_ntstatus.c',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} ${SRC[1].abspath(env)} ${TGT[0].abspath(env)} ${TGT[1].abspath(env)} ${TGT[2].abspath(env)}'
+ )
+
+bld.SAMBA_GENERATOR('werror_generated',
+ source='../../source4/scripting/bin/gen_werror.py werror_err_table.txt ../../source4/scripting/bin/gen_error_common.py',
+ target='''
+ werror_gen.h
+ werror_gen.c
+ werror_friendly_gen.c
+ py_werror.c
+ ''',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} ${SRC[1].abspath(env)} ${TGT[0].abspath(env)} ${TGT[1].abspath(env)} ${TGT[2].abspath(env)} ${TGT[3].abspath(env)}'
+ )
+
+bld.SAMBA_PYTHON('python_hresult',
+ source='py_hresult.c',
+ deps='samba-errors',
+ realname='samba/hresult.so'
+ )
+
+bld.SAMBA_PYTHON('python_ntstatus',
+ source='py_ntstatus.c',
+ deps='samba-errors',
+ realname='samba/ntstatus.so'
+ )
+
+bld.SAMBA_PYTHON('python_werror',
+ source='py_werror.c',
+ deps='samba-errors',
+ realname='samba/werror.so'
+ )
diff --git a/libcli/wsp/test_wsp_parser.c b/libcli/wsp/test_wsp_parser.c
new file mode 100644
index 0000000..9edebda
--- /dev/null
+++ b/libcli/wsp/test_wsp_parser.c
@@ -0,0 +1,402 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Noel Power
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 <setjmp.h>
+#include <cmocka.h>
+#include <talloc.h>
+#include "lib/cmdline/cmdline.h"
+#include "libcli/util/ntstatus.h"
+#include "lib/util/samba_util.h"
+#include "lib/torture/torture.h"
+#include "lib/param/param.h"
+#include "libcli/wsp/wsp_aqs.h"
+#include "bin/default/librpc/gen_ndr/ndr_wsp.h"
+#include "librpc/wsp/wsp_util.h"
+
+/*
+ * some routines to help stringify the parsed AQS
+ * query so we can test parsing
+ */
+
+static bool is_operator_node(t_query *node)
+{
+ if (node->type == eVALUE) {
+ return false;
+ }
+ return true;
+}
+
+static const char *nodetype_as_string(t_nodetype node)
+{
+ const char *result = NULL;
+ switch (node) {
+ case eNOT:
+ result = "NOT";
+ break;
+ case eAND:
+ result = "AND";
+ break;
+ case eOR:
+ result = "OR";
+ break;
+ case eVALUE:
+ default:
+ break;
+ }
+ return result;
+}
+
+static const char *restriction_as_string(TALLOC_CTX *ctx,
+ struct wsp_crestriction *crestriction )
+{
+ const char *result = NULL;
+ if (crestriction->ultype == RTPROPERTY) {
+ struct wsp_cpropertyrestriction *prop_restr =
+ &crestriction->restriction.cpropertyrestriction;
+ struct wsp_cbasestoragevariant *value = &prop_restr->prval;
+ result = variant_as_string(ctx, value, true);
+ } else {
+ struct wsp_ccontentrestriction *cont_restr = NULL;
+ cont_restr = &crestriction->restriction.ccontentrestriction;
+ result = talloc_strdup(ctx, cont_restr->pwcsphrase);
+ }
+ return result;
+}
+
+static const char *prop_name_from_restriction(
+ TALLOC_CTX *ctx,
+ struct wsp_crestriction *restriction)
+{
+ const char *result = NULL;
+ struct wsp_cfullpropspec *prop;
+ if (restriction->ultype == RTCONTENT) {
+ prop = &restriction->restriction.ccontentrestriction.property;
+ } else {
+ prop = &restriction->restriction.cpropertyrestriction.property;
+ }
+ result = prop_from_fullprop(ctx, prop);
+ return result;
+}
+
+static char *print_basic_query(TALLOC_CTX *ctx,
+ struct wsp_crestriction *restriction)
+{
+ const char *op_str = op_as_string(restriction);
+ const char *val_str = restriction_as_string(ctx, restriction);
+ const char *prop_name = prop_name_from_restriction(ctx, restriction);
+ char *res = talloc_asprintf(ctx,
+ "%s %s %s", prop_name, op_str ? op_str : "", val_str);
+ return res;
+}
+
+static char *print_node(TALLOC_CTX *ctx, t_query *node, bool is_rpn)
+{
+ switch(node->type) {
+ case eAND:
+ case eOR:
+ case eNOT:
+ return talloc_asprintf(ctx,
+ " %s ", nodetype_as_string(node->type));
+ break;
+ case eVALUE:
+ default:
+ return print_basic_query(ctx, node->restriction);
+ break;
+ }
+}
+
+/*
+ * Algorithm infix (tree)
+ * Print the infix expression for an expression tree.
+ * Pre : tree is a pointer to an expression tree
+ * Post: the infix expression has been printed
+ * start infix
+ * if (tree not empty)
+ * if (tree token is operator)
+ * print (open parenthesis)
+ * end if
+ * infix (tree left subtree)
+ * print (tree token)
+ * infix (tree right subtree)
+ * if (tree token is operator)
+ * print (close parenthesis)
+ * end if
+ * end if
+ * end infix
+ */
+
+static char *infix(TALLOC_CTX *ctx, t_query *tree)
+{
+ char *sresult = NULL;
+ char *stree = NULL;
+ char *sleft = NULL;
+ char *sright = NULL;
+ if (tree == NULL) {
+ return NULL;
+ }
+
+ if (is_operator_node(tree)) {
+ sresult = talloc_strdup(ctx, "(");
+ SMB_ASSERT(sresult != NULL);
+ }
+ sleft = infix(ctx, tree->left);
+ stree = print_node(ctx, tree, false);
+ sright = infix(ctx, tree->right);
+ sresult = talloc_asprintf(ctx, "%s%s%s%s",
+ sresult ? sresult : "",
+ sleft ? sleft : "",
+ stree? stree : "",
+ sright ? sright : "");
+
+ if (is_operator_node(tree)) {
+ sresult = talloc_asprintf(ctx, "%s)", sresult);
+ SMB_ASSERT(sresult != NULL);
+ }
+ return sresult;
+}
+
+static struct {
+ const char *aqs;
+ const char *stringified;
+} no_col_map_queries [] = {
+
+ /* equals (numeric) */
+ {
+ "System.Size:10241",
+ "System.Size = 10241"
+ },
+ {
+ "System.Size := 10241",
+ "System.Size = 10241"
+ },
+ /* not equals */
+ {
+ "System.Size:!=10241",
+ "System.Size != 10241"
+ },
+ /* equals (string property) */
+ {
+ "ALL:(somestring)",
+ "All = 'somestring'"
+ },
+ {
+ "ALL:=somestring",
+ "All = 'somestring'"
+ },
+ {
+ "ALL:somestring",
+ "All = 'somestring'"
+ },
+ /* not equals (string) */
+ {
+ "ALL:!=somestring",
+ "All != 'somestring'"
+ },
+ /* Greater than */
+ {
+ "System.Size:(>10241)",
+ "System.Size > 10241"
+ },
+ {
+ "System.Size:>10241",
+ "System.Size > 10241"
+ },
+ /* Less than */
+ {
+ "System.Size:(<10241)",
+ "System.Size < 10241"
+ },
+ /* Greater than or equals */
+ {
+ "System.Size:(>=10241)",
+ "System.Size >= 10241"
+ },
+ {
+ "System.Size:>=10241",
+ "System.Size >= 10241"
+ },
+ /* Less than or equals */
+ {
+ "System.Size:(<=10241)",
+ "System.Size <= 10241"
+ },
+ {
+ "System.Size:<=10241",
+ "System.Size <= 10241"
+ },
+ /* equals (in the sense of matches) */
+ {
+ "ALL:($=somestring)",
+ "All equals somestring"
+ },
+ /* starts with */
+ {
+ "ALL:($<somestring)",
+ "All starts with somestring"
+ },
+ /* range */
+ {
+ "System.Size:10241-102401",
+ "(System.Size >= 10241 AND System.Size < 102401)"
+ },
+ {
+ "System.Size:small",
+ "(System.Size >= 10241 AND System.Size < 102401)"
+ },
+ /* NOT */
+ {
+ "NOT System.Size:10241",
+ "( NOT System.Size = 10241)"
+ },
+ /* AND */
+ {
+ "System.Size:(>=10241) AND System.Size:(<102401)",
+ "(System.Size >= 10241 AND System.Size < 102401)"
+ },
+ /* OR */
+ {
+ "System.Kind:picture OR System.Kind:video",
+ "(System.Kind = 'picture' OR System.Kind = 'video')"
+ },
+ /* MULTIPLE LOGICAL */
+ {
+ "System.Kind:picture AND NOT System.Kind:video OR "
+ "System.Kind:movie",
+ "(System.Kind = 'picture' AND (( NOT System.Kind = 'video') OR "
+ "System.Kind = 'movie'))"
+ },
+ /* parenthesized MULTIPLE LOGICAL */
+ {
+ "(System.Kind:picture AND NOT System.Kind:video) OR "
+ "System.Kind:movie",
+ "((System.Kind = 'picture' AND ( NOT System.Kind = 'video')) "
+ "OR System.Kind = 'movie')"
+ },
+};
+
+static char *dump_cols(TALLOC_CTX *ctx, t_select_stmt *select)
+{
+ t_col_list *cols = select->cols;
+ char *res = NULL;
+ if (cols) {
+ int i;
+ for (i = 0; i < cols->num_cols; i++) {
+ if (i == 0) {
+ res = talloc_strdup(ctx,
+ cols->cols[i]);
+ } else {
+ res = talloc_asprintf(ctx,
+ "%s, %s",
+ res, cols->cols[i]);
+ }
+ }
+ }
+ return res;
+}
+
+static void test_wsp_parser(void **state)
+{
+ int i;
+ t_select_stmt *select_stmt = NULL;
+ const char *col_query =
+ "SELECT System.ItemName, System.ItemURL, System.Size WHERE "
+ "System.Kind:picture";
+ char *res = NULL;
+
+ TALLOC_CTX *frame = talloc_stackframe();
+ for (i = 0; i < ARRAY_SIZE(no_col_map_queries); i++) {
+ select_stmt = get_wsp_sql_tree(no_col_map_queries[i].aqs);
+ assert_non_null(select_stmt);
+ assert_null(select_stmt->cols);
+ res = infix(frame, select_stmt->where);
+ DBG_DEBUG("reading query => %s parsed => %s\n",
+ no_col_map_queries[i].aqs,
+ res);
+ assert_string_equal(res, no_col_map_queries[i].stringified);
+ }
+ select_stmt = get_wsp_sql_tree(col_query);
+ res = infix(frame, select_stmt->where);
+ assert_string_equal(res, "System.Kind = 'picture'");
+ assert_non_null(select_stmt->cols);
+ res = dump_cols(frame, select_stmt);
+ assert_string_equal(res,
+ "System.ItemName, System.ItemURL, System.Size");
+ TALLOC_FREE(frame);
+}
+
+int main(int argc, const char *argv[])
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_wsp_parser),
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+ poptContext pc;
+ int opt;
+ bool ok;
+ struct loadparm_context *lp_ctx = NULL;
+
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ smb_init_locale();
+
+ ok = samba_cmdline_init(frame,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(frame);
+ exit(1);
+ }
+
+ lp_ctx = samba_cmdline_get_lp_ctx();
+ if (!lp_ctx) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(frame);
+ exit(1);
+ }
+
+ lpcfg_set_cmdline(lp_ctx, "log level", "1");
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv,
+ long_options,
+ 0);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ TALLOC_FREE(frame);
+ exit(1);
+ }
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ default:
+ fprintf(stderr, "Unknown Option: %c\n", opt);
+ exit(1);
+ }
+ }
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/libcli/wsp/wscript_build b/libcli/wsp/wscript_build
new file mode 100644
index 0000000..2d34879
--- /dev/null
+++ b/libcli/wsp/wscript_build
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+#default flex recepie doesn't create a header file
+bld.SAMBA_GENERATOR('wsp_flex',
+ source='wsp_aqs_lexer.l',
+ target='wsp_aqs_lexer.h wsp_aqs_lexer.c',
+ group='build_source',
+ rule='${FLEX} --header-file=${TGT[0].abspath(env)} --outfile=${TGT[1].abspath(env)} ${SRC[0].abspath(env)}',
+ enabled=bld.env.with_wsp
+ )
+
+# With centos7-o3 CI job (and gcc 4.8.5) we get
+# an error with -Wstrict-overflow.
+# Same code is good with gcc version
+# gcc 8.5.0 (centos8) and whatever versions of
+# gcc we have in the other XXXX-o3 images.
+# We turn off strict-overflow just for this generated
+# file
+parser_cflags=''
+if bld.CONFIG_SET('HAVE_WNO_STRICT_OVERFLOW'):
+ parser_cflags += ' -Wno-strict-overflow'
+
+bld.SAMBA_SUBSYSTEM('LIBSAMBA_WSP_PARSER',
+ source='wsp_aqs_parser.y',
+ deps='talloc wsp_flex',
+ cflags_end=parser_cflags,
+ enabled=bld.env.with_wsp
+ )
+bld.SAMBA_SUBSYSTEM('LIBSAMBA_WSP',
+ source='wsp_aqs.c wsp_aqs_lexer.c',
+ public_deps='LIBSAMBA_WSP_PARSER',
+ enabled=bld.env.with_wsp
+ )
+
+bld.SAMBA_BINARY('test_wsp_parser',
+ source='test_wsp_parser.c',
+ deps= 'dcerpc CMDLINE_S3 LIBSAMBA_WSP NDR_WSP NDR_WSP_DATA WSP_UTIL cmocka',
+ enabled=bld.env.with_wsp,
+ install=False
+ )
+
diff --git a/libcli/wsp/wsp_aqs.c b/libcli/wsp/wsp_aqs.c
new file mode 100644
index 0000000..acf1229
--- /dev/null
+++ b/libcli/wsp/wsp_aqs.c
@@ -0,0 +1,877 @@
+/*
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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/wsp/wsp_aqs.h"
+#include "libcli/wsp/wsp_aqs_parser.tab.h"
+#include "libcli/wsp/wsp_aqs_lexer.h"
+#include "librpc/wsp/wsp_util.h"
+#include "librpc/gen_ndr/ndr_wsp.h"
+#include <stdio.h>
+#include <stdbool.h>
+
+int yyparse(t_select_stmt **select, yyscan_t scanner);
+
+static void reverse_cols(t_select_stmt *select)
+{
+ int num_elems, fwd, rev;
+ char **cols;
+
+
+ if (!select->cols) {
+ return;
+ }
+ num_elems = select->cols->num_cols;
+ cols = select->cols->cols;
+
+ for(fwd = 0, rev = num_elems - 1; fwd <= rev; fwd++, rev--) {
+ char * tmp = cols[rev];
+ cols[rev] = cols[fwd];
+ cols[fwd] = tmp;
+ }
+
+}
+
+t_select_stmt *get_wsp_sql_tree(const char *expr)
+{
+ t_select_stmt *select = NULL;
+ yyscan_t scanner;
+ YY_BUFFER_STATE state;
+
+ if (yylex_init(&scanner)) {
+ DBG_ERR("couldn't initialize\n");
+ return NULL;
+ }
+
+ state = yy_scan_string(expr, scanner);
+
+ if (yyparse(&select, scanner)) {
+ DBG_ERR("some parse error\n");
+ return NULL;
+ }
+ /*
+ * parsed columns are in reverse order to how they are specified
+ * in the AQS like statement, reverse them again to correct this.
+ */
+ reverse_cols(select);
+
+ yy_delete_buffer(state, scanner);
+
+ yylex_destroy(scanner);
+
+ return select;
+}
+
+
+t_col_list *create_cols(TALLOC_CTX *ctx, const char *col, t_col_list *append_list)
+{
+ t_col_list *cols = append_list;
+ if (!get_prop_info(col)) {
+ DBG_ERR("Unknown property %s\n", col);
+ return NULL;
+ }
+ if (cols == NULL) {
+ cols = talloc_zero(ctx, t_col_list);
+ if (cols == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ cols->num_cols = 0;
+ cols->cols = NULL;
+ DBG_INFO("returning new cols %p with item %s\n", cols, col);
+ }
+ if (col) {
+ int old_index = cols->num_cols;
+ if (old_index == 0) {
+ cols->cols = talloc_array(cols, char*, 1);
+ } else {
+ cols->cols = (char **)talloc_realloc(cols, cols->cols, char*, old_index + 1);
+ }
+ if (!cols->cols) {
+ return NULL; /* can we create a parser error here */
+ }
+ cols->num_cols++;
+ cols->cols[old_index] = talloc_strdup(cols, col);
+ if (cols->cols[old_index] == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+
+ }
+ return cols;
+}
+
+t_select_stmt *create_select(TALLOC_CTX *ctx, t_col_list *cols, t_query *where)
+{
+ t_select_stmt *result = talloc_zero(ctx, t_select_stmt);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ result->cols = cols;
+ result->where = where;
+ return result;
+}
+
+t_basic_restr *create_basic_restr(TALLOC_CTX *ctx,
+ uint32_t prop_type,
+ t_optype op,
+ t_value_holder *values)
+{
+ t_basic_restr *result = talloc_zero(ctx, t_basic_restr);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ result->prop_type = prop_type;
+ result->op = op;
+ if (values->type == VALUE_RANGE) {
+ t_restr *left_node;
+ t_restr *right_node;
+ t_basic_restr *left_val;
+ t_basic_restr *right_val;
+ if (op != eEQ) {
+ DBG_ERR("Unsupported operation %d\n", op);
+ TALLOC_FREE(result);
+ goto out;
+ }
+
+ if (values->value.value_range->lower == NULL) {
+ DBG_ERR("range lower limit doesn't exist\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+ /*
+ * detect special case where upper range doesn't exist
+ * and convert to a property value. (this won't happen from
+ * the cmdline directly but only as a result of a range
+ * created 'specially' in code, e.g. special gigantic size
+ * range.
+ */
+ if (values->value.value_range->upper == NULL) {
+ result->op = eGE;
+ result->values = values->value.value_range->lower;
+ goto out;
+ }
+ result->values = talloc_zero(result, t_value_holder);
+ if (result->values == NULL) {
+ DBG_ERR("out of memory\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+ /*
+ * try create a restriction tree (>=lower AND <upper) to
+ * represent the range
+ */
+ left_val = create_basic_restr(result->values,
+ prop_type,
+ eGE,
+ values->value.value_range->lower);
+
+ right_val = create_basic_restr(result->values,
+ prop_type,
+ eLT,
+ values->value.value_range->upper);
+
+ if (!left_val || !right_val) {
+ DBG_ERR("Failed creating basic_restriction values "
+ "for range\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+
+ left_node = create_restr(result->values, eVALUE, NULL, NULL, left_val);
+ right_node = create_restr(result->values, eVALUE, NULL, NULL, right_val);
+
+
+ if (!left_node || !right_node) {
+ DBG_ERR("Failed creating restr nodes for range\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+ result->values->type = RESTR;
+ result->values->value.restr_tree = create_restr(result->values,
+ eAND,
+ left_node,
+ right_node,
+ NULL);
+ if (!result->values->value.restr_tree) {
+ DBG_ERR("Failed creating restr tree for range\n");
+ TALLOC_FREE(result);
+ goto out;
+ }
+ } else {
+ result->values = values;
+ }
+out:
+ return result;
+}
+
+/*
+ * The parser reads numbers as VT_UI8, booleans as VT_BOOL and strings as
+ * VT_LPWSTR
+ */
+typedef bool (*conv_func) (TALLOC_CTX *ctx, t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type);
+
+/*
+ * default converter #TODO probably should cater for detecting over/underrun
+ * depending on the dest_type we are narrowing to
+ */
+static bool default_convertor(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+ if (src->type != NUMBER) {
+ return false;
+ }
+ dest->vvalue.vt_ui8 = src->value.number;
+ dest->vtype = dest_type;
+ return true;
+}
+
+static bool convert_string_to_lpwstr_v(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+ const char *str = src->value.string;
+ set_variant_lpwstr_vector(ctx, dest, &str, 1);
+ return true;
+}
+
+static bool convert_string_to_lpwstr(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+ const char *str = src->value.string;
+ set_variant_lpwstr(ctx, dest, str);
+ return true;
+}
+
+static bool convert_bool_to_lpwstr(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+ set_variant_lpwstr(
+ ctx,
+ dest,
+ src->value.boolean ? "true": "false");
+ return true;
+}
+
+static bool convert_string_to_filetime(TALLOC_CTX *ctx,
+ t_value_holder *src,
+ struct wsp_cbasestoragevariant *dest,
+ uint16_t dest_type)
+{
+
+ static const char *fmts[] = {
+ "%FT%TZ",
+ "%FT%T",
+ "%F %T",
+ "%F %R",
+ "%F",
+ };
+ struct tm tm;
+ time_t timeval = 0;
+ int i;
+ ZERO_STRUCT(tm);
+
+ for (i = 0; i < ARRAY_SIZE(fmts); i++) {
+ if (strptime(src->value.string, fmts[i], &tm)) {
+ timeval = timegm(&tm);
+ break;
+ }
+ }
+
+ if (timeval) {
+ NTTIME nt;
+ unix_to_nt_time(&nt, timeval);
+ dest->vtype = VT_FILETIME;
+ dest->vvalue.vt_filetime = nt;
+ return true;
+ }
+ return false;
+}
+
+const struct {
+ uint16_t src_vtype;
+ uint16_t dest_vtype;
+ conv_func convert_type;
+} type_conv_map[] = {
+ {NUMBER, VT_I8, default_convertor},
+ {NUMBER, VT_UI8, default_convertor},
+ {NUMBER, VT_INT, default_convertor},
+ {NUMBER, VT_UINT, default_convertor},
+ {NUMBER, VT_I4, default_convertor},
+ {NUMBER, VT_UI4, default_convertor},
+ {NUMBER, VT_I2, default_convertor},
+ {NUMBER, VT_UI2, default_convertor},
+ {NUMBER, VT_BOOL, default_convertor},
+ {NUMBER, VT_FILETIME, default_convertor},
+ {NUMBER, VT_BOOL, default_convertor},
+ {BOOL, VT_LPWSTR, convert_bool_to_lpwstr},
+ {STRING, VT_LPWSTR, convert_string_to_lpwstr},
+ {STRING, VT_LPWSTR | VT_VECTOR, convert_string_to_lpwstr_v},
+ {STRING, VT_FILETIME, convert_string_to_filetime},
+};
+
+static bool process_prop_value(TALLOC_CTX *ctx,
+ const struct full_propset_info *prop_info,
+ t_value_holder *node_value,
+ struct wsp_cbasestoragevariant *prop_value)
+{
+ int i;
+
+ /* coerce type as required */
+ for (i = 0; i < ARRAY_SIZE(type_conv_map); i++ ) {
+ if (type_conv_map[i].src_vtype == node_value->type &&
+ type_conv_map[i].dest_vtype == prop_info->vtype) {
+ type_conv_map[i].convert_type(ctx,
+ node_value,
+ prop_value,
+ prop_info->vtype);
+ return true;
+ }
+ }
+ return false;
+}
+
+t_basic_query *create_basic_query(TALLOC_CTX *ctx, const char *propname, t_basic_restr *restr)
+{
+ t_basic_query *result = talloc_zero(ctx, t_basic_query);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ goto out;
+ }
+ result->prop = talloc_strdup(result, propname);
+ result->prop_info = get_propset_info_with_guid(propname, &result->guid);
+
+ if (!result->prop_info) {
+ DBG_ERR("Unknown property %s\n",propname);
+ TALLOC_FREE(result);
+ goto out;
+ }
+ result->basic_restriction = restr;
+out:
+ return result;
+}
+
+static struct wsp_crestriction *create_restriction(TALLOC_CTX *ctx,
+ t_basic_query *query)
+{
+ struct wsp_crestriction *crestriction = NULL;
+ struct wsp_cfullpropspec *prop = NULL;
+ t_basic_restr *restr = NULL;
+ t_value_holder *src = NULL;
+ crestriction = talloc_zero(ctx, struct wsp_crestriction);
+ if (crestriction == NULL) {
+ DBG_ERR("out of memory\n");
+ goto done;
+ }
+
+ restr = query->basic_restriction;
+ src = restr->values;
+
+ if (restr->prop_type == RTNONE) {
+ /* shouldn't end up here */
+ DBG_ERR("Unexpected t_basic_restr type\n");
+ TALLOC_FREE(crestriction);
+ goto done;
+ }
+
+ crestriction->weight = 1000;
+
+ if (restr->prop_type == RTCONTENT) {
+ struct wsp_ccontentrestriction *content = NULL;
+ crestriction->ultype = RTCONTENT;
+ if (src->type != STRING) {
+ DBG_ERR("expected string value for %s\n",
+ query->prop);
+ TALLOC_FREE(crestriction);
+ goto done;
+ }
+ content = &crestriction->restriction.ccontentrestriction;
+ content->pwcsphrase = src->value.string;
+ content->cc = strlen(src->value.string);
+ /*
+ * In the future we might generate the lcid from
+ * environ (or config)
+ */
+ content->lcid = WSP_DEFAULT_LCID;
+ if (restr->op == eEQUALS) {
+ content->ulgeneratemethod = 0;
+ } else {
+ content->ulgeneratemethod = 1;
+ }
+
+ prop = &content->property;
+ } else if (restr->prop_type == RTPROPERTY) {
+ struct wsp_cbasestoragevariant *dest =
+ &crestriction->restriction.cpropertyrestriction.prval;
+ crestriction->ultype = RTPROPERTY;
+ if (!process_prop_value(ctx, query->prop_info, src, dest)) {
+ DBG_ERR("Failed to process value for property %s\n",
+ query->prop);
+ TALLOC_FREE(crestriction);
+ goto done;
+ }
+ crestriction->restriction.cpropertyrestriction.relop =
+ restr->op;
+ prop = &crestriction->restriction.cpropertyrestriction.property;
+ } else {
+ TALLOC_FREE(crestriction);
+ goto done;
+ }
+ prop->guidpropset = query->guid;
+ prop->ulkind = PRSPEC_PROPID;
+ prop->name_or_id.prspec = query->prop_info->id;
+done:
+ return crestriction;
+}
+
+/* expands restr_node into a tree of t_query nodes */
+static void build_query(TALLOC_CTX *ctx, t_query *node, t_restr *restr_node,
+ const char* prop)
+{
+ if (!node) {
+ return;
+ }
+ if (!restr_node) {
+ return;
+ }
+
+ node->type = restr_node->type;
+
+ if (restr_node->left) {
+ node->left = talloc_zero(ctx, t_query);
+ SMB_ASSERT(node->left != NULL);
+ build_query(ctx, node->left, restr_node->left, prop);
+ }
+
+ if (restr_node->right) {
+ node->right = talloc_zero(ctx, t_query);
+ SMB_ASSERT(node->right != NULL);
+ build_query(ctx, node->right, restr_node->right, prop);
+ }
+
+ if (restr_node->type == eVALUE) {
+ node->restriction =
+ create_restriction(ctx,
+ create_basic_query(ctx,
+ prop,
+ restr_node->basic_restr));
+ }
+}
+
+t_query *create_query_node(TALLOC_CTX *ctx, t_nodetype op, t_query *left, t_query *right, t_basic_query *value)
+{
+ t_query *result = talloc_zero(ctx, t_query);
+ if (result == NULL) {
+ return result;
+ }
+ result->type = op;
+ result->left = left;
+ result->right = right;
+ if (op == eVALUE) {
+ t_basic_restr *restr = value->basic_restriction;
+ /* expand restr node */
+ if (restr->values->type == RESTR) {
+ build_query(ctx,
+ result,
+ restr->values->value.restr_tree,
+ value->prop);
+ } else {
+ result->restriction =
+ create_restriction(ctx, value);
+ if (!result->restriction) {
+ TALLOC_FREE(result);
+ }
+ }
+ }
+ return result;
+}
+
+t_restr *create_restr(TALLOC_CTX *ctx, t_nodetype op, t_restr *left, t_restr *right, t_basic_restr *value)
+{
+ t_restr *result = talloc_zero(ctx, t_restr);
+ if (result == NULL) {
+ return result;
+ }
+ result->type = op;
+ result->right = right;
+ result->left = left;
+ result->basic_restr = value;
+ return result;
+}
+
+t_value_holder *create_string_val(TALLOC_CTX* ctx, const char *text)
+{
+ t_value_holder *result =
+ talloc_zero(ctx, t_value_holder);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ result->value.string = text;
+ result->type = STRING;
+ return result;
+}
+
+t_value_holder *create_num_val(TALLOC_CTX* ctx, int64_t val)
+{
+ t_value_holder *result =
+ talloc_zero(ctx, t_value_holder);
+
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+
+ result->type = NUMBER;
+ result->value.number = val;
+ return result;
+}
+
+t_value_holder *create_bool_val(TALLOC_CTX* ctx, bool val)
+{
+ t_value_holder *result =
+ talloc_zero(ctx, t_value_holder);
+
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+
+ result->type = BOOL;
+ result->value.boolean = val;
+ return result;
+}
+
+t_value_holder *create_value_range(TALLOC_CTX* ctx,
+ t_value_holder *left,
+ t_value_holder *right)
+{
+ t_value_holder *result =
+ talloc_zero(ctx, t_value_holder);
+
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+
+ result->type = VALUE_RANGE;
+ result->value.value_range = talloc_zero(result, struct value_range);
+ if (!result->value.value_range) {
+ TALLOC_FREE(result);
+ goto out;
+ }
+ result->value.value_range->lower = left;
+ result->value.value_range->upper = right;
+out:
+ return result;
+}
+
+static void zero_time(struct tm *tm)
+{
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+}
+
+typedef bool (*daterange_func) (TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2);
+
+
+static bool create_date_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2,
+ int32_t lower_mday_adj,
+ int32_t lower_mon_adj,
+ int32_t upper_mday_adj,
+ int32_t upper_mon_adj)
+{
+ struct tm tm_now;
+ time_t now;
+
+ struct tm tm_tmp;
+ time_t lower;
+ time_t upper;
+
+ time(&now);
+ gmtime_r(&now, &tm_now);
+
+ tm_tmp = tm_now;
+ zero_time(&tm_tmp);
+ tm_tmp.tm_mday += lower_mday_adj;
+ tm_tmp.tm_mon += lower_mon_adj;
+ lower = mktime(&tm_tmp);
+ tm_tmp = tm_now;
+ zero_time(&tm_tmp);
+ tm_tmp.tm_mday += upper_mday_adj;
+ tm_tmp.tm_mon += upper_mon_adj;
+ upper = mktime(&tm_tmp);
+ unix_to_nt_time(date1, lower);
+ unix_to_nt_time(date2, upper);
+ return true;
+}
+
+static void get_now_tm(struct tm *tm_now)
+{
+ time_t now;
+ time(&now);
+ gmtime_r(&now, tm_now);
+}
+
+static bool create_thismonth_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ int32_t firstofmonth_adj;
+
+ get_now_tm(&tm_now);
+ firstofmonth_adj = 1 - tm_now.tm_mday;
+ return create_date_range(ctx, date1,
+ date2, firstofmonth_adj,
+ 0, firstofmonth_adj, 1);
+}
+
+static bool create_lastyear_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ int32_t firstofmonth_adj;
+ int32_t january_adj;
+ get_now_tm(&tm_now);
+
+ firstofmonth_adj = 1 - tm_now.tm_mday;
+ january_adj = -tm_now.tm_mon;
+ return create_date_range(ctx, date1,
+ date2, firstofmonth_adj,
+ january_adj - 12, firstofmonth_adj, january_adj);
+}
+
+static bool create_thisyear_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ int32_t firstofmonth_adj;
+ int32_t january_adj;
+
+ get_now_tm(&tm_now);
+
+ firstofmonth_adj = 1 - tm_now.tm_mday;
+ january_adj = -tm_now.tm_mon;
+ return create_date_range(ctx, date1,
+ date2, firstofmonth_adj,
+ january_adj, firstofmonth_adj, january_adj + 12);
+}
+
+static bool create_lastmonth_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ int32_t firstofmonth_adj;
+ get_now_tm(&tm_now);
+
+ firstofmonth_adj = 1 - tm_now.tm_mday;
+ return create_date_range(ctx, date1,
+ date2, firstofmonth_adj,
+ -1, firstofmonth_adj, 0);
+}
+
+static bool create_today_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ return create_date_range(ctx, date1,
+ date2, 0, 0, 1, 0);
+}
+
+static bool create_yesterday_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ return create_date_range(ctx, date1,
+ date2, -1, 0, 0, 0);
+}
+
+static bool create_thisweek_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ time_t now;
+ int32_t startofweek_adj;
+ time(&now);
+ gmtime_r(&now, &tm_now);
+ if (tm_now.tm_wday) {
+ startofweek_adj = 1 - tm_now.tm_wday;
+ } else {
+ startofweek_adj = -6;
+ }
+ /* lower will be the start of this week */
+ return create_date_range(ctx, date1,
+ date2, startofweek_adj,
+ 0, startofweek_adj + 7, 0);
+}
+
+static bool create_lastweek_range(TALLOC_CTX *ctx, uint64_t *date1,
+ uint64_t *date2)
+{
+ struct tm tm_now;
+ time_t now;
+ int32_t startofweek_adj;
+ time(&now);
+ gmtime_r(&now, &tm_now);
+ if (tm_now.tm_wday) {
+ startofweek_adj = 1 - tm_now.tm_wday;
+ } else {
+ startofweek_adj = -6;
+ }
+ /* upper will be the start of this week */
+ return create_date_range(ctx, date1,
+ date2, startofweek_adj - 7,
+ 0,startofweek_adj, 0);
+}
+
+t_value_holder *create_date_range_shortcut(TALLOC_CTX *ctx,
+ daterange_type daterange)
+{
+ int i;
+ static const struct {
+ daterange_type range;
+ daterange_func create_fn;
+ } date_conv_map[] = {
+ {eYESTERDAY, create_yesterday_range},
+ {eTODAY, create_today_range},
+ {eTHISMONTH, create_thismonth_range},
+ {eLASTMONTH, create_lastmonth_range},
+ {eTHISWEEK, create_thisweek_range},
+ {eLASTWEEK, create_lastweek_range},
+ {eTHISYEAR, create_thisyear_range},
+ {eLASTYEAR, create_lastyear_range},
+ };
+ t_value_holder *result = NULL;
+ t_value_holder *lower = NULL;
+ t_value_holder *upper = NULL;
+
+ lower = talloc_zero(ctx, t_value_holder);
+ if (lower == NULL) {
+ DBG_ERR("out of memory\n");
+ goto out;
+ }
+
+ upper = talloc_zero(ctx, t_value_holder);
+ if (upper == NULL) {
+ DBG_ERR("out of memory\n");
+ goto out;
+ }
+
+ result = create_value_range(result, lower, upper);
+
+ if (result == NULL) {
+ TALLOC_FREE(result);
+ goto out;
+ }
+
+ lower->type = NUMBER;
+ upper->type = NUMBER;
+
+ result->value.value_range->lower = lower;
+ result->value.value_range->upper = upper;
+
+ for (i = 0; i < ARRAY_SIZE(date_conv_map); i++) {
+ if (date_conv_map[i].range == daterange) {
+ if (!date_conv_map[i].create_fn(result,
+ &lower->value.number,
+ &upper->value.number)) {
+ TALLOC_FREE(result);
+ break;
+ }
+ break;
+ }
+ }
+out:
+ return result;
+}
+
+t_value_holder *create_size_range_shortcut(TALLOC_CTX *ctx,
+ sizerange_type sizerange)
+{
+ static const struct {
+ sizerange_type range;
+ uint32_t lower;
+ uint32_t upper;
+ } sizes[] = {
+ {eEMPTY, 0x0, 0x1},
+ {eTINY, 0x1, 0x2801},
+ {eSMALL, 0x2801, 0x19001},
+ {eMEDIUM, 0x19001, 0x100001},
+ {eLARGE, 0x100001, 0x10000001},
+ {eHUGE, 0x10000001, 0x80000001},
+ {eGIGANTIC, 0x80000001, 0} /* special case not a range */
+ };
+ int i;
+ t_value_holder *result = NULL;
+ uint32_t lower_size;
+ uint32_t upper_size;
+ bool rangefound = false;
+ t_value_holder *left = NULL;
+ t_value_holder *right = NULL;
+ for (i = 0; i < ARRAY_SIZE(sizes); i++) {
+ if (sizes[i].range == sizerange) {
+ result = talloc_zero(ctx, t_value_holder);
+ if (result == NULL) {
+ DBG_ERR("out of memory\n");
+ return NULL;
+ }
+ lower_size = sizes[i].lower;
+ upper_size = sizes[i].upper;
+ rangefound = true;
+ break;
+ }
+ }
+
+ if (!rangefound) {
+ return NULL;
+ }
+
+ left = talloc_zero(ctx, t_value_holder);
+
+ if (left == NULL) {
+ return NULL;
+ }
+
+ left->type = NUMBER;
+ left->value.number = lower_size;
+
+ if (upper_size) {
+ right = talloc_zero(ctx, t_value_holder);
+ if (right == NULL) {
+ return NULL;
+ }
+ right->type = NUMBER;
+ right->value.number = upper_size;
+ }
+
+ result = create_value_range(ctx, left, right);
+ return result;
+}
diff --git a/libcli/wsp/wsp_aqs.h b/libcli/wsp/wsp_aqs.h
new file mode 100644
index 0000000..b34dd52
--- /dev/null
+++ b/libcli/wsp/wsp_aqs.h
@@ -0,0 +1,166 @@
+/*
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 __WSP_AQS_H__
+#define __WSP_AQS_H__
+#include "librpc/gen_ndr/wsp.h"
+
+typedef enum nodetype
+{
+ eAND,
+ eOR,
+ eNOT,
+ eVALUE,
+} t_nodetype;
+
+typedef enum op
+{
+ eLT = PRLT,
+ eLE = PRLE,
+ eGT = PRGT,
+ eGE = PRGE,
+ eEQ = PREQ,
+ eNE = PRNE,
+ eSTARTSWITH,
+ eEQUALS,
+ /*
+ * eMATCHES,
+ *
+ * not sure we can express the above in the grammar without
+ * some custom operator :/
+ */
+} t_optype;
+
+struct restr;
+
+typedef enum {
+ NUMBER,
+ STRING,
+ BOOL,
+ RESTR,
+ VALUE_RANGE,
+} value_type;
+
+typedef enum {
+ eTODAY,
+ eYESTERDAY,
+ eLASTWEEK,
+ eTHISWEEK,
+ eTHISMONTH,
+ eLASTMONTH,
+ eTHISYEAR,
+ eLASTYEAR,
+} daterange_type;
+
+typedef enum {
+ eEMPTY,
+ eTINY,
+ eSMALL,
+ eMEDIUM,
+ eLARGE,
+ eHUGE,
+ eGIGANTIC,
+} sizerange_type;
+
+struct value_range;
+
+typedef struct {
+ value_type type;
+ union {
+ bool boolean;
+ const char *string;
+ uint64_t number;
+ struct restr *restr_tree;
+ struct value_range *value_range;
+ } value;
+} t_value_holder;
+
+struct value_range
+{
+ t_value_holder *lower;
+ t_value_holder *upper;
+};
+typedef struct basic_restr
+{
+ uint32_t prop_type;
+ t_optype op;
+ t_value_holder *values;
+} t_basic_restr;
+
+typedef struct basic_query
+{
+ struct GUID guid;
+ const struct full_propset_info *prop_info;
+ char *prop;
+ t_basic_restr *basic_restriction;
+} t_basic_query;
+
+t_basic_query *create_basic_query(TALLOC_CTX *ctx, const char *prop, t_basic_restr *restr);
+
+typedef struct restr
+{
+ t_nodetype type;
+ struct restr *left;
+ struct restr *right;
+ t_basic_restr *basic_restr;
+} t_restr;
+
+t_restr *create_restr(TALLOC_CTX *ctx, t_nodetype op, t_restr *left, t_restr *right, t_basic_restr *value);
+
+t_basic_restr *create_basic_restr(TALLOC_CTX *ctx,
+ uint32_t prop_type,
+ t_optype op,
+ t_value_holder *values);
+
+typedef struct query
+{
+ t_nodetype type;
+ struct query *left;
+ struct query *right;
+ struct wsp_crestriction *restriction;
+} t_query;
+
+t_query *create_query_node(TALLOC_CTX *ctx, t_nodetype op, t_query *left, t_query *right, t_basic_query *value);
+
+
+typedef struct col_list {
+ int num_cols;
+ char **cols;
+} t_col_list;
+
+typedef struct select_stmt {
+ t_col_list *cols;
+ t_query *where;
+} t_select_stmt;
+
+t_col_list *create_cols(TALLOC_CTX *ctx, const char *col, t_col_list *append_list);
+t_select_stmt *create_select(TALLOC_CTX *ctx, t_col_list *cols, t_query *where);
+
+t_select_stmt *get_wsp_sql_tree(const char *expr);
+t_value_holder *create_string_val(TALLOC_CTX*, const char *text);
+t_value_holder *create_num_val(TALLOC_CTX*, int64_t val);
+t_value_holder *create_bool_val(TALLOC_CTX*, bool val);
+t_value_holder *create_value_range(TALLOC_CTX*,
+ t_value_holder *left,
+ t_value_holder *right);
+t_value_holder *create_date_range_shortcut(TALLOC_CTX *ctx,
+ daterange_type daterange);
+t_value_holder *create_size_range_shortcut(TALLOC_CTX *ctx,
+ sizerange_type size);
+#endif /* __WSP_AQS_H__ */
diff --git a/libcli/wsp/wsp_aqs_lexer.l b/libcli/wsp/wsp_aqs_lexer.l
new file mode 100644
index 0000000..dff4c10
--- /dev/null
+++ b/libcli/wsp/wsp_aqs_lexer.l
@@ -0,0 +1,152 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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/wsp/wsp_aqs.h"
+#include "libcli/wsp/wsp_aqs_parser.tab.h"
+
+
+#include <stdio.h>
+
+#define YY_NO_INPUT
+
+%}
+
+%option warn nodefault nounput
+
+%option reentrant noyywrap never-interactive nounistd
+%option bison-bridge
+
+LPAREN "("
+RPAREN ")"
+AND "AND"
+OR "OR"
+NOT "NOT"
+EQ "=="
+NE "!="
+GE ">="
+LE "<="
+LESS "<"
+GREATER ">"
+COMMA ","
+WHERE "WHERE"
+SELECT "SELECT"
+PROP_EQUALS ":"
+TRUE "true"
+FALSE "false"
+
+TODAY "today"
+YESTERDAY "yesterday"
+THISWEEK "thisweek"
+LASTWEEK "lastweek"
+THISMONTH "thismonth"
+LASTMONTH "lastmonth"
+THISYEAR "thisyear"
+LASTYEAR "lastyear"
+
+EMPTY "empty"
+TINY "tiny"
+SMALL "small"
+MEDIUM "medium"
+LARGE "large"
+HUGE "huge"
+GIGANTIC "gigantic"
+
+STARTS_WITH "$<"
+EQUALS "$="
+K "K"
+M "M"
+G "G"
+T "T"
+KB "KB"
+MB "MB"
+GB "GB"
+TB "TB"
+RANGE "-"
+
+
+NUMBER [0-9]+
+WS [ \r\n\t]*
+IDENTIFIER [a-z\."A-Z_][a-z\."A-Z_0-9]*
+STRING_LITERAL L?\"(\\.|[^\\"])*\"
+
+%%
+
+{WS} { /* Skip blanks. */ }
+
+{NUMBER} { sscanf(yytext, "%"PRId64, &yylval->num); return TOKEN_NUMBER; }
+
+{AND} { return TOKEN_AND; }
+{OR} { return TOKEN_OR; }
+{NOT} { return TOKEN_NOT; }
+{EQ} { return TOKEN_EQ; }
+{NE} { return TOKEN_NE; }
+{GE} { return TOKEN_GE; }
+{LE} { return TOKEN_LE; }
+{LESS} { return TOKEN_LT; }
+{GREATER} { return TOKEN_GT; }
+{LPAREN} { return TOKEN_LPAREN; }
+{RPAREN} { return TOKEN_RPAREN; }
+{COMMA} { return TOKEN_COMMA; }
+{WHERE} { return TOKEN_WHERE; }
+{SELECT} { return TOKEN_SELECT; }
+{TRUE} { return TOKEN_TRUE; }
+{FALSE} { return TOKEN_FALSE; }
+{PROP_EQUALS} { return TOKEN_PROP_EQUALS; }
+
+{STARTS_WITH} { return TOKEN_STARTS_WITH;}
+{EQUALS} { return TOKEN_EQUALS;}
+
+{K} { return TOKEN_K; }
+{M} { return TOKEN_M; }
+{G} { return TOKEN_G; }
+{T} { return TOKEN_T; }
+{KB} { return TOKEN_KB; }
+{MB} { return TOKEN_MB; }
+{GB} { return TOKEN_GB; }
+{TB} { return TOKEN_TB; }
+{RANGE} { return TOKEN_RANGE; }
+{TODAY} { return TOKEN_TODAY; }
+{YESTERDAY} { return TOKEN_YESTERDAY;}
+{THISWEEK} { return TOKEN_THISWEEK;}
+{LASTWEEK} { return TOKEN_LASTWEEK;}
+{THISMONTH} { return TOKEN_THISMONTH; }
+{LASTMONTH} { return TOKEN_LASTMONTH; }
+{THISYEAR} { return TOKEN_THISYEAR; }
+{LASTYEAR} { return TOKEN_LASTYEAR; }
+{EMPTY} { return TOKEN_EMPTY; }
+{TINY} { return TOKEN_TINY; }
+{SMALL} { return TOKEN_SMALL; }
+{MEDIUM} { return TOKEN_MEDIUM; }
+{LARGE} { return TOKEN_LARGE; }
+{HUGE} { return TOKEN_HUGE; }
+{GIGANTIC} { return TOKEN_GIGANTIC; }
+
+
+{STRING_LITERAL} { yylval->strval = talloc_asprintf(talloc_tos(), "%s", yytext); return TOKEN_STRING_LITERAL; }
+
+{IDENTIFIER} { yylval->strval = talloc_asprintf(talloc_tos(), "%s", yytext); return TOKEN_IDENTIFIER; }
+. { }
+
+%%
+
diff --git a/libcli/wsp/wsp_aqs_parser.y b/libcli/wsp/wsp_aqs_parser.y
new file mode 100644
index 0000000..2b0d7bd
--- /dev/null
+++ b/libcli/wsp/wsp_aqs_parser.y
@@ -0,0 +1,422 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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/wsp/wsp_aqs.h"
+#include "libcli/wsp/wsp_aqs_parser.tab.h"
+#include "libcli/wsp/wsp_aqs_lexer.h"
+
+static int yyerror(t_select_stmt **stmt, yyscan_t scanner, const char *msg)
+{
+ fprintf(stderr,"Error :%s\n",msg); return 0;
+}
+%}
+%code requires {
+
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+}
+
+%define api.pure
+%lex-param { yyscan_t scanner }
+%parse-param { t_select_stmt **select }
+%parse-param { yyscan_t scanner }
+
+%union {
+ char *strval;
+ int64_t num;
+ t_value_holder *value;
+ t_select_stmt *select_stmt;
+ t_select_stmt *query_stmt;
+ t_basic_restr *bas_rest;
+ t_basic_query *bas_query;
+ t_restr *restr;
+ t_query *query;
+ t_col_list *columns;
+ daterange_type daterange;
+ sizerange_type sizerange;
+ t_optype prop_op;
+}
+
+%left "AND" TOKEN_AND
+%left "OR" TOKEN_OR
+%left "!=" TOKEN_NE
+%left ">=" TOKEN_GE
+%left "<=" TOKEN_LE
+%left "<" TOKEN_LT
+%left ">" TOKEN_GT
+%right "NOT" TOKEN_NOT
+%right "==" TOKEN_EQ
+%right ":" TOKEN_PROP_EQUALS
+
+%right "$<" TOKEN_STARTS_WITH
+%right "$=" TOKEN_EQUALS
+
+%token TOKEN_LPAREN
+%token TOKEN_RPAREN
+%token TOKEN_AND
+%token TOKEN_OR
+%token TOKEN_WHERE
+%token TOKEN_SELECT
+%token TOKEN_TRUE
+%token TOKEN_FALSE
+%token TOKEN_COMMA
+%token TOKEN_STARTS_WITH
+%token TOKEN_EQUALS
+%token TOKEN_MATCHES
+%token TOKEN_K
+%token TOKEN_M
+%token TOKEN_G
+%token TOKEN_T
+%token TOKEN_KB
+%token TOKEN_MB
+%token TOKEN_GB
+%token TOKEN_TB
+%token TOKEN_RANGE
+%token TOKEN_TODAY
+%token TOKEN_YESTERDAY
+%token TOKEN_THISWEEK
+%token TOKEN_LASTWEEK
+%token TOKEN_THISMONTH
+%token TOKEN_LASTMONTH
+%token TOKEN_THISYEAR
+%token TOKEN_LASTYEAR
+%token TOKEN_EMPTY
+%token TOKEN_TINY
+%token TOKEN_SMALL
+%token TOKEN_MEDIUM
+%token TOKEN_LARGE
+%token TOKEN_HUGE
+%token TOKEN_GIGANTIC
+
+%token <num> TOKEN_NUMBER
+%token <strval> TOKEN_IDENTIFIER
+%token <strval> TOKEN_STRING_LITERAL
+
+%type <strval> prop
+%type <bas_rest> basic_restr
+%type <restr> restr
+%type <bas_query> basic_query
+%type <query> query
+%type <columns> cols
+%type <strval> col
+%type <select_stmt> select_stmt
+%type <value> simple_value
+%type <value> value
+%type <daterange> date_shortcut
+%type <prop_op> property_op
+%type <prop_op> content_op
+%type <sizerange> size_shortcut
+
+%%
+
+input:
+ select_stmt {
+ *select = $1;
+ }
+;
+
+select_stmt:
+ TOKEN_SELECT cols[C] TOKEN_WHERE query[Q] {
+ $$ = create_select(talloc_tos(), $C, $Q );
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | query[Q] {
+ $$ = create_select(talloc_tos(), NULL, $Q );
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+cols :
+ col[C] {
+ $$ = create_cols(talloc_tos(), $1, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | col[C] TOKEN_COMMA cols[CS] {
+ $$ = create_cols(talloc_tos(), $C, $CS);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+col:
+ TOKEN_IDENTIFIER[I] {
+ $$ = $I;
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+query:
+ basic_query {
+ $$ = create_query_node(talloc_tos(), eVALUE, NULL, NULL, $1);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_LPAREN query[Q] TOKEN_RPAREN {
+ $$ = $Q;
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | query[L] TOKEN_AND query[R] {
+ $$ = create_query_node(talloc_tos(), eAND, $L, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | query[L] TOKEN_OR query[R] {
+ $$ = create_query_node(talloc_tos(), eOR, $L, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NOT query[R] {
+ $$ = create_query_node(talloc_tos(), eNOT, NULL, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+basic_query:
+ prop[P] TOKEN_PROP_EQUALS basic_restr[V] {
+ $$ = create_basic_query(talloc_tos(), $P, $V);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+prop: TOKEN_IDENTIFIER[I] {
+ $$ = $I;
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+basic_restr:
+ value[V] {
+ $$ = create_basic_restr(talloc_tos(), RTPROPERTY, eEQ, $V);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | property_op[P] value[T] {
+ $$ = create_basic_restr(talloc_tos(), RTPROPERTY, $P, $T);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | content_op[P] value[T] {
+ $$ = create_basic_restr(talloc_tos(), RTCONTENT, $P, $T);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_LPAREN restr[R] TOKEN_RPAREN {
+ t_value_holder *holder = talloc_zero(talloc_tos(), t_value_holder);
+ holder->type = RESTR;
+ holder->value.restr_tree = $R;
+ $$ = create_basic_restr(talloc_tos(), RTNONE, eEQ, holder);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+property_op:
+ TOKEN_EQ { $$ = eEQ; }
+ | TOKEN_NE { $$ = eNE; }
+ | TOKEN_GE { $$ = eGE; }
+ | TOKEN_LE { $$ = eLE; }
+ | TOKEN_LT { $$ = eLT; }
+ | TOKEN_GT { $$ = eGT; }
+ ;
+
+content_op:
+ TOKEN_STARTS_WITH { $$ = eSTARTSWITH; }
+ | TOKEN_EQUALS { $$ = eEQUALS; }
+ ;
+
+value:
+ simple_value[V] { $$ = $V;}
+ | simple_value[L] TOKEN_RANGE simple_value[R] {
+ $$ = create_value_range(talloc_tos(), $L, $R);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | date_shortcut[D] {
+ $$ = create_date_range_shortcut(talloc_tos(), $D);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | size_shortcut[S] {
+ $$ = create_size_range_shortcut(talloc_tos(), $S);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+date_shortcut:
+ TOKEN_TODAY { $$ = eTODAY; }
+ | TOKEN_YESTERDAY { $$ = eYESTERDAY; }
+ | TOKEN_THISWEEK { $$ = eTHISWEEK; }
+ | TOKEN_LASTWEEK { $$ = eLASTWEEK; }
+ | TOKEN_THISMONTH { $$ = eTHISMONTH; }
+ | TOKEN_LASTMONTH { $$ = eTHISMONTH; }
+ | TOKEN_THISYEAR { $$ = eTHISYEAR; }
+ | TOKEN_LASTYEAR { $$ = eLASTYEAR; }
+ ;
+
+size_shortcut:
+ TOKEN_EMPTY { $$ = eEMPTY; }
+ | TOKEN_TINY { $$ = eTINY; }
+ | TOKEN_SMALL { $$ = eSMALL; }
+ | TOKEN_MEDIUM { $$ = eMEDIUM; }
+ | TOKEN_LARGE { $$ = eLARGE; }
+ | TOKEN_HUGE { $$ = eHUGE; }
+ | TOKEN_GIGANTIC { $$ = eGIGANTIC; }
+ ;
+
+simple_value:
+ TOKEN_NUMBER[N] {
+ $$ = create_num_val(talloc_tos(), $N);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_K {
+ $$ = create_num_val(talloc_tos(), $N * 1024);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_M {
+ $$ = create_num_val( talloc_tos(), $N * 1024 * 1024);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_G {
+ $$ = create_num_val(talloc_tos(), $N * 1024 * 1024 * 1024);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_T {
+ $$ = create_num_val(talloc_tos(),
+ $N * 1024 * 1024 * 1024 * 1024);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_KB {
+ $$ = create_num_val(talloc_tos(), $N * 1000);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_MB {
+ $$ = create_num_val( talloc_tos(), $N * 1000 * 1000);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_GB {
+ $$ = create_num_val(talloc_tos(), $N * 1000 * 1000 * 1000);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_NUMBER[N] TOKEN_TB {
+ $$ = create_num_val(talloc_tos(),
+ $N * 1000 * 1000 * 1000 * 1000);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_TRUE {
+ $$ = create_bool_val(talloc_tos(), true);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_FALSE {
+ $$ = create_num_val(talloc_tos(), false);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_STRING_LITERAL[S] {
+ char *tmp_str = talloc_strdup(talloc_tos(), $S+1);
+ tmp_str[strlen(tmp_str)-1] = '\0';
+ $$ = create_string_val(talloc_tos(), tmp_str);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | TOKEN_IDENTIFIER[I] {
+ $$ = create_string_val(talloc_tos(), $I);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+
+restr: basic_restr[V] {
+ $$ = create_restr(talloc_tos(), eVALUE, NULL, NULL, $V);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | restr[L] TOKEN_AND restr[R] {
+ $$ = create_restr(talloc_tos(), eAND, $L, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ | restr[L] TOKEN_OR restr[R] {
+ $$ = create_restr(talloc_tos(), eOR, $L, $R, NULL);
+ if (!$$) {
+ YYERROR;
+ }
+ }
+ ;
+%%
diff --git a/libds/common/flag_mapping.c b/libds/common/flag_mapping.c
new file mode 100644
index 0000000..fb64014
--- /dev/null
+++ b/libds/common/flag_mapping.c
@@ -0,0 +1,266 @@
+/*
+ Unix SMB/CIFS implementation.
+ helper mapping functions for the UF and ACB flags
+
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Matthias Dieter Wallnöfer 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.h"
+#include "lib/util/data_blob.h"
+#include "lib/util/time.h"
+#include "lib/util/debug.h"
+#include "librpc/gen_ndr/samr.h"
+#include "../libds/common/flags.h"
+#include "flag_mapping.h"
+
+/*
+translated the ACB_CTRL Flags to UserFlags (userAccountControl)
+*/
+/* mapping between ADS userAccountControl and SAMR acct_flags */
+static const struct {
+ uint32_t uf;
+ uint32_t acb;
+} acct_flags_map[] = {
+ { UF_ACCOUNTDISABLE, ACB_DISABLED },
+ { UF_HOMEDIR_REQUIRED, ACB_HOMDIRREQ },
+ { UF_PASSWD_NOTREQD, ACB_PWNOTREQ },
+ { UF_TEMP_DUPLICATE_ACCOUNT, ACB_TEMPDUP },
+ { UF_NORMAL_ACCOUNT, ACB_NORMAL },
+ { UF_MNS_LOGON_ACCOUNT, ACB_MNS },
+ { UF_INTERDOMAIN_TRUST_ACCOUNT, ACB_DOMTRUST },
+ { UF_WORKSTATION_TRUST_ACCOUNT, ACB_WSTRUST },
+ { UF_SERVER_TRUST_ACCOUNT, ACB_SVRTRUST },
+ { UF_DONT_EXPIRE_PASSWD, ACB_PWNOEXP },
+ { UF_LOCKOUT, ACB_AUTOLOCK },
+ { UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED, ACB_ENC_TXT_PWD_ALLOWED },
+ { UF_SMARTCARD_REQUIRED, ACB_SMARTCARD_REQUIRED },
+ { UF_TRUSTED_FOR_DELEGATION, ACB_TRUSTED_FOR_DELEGATION },
+ { UF_NOT_DELEGATED, ACB_NOT_DELEGATED },
+ { UF_USE_DES_KEY_ONLY, ACB_USE_DES_KEY_ONLY},
+ { UF_DONT_REQUIRE_PREAUTH, ACB_DONT_REQUIRE_PREAUTH },
+ { UF_PASSWORD_EXPIRED, ACB_PW_EXPIRED },
+ { UF_NO_AUTH_DATA_REQUIRED, ACB_NO_AUTH_DATA_REQD },
+ { UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION, ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION },
+ { UF_PARTIAL_SECRETS_ACCOUNT, ACB_PARTIAL_SECRETS_ACCOUNT },
+ { UF_USE_AES_KEYS, ACB_USE_AES_KEYS }
+};
+
+uint32_t ds_acb2uf(uint32_t acb)
+{
+ unsigned int i;
+ uint32_t ret = 0;
+ for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) {
+ if (acct_flags_map[i].acb & acb) {
+ ret |= acct_flags_map[i].uf;
+ }
+ }
+ return ret;
+}
+
+/*
+translated the UserFlags (userAccountControl) to ACB_CTRL Flags
+*/
+uint32_t ds_uf2acb(uint32_t uf)
+{
+ unsigned int i;
+ uint32_t ret = 0;
+ for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) {
+ if (acct_flags_map[i].uf & uf) {
+ ret |= acct_flags_map[i].acb;
+ }
+ }
+ return ret;
+}
+
+/*
+get the accountType from the UserFlags
+*/
+uint32_t ds_uf2atype(uint32_t uf)
+{
+ uint32_t atype = 0x00000000;
+
+ if (uf & UF_NORMAL_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
+ else if (uf & UF_TEMP_DUPLICATE_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
+ else if (uf & UF_SERVER_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
+ else if (uf & UF_WORKSTATION_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
+ else if (uf & UF_INTERDOMAIN_TRUST_ACCOUNT) atype = ATYPE_INTERDOMAIN_TRUST;
+
+ return atype;
+}
+
+/*
+get the accountType from the groupType
+*/
+uint32_t ds_gtype2atype(uint32_t gtype)
+{
+ uint32_t atype = 0x00000000;
+
+ switch(gtype) {
+ case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
+ atype = ATYPE_SECURITY_LOCAL_GROUP;
+ break;
+ case GTYPE_SECURITY_GLOBAL_GROUP:
+ atype = ATYPE_SECURITY_GLOBAL_GROUP;
+ break;
+ case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
+ atype = ATYPE_SECURITY_LOCAL_GROUP;
+ break;
+ case GTYPE_SECURITY_UNIVERSAL_GROUP:
+ atype = ATYPE_SECURITY_UNIVERSAL_GROUP;
+ break;
+
+ case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_GLOBAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_LOCAL_GROUP;
+ break;
+ case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
+ atype = ATYPE_DISTRIBUTION_UNIVERSAL_GROUP;
+ break;
+ }
+
+ return atype;
+}
+
+/* turn a sAMAccountType into a SID_NAME_USE */
+enum lsa_SidType ds_atype_map(uint32_t atype)
+{
+ switch (atype & 0xF0000000) {
+ case ATYPE_GLOBAL_GROUP:
+ return SID_NAME_DOM_GRP;
+ case ATYPE_SECURITY_LOCAL_GROUP:
+ return SID_NAME_ALIAS;
+ case ATYPE_ACCOUNT:
+ return SID_NAME_USER;
+ default:
+ DEBUG(1,("hmm, need to map account type 0x%x\n", atype));
+ }
+ return SID_NAME_UNKNOWN;
+}
+
+/* get the default primary group RID for a given userAccountControl
+ * (information according to MS-SAMR 3.1.1.8.1) */
+uint32_t ds_uf2prim_group_rid(uint32_t uf)
+{
+ uint32_t prim_group_rid = DOMAIN_RID_USERS;
+
+ if ((uf & UF_PARTIAL_SECRETS_ACCOUNT)
+ && (uf & UF_WORKSTATION_TRUST_ACCOUNT)) prim_group_rid = DOMAIN_RID_READONLY_DCS;
+ else if (uf & UF_SERVER_TRUST_ACCOUNT) prim_group_rid = DOMAIN_RID_DCS;
+ else if (uf & UF_WORKSTATION_TRUST_ACCOUNT) prim_group_rid = DOMAIN_RID_DOMAIN_MEMBERS;
+
+ return prim_group_rid;
+}
+
+const char *dsdb_user_account_control_flag_bit_to_string(uint32_t uf)
+{
+ switch (uf) {
+ case UF_SCRIPT:
+ return "UF_SCRIPT";
+ break;
+ case UF_ACCOUNTDISABLE:
+ return "UF_ACCOUNTDISABLE";
+ break;
+ case UF_00000004:
+ return "UF_00000004";
+ break;
+ case UF_HOMEDIR_REQUIRED:
+ return "UF_HOMEDIR_REQUIRED";
+ break;
+ case UF_LOCKOUT:
+ return "UF_LOCKOUT";
+ break;
+ case UF_PASSWD_NOTREQD:
+ return "UF_PASSWD_NOTREQD";
+ break;
+ case UF_PASSWD_CANT_CHANGE:
+ return "UF_PASSWD_CANT_CHANGE";
+ break;
+ case UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED:
+ return "UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED";
+ break;
+
+ case UF_TEMP_DUPLICATE_ACCOUNT:
+ return "UF_TEMP_DUPLICATE_ACCOUNT";
+ break;
+ case UF_NORMAL_ACCOUNT:
+ return "UF_NORMAL_ACCOUNT";
+ break;
+ case UF_00000400:
+ return "UF_00000400";
+ break;
+ case UF_INTERDOMAIN_TRUST_ACCOUNT:
+ return "UF_INTERDOMAIN_TRUST_ACCOUNT";
+ break;
+
+ case UF_WORKSTATION_TRUST_ACCOUNT:
+ return "UF_WORKSTATION_TRUST_ACCOUNT";
+ break;
+ case UF_SERVER_TRUST_ACCOUNT:
+ return "UF_SERVER_TRUST_ACCOUNT";
+ break;
+ case UF_00004000:
+ return "UF_00004000";
+ break;
+ case UF_00008000:
+ return "UF_00008000";
+ break;
+
+ case UF_DONT_EXPIRE_PASSWD:
+ return "UF_DONT_EXPIRE_PASSWD";
+ break;
+ case UF_MNS_LOGON_ACCOUNT:
+ return "UF_MNS_LOGON_ACCOUNT";
+ break;
+ case UF_SMARTCARD_REQUIRED:
+ return "UF_SMARTCARD_REQUIRED";
+ break;
+ case UF_TRUSTED_FOR_DELEGATION:
+ return "UF_TRUSTED_FOR_DELEGATION";
+ break;
+
+ case UF_NOT_DELEGATED:
+ return "UF_NOT_DELEGATED";
+ break;
+ case UF_USE_DES_KEY_ONLY:
+ return "UF_USE_DES_KEY_ONLY";
+ break;
+ case UF_DONT_REQUIRE_PREAUTH:
+ return "UF_DONT_REQUIRE_PREAUTH";
+ break;
+ case UF_PASSWORD_EXPIRED:
+ return "UF_PASSWORD_EXPIRED";
+ break;
+ case UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION:
+ return "UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION";
+ break;
+ case UF_NO_AUTH_DATA_REQUIRED:
+ return "UF_NO_AUTH_DATA_REQUIRED";
+ break;
+ case UF_PARTIAL_SECRETS_ACCOUNT:
+ return "UF_PARTIAL_SECRETS_ACCOUNT";
+ break;
+ case UF_USE_AES_KEYS:
+ return "UF_USE_AES_KEYS";
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
diff --git a/libds/common/flag_mapping.h b/libds/common/flag_mapping.h
new file mode 100644
index 0000000..f08d559
--- /dev/null
+++ b/libds/common/flag_mapping.h
@@ -0,0 +1,36 @@
+/*
+ Unix SMB/CIFS implementation.
+ helper mapping functions for the UF and ACB flags
+
+ Copyright (C) Stefan (metze) Metzmacher 2002
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Matthias Dieter Wallnöfer 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 __LIBDS_COMMON_FLAG_MAPPING_H__
+#define __LIBDS_COMMON_FLAG_MAPPING_H__
+
+/* The following definitions come from flag_mapping.c */
+
+uint32_t ds_acb2uf(uint32_t acb);
+uint32_t ds_uf2acb(uint32_t uf);
+uint32_t ds_uf2atype(uint32_t uf);
+uint32_t ds_gtype2atype(uint32_t gtype);
+enum lsa_SidType ds_atype_map(uint32_t atype);
+uint32_t ds_uf2prim_group_rid(uint32_t uf);
+const char *dsdb_user_account_control_flag_bit_to_string(uint32_t uf);
+
+#endif /* __LIBDS_COMMON_FLAG_MAPPING_H__ */
diff --git a/libds/common/flags.h b/libds/common/flags.h
new file mode 100644
index 0000000..e8e5d62
--- /dev/null
+++ b/libds/common/flags.h
@@ -0,0 +1,309 @@
+/*
+ Unix SMB/CIFS implementation.
+ User/Group specific flags
+
+ Copyright (C) Andrew Tridgell 2001-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/>.
+*/
+
+/* Please keep this list in sync with the flag_mapping.c and pydsdb.c */
+
+/* User flags for "userAccountControl" */
+#define UF_SCRIPT 0x00000001 /* NT or Lan Manager Login script must be executed */
+#define UF_ACCOUNTDISABLE 0x00000002
+#define UF_00000004 0x00000004
+#define UF_HOMEDIR_REQUIRED 0x00000008
+
+#define UF_LOCKOUT 0x00000010
+#define UF_PASSWD_NOTREQD 0x00000020
+#define UF_PASSWD_CANT_CHANGE 0x00000040
+#define UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x00000080
+
+#define UF_TEMP_DUPLICATE_ACCOUNT 0x00000100 /* Local user account in usrmgr */
+#define UF_NORMAL_ACCOUNT 0x00000200
+#define UF_00000400 0x00000400
+#define UF_INTERDOMAIN_TRUST_ACCOUNT 0x00000800
+
+#define UF_WORKSTATION_TRUST_ACCOUNT 0x00001000
+#define UF_SERVER_TRUST_ACCOUNT 0x00002000
+#define UF_00004000 0x00004000
+#define UF_00008000 0x00008000
+
+#define UF_DONT_EXPIRE_PASSWD 0x00010000
+#define UF_MNS_LOGON_ACCOUNT 0x00020000
+#define UF_SMARTCARD_REQUIRED 0x00040000
+#define UF_TRUSTED_FOR_DELEGATION 0x00080000
+
+#define UF_NOT_DELEGATED 0x00100000
+#define UF_USE_DES_KEY_ONLY 0x00200000
+#define UF_DONT_REQUIRE_PREAUTH 0x00400000
+#define UF_PASSWORD_EXPIRED 0x00800000
+#define UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION 0x01000000
+#define UF_NO_AUTH_DATA_REQUIRED 0x02000000
+#define UF_PARTIAL_SECRETS_ACCOUNT 0x04000000
+#define UF_USE_AES_KEYS 0x08000000
+
+/* Please keep this list in sync with the flag_mapping.c and pydsdb.c */
+
+
+#define UF_TRUST_ACCOUNT_MASK (\
+ UF_INTERDOMAIN_TRUST_ACCOUNT |\
+ UF_WORKSTATION_TRUST_ACCOUNT |\
+ UF_SERVER_TRUST_ACCOUNT \
+ )
+
+#define UF_ACCOUNT_TYPE_MASK (\
+ UF_TEMP_DUPLICATE_ACCOUNT |\
+ UF_NORMAL_ACCOUNT |\
+ UF_INTERDOMAIN_TRUST_ACCOUNT |\
+ UF_WORKSTATION_TRUST_ACCOUNT |\
+ UF_SERVER_TRUST_ACCOUNT \
+ )
+
+/*
+ * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are ignored by
+ * clients and servers. Other flags (like UF_LOCKOUT have special
+ * behaviours, but are not set in the traditional sense).
+ *
+ * See the samldb module for the use of this define.
+ */
+
+#define UF_SETTABLE_BITS (\
+ UF_ACCOUNTDISABLE |\
+ UF_HOMEDIR_REQUIRED |\
+ UF_PASSWD_NOTREQD |\
+ UF_ACCOUNT_TYPE_MASK | \
+ UF_DONT_EXPIRE_PASSWD | \
+ UF_MNS_LOGON_ACCOUNT |\
+ UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED |\
+ UF_SMARTCARD_REQUIRED |\
+ UF_TRUSTED_FOR_DELEGATION |\
+ UF_NOT_DELEGATED |\
+ UF_USE_DES_KEY_ONLY |\
+ UF_DONT_REQUIRE_PREAUTH |\
+ UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION |\
+ UF_NO_AUTH_DATA_REQUIRED |\
+ UF_PARTIAL_SECRETS_ACCOUNT |\
+ UF_USE_AES_KEYS \
+ )
+
+/* Group flags for "groupType" */
+#define GROUP_TYPE_BUILTIN_LOCAL_GROUP 0x00000001
+#define GROUP_TYPE_ACCOUNT_GROUP 0x00000002
+#define GROUP_TYPE_RESOURCE_GROUP 0x00000004
+#define GROUP_TYPE_UNIVERSAL_GROUP 0x00000008
+#define GROUP_TYPE_APP_BASIC_GROUP 0x00000010
+#define GROUP_TYPE_APP_QUERY_GROUP 0x00000020
+#define GROUP_TYPE_SECURITY_ENABLED 0x80000000
+
+#define GTYPE_SECURITY_BUILTIN_LOCAL_GROUP ( \
+ /* 0x80000005 -2147483643 */ \
+ GROUP_TYPE_BUILTIN_LOCAL_GROUP| \
+ GROUP_TYPE_RESOURCE_GROUP| \
+ GROUP_TYPE_SECURITY_ENABLED \
+ )
+#define GTYPE_SECURITY_DOMAIN_LOCAL_GROUP ( \
+ /* 0x80000004 -2147483644 */ \
+ GROUP_TYPE_RESOURCE_GROUP| \
+ GROUP_TYPE_SECURITY_ENABLED \
+ )
+#define GTYPE_SECURITY_GLOBAL_GROUP ( \
+ /* 0x80000002 -2147483646 */ \
+ GROUP_TYPE_ACCOUNT_GROUP| \
+ GROUP_TYPE_SECURITY_ENABLED \
+ )
+#define GTYPE_SECURITY_UNIVERSAL_GROUP ( \
+ /* 0x80000008 -2147483640 */ \
+ GROUP_TYPE_UNIVERSAL_GROUP| \
+ GROUP_TYPE_SECURITY_ENABLED \
+ )
+#define GTYPE_DISTRIBUTION_GLOBAL_GROUP 0x00000002 /* 2 */
+#define GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP 0x00000004 /* 4 */
+#define GTYPE_DISTRIBUTION_UNIVERSAL_GROUP 0x00000008 /* 8 */
+
+/* Account flags for "sAMAccountType" */
+#define ATYPE_NORMAL_ACCOUNT 0x30000000 /* 805306368 */
+#define ATYPE_WORKSTATION_TRUST 0x30000001 /* 805306369 */
+#define ATYPE_INTERDOMAIN_TRUST 0x30000002 /* 805306370 */
+#define ATYPE_SECURITY_GLOBAL_GROUP 0x10000000 /* 268435456 */
+#define ATYPE_SECURITY_LOCAL_GROUP 0x20000000 /* 536870912 */
+#define ATYPE_SECURITY_UNIVERSAL_GROUP ATYPE_SECURITY_GLOBAL_GROUP
+#define ATYPE_DISTRIBUTION_GLOBAL_GROUP 0x10000001 /* 268435457 */
+#define ATYPE_DISTRIBUTION_LOCAL_GROUP 0x20000001 /* 536870913 */
+#define ATYPE_DISTRIBUTION_UNIVERSAL_GROUP ATYPE_DISTRIBUTION_GLOBAL_GROUP
+
+#define ATYPE_ACCOUNT ATYPE_NORMAL_ACCOUNT /* 0x30000000 805306368 */
+#define ATYPE_GLOBAL_GROUP ATYPE_SECURITY_GLOBAL_GROUP /* 0x10000000 268435456 */
+#define ATYPE_LOCAL_GROUP ATYPE_SECURITY_LOCAL_GROUP /* 0x20000000 536870912 */
+
+/* "instanceType" */
+#define INSTANCE_TYPE_IS_NC_HEAD 0x00000001
+#define INSTANCE_TYPE_UNINSTANT 0x00000002
+#define INSTANCE_TYPE_WRITE 0x00000004
+#define INSTANCE_TYPE_NC_ABOVE 0x00000008
+#define INSTANCE_TYPE_NC_COMING 0x00000010
+#define INSTANCE_TYPE_NC_GOING 0x00000020
+
+/* "systemFlags" */
+#define SYSTEM_FLAG_CR_NTDS_NC 0x00000001
+#define SYSTEM_FLAG_CR_NTDS_DOMAIN 0x00000002
+#define SYSTEM_FLAG_CR_NTDS_NOT_GC_REPLICATED 0x00000004
+#define SYSTEM_FLAG_SCHEMA_BASE_OBJECT 0x00000010
+#define SYSTEM_FLAG_ATTR_IS_RDN 0x00000020
+#define SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE 0x02000000
+#define SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE 0x04000000
+#define SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME 0x08000000
+#define SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE 0x10000000
+#define SYSTEM_FLAG_CONFIG_ALLOW_MOVE 0x20000000
+#define SYSTEM_FLAG_CONFIG_ALLOW_RENAME 0x40000000
+#define SYSTEM_FLAG_DISALLOW_DELETE 0x80000000
+
+/* schemaFlags_Ex */
+#define SCHEMA_FLAG_ATTR_IS_CRITICAL 0x0000001
+
+/* "searchFlags" */
+#define SEARCH_FLAG_ATTINDEX 0x0000001
+#define SEARCH_FLAG_PDNTATTINDEX 0x0000002
+#define SEARCH_FLAG_ANR 0x0000004
+#define SEARCH_FLAG_PRESERVEONDELETE 0x0000008
+#define SEARCH_FLAG_COPY 0x0000010
+#define SEARCH_FLAG_TUPLEINDEX 0x0000020
+#define SEARCH_FLAG_SUBTREEATTRINDEX 0x0000040
+#define SEARCH_FLAG_CONFIDENTIAL 0x0000080
+#define SEARCH_FLAG_NEVERVALUEAUDIT 0x0000100
+#define SEARCH_FLAG_RODC_ATTRIBUTE 0x0000200
+
+/* "domainFunctionality", "forestFunctionality" and "domainControllerFunctionality" in the rootDSE */
+#define DS_DOMAIN_FUNCTION_2000 0
+#define DS_DOMAIN_FUNCTION_2003_MIXED 1 /* Not a valid/meaningful
+ * domainControllerFunctionality
+ * Level */
+#define DS_DOMAIN_FUNCTION_2003 2
+#define DS_DOMAIN_FUNCTION_2008 3
+#define DS_DOMAIN_FUNCTION_2008_R2 4
+#define DS_DOMAIN_FUNCTION_2012 5
+#define DS_DOMAIN_FUNCTION_2012_R2 6
+#define DS_DOMAIN_FUNCTION_2016 7
+
+/* sa->systemFlags on attributes */
+#define DS_FLAG_ATTR_NOT_REPLICATED 0x00000001
+#define DS_FLAG_ATTR_REQ_PARTIAL_SET_MEMBER 0x00000002
+#define DS_FLAG_ATTR_IS_CONSTRUCTED 0x00000004
+
+/* 7.1.1.2.2.1.1 nTDSSiteSettings Object options */
+#define DS_NTDSSETTINGS_OPT_IS_AUTO_TOPOLOGY_DISABLED 0x00000001
+#define DS_NTDSSETTINGS_OPT_IS_TOPL_CLEANUP_DISABLED 0x00000002
+#define DS_NTDSSETTINGS_OPT_IS_TOPL_MIN_HOPS_DISABLED 0x00000004
+#define DS_NTDSSETTINGS_OPT_IS_TOPL_DETECT_STALE_DISABLED 0x00000008
+#define DS_NTDSSETTINGS_OPT_IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED 0x00000010
+#define DS_NTDSSETTINGS_OPT_IS_GROUP_CACHING_ENABLED 0x00000020
+#define DS_NTDSSETTINGS_OPT_FORCE_KCC_WHISTLER_BEHAVIOR 0x00000040
+#define DS_NTDSSETTINGS_OPT_IS_RAND_BH_SELECTION_DISABLED 0x00000100
+#define DS_NTDSSETTINGS_OPT_IS_SCHEDULE_HASHING_ENABLED 0x00000200
+#define DS_NTDSSETTINGS_OPT_IS_REDUNDANT_SERVER_TOPOLOGY_ENABLED 0x00000400
+
+/* 7.1.1.2.2.1.2.1.1 nTDSDSA Object options flags */
+#define DS_NTDSDSA_OPT_IS_GC 0x00000001
+#define DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL 0x00000002
+#define DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL 0x00000004
+#define DS_NTDSDSA_OPT_DISABLE_NTDSCONN_XLATE 0x00000008
+#define DS_NTDSDSA_OPT_DISABLE_SPN_REGISTRATION 0x00000010
+
+/* wellknown GUID strings for AD objects. See MS-ADTS 7.1.1.4 */
+#define DS_GUID_COMPUTERS_CONTAINER "AA312825768811D1ADED00C04FD8D5CD"
+#define DS_GUID_DELETED_OBJECTS_CONTAINER "18E2EA80684F11D2B9AA00C04F79F805"
+#define DS_GUID_DOMAIN_CONTROLLERS_CONTAINER "A361B2FFFFD211D1AA4B00C04FD7D83A"
+#define DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER "22B70C67D56E4EFB91E9300FCA3DC1AA"
+#define DS_GUID_INFRASTRUCTURE_CONTAINER "2FBAC1870ADE11D297C400C04FD8D5CD"
+#define DS_GUID_LOSTANDFOUND_CONTAINER "AB8153B7768811D1ADED00C04FD8D5CD"
+#define DS_GUID_MICROSOFT_PROGRAM_DATA_CONTAINER "F4BE92A4C777485E878E9421D53087DB"
+#define DS_GUID_NTDS_QUOTAS_CONTAINER "6227F0AF1FC2410D8E3BB10615BB5B0F"
+#define DS_GUID_PROGRAM_DATA_CONTAINER "09460C08AE1E4A4EA0F64AEE7DAA1E5A"
+#define DS_GUID_SYSTEMS_CONTAINER "AB1D30F3768811D1ADED00C04FD8D5CD"
+#define DS_GUID_USERS_CONTAINER "A9D1CA15768811D1ADED00C04FD8D5CD"
+#define DS_GUID_MANAGED_SERVICE_ACCOUNTS_CONTAINER "1EB93889E40C45DF9F0C64D23BBB6237"
+
+/* wellknown GUIDs for optional directory features */
+#define DS_GUID_FEATURE_RECYCLE_BIN "766ddcd8-acd0-445e-f3b9-a7f9b6744f2a"
+
+/* GUIDs for AD schema attributes and classes */
+#define DS_GUID_SCHEMA_ATTR_DEPARTMENT "bf96794f-0de6-11d0-a285-00aa003049e2"
+#define DS_GUID_SCHEMA_ATTR_DNS_HOST_NAME "72e39547-7b18-11d1-adef-00c04fd8d5cd"
+#define DS_GUID_SCHEMA_ATTR_INSTANCE_TYPE "bf96798c-0de6-11d0-a285-00aa003049e2"
+#define DS_GUID_SCHEMA_ATTR_MS_SFU_30 "16c5d1d3-35c2-4061-a870-a5cefda804f0"
+#define DS_GUID_SCHEMA_ATTR_NT_SECURITY_DESCRIPTOR "bf9679e3-0de6-11d0-a285-00aa003049e2"
+#define DS_GUID_SCHEMA_ATTR_PRIMARY_GROUP_ID "bf967a00-0de6-11d0-a285-00aa003049e2"
+#define DS_GUID_SCHEMA_ATTR_SERVICE_PRINCIPAL_NAME "f3a64788-5306-11d1-a9c5-0000f80367c1"
+#define DS_GUID_SCHEMA_ATTR_USER_ACCOUNT_CONTROL "bf967a68-0de6-11d0-a285-00aa003049e2"
+#define DS_GUID_SCHEMA_ATTR_USER_PASSWORD "bf967a6e-0de6-11d0-a285-00aa003049e2"
+#define DS_GUID_SCHEMA_CLASS_COMPUTER "bf967a86-0de6-11d0-a285-00aa003049e2"
+#define DS_GUID_SCHEMA_CLASS_MANAGED_SERVICE_ACCOUNT "ce206244-5827-4a86-ba1c-1c0c386c1b64"
+#define DS_GUID_SCHEMA_CLASS_USER "bf967aba-0de6-11d0-a285-00aa003049e2"
+
+/* dsHeuristics character indexes see MS-ADTS 7.1.1.2.4.1.2 */
+
+#define DS_HR_SUPFIRSTLASTANR 0x00000001
+#define DS_HR_SUPLASTFIRSTANR 0x00000002
+#define DS_HR_DOLISTOBJECT 0x00000003
+#define DS_HR_DONICKRES 0x00000004
+#define DS_HR_LDAP_USEPERMMOD 0x00000005
+#define DS_HR_HIDEDSID 0x00000006
+#define DS_HR_BLOCK_ANONYMOUS_OPS 0x00000007
+#define DS_HR_ALLOW_ANON_NSPI 0x00000008
+#define DS_HR_USER_PASSWORD_SUPPORT 0x00000009
+#define DS_HR_TENTH_CHAR 0x0000000A
+#define DS_HR_SPECIFY_GUID_ON_ADD 0x0000000B
+#define DS_HR_NO_STANDARD_SD 0x0000000C
+#define DS_HR_ALLOW_NONSECURE_PWD_OPS 0x0000000D
+#define DS_HR_NO_PROPAGATE_ON_NOCHANGE 0x0000000E
+#define DS_HR_COMPUTE_ANR_STATS 0x0000000F
+#define DS_HR_ADMINSDEXMASK 0x00000010
+#define DS_HR_KVNOEMUW2K 0x00000011
+
+#define DS_HR_TWENTIETH_CHAR 0x00000014
+#define DS_HR_ATTR_AUTHZ_ON_LDAP_ADD 0x0000001C
+#define DS_HR_BLOCK_OWNER_IMPLICIT_RIGHTS 0x0000001D
+#define DS_HR_THIRTIETH_CHAR 0x0000001E
+#define DS_HR_FOURTIETH_CHAR 0x00000028
+#define DS_HR_FIFTIETH_CHAR 0x00000032
+#define DS_HR_SIXTIETH_CHAR 0x0000003C
+#define DS_HR_SEVENTIETH_CHAR 0x00000046
+#define DS_HR_EIGHTIETH_CHAR 0x00000050
+#define DS_HR_NINETIETH_CHAR 0x0000005A
+
+/* mS-DS-ReplicatesNCReason */
+#define NTDSCONN_KCC_GC_TOPOLOGY 0x00000001
+#define NTDSCONN_KCC_RING_TOPOLOGY 0x00000002
+#define NTDSCONN_KCC_MINIMIZE_HOPS_TOPOLOGY 0x00000004
+#define NTDSCONN_KCC_STALE_SERVERS_TOPOLOGY 0x00000008
+#define NTDSCONN_KCC_OSCILLATING_CONNECTION_TOPOLOGY 0x00000010
+#define NTDSCONN_KCC_INTERSITE_GC_TOPOLOGY 0x00000020
+#define NTDSCONN_KCC_INTERSITE_TOPOLOGY 0x00000040
+#define NTDSCONN_KCC_SERVER_FAILOVER_TOPOLOGY 0x00000080
+#define NTDSCONN_KCC_SITE_FAILOVER_TOPOLOGY 0x00000100
+#define NTDSCONN_KCC_REDUNDANT_SERVER_TOPOLOGY 0x00000200
+
+#define NTDSCONN_OPT_IS_GENERATED 0x00000001
+#define NTDSCONN_OPT_TWOWAY_SYNC 0x00000002
+#define NTDSCONN_OPT_OVERRIDE_NOTIFY_DEFAULT 0x00000004
+#define NTDSCONN_OPT_USE_NOTIFY 0x00000008
+#define NTDSCONN_OPT_DISABLE_INTERSITE_COMPRESSION 0x00000010
+#define NTDSCONN_OPT_USER_OWNED_SCHEDULE 0x00000020
+#define NTDSCONN_OPT_RODC_TOPOLOGY 0x00000040
+
+/* 7.1.1.2.2.3.3 Site Link Object options flags */
+#define NTDSSITELINK_OPT_USE_NOTIFY 0x00000001
+#define NTDSSITELINK_OPT_TWOWAY_SYNC 0x00000002
+#define NTDSSITELINK_OPT_DISABLE_COMPRESSION 0x00000004
diff --git a/libds/common/roles.h b/libds/common/roles.h
new file mode 100644
index 0000000..03ba191
--- /dev/null
+++ b/libds/common/roles.h
@@ -0,0 +1,82 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ domain roles
+
+ Copyright (C) Andrew Tridgell 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 _LIBDS_ROLES_H_
+#define _LIBDS_ROLES_H_
+
+/* server roles. If you add new roles, please keep ensure that the
+ * existing role values match samr_Role from samr.idl
+ */
+enum server_role {
+ ROLE_STANDALONE = 0,
+ ROLE_DOMAIN_MEMBER = 1,
+ ROLE_DOMAIN_BDC = 2,
+ ROLE_DOMAIN_PDC = 3,
+
+ /* not in samr.idl */
+ ROLE_ACTIVE_DIRECTORY_DC = 4,
+ ROLE_IPA_DC = 5,
+
+ /* To determine the role automatically, this is not a valid role */
+ ROLE_AUTO = 100
+};
+
+/* security levels for 'security =' option
+
+ --------------
+ / \
+ / REST \
+ / IN \
+ / PEACE \
+ / \
+ | SEC_SHARE |
+ | security=share |
+ | |
+ | |
+ | 5 March |
+ | |
+ | 2012 |
+ *| * * * | *
+ _________)/\\_//(\/(/\)/\//\/\///|_)_______
+
+ --------------
+ / \
+ / REST \
+ / IN \
+ / PEACE \
+ / \
+ | SEC_SERVER |
+ | security=server |
+ | |
+ | |
+ | 12 May |
+ | |
+ | 2012 |
+ *| * * * | *
+ _________)/\\_//(\/(/\)/\//\/\///|_)_______
+
+*/
+enum security_types {SEC_AUTO = 0,
+ SEC_USER = 2,
+ SEC_DOMAIN = 4,
+ SEC_ADS = 5};
+
+#endif /* _LIBDS_ROLES_H_ */
diff --git a/libds/common/wscript_build b/libds/common/wscript_build
new file mode 100644
index 0000000..3da3be2
--- /dev/null
+++ b/libds/common/wscript_build
@@ -0,0 +1,7 @@
+
+bld.SAMBA_LIBRARY('flag_mapping',
+ public_deps='talloc replace',
+ source='flag_mapping.c',
+ private_library=True,
+ private_headers='roles.h',
+ deps='samba-util')
diff --git a/libgpo/admx/GNOME_Settings.admx b/libgpo/admx/GNOME_Settings.admx
new file mode 100644
index 0000000..202960b
--- /dev/null
+++ b/libgpo/admx/GNOME_Settings.admx
@@ -0,0 +1,88 @@
+<policyDefinitions revision="1.0" schemaVersion="1.0">
+ <policyNamespaces>
+ <target prefix="system" namespace="Samba.Policies.System" />
+ <using prefix="windows" namespace="Microsoft.Policies.Windows" />
+ </policyNamespaces>
+ <resources minRequiredRevision="1.0" />
+ <supportedOn>
+ <definitions>
+ <definition name="SUPPORTED_SAMBA_4_15" displayName="$(string.SUPPORTED_SAMBA_4_15)"/>
+ </definitions>
+ </supportedOn>
+ <categories>
+ <category name="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" displayName="$(string.CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323)" />
+ <category name="CAT_7E067B4B_2FE1_4AAD_8D76_54209466A491" displayName="$(string.CAT_7E067B4B_2FE1_4AAD_8D76_54209466A491)">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ </category>
+ </categories>
+ <policies>
+ <policy name="POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC" class="Machine" displayName="$(string.POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC)" explainText="$(string.POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC_Help)" presentation="$(presentation.POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC)" key="GNOME Settings\Lock Down Settings" valueName="Whitelisted Online Accounts">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ <elements>
+ <list id="LST_B2FA2836_7FE0_4C2D_9D40_073E4BBDF0F3" key="GNOME Settings\Lock Down Settings\Whitelisted Online Accounts" />
+ </elements>
+ </policy>
+ <policy name="POL_6307C5EA_766A_4D39_BBAE_B1F9A651F08C" class="Machine" displayName="$(string.POL_6307C5EA_766A_4D39_BBAE_B1F9A651F08C)" explainText="$(string.POL_6307C5EA_766A_4D39_BBAE_B1F9A651F08C_Help)" key="GNOME Settings\Lock Down Settings" valueName="Disable Command-Line Access">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ </policy>
+ <policy name="POL_373CCAD2_D0BC_49A3_A078_10CB073AA949" class="Machine" displayName="$(string.POL_373CCAD2_D0BC_49A3_A078_10CB073AA949)" explainText="$(string.POL_373CCAD2_D0BC_49A3_A078_10CB073AA949_Help)" key="GNOME Settings\Lock Down Settings" valueName="Disable File Saving">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ </policy>
+ <policy name="POL_2B71227C_C44B_4F77_B32A_FF92F312BCE2" class="Machine" displayName="$(string.POL_2B71227C_C44B_4F77_B32A_FF92F312BCE2)" explainText="$(string.POL_2B71227C_C44B_4F77_B32A_FF92F312BCE2_Help)" key="GNOME Settings\Lock Down Settings" valueName="Disable Printing">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ </policy>
+ <policy name="POL_F5785112_422C_4426_BF69_164FED2D6075" class="Machine" displayName="$(string.POL_F5785112_422C_4426_BF69_164FED2D6075)" explainText="$(string.POL_F5785112_422C_4426_BF69_164FED2D6075_Help)" key="GNOME Settings\Lock Down Settings" valueName="Disable Repartitioning">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ </policy>
+ <policy name="POL_DBD5262E_1014_4778_92C8_C3258C0D8EEE" class="Machine" displayName="$(string.POL_DBD5262E_1014_4778_92C8_C3258C0D8EEE)" explainText="$(string.POL_DBD5262E_1014_4778_92C8_C3258C0D8EEE_Help)" key="GNOME Settings\Lock Down Settings" valueName="Disable User Logout">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ </policy>
+ <policy name="POL_E5211A0E_F684_4E93_B62B_4F6B8BE5BBAD" class="Machine" displayName="$(string.POL_E5211A0E_F684_4E93_B62B_4F6B8BE5BBAD)" explainText="$(string.POL_E5211A0E_F684_4E93_B62B_4F6B8BE5BBAD_Help)" key="GNOME Settings\Lock Down Settings" valueName="Disable User Switching">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ </policy>
+ <policy name="POL_942D0D38_C946_4805_8339_92B661BE64E7" class="Machine" displayName="$(string.POL_942D0D38_C946_4805_8339_92B661BE64E7)" explainText="$(string.POL_942D0D38_C946_4805_8339_92B661BE64E7_Help)" key="GNOME Settings\Lock Down Settings" valueName="Disallow Login Using a Fingerprint">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ </policy>
+ <policy name="POL_0906773B_31CA_48E7_B173_A2A8435FA31C" class="Machine" displayName="$(string.POL_0906773B_31CA_48E7_B173_A2A8435FA31C)" explainText="$(string.POL_0906773B_31CA_48E7_B173_A2A8435FA31C_Help)" key="GNOME Settings\Lock Down Settings" valueName="Lock Down Enabled Extensions">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ </policy>
+ <policy name="POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B" class="Machine" displayName="$(string.POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B)" explainText="$(string.POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B_Help)" presentation="$(presentation.POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B)" key="GNOME Settings\Lock Down Settings" valueName="Lock Down Specific Settings">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ <elements>
+ <list id="LST_19198E2B_79A2_4263_B09E_CC40151A265B" key="GNOME Settings\Lock Down Settings\Lock Down Specific Settings" />
+ </elements>
+ </policy>
+ <policy name="POL_1F00D0C9_3190_42E1_870F_33A0E560E873" class="Machine" displayName="$(string.POL_1F00D0C9_3190_42E1_870F_33A0E560E873)" explainText="$(string.POL_1F00D0C9_3190_42E1_870F_33A0E560E873_Help)" presentation="$(presentation.POL_1F00D0C9_3190_42E1_870F_33A0E560E873)" key="GNOME Settings\Lock Down Settings" valueName="Dim Screen when User is Idle">
+ <parentCategory ref="CAT_7E067B4B_2FE1_4AAD_8D76_54209466A491" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ <elements>
+ <decimal id="DXT_B46B9503_767D_43E6_8844_8852AC9211C9" key="GNOME Settings\Lock Down Settings\Dim Screen when User is Idle" valueName="Delay" />
+ <decimal id="DXT_C652079A_D03D_4DE0_A43A_F5AC3F416F4D" key="GNOME Settings\Lock Down Settings\Dim Screen when User is Idle" valueName="Dim Idle Brightness" />
+ </elements>
+ </policy>
+ <policy name="POL_05BFA99F_C8C1_4486_AA35_CFB72EF94CAE" class="Machine" displayName="$(string.POL_05BFA99F_C8C1_4486_AA35_CFB72EF94CAE)" presentation="$(presentation.POL_05BFA99F_C8C1_4486_AA35_CFB72EF94CAE)" key="GNOME Settings\Lock Down Settings" valueName="Compose Key">
+ <parentCategory ref="CAT_7E067B4B_2FE1_4AAD_8D76_54209466A491" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ <elements>
+ <text id="CMB_F3CCB880_E12B_4068_8B8A_66DE04211F69" key="GNOME Settings\Lock Down Settings\Compose Key" valueName="Key Name" required="true" />
+ </elements>
+ </policy>
+ <policy name="POL_93280789_E7BA_4EB8_924B_61BA1EEB0437" class="Machine" displayName="$(string.POL_93280789_E7BA_4EB8_924B_61BA1EEB0437)" explainText="$(string.POL_93280789_E7BA_4EB8_924B_61BA1EEB0437_Help)" presentation="$(presentation.POL_93280789_E7BA_4EB8_924B_61BA1EEB0437)" key="GNOME Settings\Lock Down Settings" valueName="Enabled Extensions">
+ <parentCategory ref="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_15" />
+ <elements>
+ <list id="LST_FAD2DD29_CDD9_45BC_99CA_1C47084D09A8" key="GNOME Settings\Lock Down Settings\Enabled Extensions" />
+ </elements>
+ </policy>
+ </policies>
+</policyDefinitions>
diff --git a/libgpo/admx/en-US/GNOME_Settings.adml b/libgpo/admx/en-US/GNOME_Settings.adml
new file mode 100644
index 0000000..5cc8534
--- /dev/null
+++ b/libgpo/admx/en-US/GNOME_Settings.adml
@@ -0,0 +1,110 @@
+<policyDefinitionResources revision="1.0" schemaVersion="1.0">
+ <displayName>
+ </displayName>
+ <description>
+ </description>
+ <resources>
+ <stringTable>
+ <string id="SUPPORTED_SAMBA_4_15">Samba 4.15</string>
+ <string id="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323">GNOME Settings</string>
+ <string id="POL_541A888A_A96D_4A21_9A8F_1021EF6D2F25">Allow Online Accounts</string>
+ <string id="POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC">Whitelisted Online Accounts</string>
+ <string id="POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC_Help">The GNOME Online Accounts (GOA) are used for integrating personal network accounts with the GNOME Desktop and applications. The user can add their online accounts, such as Google, Facebook, Flickr, ownCloud, and others using the Online Accounts application.
+As a system administrator, you can:
+selectively enable a few online accounts.</string>
+ <string id="POL_541A888A_A96D_4A21_9A8F_1021EF6D2F25_Help">The GNOME Online Accounts (GOA) are used for integrating personal network accounts with the GNOME Desktop and applications. The user can add their online accounts, such as Google, Facebook, Flickr, ownCloud, and others using the Online Accounts application.
+As a system administrator, you can:
+enable all online accounts;
+disable all online accounts.</string>
+ <string id="POL_6307C5EA_766A_4D39_BBAE_B1F9A651F08C">Disable Command-Line Access</string>
+ <string id="POL_6307C5EA_766A_4D39_BBAE_B1F9A651F08C_Help">To disable command-line access for your desktop user, you need to make configuration changes in a number of different contexts. Bear in mind that the following steps do not remove the desktop user's permissions to access a command line, but rather remove the ways that the desktop user could access the command line.
+
+Set the org.gnome.desktop.lockdown.disable-command-line GSettings key, which prevents the user from accessing the terminal or specifying a command line to be executed (the Alt+F2 command prompt).
+
+Prevent users from accessing the Alt+F2 command prompt.
+
+Disable switching to virtual terminals (VTs) with the Ctrl+Alt+function key shortcuts by modifying the X server configuration.
+
+Remove Terminal and all other terminal applications from the Activities overview in GNOME Shell. You will also need to prevent the user from installing a new terminal application.</string>
+ <string id="POL_373CCAD2_D0BC_49A3_A078_10CB073AA949">Disable File Saving</string>
+ <string id="POL_373CCAD2_D0BC_49A3_A078_10CB073AA949_Help">You can disable the Save and Save As dialogs. This can be useful if you are giving temporary access to a user or you do not want the user to save files to the computer.
+
+WARNING: This feature will only work in applications which support it! Not all GNOME and third party applications have this feature enabled. These changes will have no effect on applications which do not support this feature.</string>
+ <string id="POL_2B71227C_C44B_4F77_B32A_FF92F312BCE2">Disable Printing</string>
+ <string id="POL_2B71227C_C44B_4F77_B32A_FF92F312BCE2_Help">You can disable the print dialog from being shown to users. This can be useful if you are giving temporary access to a user or you do not want the user to print to network printers.
+
+WARNING: This feature will only work in applications which support it! Not all GNOME and third party applications have this feature enabled. These changes will have no effect on applications which do not support this feature.</string>
+ <string id="POL_F5785112_422C_4426_BF69_164FED2D6075">Disable Repartitioning</string>
+ <string id="POL_F5785112_422C_4426_BF69_164FED2D6075_Help">polkit enables you to set permissions for individual operations. For udisks2, the utility for disk management services, the configuration is located at /usr/share/polkit-1/actions/org.freedesktop.udisks2.policy. This file contains a set of actions and default values, which can be overridden by system administrator.
+
+TIP: The polkit configuration in /etc overrides that shipped by packages in /usr/share.</string>
+ <string id="POL_DBD5262E_1014_4778_92C8_C3258C0D8EEE">Disable User Logout</string>
+ <string id="POL_DBD5262E_1014_4778_92C8_C3258C0D8EEE_Help">Preventing the user from logging out is useful for special kind of GNOME deployments (unmanned kiosks, public internet access terminals, and so on).
+
+IMPORTANT: Users can evade the logout lockdown by switching to a different user. That is the reason why it is recommended to also disable user switching when configuring the system.</string>
+ <string id="POL_E5211A0E_F684_4E93_B62B_4F6B8BE5BBAD">Disable User Switching</string>
+ <string id="POL_E5211A0E_F684_4E93_B62B_4F6B8BE5BBAD_Help">Preventing the user from logging out is useful for special kind of GNOME deployments (unmanned kiosks, public internet access terminals, and so on).
+
+IMPORTANT: Users can evade the logout lockdown by switching to a different user. That is the reason why it is recommended to also disable user switching when configuring the system.</string>
+ <string id="POL_942D0D38_C946_4805_8339_92B661BE64E7">Disallow Login Using a Fingerprint</string>
+ <string id="POL_942D0D38_C946_4805_8339_92B661BE64E7_Help">Users with a fingerprint scanner can use their fingerprints instead of a password to log in. Fingerprint login needs to be set up by the user before it can be used.
+
+Fingerprint readers are not always reliable, so you may wish to disable login using the reader for security reasons.
+ </string>
+ <string id="POL_0906773B_31CA_48E7_B173_A2A8435FA31C">Lock Down Enabled Extensions</string>
+ <string id="POL_0906773B_31CA_48E7_B173_A2A8435FA31C_Help">In GNOME Shell, you can prevent the user from enabling or disabling extensions by locking down the org.gnome.shell.enabled-extensions and org.gnome.shell.development-tools keys. This allows you to provide a set of extensions that the user has to use.
+
+Locking down the org.gnome.shell.development-tools key ensures that the user cannot use GNOME Shell’s integrated debugger and inspector tool (Looking Glass) to disable any mandatory extensions.</string>
+ <string id="POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B">Lock Down Specific Settings</string>
+ <string id="POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B_Help">By using the lockdown mode in dconf, you can prevent users from changing specific settings. Without locking down the system settings, user settings take precedence over the system settings.
+
+To lock down a dconf key or subpath, you will need to create a locks subdirectory in the keyfile directory. The files inside this directory contain a list of keys or subpaths to lock. Just as with the keyfiles, you may add any number of files to this directory.</string>
+ <string id="CAT_7E067B4B_2FE1_4AAD_8D76_54209466A491">User Settings</string>
+ <string id="POL_1F00D0C9_3190_42E1_870F_33A0E560E873">Dim Screen when User is Idle</string>
+ <string id="POL_1F00D0C9_3190_42E1_870F_33A0E560E873_Help">You can make the computer screen dim after the computer has been idle (not used) for some period of time.</string>
+ <string id="POL_05BFA99F_C8C1_4486_AA35_CFB72EF94CAE">Compose Key</string>
+ <string id="POL_93280789_E7BA_4EB8_924B_61BA1EEB0437">Enabled Extensions</string>
+ <string id="POL_93280789_E7BA_4EB8_924B_61BA1EEB0437_Help">The enabled-extensions key specifies the enabled extensions using the extensions’ uuid.</string>
+ </stringTable>
+ <presentationTable>
+ <presentation id="POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC">
+ <listBox refId="LST_B2FA2836_7FE0_4C2D_9D40_073E4BBDF0F3">
+ </listBox>
+ </presentation>
+ <presentation id="POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B">
+ <listBox refId="LST_19198E2B_79A2_4263_B09E_CC40151A265B">Settings</listBox>
+ </presentation>
+ <presentation id="POL_1F00D0C9_3190_42E1_870F_33A0E560E873">
+ <decimalTextBox refId="DXT_B46B9503_767D_43E6_8844_8852AC9211C9" defaultValue="300">Idle Delay</decimalTextBox>
+ <decimalTextBox refId="DXT_C652079A_D03D_4DE0_A43A_F5AC3F416F4D" defaultValue="30">Idle Brightness</decimalTextBox>
+ </presentation>
+ <presentation id="POL_05BFA99F_C8C1_4486_AA35_CFB72EF94CAE">
+ <comboBox refId="CMB_F3CCB880_E12B_4068_8B8A_66DE04211F69">
+ <label>Compose Key</label>
+ <default>Right Alt</default>
+ <suggestion>Right Alt</suggestion>
+ <suggestion>Left Win</suggestion>
+ <suggestion>3rd level of Left Win</suggestion>
+ <suggestion>Right Win</suggestion>
+ <suggestion>3rd level of Right Win</suggestion>
+ <suggestion>Menu</suggestion>
+ <suggestion>3rd level of Menu</suggestion>
+ <suggestion>Left Ctrl</suggestion>
+ <suggestion>3rd level of Left Ctrl</suggestion>
+ <suggestion>Right Ctrl</suggestion>
+ <suggestion>3rd level of Right Ctrl</suggestion>
+ <suggestion>Caps Lock</suggestion>
+ <suggestion>3rd level of Caps Lock</suggestion>
+ <suggestion>The "&lt; &gt;" key</suggestion>
+ <suggestion>3rd level of the "&lt; &gt;" key</suggestion>
+ <suggestion>Pause</suggestion>
+ <suggestion>PrtSc</suggestion>
+ <suggestion>Scroll Lock</suggestion>
+ </comboBox>
+ </presentation>
+ <presentation id="POL_93280789_E7BA_4EB8_924B_61BA1EEB0437">
+ <listBox refId="LST_FAD2DD29_CDD9_45BC_99CA_1C47084D09A8">Enabled Extensions</listBox>
+ </presentation>
+ </presentationTable>
+ </resources>
+</policyDefinitionResources>
diff --git a/libgpo/admx/en-US/samba.adml b/libgpo/admx/en-US/samba.adml
new file mode 100755
index 0000000..133ed9c
--- /dev/null
+++ b/libgpo/admx/en-US/samba.adml
@@ -0,0 +1,4730 @@
+<?xml version="1.0" ?>
+<policyDefinitionResources revision="1.0" schemaVersion="1.0">
+ <displayName>
+ </displayName>
+ <description>
+ </description>
+ <resources>
+ <stringTable>
+ <string id="CAT_3338C1DD_8A00_4273_8547_158D8B8C19E9">Samba</string>
+ <string id="CAT_7D8D7DC8_5A9D_4BE1_8227_F09CDD5AFFC6">Unix Settings</string>
+ <string id="CAT_2B6D622C_5721_4C23_A2D6_5C70D6E059BA">Scripts</string>
+ <string id="POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061">Daily</string>
+ <string id="POL_825D441F_905E_4C7E_9E4B_03013697C6C1">Hourly</string>
+ <string id="POL_D298F3BD_44D9_426D_AF11_3163D31582F6">Monthly</string>
+ <string id="POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674">Weekly</string>
+ <string id="POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3">Sudo Rights</string>
+ <string id="POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061_Help">This policy setting allows you to execute commands, either local or on remote storage, daily.</string>
+ <string id="POL_825D441F_905E_4C7E_9E4B_03013697C6C1_Help">This policy setting allows you to execute commands, either local or on remote storage, hourly.</string>
+ <string id="POL_D298F3BD_44D9_426D_AF11_3163D31582F6_Help">This policy setting allows you to execute commands, either local or on remote storage, monthly.</string>
+ <string id="POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674_Help">This policy setting allows you to execute commands, either local or on remote storage, weekly.</string>
+ <string id="POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3_Help">This policy configures the sudoers file with the lines specified.</string>
+ <string id="CAT_10827749_64ED_5052_87F7_E81AD421856A">smb.conf</string>
+ <string id="POL_33AAE399_07A8_5CC8_882A_393E4B96B259">additional dns hostnames</string>
+ <string id="POL_33AAE399_07A8_5CC8_882A_393E4B96B259_Help">A list of additional DNS names by which this host can be identified
+
+Example: host2.example.com host3.other.com </string>
+ <string id="POL_3CD2A970_826E_518E_B5F0_5E6725FF354D">bind interfaces only</string>
+ <string id="POL_3CD2A970_826E_518E_B5F0_5E6725FF354D_Help">This global parameter allows the Samba admin
+ to limit what interfaces on a machine will serve SMB requests. It
+ affects file service smbd
+ 8 and name service nmbd
+ 8 in a slightly different ways.
+ For name service it causes nmbd to bind to ports 137 and 138 on the interfaces listed in the parameter. nmbd also binds to the &quot;all addresses&quot; interface (0.0.0.0) on ports 137 and 138 for the purposes of reading broadcast messages. If this option is not set then nmbd will service name requests on all of these sockets. If is set then nmbd will check the source address of any packets coming in on the broadcast sockets and discard any that don't match the broadcast addresses of the interfaces in the parameter list. As unicast packets are received on the other sockets it allows nmbd to refuse to serve names to machines that send packets that arrive through any interfaces not listed in the list. IP Source address spoofing does defeat this simple check, however, so it must not be used seriously as a security feature for nmbd.
+ For file service it causes smbd 8 to bind only to the interface list given in the parameter. This restricts the networks that smbd will serve, to packets coming in on those interfaces. Note that you should not use this parameter for machines that are serving PPP or other intermittent or non-broadcast network interfaces as it will not cope with non-permanent interfaces.
+ If is set and the network address 127.0.0.1 is not added to the parameter list smbpasswd 8 may not work as expected due to the reasons covered below.
+ To change a users SMB password, the smbpasswd by default connects to the localhost - 127.0.0.1 address as an SMB client to issue the password change request. If is set then unless the network address 127.0.0.1 is added to the parameter list then smbpasswd will fail to connect in it's default mode. smbpasswd can be forced to use the primary IP interface of the local host by using its smbpasswd 8 -r remote machine parameter, with remote machine set to the IP name of the primary interface of the local host.</string>
+ <string id="POL_109FA3A4_0F92_5052_A7D9_D4BBCA75F765">config backend</string>
+ <string id="POL_109FA3A4_0F92_5052_A7D9_D4BBCA75F765_Help">This controls the backend for storing the configuration. Possible values are file (the default) and registry. When registry is encountered while loading smb.conf, the configuration read so far is dropped and the global options are read from registry instead. So this triggers a registry only configuration. Share definitions are not read immediately but instead registry shares is set to yes. Note: This option can not be set inside the registry configuration itself.
+
+Example: registry</string>
+ <string id="POL_08734B25_7265_5D0B_B857_B2E831B624F1">dos charset</string>
+ <string id="POL_08734B25_7265_5D0B_B857_B2E831B624F1_Help">DOS SMB clients assume the server has the same charset as they do. This option specifies which charset Samba should talk to DOS clients.
+ The default depends on which charsets you have installed. Samba tries to use charset 850 but falls back to ASCII in case it is not available. Run testparm 1 to check the default on your system.</string>
+ <string id="POL_4CCDFFB7_07DF_58F9_904E_13A024A3F54A">enable core files</string>
+ <string id="POL_4CCDFFB7_07DF_58F9_904E_13A024A3F54A_Help">This parameter specifies whether core dumps should be written on internal exits. Normally set to yes. You should never need to change this.
+
+Example: no</string>
+ <string id="POL_5B751E57_31A9_5EC2_A3CD_A8511D74FCFB">mdns name</string>
+ <string id="POL_5B751E57_31A9_5EC2_A3CD_A8511D74FCFB_Help">This parameter controls the name that multicast DNS support advertises as its' hostname.
+ The default is to use the NETBIOS name which is typically the hostname in all capital letters.
+ A setting of mdns will defer the hostname configuration to the MDNS library that is used.</string>
+ <string id="POL_461A8AAF_F51E_5FF5_9433_A8D25BBCF783">multicast dns register</string>
+ <string id="POL_461A8AAF_F51E_5FF5_9433_A8D25BBCF783_Help">If compiled with proper support for it, Samba will
+ announce itself with multicast DNS services like for example
+ provided by the Avahi daemon.
+ This parameter allows disabling Samba to register itself.</string>
+ <string id="POL_04F98D09_4223_5390_B66F_A6DA05F97FCC">netbios aliases</string>
+ <string id="POL_04F98D09_4223_5390_B66F_A6DA05F97FCC_Help">This is a list of NetBIOS names that nmbd will
+ advertise as additional names by which the Samba server is known. This allows one machine to appear in browse lists under multiple names. If a machine is acting as a browse server
+ or logon server none of these names will be advertised as either browse server or logon servers, only the primary name of the machine will be advertised with these capabilities.
+
+Example: TEST TEST1 TEST2</string>
+ <string id="POL_90CE7832_31B7_51D8_9EF2_92FEF396F49B">netbios name</string>
+ <string id="POL_90CE7832_31B7_51D8_9EF2_92FEF396F49B_Help">This sets the NetBIOS name by which a Samba server is known. By default it is the same as the first component of the host's DNS name. If a machine is a browse server or logon server this name (or the first component of the hosts DNS name) will be the name that these services are advertised under.
+ Note that the maximum length for a NetBIOS name is 15 characters.
+ There is a bug in Samba that breaks operation of browsing and access to shares if the netbios name is set to the literal name PIPE. To avoid this problem, do not name your Samba server PIPE.
+
+Example: MYNAME</string>
+ <string id="POL_3B93FDE1_6461_572C_AD2E_6AEEAE4EA949">netbios scope</string>
+ <string id="POL_3B93FDE1_6461_572C_AD2E_6AEEAE4EA949_Help">This sets the NetBIOS scope that Samba will operate under. This should not be set unless every machine on your LAN also sets this value.</string>
+ <string id="POL_E633B0BE_9CF3_5D79_A9F1_CB782C82A19C">prefork backoff increment</string>
+ <string id="POL_E633B0BE_9CF3_5D79_A9F1_CB782C82A19C_Help">This option specifies the number of seconds added to the delay before a prefork master or worker process is restarted. The restart is initially zero, the prefork backoff increment is added to the delay on each restart up to the value specified by &quot;prefork maximum backoff&quot;.
+ Additionally the the backoff for an individual service by using &quot;prefork backoff increment: service name&quot; i.e. &quot;prefork backoff increment:ldap = 2&quot; to set the backoff increment to 2.
+ If the backoff increment is 2 and the maximum backoff is 5. There will be a zero second delay for the first restart. A two second delay for the second restart. A four second delay for the third and any subsequent restarts</string>
+ <string id="POL_B4E848BD_E606_552C_8C9F_3F8CC1AEF191">prefork children</string>
+ <string id="POL_B4E848BD_E606_552C_8C9F_3F8CC1AEF191_Help">This option controls the number of worker processes that are started for each service when prefork process model is enabled (see samba 8 -M) The prefork children are only started for those services that support prefork (currently ldap, kdc and netlogon). For processes that don't support preforking all requests are handled by a single process for that service.
+ This should be set to a small multiple of the number of CPU's available on the server
+ Additionally the number of prefork children can be specified for an individual service by using &quot;prefork children: service name&quot; i.e. &quot;prefork children:ldap = 8&quot; to set the number of ldap worker processes.</string>
+ <string id="POL_D721EFAF_A53D_57B7_9639_3859CF9CE31E">prefork maximum backoff</string>
+ <string id="POL_D721EFAF_A53D_57B7_9639_3859CF9CE31E_Help">This option controls the maximum delay before a failed pre-fork process is restarted.</string>
+ <string id="POL_1630255E_61BA_5686_B3E0_995F8C4DAA5E">realm</string>
+ <string id="POL_1630255E_61BA_5686_B3E0_995F8C4DAA5E_Help">This option specifies the kerberos realm to use. The realm is used as the ADS equivalent of the NT4 domain. It is usually set to the DNS name of the kerberos server.
+
+Example: mysambabox.mycompany.com</string>
+ <string id="POL_E1D45258_0E70_5AF8_AE28_DAB6B318BB8A">server services</string>
+ <string id="POL_E1D45258_0E70_5AF8_AE28_DAB6B318BB8A_Help">This option contains the services that the Samba daemon will run.
+ An entry in the smb.conf file can either override the previous value completely or entries can be removed from or added to it by prefixing them with + or -.
+
+Example: -s3fs, +smb</string>
+ <string id="POL_351CFFDA_9DC3_54FB_BE9A_E434F0DB9955">server string</string>
+ <string id="POL_351CFFDA_9DC3_54FB_BE9A_E434F0DB9955_Help">This controls what string will show up in the printer comment box in print
+ manager and next to the IPC connection in net view. It
+ can be any string that you wish to show to your users. It also sets what will appear in browse lists next to the machine name.
+ A %v will be replaced with the Samba version number.
+ A %h will be replaced with the hostname.
+
+Example: University of GNUs Samba Server</string>
+ <string id="POL_32A7428D_00FC_5203_9943_2BDCDC3D9E0D">share backend</string>
+ <string id="POL_32A7428D_00FC_5203_9943_2BDCDC3D9E0D_Help">This option specifies the backend that will be used to access the configuration of file shares.
+ Traditionally, Samba file shares have been configured in the smb.conf file and this is still the default.
+ At the moment there are no other supported backends.</string>
+ <string id="POL_ABDCEE90_90DE_55C2_A2DC_1C7D017F4B2B">unix charset</string>
+ <string id="POL_ABDCEE90_90DE_55C2_A2DC_1C7D017F4B2B_Help">Specifies the charset the unix machine Samba runs on uses. Samba needs to know this in order to be able to convert text to the charsets other SMB clients use.
+ This is also the charset Samba will use when specifying arguments to scripts that it invokes.
+
+Example: ASCII</string>
+ <string id="POL_D1FAAF87_1E1E_596F_A915_BE72D67A5DC5">workgroup</string>
+ <string id="POL_D1FAAF87_1E1E_596F_A915_BE72D67A5DC5_Help">This controls what workgroup your server will appear to be in when queried by clients. Note that this parameter also controls the Domain name used with the domain setting.
+
+Example: MYGROUP</string>
+ <string id="POL_163183B9_195A_5290_927E_08FBB6C76AA0">interfaces</string>
+ <string id="POL_163183B9_195A_5290_927E_08FBB6C76AA0_Help">This option allows you to override the default network interfaces list that Samba will use for browsing, name registration and other NetBIOS over TCP/IP (NBT) traffic. By default Samba will query the kernel for the list of all active interfaces and use any interfaces except 127.0.0.1 that are broadcast capable.
+ The option takes a list of interface strings. Each string can be in any of the following forms:
+ a network interface name (such as eth0). This may include shell-like wildcards so eth* will match any interface starting with the substring &quot;eth&quot; an IP address. In this case the netmask is determined from the list of interfaces obtained from the kernel an IP/mask pair. a broadcast/mask pair.
+ The &quot;mask&quot; parameters can either be a bit length (such as 24 for a C class network) or a full netmask in dotted decimal form.
+ The &quot;IP&quot; parameters above can either be a full dotted decimal IP address or a hostname which will be looked up via the OS's normal hostname resolution mechanisms.
+ By default Samba enables all active interfaces that are broadcast capable except the loopback adaptor (IP address 127.0.0.1).
+ In order to support SMB3 multi-channel configurations, smbd understands some extra parameters which can be appended after the actual interface with this extended syntax (note that the quoting is important in order to handle the ; and , characters):
+ &quot;interface[;key1=value1[,key2=value2[...]]]&quot;
+ Known keys are speed, capability, and if_index. Speed is specified in bits per second. Known capabilities are RSS and RDMA. The if_index should be used with care: the values must not coincide with indexes used by the kernel. Note that these options are mainly intended for testing and development rather than for production use. At least on Linux systems, these values should be auto-detected, but the settings can serve as last a resort when autodetection is not working or is not available. The specified values overwrite the auto-detected values.
+ The first two example below configures three network interfaces corresponding to the eth0 device and IP addresses 192.168.2.10 and 192.168.3.10. The netmasks of the latter two interfaces would be set to 255.255.255.0.
+ The other examples show how per interface extra parameters can be specified. Notice the possible usage of &quot;,&quot; and &quot;;&quot;, which makes the double quoting necessary.
+
+Example: eth0 192.168.2.10/24 192.168.3.10/255.255.255.0
+
+Example: eth0, 192.168.2.10/24; 192.168.3.10/255.255.255.0
+
+Example: &quot;eth0;if_index=65,speed=1000000000,capability=RSS&quot;
+
+Example: &quot;lo;speed=1000000000&quot; &quot;eth0;capability=RSS&quot;
+
+Example: &quot;lo;speed=1000000000&quot; , &quot;eth0;capability=RSS&quot;
+
+Example: &quot;eth0;capability=RSS&quot; , &quot;rdma1;capability=RDMA&quot; ; &quot;rdma2;capability=RSS,capability=RDMA&quot;</string>
+ <string id="POL_25731B61_FC84_5A83_93AE_296F7D6311C4">browse list</string>
+ <string id="POL_25731B61_FC84_5A83_93AE_296F7D6311C4_Help">This controls whether smbd 8 will serve a browse list to a client doing a NetServerEnum call. Normally set to yes. You should never need to change this.</string>
+ <string id="POL_3E9E3188_6F1A_54F8_8E13_265E2AD1BE71">domain master</string>
+ <string id="POL_3E9E3188_6F1A_54F8_8E13_265E2AD1BE71_Help">Tell smbd 8 to enable WAN-wide browse list collation. Setting this option causes nmbd to claim a special domain specific NetBIOS name that identifies it as a domain master browser for its given . Local master browsers in the same on broadcast-isolated subnets will give this nmbd their local browse lists, and then ask smbd 8 for a complete copy of the browse list for the whole wide area network. Browser clients will then contact their local master browser, and will receive the domain-wide browse list, instead of just the list for their broadcast-isolated subnet.
+ Note that Windows NT Primary Domain Controllers expect to be able to claim this specific special NetBIOS name that identifies them as domain master browsers for that by default (i.e. there is no way to prevent a Windows NT PDC from attempting to do this). This means that if this parameter is set and nmbd claims the special name for a before a Windows NT PDC is able to do so then cross subnet browsing will behave strangely and may fail. If yes, then the default behavior is to enable the parameter. If is not enabled (the default setting), then neither will be enabled by default.
+ When Yes the default setting for this parameter is Yes, with the result that Samba will be a PDC. If No, Samba will function as a BDC. In general, this parameter should be set to 'No' only on a BDC.</string>
+ <string id="POL_E14519D2_9B84_5A1B_B4A4_89F6151BFCE2">enhanced browsing</string>
+ <string id="POL_E14519D2_9B84_5A1B_B4A4_89F6151BFCE2_Help">This option enables a couple of enhancements to cross-subnet browse propagation that have been added in Samba but which are not standard in Microsoft implementations.
+ The first enhancement to browse propagation consists of a regular wildcard query to a Samba WINS server for all Domain Master Browsers, followed by a browse synchronization with each of the returned DMBs. The second enhancement consists of a regular randomised browse synchronization with all currently known DMBs.
+ You may wish to disable this option if you have a problem with empty workgroups not disappearing from browse lists. Due to the restrictions of the browse protocols, these enhancements can cause a empty workgroup to stay around forever which can be annoying.
+ In general you should leave this option enabled as it makes cross-subnet browse propagation much more reliable.</string>
+ <string id="POL_7E8FBFDB_CBDD_5CE7_B101_07AB8AA71209">lm announce</string>
+ <string id="POL_7E8FBFDB_CBDD_5CE7_B101_07AB8AA71209_Help">This parameter determines if nmbd 8 will produce Lanman announce broadcasts that are needed by OS/2 clients in order for them to see the Samba server in their browse list. This parameter can have three values, yes, no, or auto. The default is auto. If set to no Samba will never produce these broadcasts. If set to yes Samba will produce Lanman announce broadcasts at a frequency set by the parameter . If set to auto Samba will not send Lanman announce broadcasts by default but will listen for them. If it hears such a broadcast on the wire it will then start sending them at a frequency set by the parameter .
+
+Example: yes</string>
+ <string id="POL_6D665B21_1F08_5183_B9CD_CFD712C1D4AB">lm interval</string>
+ <string id="POL_6D665B21_1F08_5183_B9CD_CFD712C1D4AB_Help">If Samba is set to produce Lanman announce broadcasts needed by OS/2 clients (see the parameter) then this parameter defines the frequency in seconds with which they will be made. If this is set to zero then no Lanman announcements will be made despite the setting of the parameter.
+
+Example: 120</string>
+ <string id="POL_40EA4C73_20A7_580A_A830_0EDA7FC72B7D">local master</string>
+ <string id="POL_40EA4C73_20A7_580A_A830_0EDA7FC72B7D_Help">This option allows nmbd 8 to try and become a local master browser on a subnet. If set to no then nmbd will not attempt to become a local master browser on a subnet and will also lose in all browsing elections. By default this value is set to yes. Setting this value to yes doesn't mean that Samba will become the local master browser on a subnet, just that nmbd will participate in elections for local master browser.
+ Setting this value to no will cause nmbd never to become a local
+master browser.</string>
+ <string id="POL_95C311BC_3067_5654_A978_70326D928F48">os level</string>
+ <string id="POL_95C311BC_3067_5654_A978_70326D928F48_Help">This integer value controls what level Samba advertises itself as for browse elections. The value of this parameter determines whether nmbd 8 has a chance of becoming a local master browser for the in the local broadcast area.
+ Note: By default, Samba will win a local master browsing election over all Microsoft operating systems except a Windows NT 4.0/2000 Domain Controller. This means that a misconfigured Samba host can effectively isolate a subnet for browsing purposes. This parameter is largely auto-configured in the Samba-3 release series and it is seldom necessary to manually override the default setting. Please refer to the chapter on Network Browsing in the Samba-3 HOWTO document for further information regarding the use of this parameter. Note: The maximum value for this parameter is 255. If you use higher values, counting will start at 0!
+
+Example: 65</string>
+ <string id="POL_516D10CE_AECD_50DE_B4F5_D9DBF85FA582">preferred master</string>
+ <string id="POL_516D10CE_AECD_50DE_B4F5_D9DBF85FA582_Help">This boolean parameter controls if nmbd 8 is a preferred master browser for its workgroup.
+ If this is set to yes, on startup, nmbd will force an election, and it will have a slight advantage in winning the election. It is recommended that this parameter is used in conjunction with yes, so that nmbd can guarantee becoming a domain master.
+ Use this option with caution, because if there are several hosts (whether Samba servers, Windows 95 or NT) that are preferred master browsers on the same subnet, they will each periodically and continuously attempt to become the local master browser. This will result in unnecessary broadcast traffic and reduced browsing capabilities.</string>
+ <string id="POL_E468B4EF_D43C_572D_9A57_390D5D22F485">allow dns updates</string>
+ <string id="POL_E468B4EF_D43C_572D_9A57_390D5D22F485_Help">This option determines what kind of updates to the DNS are allowed.
+ DNS updates can either be disallowed completely by setting it to disabled, enabled over secure connections only by setting it to secure only or allowed in all cases by setting it to nonsecure.
+
+Example: disabled</string>
+ <string id="POL_7E805DF0_F3AD_55F6_AC1E_B13987AE73FC">dns forwarder</string>
+ <string id="POL_7E805DF0_F3AD_55F6_AC1E_B13987AE73FC_Help">This option specifies the list of DNS servers that DNS requests will be forwarded to if they can not be handled by Samba itself.
+ The DNS forwarder is only used if the internal DNS server in Samba is used.
+
+Example: 192.168.0.1 192.168.0.2</string>
+ <string id="POL_DE5786B0_C694_53AA_85F2_F9B4EB2F9923">dns update command</string>
+ <string id="POL_DE5786B0_C694_53AA_85F2_F9B4EB2F9923_Help">This option sets the command that is called when there are DNS updates. It should update the local machines DNS names using TSIG-GSS.
+
+Example: /usr/local/sbin/dnsupdate</string>
+ <string id="POL_C5C16F87_0017_5CC1_810B_398855115BC9">dns zone scavenging</string>
+ <string id="POL_C5C16F87_0017_5CC1_810B_398855115BC9_Help">When enabled (the default is disabled) unused dynamic dns records are periodically removed. This option should not be enabled for installations created with versions of samba before 4.9. Doing this will result in the loss of static DNS entries. This is due to a bug in previous versions of samba (BUG 12451) which marked dynamic DNS records as static and static records as dynamic. If one record for a DNS name is static (non-aging) then no other record for that DNS name will be scavenged.</string>
+ <string id="POL_23A4E426_BE59_5616_849E_94C825DDFC5B">gpo update command</string>
+ <string id="POL_23A4E426_BE59_5616_849E_94C825DDFC5B_Help">This option sets the command that is called to apply GPO policies.
+ The samba-gpupdate script applies System Access and Kerberos Policies to the KDC. System Access policies set minPwdAge, maxPwdAge, minPwdLength, and pwdProperties in the samdb. Kerberos Policies set kdc:service ticket lifetime, kdc:user ticket lifetime, and kdc:renewal lifetime in smb.conf.
+
+Example: /usr/local/sbin/gpoupdate</string>
+ <string id="POL_D32F3D0B_74B1_5C8F_81B4_CC9574EAB9B7">machine password timeout</string>
+ <string id="POL_D32F3D0B_74B1_5C8F_81B4_CC9574EAB9B7_Help">If a Samba server is a member of a Windows NT or Active Directory Domain (see the domain and ads parameters), then periodically a running winbindd process will try and change the MACHINE ACCOUNT PASSWORD stored in the TDB called secrets.tdb . This parameter specifies how often this password will be changed, in seconds. The default is one week (expressed in seconds), the same as a Windows NT Domain member server.
+ See also smbpasswd 8, and the domain and ads parameters.</string>
+ <string id="POL_07339CF8_68F5_5B5F_9207_93D2E4526C44">nsupdate command</string>
+ <string id="POL_07339CF8_68F5_5B5F_9207_93D2E4526C44_Help">This option sets the path to the nsupdate command which is used for GSS-TSIG dynamic DNS updates.</string>
+ <string id="POL_D0F6F805_6160_55CF_9B8B_F5AD874B1E2C">spn update command</string>
+ <string id="POL_D0F6F805_6160_55CF_9B8B_F5AD874B1E2C_Help">This option sets the command that for updating servicePrincipalName names from spn_update_list.
+
+Example: /usr/local/sbin/spnupdate</string>
+ <string id="POL_6FFBB02C_6B3E_5D0E_9193_15F9B38E487D">mangle prefix</string>
+ <string id="POL_6FFBB02C_6B3E_5D0E_9193_15F9B38E487D_Help">controls the number of prefix characters from the original name used when generating the mangled names. A larger value will give a weaker hash and therefore more name collisions. The minimum value is 1 and the maximum value is 6.
+ mangle prefix is effective only when mangling method is hash2.
+
+Example: 4</string>
+ <string id="POL_BE8F8AE7_99AC_582E_8105_00326D511339">mangling method</string>
+ <string id="POL_BE8F8AE7_99AC_582E_8105_00326D511339_Help">controls the algorithm used for the generating the mangled names. Can take two different values, &quot;hash&quot; and &quot;hash2&quot;. &quot;hash&quot; is the algorithm that was used in Samba for many years and was the default in Samba 2.2.x &quot;hash2&quot; is
+ now the default and is newer and considered a better algorithm (generates less collisions) in
+ the names. Many Win32 applications store the mangled names and so changing to algorithms must not be done lightly as these applications
+ may break unless reinstalled.
+
+Example: hash</string>
+ <string id="POL_62095050_5FA9_5E4F_8792_595D30BEF047">max stat cache size</string>
+ <string id="POL_62095050_5FA9_5E4F_8792_595D30BEF047_Help">This parameter limits the size in memory of any stat cache being used to speed up case insensitive name mappings. It represents the number of kilobyte (1024) units the stat cache can use. A value of zero, meaning unlimited, is not advisable due to increased memory usage. You should not need to change this parameter.
+
+Example: 100</string>
+ <string id="POL_63F6A053_E2E9_57D0_A0F8_003024AD6470">stat cache</string>
+ <string id="POL_63F6A053_E2E9_57D0_A0F8_003024AD6470_Help">This parameter determines if smbd 8 will use a cache in order to speed up case insensitive name mappings. You should never need to change this parameter.</string>
+ <string id="POL_FBDCB316_EDD2_526C_AE9F_32F50A97A72F">client ldap sasl wrapping</string>
+ <string id="POL_FBDCB316_EDD2_526C_AE9F_32F50A97A72F_Help">The defines whether ldap traffic will be signed or signed and encrypted (sealed). Possible values are plain, sign and seal.
+ The values sign and seal are only available if Samba has been compiled against a modern OpenLDAP version (2.3.x or higher). This option is needed in the case of Domain Controllers enforcing the usage of signed LDAP connections (e.g. Windows 2000 SP3 or higher). LDAP sign and seal can be controlled with the registry key &quot;HKLM\System\CurrentControlSet\Services\ NTDS\Parameters\LDAPServerIntegrity&quot; on the Windows server side.
+ Depending on the used KRB5 library (MIT and older Heimdal versions) it is possible that the message &quot;integrity only&quot; is not supported. In this case, sign is just an alias for seal.
+ The default value is sign. That implies synchronizing the time with the KDC in the case of using Kerberos.</string>
+ <string id="POL_712CFB73_7887_55DD_975B_48DEDBDB9441">ldap admin dn</string>
+ <string id="POL_712CFB73_7887_55DD_975B_48DEDBDB9441_Help">The defines the Distinguished Name (DN) name used by Samba to contact the ldap server when retrieving user account information. The is used in conjunction with the admin dn password stored in the private/secrets.tdb file. See the smbpasswd 8 man page for more information on how to accomplish this.
+ The requires a fully specified DN. The is not appended to the .</string>
+ <string id="POL_CEAB52CA_95EB_5DE5_863B_2399BEF5C727">ldap connection timeout</string>
+ <string id="POL_CEAB52CA_95EB_5DE5_863B_2399BEF5C727_Help">This parameter tells the LDAP library calls which timeout in seconds they should honor during initial connection establishments to LDAP servers. It is very useful in failover scenarios in particular. If one or more LDAP servers are not reachable at all, we do not have to wait until TCP timeouts are over. This feature must be supported by your LDAP library.
+ This parameter is different from which affects operations on LDAP servers using an existing connection and not establishing an initial connection.</string>
+ <string id="POL_4750A945_176C_5FFF_AB50_DF2BE31C3FBB">ldap delete dn</string>
+ <string id="POL_4750A945_176C_5FFF_AB50_DF2BE31C3FBB_Help">This parameter specifies whether a delete operation in the ldapsam deletes the complete entry or only the attributes specific to Samba.</string>
+ <string id="POL_27BBF4DB_E2AE_58D3_8018_E83C4B185A3C">ldap deref</string>
+ <string id="POL_27BBF4DB_E2AE_58D3_8018_E83C4B185A3C_Help">This option controls whether Samba should tell the LDAP library to use a certain alias dereferencing method. The default is auto, which means that the default setting of the ldap client library will be kept. Other possible values are never, finding, searching and always. Grab your LDAP manual for more information.
+
+Example: searching</string>
+ <string id="POL_B383A7ED_F6A4_5BD3_B85E_E6B6527D8D79">ldap follow referral</string>
+ <string id="POL_B383A7ED_F6A4_5BD3_B85E_E6B6527D8D79_Help">This option controls whether to follow LDAP referrals or not when searching for entries in the LDAP database. Possible values are on to enable following referrals, off to disable this, and auto, to use the libldap default settings. libldap's choice of following referrals or not is set in /etc/openldap/ldap.conf with the REFERRALS parameter as documented in ldap.conf(5).
+
+Example: off</string>
+ <string id="POL_E31CD0A8_5A4A_5657_8ACA_123A200C6E06">ldap group suffix</string>
+ <string id="POL_E31CD0A8_5A4A_5657_8ACA_123A200C6E06_Help">This parameter specifies the suffix that is used for groups when these are added to the LDAP directory. If this parameter is unset, the value of will be used instead. The suffix string is prepended to the
+ string so use a partial DN.
+
+Example: ou=Groups</string>
+ <string id="POL_FC4495FC_4C6E_50C8_9B37_08D9955A883B">ldap idmap suffix</string>
+ <string id="POL_FC4495FC_4C6E_50C8_9B37_08D9955A883B_Help">This parameters specifies the suffix that is used when storing idmap mappings. If this parameter is unset, the value of will be used instead. The suffix string is prepended to the string so use a partial DN.
+
+Example: ou=Idmap</string>
+ <string id="POL_2ED1402F_4CF6_5CED_BE40_9B112E1238DC">ldap machine suffix</string>
+ <string id="POL_2ED1402F_4CF6_5CED_BE40_9B112E1238DC_Help">It specifies where machines should be added to the ldap tree. If this parameter is unset, the value of will be used instead. The suffix string is prepended to the string so use a partial DN.
+
+Example: ou=Computers</string>
+ <string id="POL_12C5B04D_D734_576A_99F1_7475BC9E90D7">ldap page size</string>
+ <string id="POL_12C5B04D_D734_576A_99F1_7475BC9E90D7_Help">This parameter specifies the number of entries per page.
+ If the LDAP server supports paged results, clients can request subsets of search results (pages) instead of the entire list. This parameter specifies the size of these pages.
+
+Example: 512</string>
+ <string id="POL_DB427B53_CF02_5410_AE37_5BD4E8B968CE">ldap passwd sync</string>
+ <string id="POL_DB427B53_CF02_5410_AE37_5BD4E8B968CE_Help">This option is used to define whether or not Samba should sync the LDAP password with the NT and LM hashes for normal accounts (NOT for workstation, server or domain trusts) on a password change via SAMBA.
+ The can be set to one of three values: Yes = Try to update the LDAP, NT and LM passwords and update the pwdLastSet time. No = Update NT and LM passwords and update the pwdLastSet time.
+ Only = Only update the LDAP password and let the LDAP server do the rest.</string>
+ <string id="POL_0C51A40C_E06E_5A0A_B160_5EB21289B17D">ldap replication sleep</string>
+ <string id="POL_0C51A40C_E06E_5A0A_B160_5EB21289B17D_Help">When Samba is asked to write to a read-only LDAP replica, we are redirected to talk to the read-write master server. This server then replicates our changes back to the 'local' server, however the replication might take some seconds, especially over slow links. Certain client activities, particularly domain joins, can become confused by the 'success' that does not immediately change the LDAP back-end's data.
+ This option simply causes Samba to wait a short time, to allow the LDAP server to catch up. If you have a particularly high-latency network, you may wish to time the LDAP replication with a network sniffer, and increase this value accordingly. Be aware that no checking is performed that the data has actually replicated.
+ The value is specified in milliseconds, the maximum value is 5000 (5 seconds).</string>
+ <string id="POL_763BAFE2_3FE0_5C25_B3DC_34AE48F2F569">ldapsam:editposix</string>
+ <string id="POL_763BAFE2_3FE0_5C25_B3DC_34AE48F2F569_Help">Editposix is an option that leverages ldapsam:trusted to make it simpler to manage a domain controller eliminating the need to set up custom scripts to add and manage the posix users and groups. This option will instead directly manipulate the ldap tree to create, remove and modify user and group entries. This option also requires a running winbindd as it is used to allocate new uids/gids on user/group creation. The allocation range must be therefore configured.
+ To use this option, a basic ldap tree must be provided and the ldap suffix parameters must be properly configured. On virgin servers the default users and groups (Administrator, Guest, Domain Users, Domain Admins, Domain Guests) can be precreated with the command net sam provision. To run this command the ldap server must be running, Winbindd must be running and the smb.conf ldap options must be properly configured.
+ The typical ldap setup used with the yes option is usually sufficient to use yes as well.
+ An example configuration can be the following:
+ encrypt passwords = true passdb backend = ldapsam
+ ldapsam:trusted=yes ldapsam:editposix=yes
+ ldap admin dn = cn=admin,dc=samba,dc=org ldap delete dn = yes ldap group suffix = ou=groups ldap idmap suffix = ou=idmap ldap machine suffix = ou=computers ldap user suffix = ou=users ldap suffix = dc=samba,dc=org
+ idmap backend = ldap:&quot;ldap://localhost&quot;
+ idmap uid = 5000-50000 idmap gid = 5000-50000
+ This configuration assumes a directory layout like described in the following ldif:
+ dn: dc=samba,dc=org objectClass: top objectClass: dcObject objectClass: organization o: samba.org dc: samba
+ dn: cn=admin,dc=samba,dc=org objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator userPassword: secret
+ dn: ou=users,dc=samba,dc=org objectClass: top objectClass: organizationalUnit ou: users
+ dn: ou=groups,dc=samba,dc=org objectClass: top objectClass: organizationalUnit ou: groups
+ dn: ou=idmap,dc=samba,dc=org objectClass: top objectClass: organizationalUnit ou: idmap
+ dn: ou=computers,dc=samba,dc=org objectClass: top objectClass: organizationalUnit ou: computers</string>
+ <string id="POL_F7979912_0010_5656_BC3A_08876A56418C">ldapsam:trusted</string>
+ <string id="POL_F7979912_0010_5656_BC3A_08876A56418C_Help">By default, Samba as a Domain Controller with an LDAP backend needs to use the Unix-style NSS subsystem to access user and group information. Due to the way Unix stores user information in /etc/passwd and /etc/group this inevitably leads to inefficiencies. One important question a user needs to know is the list of groups he is member of. The plain UNIX model involves a complete enumeration of the file /etc/group and its NSS counterparts in LDAP. UNIX has optimized functions to enumerate group membership. Sadly, other functions that are used to deal with user and group attributes lack such optimization.
+ To make Samba scale well in large environments, the yes option assumes that the complete user and group database that is relevant to Samba is stored in LDAP with the standard posixAccount/posixGroup attributes. It further assumes that the Samba auxiliary object classes are stored together with the POSIX data in the same LDAP object. If these assumptions are met, yes can be activated and Samba can bypass the NSS system to query user group memberships. Optimized LDAP queries can greatly speed up domain logon and administration tasks. Depending on the size of the LDAP database a factor of 100 or more for common queries is easily achieved.</string>
+ <string id="POL_04D79AF3_042D_5ABC_BE8F_4C6628E0F703">ldap server require strong auth</string>
+ <string id="POL_04D79AF3_042D_5ABC_BE8F_4C6628E0F703_Help">The defines whether the ldap server requires ldap traffic to be signed or signed and encrypted (sealed). Possible values are no, allow_sasl_over_tls and yes.
+ A value of no allows simple and sasl binds over all transports.
+ A value of allow_sasl_over_tls allows simple and sasl binds (without sign or seal) over TLS encrypted connections. Unencrypted connections only allow sasl binds with sign or seal.
+ A value of yes allows only simple binds over TLS encrypted connections. Unencrypted connections only allow sasl binds with sign or seal.</string>
+ <string id="POL_5B8B9520_4858_5C2F_AA85_F972FF86784A">ldap ssl</string>
+ <string id="POL_5B8B9520_4858_5C2F_AA85_F972FF86784A_Help">This option is used to define whether or not Samba should use SSL when connecting to the ldap server This is NOT related to Samba's previous SSL support which was enabled by specifying the --with-ssl option to the configure script.
+ LDAP connections should be secured where possible. This may be done setting either this parameter to start tls or by specifying ldaps:// in
+ the URL argument of .
+ The can be set to one of two values: Off = Never use SSL when querying the directory.
+ start tls = Use the LDAPv3 StartTLS extended operation (RFC2830) for communicating with the directory server. Please note that this parameter does only affect rpc methods. To enable the LDAPv3 StartTLS extended operation (RFC2830) for ads, set start tls and yes. See smb.conf5 for more information on .</string>
+ <string id="POL_42494B88_7254_5F5F_B738_D5D10BCFBC6C">ldap ssl ads</string>
+ <string id="POL_42494B88_7254_5F5F_B738_D5D10BCFBC6C_Help">This option is used to define whether or not Samba should use SSL when connecting to the ldap server using ads methods. Rpc methods are not affected by this parameter. Please note, that this parameter won't have any effect if is set to no.
+ See smb.conf5 for more information on .</string>
+ <string id="POL_9B071174_FBD3_5CA8_82AA_3BD1EB7BCF45">ldap suffix</string>
+ <string id="POL_9B071174_FBD3_5CA8_82AA_3BD1EB7BCF45_Help">Specifies the base for all ldap suffixes and for storing the sambaDomain object.
+ The ldap suffix will be appended to the values specified for the , , , and the . Each of these should be given only a DN relative to the .
+
+Example: dc=samba,dc=org</string>
+ <string id="POL_40F4D046_B9E1_53B0_9DC9_1AE4DE9B1976">ldap timeout</string>
+ <string id="POL_40F4D046_B9E1_53B0_9DC9_1AE4DE9B1976_Help">This parameter defines the number of seconds that Samba should use as timeout for LDAP operations.</string>
+ <string id="POL_26984E46_7C64_57A4_B4BF_C2C2B13C330E">ldap user suffix</string>
+ <string id="POL_26984E46_7C64_57A4_B4BF_C2C2B13C330E_Help">This parameter specifies where users are added to the tree. If this parameter is unset, the value of will be used instead. The suffix string is prepended to the string so use a partial DN.
+
+Example: ou=people</string>
+ <string id="POL_AB95F2C5_BFBC_5955_8062_8B446AF7E84C">ldap max anonymous request size</string>
+ <string id="POL_AB95F2C5_BFBC_5955_8062_8B446AF7E84C_Help">This parameter specifies the maximum permitted size (in bytes) for an LDAP request received on an anonymous connection.
+ If the request size exceeds this limit the request will be rejected.
+
+Example: 500000</string>
+ <string id="POL_23FFECD5_A3C4_566C_AEB3_015F25B1A978">ldap max authenticated request size</string>
+ <string id="POL_23FFECD5_A3C4_566C_AEB3_015F25B1A978_Help">This parameter specifies the maximum permitted size (in bytes) for an LDAP request received on an authenticated connection.
+ If the request size exceeds this limit the request will be rejected.
+
+Example: 4194304</string>
+ <string id="POL_F7C651B1_70B4_5047_BC65_2E4D382CBD15">ldap max search request size</string>
+ <string id="POL_F7C651B1_70B4_5047_BC65_2E4D382CBD15_Help">This parameter specifies the maximum permitted size (in bytes) for an LDAP search request.
+ If the request size exceeds this limit the request will be rejected.
+
+Example: 4194304</string>
+ <string id="POL_B3B2B9CC_3DBC_5C45_AA31_7C1E52AFEFAF">lock spin time</string>
+ <string id="POL_B3B2B9CC_3DBC_5C45_AA31_7C1E52AFEFAF_Help">The time in milliseconds that smbd should keep waiting to see if a failed lock request can be granted. This parameter has changed in default value from Samba 3.0.23 from 10 to 200. The associated parameter is no longer used in Samba 3.0.24. You should not need to change the value of this parameter.</string>
+ <string id="POL_4A0366F2_6815_5654_8DC2_F68E840E53F4">oplock break wait time</string>
+ <string id="POL_4A0366F2_6815_5654_8DC2_F68E840E53F4_Help">This is a tuning parameter added due to bugs in both Windows 9x and WinNT. If Samba responds to a client too quickly when that client issues an SMB that can cause an oplock break request, then the network client can fail and not respond to the break request. This tuning parameter (which is set in milliseconds) is the amount of time Samba will wait before sending an oplock break request to such (broken) clients.
+ DO NOT CHANGE THIS PARAMETER UNLESS YOU HAVE READ AND UNDERSTOOD THE SAMBA OPLOCK CODE.</string>
+ <string id="POL_B49FAE41_B4C1_5AFA_870E_9E1C35F9A96F">smb2 leases</string>
+ <string id="POL_B49FAE41_B4C1_5AFA_870E_9E1C35F9A96F_Help">This boolean option tells smbd whether to globally negotiate SMB2 leases on file open requests. Leasing is an SMB2-only feature which allows clients to aggressively cache files locally above and beyond the caching allowed by SMB1 oplocks.
+ This is only available with yes and no.</string>
+ <string id="POL_1E9B5BE6_8C81_5141_88CD_B5AC0E8D964B">debug class</string>
+ <string id="POL_1E9B5BE6_8C81_5141_88CD_B5AC0E8D964B_Help">With this boolean parameter enabled, the debug class (DBGC_CLASS)
+ will be displayed in the debug header.
+
+
+ For more information about currently available debug classes, see
+ section about .</string>
+ <string id="POL_07D2E039_C5A0_5123_BD71_0C74E2569310">debug hires timestamp</string>
+ <string id="POL_07D2E039_C5A0_5123_BD71_0C74E2569310_Help">Sometimes the timestamps in the log messages are needed with a resolution of higher that seconds, this
+ boolean parameter adds microsecond resolution to the timestamp message header when turned on.
+
+
+
+ Note that the parameter must be on for this to have an effect.</string>
+ <string id="POL_E066DF4A_5BA1_5B35_A96F_90DE6CF27132">debug pid</string>
+ <string id="POL_E066DF4A_5BA1_5B35_A96F_90DE6CF27132_Help">When using only one log file for more then one forked smbd
+ 8-process there may be hard to follow which process outputs which
+ message. This boolean parameter is adds the process-id to the timestamp message headers in the
+ logfile when turned on.
+
+
+
+ Note that the parameter must be on for this to have an effect.</string>
+ <string id="POL_4B4EF8B5_3526_5583_8174_E3E332727970">debug prefix timestamp</string>
+ <string id="POL_4B4EF8B5_3526_5583_8174_E3E332727970_Help">With this option enabled, the timestamp message header is prefixed to the debug message without the
+ filename and function information that is included with the
+ parameter. This gives timestamps to the messages without adding an additional line.
+
+
+
+ Note that this parameter overrides the parameter.</string>
+ <string id="POL_571A8B87_3CCC_5725_BA33_BDEE367BB740">debug uid</string>
+ <string id="POL_571A8B87_3CCC_5725_BA33_BDEE367BB740_Help">Samba is sometimes run as root and sometime run as the connected user, this boolean parameter inserts the
+ current euid, egid, uid and gid to the timestamp message headers in the log file if turned on.
+
+
+ Note that the parameter must be on for this to have an effect.</string>
+ <string id="POL_2167CEE9_B2C9_5574_8F7D_F38DA9EBBFF1">ldap debug level</string>
+ <string id="POL_2167CEE9_B2C9_5574_8F7D_F38DA9EBBFF1_Help">This parameter controls the debug level of the LDAP library calls. In the case of OpenLDAP, it is the same bit-field as understood by the server and documented in the slapd.conf 5 manpage. A typical useful value will be 1 for tracing function calls. The debug output from the LDAP libraries appears with the prefix [LDAP] in Samba's logging output. The level at which LDAP logging is printed is controlled by the parameter ldap debug threshold.
+
+Example: 1</string>
+ <string id="POL_F324946B_9B0D_53F0_AD4F_56800DD63085">ldap debug threshold</string>
+ <string id="POL_F324946B_9B0D_53F0_AD4F_56800DD63085_Help">This parameter controls the Samba debug level at which the ldap library debug output is printed in the Samba logs. See the description of ldap debug level for details.
+
+Example: 5</string>
+ <string id="POL_3A601C55_A5EB_5E86_817B_38DACFD45CF9">log file</string>
+ <string id="POL_3A601C55_A5EB_5E86_817B_38DACFD45CF9_Help">This option allows you to override the name of the Samba log file (also known as the debug file).
+
+
+
+ This option takes the standard substitutions, allowing you to have separate log files for each user or machine.
+
+Example: /usr/local/samba/var/log.%m</string>
+ <string id="POL_A3E0303F_93B5_5C1F_8C01_362881F843CC">logging</string>
+ <string id="POL_A3E0303F_93B5_5C1F_8C01_362881F843CC_Help">This parameter configures logging backends. Multiple
+ backends can be specified at the same time, with different log
+ levels for each backend. The parameter is a list of backends,
+ where each backend is specified as backend[:option][@loglevel].
+
+ The 'option' parameter can be used to pass backend-specific
+ options.
+
+ The log level for a backend is optional, if it is not set for
+ a backend, all messages are sent to this backend. The parameter
+ determines overall log levels,
+ while the log levels specified here define what is sent to the
+ individual backends.
+
+ When is set, it overrides the
+ and parameters.
+
+ Some backends are only available when Samba has been compiled
+ with the additional libraries. The overall list of logging backends:
+
+
+ syslog
+ file
+ systemd
+ lttng
+ gpfs
+ ringbuf
+
+
+ The ringbuf backend supports an
+ optional size argument to change the buffer size used, the default is 1 MB:
+ ringbuf:size=NBYTES
+
+Example: syslog@1 file</string>
+ <string id="POL_E077BD91_3587_5DBA_A7CB_13044D97E451">log level</string>
+ <string id="POL_E077BD91_3587_5DBA_A7CB_13044D97E451_Help">The value of the parameter (a string) allows the debug level (logging level) to be specified in the
+ smb.conf file.
+
+
+ This parameter has been extended since the 2.2.x
+ series, now it allows one to specify the debug level for multiple
+ debug classes and distinct logfiles for debug classes. This is to give
+ greater flexibility in the configuration of the system. The following
+ debug classes are currently implemented:
+
+
+ all tdb printdrivers lanman smb smb2 smb2_credits rpc_parse rpc_srv rpc_cli passdb sam auth winbind vfs idmap quota acls locking msdfs dmapi registry
+ scavenger
+ dns
+ ldb
+ tevent
+ auth_audit
+ auth_json_audit
+ kerberos
+ dsdb_audit
+ dsdb_json_audit
+ dsdb_password_audit
+ dsdb_password_json_audit
+ dsdb_transaction_audit
+ dsdb_transaction_json_audit
+
+
+ To configure the logging for specific classes to go into a different
+ file then , you can append
+ @PATH to the class, eg log level = 1
+ full_audit:1@/var/log/audit.log.
+
+ Authentication and authorization audit information is logged
+ under the auth_audit, and if Samba was not compiled with
+ --without-json, a JSON representation is logged under
+ auth_json_audit.
+
+ Support is comprehensive for all authentication and authorisation
+ of user accounts in the Samba Active Directory Domain Controller,
+ as well as the implicit authentication in password changes. In
+ the file server, NTLM authentication, SMB and RPC authorization is
+ covered.
+
+ Log levels for auth_audit and auth_audit_json are:
+ 2: Authentication Failure 3: Authentication Success 4: Authorization Success 5: Anonymous Authentication and Authorization Success
+
+
+ Changes to the sam.ldb database are logged
+ under the dsdb_audit and a JSON representation is logged under
+ dsdb_json_audit.
+
+ Password changes and Password resets are logged under
+ dsdb_password_audit and a JSON representation is logged under the
+ dsdb_password_json_audit.
+
+ Transaction rollbacks and prepare commit failures are logged under
+ the dsdb_transaction_audit and a JSON representation is logged under the
+ password_json_audit. Logging the transaction details allows the
+ identification of password and sam.ldb operations that have been rolled
+ back.
+
+Example: 3 passdb:5 auth:10 winbind:2
+
+Example: 1 full_audit:1@/var/log/audit.log winbind:2</string>
+ <string id="POL_7E7EB779_098F_5383_A0B3_66216F434918">max log size</string>
+ <string id="POL_7E7EB779_098F_5383_A0B3_66216F434918_Help">This option (an integer in kilobytes) specifies the max size the log file should grow to.
+ Samba periodically checks the size and if it is exceeded it will rename the file, adding a .old extension.
+ A size of 0 means no limit.
+
+Example: 1000</string>
+ <string id="POL_57C1D731_63A4_519D_BD0B_05683B94BFDB">syslog</string>
+ <string id="POL_57C1D731_63A4_519D_BD0B_05683B94BFDB_Help">This parameter maps how Samba debug messages are logged onto the system syslog logging levels.
+ Samba debug level zero maps onto syslog LOG_ERR, debug level one maps onto
+ LOG_WARNING, debug level two maps onto LOG_NOTICE,
+ debug level three maps onto LOG_INFO. All higher levels are mapped to LOG_DEBUG.
+
+
+
+ This parameter sets the threshold for sending messages to syslog. Only messages with debug
+ level less than this value will be sent to syslog. There still will be some
+ logging to log.[sn]mbd even if syslog only is enabled.
+
+
+ The parameter should be used
+ instead. When is set, it
+ overrides the parameter.</string>
+ <string id="POL_07C28AF5_BA9B_5B55_A018_28B10E803B26">syslog only</string>
+ <string id="POL_07C28AF5_BA9B_5B55_A018_28B10E803B26_Help">If this parameter is set then Samba debug messages are logged into the system
+ syslog only, and not to the debug log files. There still will be some logging to log.[sn]mbd even if syslog only is enabled.
+
+
+
+ The parameter should be used
+ instead. When is set, it
+ overrides the parameter.</string>
+ <string id="POL_C2541812_F829_51FC_93D7_75BA34C1F487">timestamp logs</string>
+ <string id="POL_C2541812_F829_51FC_93D7_75BA34C1F487_Help">Samba debug log messages are timestamped by default. If you are running at a high
+ these timestamps can be distracting. This
+ boolean parameter allows timestamping to be turned off.</string>
+ <string id="POL_3B7BF4ED_04E2_5466_9368_8610A5657F8F">abort shutdown script</string>
+ <string id="POL_3B7BF4ED_04E2_5466_9368_8610A5657F8F_Help">This a full path name to a script called by smbd 8 that should stop a shutdown procedure issued by the . If the connected user possesses the SeRemoteShutdownPrivilege, right, this command will be run as root.
+
+Example: /sbin/shutdown -c</string>
+ <string id="POL_7EEBACBA_ED90_5C68_826F_737212B364EF">add group script</string>
+ <string id="POL_7EEBACBA_ED90_5C68_826F_737212B364EF_Help">This is the full pathname to a script that will be run AS ROOT by smbd8 when a new group is requested. It will expand any %g to the group name passed. This script is only useful for installations using the Windows NT domain administration tools. The script is free to create a group with an arbitrary name to circumvent unix group name restrictions. In that case the script must print the numeric gid of the created group on stdout.
+
+Example: /usr/sbin/groupadd %g</string>
+ <string id="POL_96F9DA59_163C_56B8_9F66_40CAAD868F91">add machine script</string>
+ <string id="POL_96F9DA59_163C_56B8_9F66_40CAAD868F91_Help">This is the full pathname to a script that will be run by smbd 8 when a machine is added to Samba's domain and a Unix account matching the machine's name appended with a &quot;$&quot; does not already exist.
+ This option is very similar to the , and likewise uses the %u
+ substitution for the account name. Do not use the %m
+ substitution.
+
+Example: /usr/sbin/adduser -n -g machines -c Machine -d /var/lib/nobody -s /bin/false %u</string>
+ <string id="POL_4AEC4EDA_3303_57E2_BC12_784F40DACA8F">add user script</string>
+ <string id="POL_4AEC4EDA_3303_57E2_BC12_784F40DACA8F_Help">This is the full pathname to a script that will be run AS ROOT by smbd 8 under special circumstances described below.
+ Normally, a Samba server requires that UNIX users are created for all users accessing files on this server. For sites that use Windows NT account databases as their primary user database creating these users and keeping the user list in sync with the Windows NT PDC is an onerous task. This option allows smbd to create the required UNIX users ON DEMAND when a user accesses the Samba server.
+ When the Windows user attempts to access the Samba server, at login (session setup in the SMB protocol) time, smbd 8 contacts the and attempts to authenticate the given user with the given password. If the authentication succeeds then smbd attempts to find a UNIX user in the UNIX password database to map the Windows user into. If this lookup fails, and is set then smbd will call the specified script AS ROOT, expanding any %u argument to be the user name to create.
+ If this script successfully creates the user then smbd will continue on as though the UNIX user already existed. In this way, UNIX users are dynamically created to match existing Windows NT accounts.
+ See also , , .
+
+Example: /usr/local/samba/bin/add_user %u</string>
+ <string id="POL_5268249C_58BD_59DA_B44F_DA9109370C58">add user to group script</string>
+ <string id="POL_5268249C_58BD_59DA_B44F_DA9109370C58_Help">Full path to the script that will be called when a user is added to a group using the Windows NT domain administration tools. It will be run by smbd 8 AS ROOT. Any %g will be replaced with the group name and any %u will be replaced with the user name.
+ Note that the adduser command used in the example below does not support the used syntax on all systems.
+
+Example: /usr/sbin/adduser %u %g</string>
+ <string id="POL_89206841_7524_5BFF_872C_444F45C82318">allow nt4 crypto</string>
+ <string id="POL_89206841_7524_5BFF_872C_444F45C82318_Help">This option controls whether the netlogon server (currently only in 'active directory domain controller' mode), will reject clients which does not support NETLOGON_NEG_STRONG_KEYS nor NETLOGON_NEG_SUPPORTS_AES.
+ This option was added with Samba 4.2.0. It may lock out clients which worked fine with Samba versions up to 4.1.x. as the effective default was &quot;yes&quot; there, while it is &quot;no&quot; now.
+ If you have clients without RequireStrongKey = 1 in the registry, you may need to set &quot;allow nt4 crypto = yes&quot;, until you have fixed all clients.
+ &quot;allow nt4 crypto = yes&quot; allows weak crypto to be negotiated, maybe via downgrade attacks.
+ This option yields precedence to the 'reject md5 clients' option.</string>
+ <string id="POL_9A41AF51_88E9_5566_B12E_36DEA5C42D49">auth event notification</string>
+ <string id="POL_9A41AF51_88E9_5566_B12E_36DEA5C42D49_Help">When enabled, this option causes Samba (acting as an Active Directory Domain Controller) to stream authentication events across the internal message bus. Scripts built using Samba's python bindings can listen to these events by registering as the service auth_event.
+ This should be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around). Additionally Samba must be compiled with the jansson support for this option to be effective.
+ The authentication events are also logged via the normal logging methods when the is set appropriately.</string>
+ <string id="POL_1CAC5DAB_3CB5_586A_AB6F_84E39DDF4796">delete group script</string>
+ <string id="POL_1CAC5DAB_3CB5_586A_AB6F_84E39DDF4796_Help">This is the full pathname to a script that will be run AS ROOT by smbd 8 when a group is requested to be deleted. It will expand any %g to the group name passed. This script is only useful for installations using the Windows NT domain administration tools.</string>
+ <string id="POL_789E0632_E8D7_5FD6_86C6_0EBD079D28C4">delete user from group script</string>
+ <string id="POL_789E0632_E8D7_5FD6_86C6_0EBD079D28C4_Help">Full path to the script that will be called when a user is removed from a group using the Windows NT domain administration tools. It will be run by smbd 8 AS ROOT. Any %g will be replaced with the group name and any %u will be replaced with the user name.
+
+Example: /usr/sbin/deluser %u %g</string>
+ <string id="POL_A399CF3E_C0C6_594B_8F31_F2AA4A18B5AC">delete user script</string>
+ <string id="POL_A399CF3E_C0C6_594B_8F31_F2AA4A18B5AC_Help">This is the full pathname to a script that will be run by smbd 8 when managing users with remote RPC (NT) tools.
+ This script is called when a remote client removes a user from the server, normally using 'User Manager for Domains' or rpcclient.
+ This script should delete the given UNIX username.
+
+Example: /usr/local/samba/bin/del_user %u</string>
+ <string id="POL_B35B056A_EEB8_5B89_9FCC_127565F4A6AC">domain logons</string>
+ <string id="POL_B35B056A_EEB8_5B89_9FCC_127565F4A6AC_Help">If set to yes, the Samba server will provide the netlogon service for Windows 9X network logons for the it is in. This will also cause the Samba server to act as a domain controller for NT4 style domain services. For more details on setting up this feature see the Domain Control chapter of the Samba HOWTO Collection.</string>
+ <string id="POL_3B3E3AD6_FB80_5225_8EDA_6066E5987CE1">enable privileges</string>
+ <string id="POL_3B3E3AD6_FB80_5225_8EDA_6066E5987CE1_Help">This deprecated parameter controls whether or not smbd will honor privileges assigned to specific SIDs via either net rpc rights or one of the Windows user and group manager tools. This parameter is enabled by default. It can be disabled to prevent members of the Domain Admins group from being able to assign privileges to users or groups which can then result in certain smbd operations running as root that would normally run under the context of the connected user.
+ An example of how privileges can be used is to assign the right to join clients to a Samba controlled domain without providing root access to the server via smbd.
+ Please read the extended description provided in the Samba HOWTO documentation.</string>
+ <string id="POL_130E1C0E_9AED_52F5_B1AB_20FD88C999E8">init logon delay</string>
+ <string id="POL_130E1C0E_9AED_52F5_B1AB_20FD88C999E8_Help">This parameter specifies a delay in milliseconds for the hosts configured for delayed initial samlogon with .</string>
+ <string id="POL_EEBDC4C9_64BA_58DF_B7A3_C384D6972690">init logon delayed hosts</string>
+ <string id="POL_EEBDC4C9_64BA_58DF_B7A3_C384D6972690_Help">This parameter takes a list of host names, addresses or networks for which the initial samlogon reply should be delayed (so other DCs get preferred by XP workstations if there are any).
+ The length of the delay can be specified with the parameter.
+
+Example: 150.203.5. myhost.mynet.de</string>
+ <string id="POL_2FCE2207_11A6_5B55_9ECC_49D171438176">logon drive</string>
+ <string id="POL_2FCE2207_11A6_5B55_9ECC_49D171438176_Help">This parameter specifies the local path to which the home directory will be connected (see ) and is only used by NT Workstations.
+ Note that this option is only useful if Samba is set up as a logon server.
+
+Example: h:</string>
+ <string id="POL_12DCA5BB_14ED_5BC6_AB9D_E6A57E943B24">logon home</string>
+ <string id="POL_12DCA5BB_14ED_5BC6_AB9D_E6A57E943B24_Help">This parameter specifies the home directory location when a Win95/98 or NT Workstation logs into a Samba PDC. It allows you to do C:\&gt;NET USE H: /HOME
+ from a command prompt, for example.
+ This option takes the standard substitutions, allowing you to have separate logon scripts for each user or machine.
+ This parameter can be used with Win9X workstations to ensure that roaming profiles are stored in a subdirectory of the user's home directory. This is done in the following way:
+ logon home = \\%N\%U\profile
+ This tells Samba to return the above string, with substitutions made when a client requests the info, generally in a NetUserGetInfo request. Win9X clients truncate the info to \\server\share when a user does
+ net use /home but use the whole string when dealing with profiles.
+ Note that in prior versions of Samba, the was returned rather than logon home. This broke net use /home but allowed profiles outside the home directory. The current implementation is correct, and can be used for profiles if you use the above trick.
+ Disable this feature by setting &quot;&quot; - using the empty string.
+ This option is only useful if Samba is set up as a logon server.
+
+Example: \\remote_smb_server\%U</string>
+ <string id="POL_6C04D9F3_27E3_51A9_82B5_BEB5265E1236">logon path</string>
+ <string id="POL_6C04D9F3_27E3_51A9_82B5_BEB5265E1236_Help">This parameter specifies the directory where roaming profiles (Desktop, NTuser.dat, etc) are stored. Contrary to previous versions of these manual pages, it has nothing to do with Win 9X roaming profiles. To find out how to handle roaming profiles for Win 9X system, see the parameter.
+ This option takes the standard substitutions, allowing you to have separate logon scripts for each user or machine. It also specifies the directory from which the &quot;Application Data&quot;, desktop, start menu, network neighborhood, programs and other folders, and their contents, are loaded and displayed on your Windows NT client.
+ The share and the path must be readable by the user for the preferences and directories to be loaded onto the Windows NT client. The share must be writeable when the user logs in for the first time, in order that the Windows NT client can create the NTuser.dat and other directories. Thereafter, the directories and any of the contents can, if required, be made read-only. It is not advisable that the NTuser.dat file be made read-only - rename it to NTuser.man to achieve the desired effect (a MANdatory profile).
+ Windows clients can sometimes maintain a connection to the [homes] share, even though there is no user logged in. Therefore, it is vital that the logon path does not include a reference to the homes share (i.e. setting this parameter to \\%N\homes\profile_path will cause problems).
+ This option takes the standard substitutions, allowing you to have separate logon scripts for each user or machine.
+ Do not quote the value. Setting this as \\%N\profile\%U will break profile handling. Where the tdbsam or ldapsam passdb backend is used, at the time the user account is created the value configured for this parameter is written to the passdb backend and that value will over-ride the parameter value present in the smb.conf file. Any error present in the passdb backend account record must be edited using the appropriate tool (pdbedit on the command-line, or any other locally provided system tool).
+ Note that this option is only useful if Samba is set up as a domain controller.
+ Disable the use of roaming profiles by setting the value of this parameter to the empty string. For example, &quot;&quot;. Take note that even if the default setting in the smb.conf file is the empty string, any value specified in the user account settings in the passdb backend will over-ride the effect of setting this parameter to null. Disabling of all roaming profile use requires that the user account settings must also be blank.
+ An example of use is:
+
+logon path = \\PROFILESERVER\PROFILE\%U</string>
+ <string id="POL_D354C217_6C18_5AD8_B0A2_DDC89463D0C6">logon script</string>
+ <string id="POL_D354C217_6C18_5AD8_B0A2_DDC89463D0C6_Help">This parameter specifies the batch file (.bat) or NT command file (.cmd) to be downloaded and run on a machine when a user successfully logs in. The file must contain the DOS style CR/LF line endings. Using a DOS-style editor to create the file is recommended. The script must be a relative path to the service. If the [netlogon] service specifies a of /usr/local/samba/netlogon, and STARTUP.BAT, then the file that will be downloaded is:
+ /usr/local/samba/netlogon/STARTUP.BAT
+
+ The contents of the batch file are entirely your choice. A suggested command would be to add NET TIME \\SERVER /SET /YES, to force every machine to synchronize clocks with the same time server. Another use would be to add NET USE U: \\SERVER\UTILS for commonly used utilities, or
+
+NET USE Q: \\SERVER\ISO9001_QA
+ for example.
+ Note that it is particularly important not to allow write access to the [netlogon] share, or to grant users write permission on the batch files in a secure environment, as this would allow the batch files to be arbitrarily modified and security to be breached.
+ This option takes the standard substitutions, allowing you to have separate logon scripts for each user or machine.
+ This option is only useful if Samba is set up as a logon server in a classic domain controller role.
+ If Samba is set up as an Active Directory domain controller, LDAP attribute scriptPath
+ is used instead. For configurations where ldapsam is in use,
+ this option only defines a default value in case LDAP attribute sambaLogonScript
+ is missing.
+
+Example: scripts\%U.bat</string>
+ <string id="POL_0AABECB8_5A60_50DA_973A_7EED1138DB0C">reject md5 clients</string>
+ <string id="POL_0AABECB8_5A60_50DA_973A_7EED1138DB0C_Help">This option controls whether the netlogon server (currently only in 'active directory domain controller' mode), will reject clients which does not support NETLOGON_NEG_SUPPORTS_AES.
+ You can set this to yes if all domain members support aes. This will prevent downgrade attacks.
+ This option takes precedence to the 'allow nt4 crypto' option.</string>
+ <string id="POL_68A94D8F_DA35_5CEC_90E6_4FB245FF32D3">set primary group script</string>
+ <string id="POL_68A94D8F_DA35_5CEC_90E6_4FB245FF32D3_Help">Thanks to the Posix subsystem in NT a Windows User has a primary group in addition to the auxiliary groups. This script sets the primary group in the unix user database when an administrator sets the primary group from the windows user manager or when fetching a SAM with net rpc vampire. %u will be replaced with the user whose primary group is to be set. %g will be replaced with the group to set.
+
+Example: /usr/sbin/usermod -g '%g' '%u'</string>
+ <string id="POL_5CDF89E1_F318_5495_BEA0_DA44F0542D49">shutdown script</string>
+ <string id="POL_5CDF89E1_F318_5495_BEA0_DA44F0542D49_Help">This a full path name to a script called by smbd
+ 8 that should start a shutdown procedure.
+ If the connected user possesses the SeRemoteShutdownPrivilege, right, this command will be run as root.
+ The %z %t %r %f variables are expanded as follows: %z will be substituted with the shutdown message sent to the server. %t will be substituted with the number of seconds to wait before effectively starting the shutdown procedure. %r will be substituted with the switch -r. It means reboot after shutdown for NT. %f will be substituted with the switch -f. It means force the shutdown even if applications do not respond for NT.
+ Shutdown script example:
+
+#!/bin/bash
+
+time=$2
+let time=&quot;${time} / 60&quot;
+let time=&quot;${time} + 1&quot;
+
+/sbin/shutdown $3 $4 +$time $1 &amp;
+
+
+ Shutdown does not return so we need to launch it in background.
+
+Example: /usr/local/samba/sbin/shutdown %m %t %r %f</string>
+ <string id="POL_3F1B0630_F3F0_5FDE_B66B_1A315CC059B3">add share command</string>
+ <string id="POL_3F1B0630_F3F0_5FDE_B66B_1A315CC059B3_Help">Samba 2.2.0 introduced the ability to dynamically add and delete shares via the Windows NT 4.0 Server Manager. The add share command is used to define an external program or script which will add a new service definition to smb.conf.
+ In order to successfully execute the add share command, smbd requires that the administrator connects using a root account (i.e. uid == 0) or has the SeDiskOperatorPrivilege. Scripts defined in the add share command parameter are executed as root.
+ When executed, smbd will automatically invoke the add share command with five parameters.
+ configFile - the location of the global smb.conf file.
+ shareName - the name of the new share.
+ pathName - path to an **existing** directory on disk.
+ comment - comment string to associate with the new share.
+ max connections Number of maximum simultaneous connections to this share.
+ This parameter is only used to add file shares. To add printer shares, see the .
+
+Example: /usr/local/bin/addshare</string>
+ <string id="POL_66A8EC32_6235_5E7C_A085_189166239268">afs token lifetime</string>
+ <string id="POL_66A8EC32_6235_5E7C_A085_189166239268_Help">This parameter controls the lifetime of tokens that the AFS fake-kaserver claims. In reality these never expire but this lifetime controls when the afs client will forget the token.
+ Set this parameter to 0 to get NEVERDATE.</string>
+ <string id="POL_78946CAB_73BD_507E_96D5_C643814290D0">afs username map</string>
+ <string id="POL_78946CAB_73BD_507E_96D5_C643814290D0_Help">If you are using the fake kaserver AFS feature, you might want to hand-craft the usernames you are creating tokens for. For example this is necessary if you have users from several domain in your AFS Protection Database. One possible scheme to code users as DOMAIN+User as it is done by winbind with the + as a separator.
+ The mapped user name must contain the cell name to log into, so without setting this parameter there will be no token.
+
+Example: %u@afs.samba.org</string>
+ <string id="POL_DEF84B6C_B415_56EB_B3E7_1ED683BFEDE5">allow insecure wide links</string>
+ <string id="POL_DEF84B6C_B415_56EB_B3E7_1ED683BFEDE5_Help">In normal operation the option which allows the server to follow symlinks outside of a share path is automatically disabled when are enabled on a Samba server. This is done for security purposes to prevent UNIX clients creating symlinks to areas of the server file system that the administrator does not wish to export. Setting to true disables the link between these two parameters, removing this protection and allowing a site to configure the server to follow symlinks (by setting to &quot;true&quot;) even when is turned on. It is not recommended to enable this option unless you fully understand the implications of allowing the server to follow symbolic links created by UNIX clients. For most normal Samba configurations this would be considered a security hole and setting this parameter is not recommended. This option was added at the request of sites who had deliberately set Samba up in this way and needed to continue supporting this functionality without having to patch the Samba code.</string>
+ <string id="POL_8539DC0B_8971_5145_8173_C77681F13A94">allow unsafe cluster upgrade</string>
+ <string id="POL_8539DC0B_8971_5145_8173_C77681F13A94_Help">If set to no (the default), smbd checks at startup if other smbd versions are running in the cluster and refuses to start if so. This is done to protect data corruption in internal data structures due to incompatible Samba versions running concurrently in the same cluster. Setting this parameter to yes disables this safety check.</string>
+ <string id="POL_A05EAA54_C6F4_567A_8DE6_7541F9B11046">async smb echo handler</string>
+ <string id="POL_A05EAA54_C6F4_567A_8DE6_7541F9B11046_Help">This parameter specifies whether Samba should fork the async smb echo handler. It can be beneficial if your file system can block syscalls for a very long time. In some circumstances, it prolongs the timeout that Windows uses to determine whether a connection is dead. This parameter is only for SMB1. For SMB2 and above TCP keepalives can be used instead.</string>
+ <string id="POL_087EEAB6_7F83_50CF_A3D0_97B4C6F94F67">auto services</string>
+ <string id="POL_087EEAB6_7F83_50CF_A3D0_97B4C6F94F67_Help">This is a list of services that you want to be automatically added to the browse lists. This is most useful for homes and printers services that would otherwise not be visible.
+ Note that if you just want all printers in your printcap file loaded then the option is easier.
+
+Example: fred lp colorlp</string>
+ <string id="POL_5518624A_7DB9_51BA_A891_F00A40152354">cache directory</string>
+ <string id="POL_5518624A_7DB9_51BA_A891_F00A40152354_Help">Usually, most of the TDB files are stored in the lock directory. Since Samba 3.4.0, it is possible to differentiate between TDB files with persistent data and TDB files with non-persistent data using the state directory and the cache directory options.
+ This option specifies the directory for storing TDB files containing non-persistent data that will be kept across service restarts. The directory should be placed on persistent storage, but the data can be safely deleted by an administrator.
+
+Example: /var/run/samba/locks/cache</string>
+ <string id="POL_3E23F826_A699_511F_9370_F79DBB4977A9">change notify</string>
+ <string id="POL_3E23F826_A699_511F_9370_F79DBB4977A9_Help">This parameter specifies whether Samba should reply to a client's file change notify requests.
+ You should never need to change this parameter</string>
+ <string id="POL_3EF254FF_4CC2_58A5_9A1B_4E0655610DCA">change share command</string>
+ <string id="POL_3EF254FF_4CC2_58A5_9A1B_4E0655610DCA_Help">Samba 2.2.0 introduced the ability to dynamically add and delete shares via the Windows NT 4.0 Server
+Manager. The change share command is used to define an external
+program or script which will modify an existing service definition in smb.conf.
+ In order to successfully execute the change share command, smbd requires that the administrator connects using a root account (i.e. uid == 0) or has the SeDiskOperatorPrivilege. Scripts defined in the change share command parameter are executed as root.
+ When executed, smbd will automatically invoke the change share command with six parameters.
+ configFile - the location of the global smb.conf file.
+ shareName - the name of the new share.
+ pathName - path to an **existing** directory on disk.
+ comment - comment string to associate with the new share.
+ max connections Number of maximum simultaneous connections to this share.
+ CSC policy - client side caching policy in string form. Valid values are: manual, documents, programs, disable.
+ This parameter is only used to modify existing file share definitions. To modify printer shares, use the &quot;Printers...&quot; folder as seen when browsing the Samba host.
+
+Example: /usr/local/bin/changeshare</string>
+ <string id="POL_93ADB149_A45A_56A2_9462_0BE437084E47">cluster addresses</string>
+ <string id="POL_93ADB149_A45A_56A2_9462_0BE437084E47_Help">With this parameter you can add additional addresses that nmbd will register with a WINS server. Similarly, these addresses will be registered by default when net ads dns register is called with yes configured.
+
+Example: 10.0.0.1 10.0.0.2 10.0.0.3</string>
+ <string id="POL_306A8E87_1400_5208_8ABF_B9802BFA685B">clustering</string>
+ <string id="POL_306A8E87_1400_5208_8ABF_B9802BFA685B_Help">This parameter specifies whether Samba should contact ctdb for accessing its tdb files and use ctdb as a backend for its messaging backend.
+ Set this parameter to yes only if you have a cluster setup with ctdb running.</string>
+ <string id="POL_2D29302D_8AD7_5BC3_B681_8C54D0A61E68">config file</string>
+ <string id="POL_2D29302D_8AD7_5BC3_B681_8C54D0A61E68_Help">This allows you to override the config file to use, instead of the default (usually smb.conf). There is a chicken and egg problem here as this option is set in the config file!
+ For this reason, if the name of the config file has changed when the parameters are loaded then it will reload them from the new config file.
+ This option takes the usual substitutions, which can be very useful.
+ If the config file doesn't exist then it won't be loaded (allowing you to special case the config files of just a few clients).
+
+Example: /usr/local/samba/lib/smb.conf.%m</string>
+ <string id="POL_3838911B_D4E6_50BD_B168_85F113E29165">ctdbd socket</string>
+ <string id="POL_3838911B_D4E6_50BD_B168_85F113E29165_Help">If you set clustering=yes, you need to tell Samba where ctdbd listens on its unix domain socket. The default path as of ctdb 1.0 is /tmp/ctdb.socket which you have to explicitly set for Samba in smb.conf.
+
+Example: /tmp/ctdb.socket</string>
+ <string id="POL_57D6924C_3F94_5C29_8F63_39808A84FA0F">ctdb locktime warn threshold</string>
+ <string id="POL_57D6924C_3F94_5C29_8F63_39808A84FA0F_Help">In a cluster environment using Samba and ctdb it is critical that locks on central ctdb-hosted databases like locking.tdb are not held for long. With the current Samba architecture it happens that Samba takes a lock and while holding that lock makes file system calls into the shared cluster file system. This option makes Samba warn if it detects that it has held locks for the specified number of milliseconds. If this happens, smbd will emit a debug level 0 message into its logs and potentially into syslog. The most likely reason for such a log message is that an operation of the cluster file system Samba exports is taking longer than expected. The messages are meant as a debugging aid for potential cluster problems.
+ The default value of 0 disables this logging.</string>
+ <string id="POL_6392B974_5997_5E87_916F_FCDCCCCA6069">ctdb timeout</string>
+ <string id="POL_6392B974_5997_5E87_916F_FCDCCCCA6069_Help">This parameter specifies a timeout in milliseconds for the connection between Samba and ctdb. It is only valid if you have compiled Samba with clustering and if you have set clustering=yes. When something in the cluster blocks, it can happen that we wait indefinitely long for ctdb, just adding to the blocking condition. In a well-running cluster this should never happen, but there are too many components in a cluster that might have hickups. Choosing the right balance for this value is very tricky, because on a busy cluster long service times to transfer something across the cluster might be valid. Setting it too short will degrade the service your cluster presents, setting it too long might make the cluster itself not recover from something severely broken for too long. Be aware that if you set this parameter, this needs to be in the file smb.conf, it is not really helpful to put this into a registry configuration (typical on a cluster), because to access the registry contact to ctdb is required. Setting ctdb timeout to n makes any process waiting longer than n milliseconds for a reply by the cluster panic. Setting it to 0 (the default) makes Samba block forever, which is the highly recommended default.</string>
+ <string id="POL_65E02D5E_EC95_5CD1_9976_6FF4E023ADDD">default service</string>
+ <string id="POL_65E02D5E_EC95_5CD1_9976_6FF4E023ADDD_Help">This parameter specifies the name of a service which will be connected to if the service actually requested cannot be found. Note that the square brackets are NOT given in the parameter value (see example below).
+ There is no default value for this parameter. If this parameter is not given, attempting to connect to a nonexistent service results in an error.
+ Typically the default service would be a , service. Also note that the apparent service name will be changed to equal that of the requested service, this is very useful as it allows you to use macros like %S to make a wildcard service.
+ Note also that any &quot;_&quot; characters in the name of the service used in the default service will get mapped to a &quot;/&quot;. This allows for interesting things.
+
+Example: pub</string>
+ <string id="POL_6CD86A19_3EBF_5E3B_A686_462CA044C5D8">delete share command</string>
+ <string id="POL_6CD86A19_3EBF_5E3B_A686_462CA044C5D8_Help">Samba 2.2.0 introduced the ability to dynamically add and delete shares via the Windows NT 4.0 Server Manager. The delete share command is used to define an external program or script which will remove an existing service definition from smb.conf.
+ In order to successfully execute the delete share command, smbd requires that the administrator connects using a root account (i.e. uid == 0) or has the SeDiskOperatorPrivilege. Scripts defined in the delete share command parameter are executed as root.
+ When executed, smbd will automatically invoke the delete share command with two parameters.
+ configFile - the location of the global smb.conf file.
+ shareName - the name of the existing service.
+ This parameter is only used to remove file shares. To delete printer shares, see the .
+
+Example: /usr/local/bin/delshare</string>
+ <string id="POL_EA272781_6D7D_5FD5_96BF_069193C67F65">dsdb event notification</string>
+ <string id="POL_EA272781_6D7D_5FD5_96BF_069193C67F65_Help">When enabled, this option causes Samba (acting as an Active Directory Domain Controller) to stream Samba database events across the internal message bus. Scripts built using Samba's python bindings can listen to these events by registering as the service dsdb_event.
+ This should be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around).
+ The Samba database events are also logged via the normal logging methods when the is set appropriately.</string>
+ <string id="POL_560BC356_6AEC_5D1A_9859_6479FE0F97C0">dsdb group change notification</string>
+ <string id="POL_560BC356_6AEC_5D1A_9859_6479FE0F97C0_Help">When enabled, this option causes Samba (acting as an Active Directory Domain Controller) to stream group membership change events across the internal message bus. Scripts built using Samba's python bindings can listen to these events by registering as the service dsdb_group_event.
+ This should be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around).
+ The group events are also logged via the normal logging methods when the is set appropriately.</string>
+ <string id="POL_2CF8E791_3F03_5CE3_AC93_0B8078E9667D">dsdb password event notification</string>
+ <string id="POL_2CF8E791_3F03_5CE3_AC93_0B8078E9667D_Help">When enabled, this option causes Samba (acting as an Active Directory Domain Controller) to stream password change and reset events across the internal message bus. Scripts built using Samba's python bindings can listen to these events by registering as the service password_event.
+ This should be considered a developer option (it assists in the Samba testsuite) rather than a facility for external auditing, as message delivery is not guaranteed (a feature that the testsuite works around).
+ The password events are also logged via the normal logging methods when the is set appropriately.</string>
+ <string id="POL_C8A040D9_B798_5FE4_A736_BAD9C81CE976">elasticsearch:mappings</string>
+ <string id="POL_C8A040D9_B798_5FE4_A736_BAD9C81CE976_Help">Path to a file specifying metadata attribute mappings in JSON format. Use
+ by the Elasticsearch backend of the Spotlight RPC service.
+
+Example: /usr/share/foo/mymappings.json</string>
+ <string id="POL_66C9072D_C818_5DFB_AB72_5EDDD4CAE999">fss: prune stale</string>
+ <string id="POL_66C9072D_C818_5DFB_AB72_5EDDD4CAE999_Help">When enabled, Samba's File Server Remote VSS Protocol (FSRVP) server checks all FSRVP initiated snapshots on startup, and removes any corresponding state (including share definitions) for nonexistent snapshot paths.
+
+Example: yes</string>
+ <string id="POL_A7F4325A_910F_5437_B911_6D94050EF882">fss: sequence timeout</string>
+ <string id="POL_A7F4325A_910F_5437_B911_6D94050EF882_Help">The File Server Remote VSS Protocol (FSRVP) server includes a message sequence timer to ensure cleanup on unexpected client disconnect. This parameter overrides the default timeout between FSRVP operations. FSRVP timeouts can be completely disabled via a value of 0.
+
+Example: 0</string>
+ <string id="POL_529A6287_1697_57CA_A6D0_811F61A441A0">homedir map</string>
+ <string id="POL_529A6287_1697_57CA_A6D0_811F61A441A0_Help">If is yes, and smbd 8 is also acting as a Win95/98 logon server then this parameter specifies the NIS (or YP) map from which the server for the user's home directory should be extracted. At present, only the Sun auto.home map format is understood. The form of the map is:
+
+username server:/some/file/system
+ and the program will extract the servername from before the first ':'. There should probably be a better parsing system that copes with different map formats and also Amd (another automounter) maps. A working NIS client is required on the system for this option to work.
+
+Example: amd.homedir</string>
+ <string id="POL_3EE25C0A_C920_54B4_8B7B_D0A91CF3E3F1">kernel change notify</string>
+ <string id="POL_3EE25C0A_C920_54B4_8B7B_D0A91CF3E3F1_Help">This parameter specifies whether Samba should ask the kernel for change notifications in directories so that SMB clients can refresh whenever the data on the server changes.
+ This parameter is only used when your kernel supports change notification to user programs using the inotify interface.</string>
+ <string id="POL_15EAB330_0CF4_537E_AD96_8FCECB55194F">lock directory</string>
+ <string id="POL_15EAB330_0CF4_537E_AD96_8FCECB55194F_Help">This option specifies the directory where lock files will be placed. The lock files are used to implement the option.
+ Note: This option can not be set inside registry configurations. The files placed in this directory are not required across service restarts and can be safely placed on volatile storage (e.g. tmpfs in Linux)
+
+Example: /var/run/samba/locks</string>
+ <string id="POL_A53007F8_7951_51F3_9753_B6FA4B38B9B7">log writeable files on exit</string>
+ <string id="POL_A53007F8_7951_51F3_9753_B6FA4B38B9B7_Help">When the network connection between a CIFS client and Samba dies, Samba has no option but to simply shut down the server side of the network connection. If this happens, there is a risk of data corruption because the Windows client did not complete all write operations that the Windows application requested. Setting this option to &quot;yes&quot; makes smbd log with a level 0 message a list of all files that have been opened for writing when the network connection died. Those are the files that are potentially corrupted. It is meant as an aid for the administrator to give him a list of files to do consistency checks on.</string>
+ <string id="POL_7DD9B43E_A2B8_59F8_9927_2B56698E65B6">message command</string>
+ <string id="POL_7DD9B43E_A2B8_59F8_9927_2B56698E65B6_Help">This specifies what command to run when the server receives a WinPopup style message.
+ This would normally be a command that would deliver the message somehow. How this is to be done is up to your imagination.
+ An example is:
+
+message command = csh -c 'xedit %s;rm %s' &amp;
+
+ This delivers the message using xedit, then removes it afterwards. NOTE THAT IT IS VERY IMPORTANT THAT THIS COMMAND RETURN IMMEDIATELY. That's why I have the '&amp;' on the end. If it doesn't return immediately then your PCs may freeze when sending messages (they should recover after 30 seconds, hopefully).
+ All messages are delivered as the global guest user. The command takes the standard substitutions, although %u won't work (%U may be better in this case).
+ Apart from the standard substitutions, some additional ones apply. In particular:
+ %s = the filename containing the message. %t = the destination that the message was sent to (probably the server name).
+ %f = who the message is from.
+ You could make this command send mail, or whatever else takes your fancy. Please let us know of any really interesting ideas you have.
+ Here's a way of sending the messages as mail to root:
+
+message command = /bin/mail -s 'message from %f on %m' root &lt; %s; rm %s
+
+ If you don't have a message command then the message won't be delivered and Samba will tell the sender there was an error. Unfortunately WfWg totally ignores the error code and carries on regardless, saying that the message was delivered.
+ If you want to silently delete it then try:
+
+message command = rm %s
+
+Example: csh -c 'xedit %s; rm %s' &amp;</string>
+ <string id="POL_3BDFEE33_A965_5CA9_BC8C_7E5FDA1BB1D5">nbt client socket address</string>
+ <string id="POL_3BDFEE33_A965_5CA9_BC8C_7E5FDA1BB1D5_Help">This option allows you to control what address Samba will send NBT client packets from, and process replies using, including in nmbd. Setting this option should never be necessary on usual Samba servers running only one nmbd.
+ By default Samba will send UDP packets from the OS default address for the destination, and accept replies on 0.0.0.0. This parameter is deprecated. See Yes and for the previous behaviour of controlling the normal listening sockets.
+
+Example: 192.168.2.20</string>
+ <string id="POL_C4D98472_F115_59FD_A3E6_A7984D662B99">ncalrpc dir</string>
+ <string id="POL_C4D98472_F115_59FD_A3E6_A7984D662B99_Help">This directory will hold a series of named pipes to allow RPC over inter-process communication. This will allow Samba and other unix processes to interact over DCE/RPC without using TCP/IP. Additionally a sub-directory 'np' has restricted permissions, and allows a trusted communication channel between Samba processes
+
+Example: /var/run/samba/ncalrpc</string>
+ <string id="POL_4308D035_8B4B_575A_8984_BAC33A169EBA">NIS homedir</string>
+ <string id="POL_4308D035_8B4B_575A_8984_BAC33A169EBA_Help">Get the home share server from a NIS map. For UNIX systems that use an automounter, the user's home directory will often be mounted on a workstation on demand from a remote server.
+ When the Samba logon server is not the actual home directory server, but is mounting the home directories via NFS then two network hops would be required to access the users home directory if the logon server told the client to use itself as the SMB server for home directories (one over SMB and one over NFS). This can be very slow.
+ This option allows Samba to return the home share as being on a different server to the logon server and as long as a Samba daemon is running on the home directory server, it will be mounted on the Samba client directly from the directory server. When Samba is returning the home share to the client, it will consult the NIS map specified in and return the server listed there.
+ Note that for this option to work there must be a working NIS system and the Samba server with this option must also be a logon server.</string>
+ <string id="POL_359CDEF8_9711_56A5_8621_C50718A5B8A1">nmbd bind explicit broadcast</string>
+ <string id="POL_359CDEF8_9711_56A5_8621_C50718A5B8A1_Help">This option causes nmbd 8 to explicitly bind to the broadcast address of the local subnets. This is needed to make nmbd work correctly in combination with the option. You should not need to unset this option.</string>
+ <string id="POL_23418947_2DAF_54B3_812C_D9B43F49CFCB">panic action</string>
+ <string id="POL_23418947_2DAF_54B3_812C_D9B43F49CFCB_Help">This is a Samba developer option that allows a system command to be called when either smbd 8 or nmbd 8 crashes. This is usually used to draw attention to the fact that a problem occurred.
+
+Example: /bin/sleep 90000</string>
+ <string id="POL_C5C3267E_6E80_5311_96A5_B492C8C3C0AF">perfcount module</string>
+ <string id="POL_C5C3267E_6E80_5311_96A5_B492C8C3C0AF_Help">This parameter specifies the perfcount backend to be used when monitoring SMB operations. Only one perfcount module may be used, and it must implement all of the apis contained in the smb_perfcount_handler structure defined in smb.h.</string>
+ <string id="POL_02EAE588_9ED7_589C_A454_5B168B65A48A">pid directory</string>
+ <string id="POL_02EAE588_9ED7_589C_A454_5B168B65A48A_Help">This option specifies the directory where pid files will be placed.
+
+Example: /var/run/</string>
+ <string id="POL_77C5FC2D_BBFA_5B4E_906F_ED49B11BF069">registry shares</string>
+ <string id="POL_77C5FC2D_BBFA_5B4E_906F_ED49B11BF069_Help">This turns on or off support for share definitions read from registry. Shares defined in smb.conf take precedence over shares with the same name defined in registry. See the section on registry-based configuration for details.
+ Note that this parameter defaults to no, but it is set to yes when config backend is set to registry.
+
+Example: yes</string>
+ <string id="POL_0FB22970_94A4_5403_888E_3CF8242A955C">remote announce</string>
+ <string id="POL_0FB22970_94A4_5403_888E_3CF8242A955C_Help">This option allows you to setup nmbd 8 to periodically announce itself to arbitrary IP addresses with an arbitrary workgroup name.
+ This is useful if you want your Samba server to appear in a remote workgroup for which the normal browse propagation rules don't work. The remote workgroup can be anywhere that you can send IP packets to.
+ For example:
+
+remote announce = 192.168.2.255/SERVERS 192.168.4.255/STAFF
+ the above line would cause nmbd to announce itself to the two given IP addresses using the given workgroup names. If you leave out the workgroup name, then the one given in the parameter is used instead.
+ The IP addresses you choose would normally be the broadcast addresses of the remote networks, but can also be the IP addresses of known browse masters if your network config is that stable.
+ See the chapter on Network Browsing in the Samba-HOWTO book.</string>
+ <string id="POL_B570A06A_7945_5818_B81D_D27007986548">remote browse sync</string>
+ <string id="POL_B570A06A_7945_5818_B81D_D27007986548_Help">This option allows you to setup nmbd 8 to periodically request synchronization of browse lists with the master browser of a Samba server that is on a remote segment. This option will allow you to gain browse lists for multiple workgroups across routed networks. This is done in a manner that does not work with any non-Samba servers.
+ This is useful if you want your Samba server and all local clients to appear in a remote workgroup for which the normal browse propagation rules don't work. The remote workgroup can be anywhere that you can send IP packets to.
+ For example:
+
+remote browse sync = 192.168.2.255 192.168.4.255
+ the above line would cause nmbd to request the master browser on the specified subnets or addresses to synchronize their browse lists with the local server.
+ The IP addresses you choose would normally be the broadcast addresses of the remote networks, but can also be the IP addresses of known browse masters if your network config is that stable. If a machine IP address is given Samba makes NO attempt to validate that the remote machine is available, is listening, nor that it is in fact the browse master on its segment.
+ The may be used on networks where there is no WINS server, and may be used on disjoint networks where each network has its own WINS server.</string>
+ <string id="POL_BA134175_B8C1_5781_9585_AF3A47C44354">reset on zero vc</string>
+ <string id="POL_BA134175_B8C1_5781_9585_AF3A47C44354_Help">This boolean option controls whether an incoming SMB1 session setup should kill other connections coming from the same IP. This matches
+ the default Windows 2003 behaviour.
+ Setting this parameter to yes becomes necessary when you have a flaky network and windows decides to reconnect while the old connection still has files with share modes open. These files become inaccessible over the new connection.
+ The client sends a zero VC on the new connection, and Windows 2003 kills all other connections coming from the same IP. This way the locked files are accessible again.
+ Please be aware that enabling this option will kill connections behind a masquerading router, and will not trigger for clients that only use SMB2 or SMB3.</string>
+ <string id="POL_F0071286_C011_5F1C_A520_2DD14DF7682C">rpc_daemon:DAEMON</string>
+ <string id="POL_F0071286_C011_5F1C_A520_2DD14DF7682C_Help">Defines whether to use the embedded code or start a separate daemon for the defined rpc services. The rpc_daemon prefix must be followed by the server name, and a value.
+ Two possible values are currently supported: disabled fork
+ The classic method is to run rpc services as internal daemons embedded in smbd, therefore the external daemons are disabled by default.
+ Choosing the fork option will cause samba to fork a separate process for each daemon configured this way. Each daemon may in turn fork a number of children used to handle requests from multiple smbds and direct tcp/ip connections (if the Endpoint Mapper is enabled). Communication with smbd happens over named pipes and require that said pipes are forward to the external daemon (see ).
+ Forked RPC Daemons support dynamically forking children to handle connections. The heuristics about how many children to keep around and how fast to allow them to fork and also how many clients each child is allowed to handle concurrently is defined by parametrical options named after the daemon. Five options are currently supported: prefork_min_children prefork_max_children prefork_spawn_rate prefork_max_allowed_clients prefork_child_min_life
+ To set one of these options use the following syntax: daemonname:prefork_min_children = 5
+ Samba includes separate daemons for spoolss, lsarpc/lsass, netlogon, samr, FSRVP and mdssvc(Spotlight). Currently five daemons are available and they are called: epmd lsasd spoolssd fssd mdssd Example: rpc_daemon:spoolssd = fork</string>
+ <string id="POL_820BF686_A78C_5314_A371_3633A8448DC2">rpc_server:SERVER</string>
+ <string id="POL_820BF686_A78C_5314_A371_3633A8448DC2_Help">With this option you can define if a rpc service should be running internal/embedded in smbd or should be redirected to an external daemon like Samba4, the endpoint mapper daemon, the spoolss daemon or the new LSA service daemon. The rpc_server prefix must be followed by the pipe name, and a value.
+ This option can be set for each available rpc service in Samba. The following list shows all available pipe names services you can modify with this option.
+ epmapper - Endpoint Mapper winreg - Remote Registry Service srvsvc - Remote Server Services lsarpc - Local Security Authority samr - Security Account Management netlogon - Netlogon Remote Protocol netdfs - Settings for Distributed File System dssetup - Active Directory Setup wkssvc - Workstation Services spoolss - Network Printing Spooler svcctl - Service Control ntsvcs - Plug and Play Services eventlog - Event Logger initshutdown - Init Shutdown Service mdssvc - Spotlight
+ Three possible values currently supported are: embedded external disabled
+ The classic method is to run every pipe as an internal function embedded in smbd. The defaults may vary depending on the service.
+ Choosing the external option allows one to run a separate daemon or even a completely independent (3rd party) server capable of interfacing with samba via the MS-RPC interface over named pipes.
+ Currently in Samba3 we support four daemons, spoolssd, epmd, lsasd and mdssd. These daemons can be enabled using the rpc_daemon option. For spoolssd you have to enable the daemon and proxy the named pipe with:
+ Examples: rpc_daemon:lsasd = fork rpc_server:lsarpc = external rpc_server:samr = external rpc_server:netlogon = external
+ rpc_server:spoolss = external rpc_server:epmapper = disabled
+ rpc_daemon:mdssd = fork rpc_server:mdssvc = external
+ There is one special option which allows you to enable rpc services to listen for ncacn_ip_tcp connections too. Currently this is only used for testing and doesn't scale!
+ rpc_server:tcpip = yes</string>
+ <string id="POL_70434A64_4979_53D2_80EE_09FBF1562741">smbd profiling level</string>
+ <string id="POL_70434A64_4979_53D2_80EE_09FBF1562741_Help">This parameter allows the administrator to enable profiling support. Possible values are off, count and on.
+
+Example: on</string>
+ <string id="POL_9598A191_3D22_5B49_8188_8D6901A5B4CE">state directory</string>
+ <string id="POL_9598A191_3D22_5B49_8188_8D6901A5B4CE_Help">Usually, most of the TDB files are stored in the lock directory. Since Samba 3.4.0, it is possible to differentiate between TDB files with persistent data and TDB files with non-persistent data using the state directory and the cache directory options.
+ This option specifies the directory where TDB files containing important persistent data will be stored.
+
+Example: /var/run/samba/locks/state</string>
+ <string id="POL_73FD8B56_579A_5BC6_A49A_4000BE94A02F">usershare allow guests</string>
+ <string id="POL_73FD8B56_579A_5BC6_A49A_4000BE94A02F_Help">This parameter controls whether user defined shares are allowed to be accessed by non-authenticated users or not. It is the equivalent of allowing people who can create a share the option of setting guest ok = yes in a share definition. Due to its security sensitive nature, the default is set to off.</string>
+ <string id="POL_A0CE47E8_AE8A_5602_8265_1C8D3AEC6064">usershare max shares</string>
+ <string id="POL_A0CE47E8_AE8A_5602_8265_1C8D3AEC6064_Help">This parameter specifies the number of user defined shares that are allowed to be created by users belonging to the group owning the usershare directory. If set to zero (the default) user defined shares are ignored.</string>
+ <string id="POL_411611B5_93F6_546F_B68B_05167A064628">usershare owner only</string>
+ <string id="POL_411611B5_93F6_546F_B68B_05167A064628_Help">This parameter controls whether the pathname exported by a user defined shares must be owned by the user creating the user defined share or not. If set to True (the default) then smbd checks that the directory path being shared is owned by the user who owns the usershare file defining this share and refuses to create the share if not. If set to False then no such check is performed and any directory path may be exported regardless of who owns it.</string>
+ <string id="POL_DD97B40A_CB2A_5818_8D39_F94911EB3F13">usershare path</string>
+ <string id="POL_DD97B40A_CB2A_5818_8D39_F94911EB3F13_Help">This parameter specifies the absolute path of the directory on the filesystem used to store the user defined share definition files. This directory must be owned by root, and have no access for other, and be writable only by the group owner. In addition the &quot;sticky&quot; bit must also be set, restricting rename and delete to owners of a file (in the same way the /tmp directory is usually configured). Members of the group owner of this directory are the users allowed to create usershares. For example, a valid usershare directory might be /usr/local/samba/lib/usershares, set up as follows. ls -ld /usr/local/samba/lib/usershares/ drwxrwx--T 2 root power_users 4096 2006-05-05 12:27 /usr/local/samba/lib/usershares/ In this case, only members of the group &quot;power_users&quot; can create user defined shares.</string>
+ <string id="POL_4AAFAB11_EB55_5600_A574_08E074B5DC28">usershare prefix allow list</string>
+ <string id="POL_4AAFAB11_EB55_5600_A574_08E074B5DC28_Help">This parameter specifies a list of absolute pathnames the root of which are allowed to be exported by user defined share definitions. If the pathname to be exported doesn't start with one of the strings in this list, the user defined share will not be allowed. This allows the Samba administrator to restrict the directories on the system that can be exported by user defined shares. If there is a &quot;usershare prefix deny list&quot; and also a &quot;usershare prefix allow list&quot; the deny list is processed first, followed by the allow list, thus leading to the most restrictive interpretation.
+
+Example: /home /data /space</string>
+ <string id="POL_1D783E13_3E5A_5FEB_B1C0_486FF385960E">usershare prefix deny list</string>
+ <string id="POL_1D783E13_3E5A_5FEB_B1C0_486FF385960E_Help">This parameter specifies a list of absolute pathnames the root of which are NOT allowed to be exported by user defined share definitions. If the pathname exported starts with one of the strings in this list the user defined share will not be allowed. Any pathname not starting with one of these strings will be allowed to be exported as a usershare. This allows the Samba administrator to restrict the directories on the system that can be exported by user defined shares. If there is a &quot;usershare prefix deny list&quot; and also a &quot;usershare prefix allow list&quot; the deny list is processed first, followed by the allow list, thus leading to the most restrictive interpretation.
+
+Example: /etc /dev /private</string>
+ <string id="POL_2974E59A_2225_59CA_A4C8_C967FDB0E588">usershare template share</string>
+ <string id="POL_2974E59A_2225_59CA_A4C8_C967FDB0E588_Help">User defined shares only have limited possible parameters such as path, guest ok, etc. This parameter allows usershares to &quot;cloned&quot; from an existing share. If &quot;usershare template share&quot; is set to the name of an existing share, then all usershares created have their defaults set from the parameters set on this share. The target share may be set to be invalid for real file sharing by setting the parameter &quot;-valid = False&quot; on the template share definition. This causes it not to be seen as a real exported share but to be able to be used as a template for usershares.
+
+Example: template_share</string>
+ <string id="POL_99ADA47F_F025_52B8_B8F5_DDFA0EEFEF31">utmp</string>
+ <string id="POL_99ADA47F_F025_52B8_B8F5_DDFA0EEFEF31_Help">This boolean parameter is only available if Samba has been configured and compiled with the option --with-utmp. If set to yes then Samba will attempt to add utmp or utmpx records (depending on the UNIX system) whenever a connection is made to a Samba server. Sites may use this to record the user connecting to a Samba share.
+ Due to the requirements of the utmp record, we are required to create a unique identifier for the incoming user. Enabling this option creates an n^2 algorithm to find this number. This may impede performance on large installations.</string>
+ <string id="POL_21565354_4253_5482_97D2_9C2558461C47">utmp directory</string>
+ <string id="POL_21565354_4253_5482_97D2_9C2558461C47_Help">This parameter is only available if Samba has been configured and compiled with the option --with-utmp. It specifies a directory pathname that is used to store the utmp or utmpx files (depending on the UNIX system) that record user connections to a Samba server. By default this is not set, meaning the system will use whatever utmp file the native system is set to use (usually /var/run/utmp on Linux).
+
+Example: /var/run/utmp</string>
+ <string id="POL_4F8E9BC0_CFAB_52F8_9C49_B8BB7400E60A">wtmp directory</string>
+ <string id="POL_4F8E9BC0_CFAB_52F8_9C49_B8BB7400E60A_Help">This parameter is only available if Samba has been configured and compiled with the option --with-utmp. It specifies a directory pathname that is used to store the wtmp or wtmpx files (depending on the UNIX system) that record user connections to a Samba server. The difference with the utmp directory is the fact that user info is kept after a user has logged out. By default this is not set, meaning the system will use whatever utmp file the native system is set to use (usually /var/run/wtmp on Linux).
+
+Example: /var/log/wtmp</string>
+ <string id="POL_83F826D3_2069_552C_8376_C0512E99728D">addport command</string>
+ <string id="POL_83F826D3_2069_552C_8376_C0512E99728D_Help">Samba 3.0.23 introduced support for adding printer ports remotely using the Windows &quot;Add Standard TCP/IP Port Wizard&quot;. This option defines an external program to be executed when smbd receives a request to add a new Port to the system. The script is passed two parameters:
+ port name device URI
+
+ The deviceURI is in the format of socket://&lt;hostname&gt;[:&lt;portnumber&gt;] or lpd://&lt;hostname&gt;/&lt;queuename&gt;.
+
+Example: /etc/samba/scripts/addport.sh</string>
+ <string id="POL_B4BE84FF_FB13_5496_AC34_B15BF764F654">addprinter command</string>
+ <string id="POL_B4BE84FF_FB13_5496_AC34_B15BF764F654_Help">With the introduction of MS-RPC based printing
+ support for Windows NT/2000 clients in Samba 2.2, The MS Add
+ Printer Wizard (APW) icon is now also available in the
+ &quot;Printers...&quot; folder displayed a share listing. The APW
+ allows for printers to be add remotely to a Samba or Windows
+ NT/2000 print server.
+ For a Samba host this means that the printer must be
+ physically added to the underlying printing system.
+ The addprinter command
+ defines a script to be run which
+ will perform the necessary operations for adding the printer
+ to the print system and to add the appropriate service definition
+ to the smb.conf file in order that it can be
+ shared by smbd
+ 8.
+ The addprinter command is
+ automatically invoked with the following parameter (in
+ order):
+ printer name share name port name driver name location Windows 9x driver location
+
+ All parameters are filled in from the PRINTER_INFO_2 structure sent
+ by the Windows NT/2000 client with one exception. The &quot;Windows 9x
+ driver location&quot; parameter is included for backwards compatibility
+ only. The remaining fields in the structure are generated from answers
+ to the APW questions.
+
+ Once the addprinter command has
+ been executed, smbd will reparse the
+ smb.conf to determine if the share defined by the APW
+ exists. If the sharename is still invalid, then smbd
+ will return an ACCESS_DENIED error to the client.
+
+
+ The addprinter command program
+ can output a single line of text,
+ which Samba will set as the port the new printer is connected to.
+ If this line isn't output, Samba won't reload its printer shares.
+
+Example: /usr/bin/addprinter</string>
+ <string id="POL_D9D048A2_779C_5D85_A26E_131535508B70">cups connection timeout</string>
+ <string id="POL_D9D048A2_779C_5D85_A26E_131535508B70_Help">This parameter is only applicable if is set to cups.
+
+
+
+ If set, this option specifies the number of seconds that smbd will wait
+ whilst trying to contact to the CUPS server. The connection will fail
+ if it takes longer than this number of seconds.
+
+Example: 60</string>
+ <string id="POL_AB9D00A2_AB72_5D21_94C6_8EC1238F2793">cups encrypt</string>
+ <string id="POL_AB9D00A2_AB72_5D21_94C6_8EC1238F2793_Help">This parameter is only applicable if is set to cups and if you use CUPS newer than 1.0.x.It is used to define whether or not Samba should use encryption when talking to the CUPS server. Possible values are auto, yes and no
+ When set to auto we will try to do a TLS handshake on each CUPS connection setup. If that fails, we will fall back to unencrypted operation.</string>
+ <string id="POL_CDEAD263_A87A_550A_A067_3FF8C0C60986">cups server</string>
+ <string id="POL_CDEAD263_A87A_550A_A067_3FF8C0C60986_Help">This parameter is only applicable if is set to cups.
+
+
+
+ If set, this option overrides the ServerName option in the CUPS client.conf. This is
+ necessary if you have virtual samba servers that connect to different CUPS daemons.
+
+
+ Optionally, a port can be specified by separating the server name and port number with a colon. If no port was specified, the default port for IPP (631) will be used.
+
+Example: mycupsserver
+
+Example: mycupsserver:1631</string>
+ <string id="POL_7CC90037_633A_5C8D_99C5_380E6B2E1EF0">deleteprinter command</string>
+ <string id="POL_7CC90037_633A_5C8D_99C5_380E6B2E1EF0_Help">With the introduction of MS-RPC based printer
+ support for Windows NT/2000 clients in Samba 2.2, it is now
+ possible to delete a printer at run time by issuing the
+ DeletePrinter() RPC call.
+ For a Samba host this means that the printer must be
+ physically deleted from the underlying printing system. The
+ defines a script to be run which
+ will perform the necessary operations for removing the printer
+ from the print system and from smb.conf.
+
+ The is
+ automatically called with only one parameter: .
+ Once the has
+ been executed, smbd will reparse the
+ smb.conf to check that the associated printer no longer exists.
+ If the sharename is still valid, then smbd
+ will return an ACCESS_DENIED error to the client.
+
+Example: /usr/bin/removeprinter</string>
+ <string id="POL_60B548F0_E8B3_576F_B520_D4954AF3ED8E">disable spoolss</string>
+ <string id="POL_60B548F0_E8B3_576F_B520_D4954AF3ED8E_Help">Enabling this parameter will disable Samba's support
+ for the SPOOLSS set of MS-RPC's and will yield identical behavior
+ as Samba 2.0.x. Windows NT/2000 clients will downgrade to using
+ Lanman style printing commands. Windows 9x/ME will be unaffected by
+ the parameter. However, this will also disable the ability to upload
+ printer drivers to a Samba server via the Windows NT Add Printer
+ Wizard or by using the NT printer properties dialog window. It will
+ also disable the capability of Windows NT/2000 clients to download
+ print drivers from the Samba host upon demand.
+ Be very careful about enabling this parameter.</string>
+ <string id="POL_EAFBD5E6_54EC_5776_A757_5401DE77BBCE">enable spoolss</string>
+ <string id="POL_EAFBD5E6_54EC_5776_A757_5401DE77BBCE_Help">Inverted synonym for .</string>
+ <string id="POL_88C2E1AE_E15B_561A_83B3_A7A7610CB3A2">enumports command</string>
+ <string id="POL_88C2E1AE_E15B_561A_83B3_A7A7610CB3A2_Help">The concept of a &quot;port&quot; is fairly foreign
+ to UNIX hosts. Under Windows NT/2000 print servers, a port
+ is associated with a port monitor and generally takes the form of
+ a local port (i.e. LPT1:, COM1:, FILE:) or a remote port
+ (i.e. LPD Port Monitor, etc...). By default, Samba has only one
+ port defined--&quot;Samba Printer Port&quot;. Under
+ Windows NT/2000, all printers must have a valid port name.
+ If you wish to have a list of ports displayed (smbd
+ does not use a port name for anything) other than
+ the default &quot;Samba Printer Port&quot;, you
+ can define enumports command to point to
+ a program which should generate a list of ports, one per line,
+ to standard output. This listing will then be used in response
+ to the level 1 and 2 EnumPorts() RPC.
+
+Example: /usr/bin/listports</string>
+ <string id="POL_5247D3AE_60E1_526B_B3A0_956818E2EA49">iprint server</string>
+ <string id="POL_5247D3AE_60E1_526B_B3A0_956818E2EA49_Help">This parameter is only applicable if is set to iprint.
+
+
+
+ If set, this option overrides the ServerName option in the CUPS client.conf. This is
+ necessary if you have virtual samba servers that connect to different CUPS daemons.
+
+Example: MYCUPSSERVER</string>
+ <string id="POL_A6ACC104_2480_55A0_A53C_D38DFF7A093B">load printers</string>
+ <string id="POL_A6ACC104_2480_55A0_A53C_D38DFF7A093B_Help">A boolean variable that controls whether all
+ printers in the printcap will be loaded for browsing by default.
+ See the section for
+ more details.</string>
+ <string id="POL_5CC89C3B_45B2_5C52_ADE0_79FB968E5EDE">lpq cache time</string>
+ <string id="POL_5CC89C3B_45B2_5C52_ADE0_79FB968E5EDE_Help">This controls how long lpq info will be cached for to prevent the lpq command being called too often. A separate cache is kept for each variation of the lpq command used by the system, so if you use different lpq commands for different users then they won't share cache information.
+ The cache files are stored in /tmp/lpq.xxxx where xxxx is a hash of the lpq command in use.
+ The default is 30 seconds, meaning that the cached results of a previous identical lpq command will be used if the cached data is less than 30 seconds old. A large value may be advisable if your lpq command is very slow.
+
+A value of 0 will disable caching completely.
+
+Example: 10</string>
+ <string id="POL_45819251_B577_5069_AA0C_AD798BFDC903">os2 driver map</string>
+ <string id="POL_45819251_B577_5069_AA0C_AD798BFDC903_Help">The parameter is used to define the absolute
+ path to a file containing a mapping of Windows NT printer driver
+ names to OS/2 printer driver names. The format is:
+ &lt;nt driver name&gt; = &lt;os2 driver name&gt;.&lt;device name&gt;
+ For example, a valid entry using the HP LaserJet 5
+ printer driver would appear as HP LaserJet 5L = LASERJET.HP
+ LaserJet 5L.
+
+ The need for the file is due to the printer driver namespace problem described in
+ the chapter on Classical Printing in the Samba3-HOWTO book. For more
+ details on OS/2 clients, please refer to chapter on other clients in the Samba3-HOWTO book.</string>
+ <string id="POL_40CAC79E_549A_5AAA_8FD3_DDF6FDC3EF35">printcap cache time</string>
+ <string id="POL_40CAC79E_549A_5AAA_8FD3_DDF6FDC3EF35_Help">This option specifies the number of seconds before the printing
+ subsystem is again asked for the known printers.
+
+
+ Setting this parameter to 0 disables any rescanning for new
+ or removed printers after the initial startup.
+
+Example: 600</string>
+ <string id="POL_A0530959_BE77_53B1_82AC_B3E11CA6D2D8">printcap name</string>
+ <string id="POL_A0530959_BE77_53B1_82AC_B3E11CA6D2D8_Help">This parameter may be used to override the compiled-in default printcap name used by the server (usually /etc/printcap). See the discussion of the [printers] section above for reasons why you might want to do this.
+
+ To use the CUPS printing interface set printcap name = cups . This should be supplemented by an additional setting cups in the [global] section. printcap name = cups will use the &quot;dummy&quot; printcap created by CUPS, as specified in your CUPS configuration file.
+
+
+ On System V systems that use lpstat to
+ list available printers you can use printcap name = lpstat
+ to automatically obtain lists of available printers. This
+ is the default for systems that define SYSV at configure time in
+ Samba (this includes most System V based systems). If
+ printcap name is set to lpstat on
+ these systems then Samba will launch lpstat -v and
+ attempt to parse the output to obtain a printer list.
+
+ A minimal printcap file would look something like this:
+
+print1|My Printer 1
+print2|My Printer 2
+print3|My Printer 3
+print4|My Printer 4
+print5|My Printer 5
+
+ where the '|' separates aliases of a printer. The fact that the second alias has a space in it gives a hint to Samba that it's a comment.
+
+ Under AIX the default printcap name is /etc/qconfig. Samba will assume the file is in AIX qconfig format if the string qconfig appears in the printcap filename.
+
+Example: /etc/myprintcap</string>
+ <string id="POL_73B2297D_6138_544A_BAF8_A31CC8192C22">show add printer wizard</string>
+ <string id="POL_73B2297D_6138_544A_BAF8_A31CC8192C22_Help">With the introduction of MS-RPC based printing support
+ for Windows NT/2000 client in Samba 2.2, a &quot;Printers...&quot; folder will
+ appear on Samba hosts in the share listing. Normally this folder will
+ contain an icon for the MS Add Printer Wizard (APW). However, it is
+ possible to disable this feature regardless of the level of privilege
+ of the connected user.
+ Under normal circumstances, the Windows NT/2000 client will
+ open a handle on the printer server with OpenPrinterEx() asking for
+ Administrator privileges. If the user does not have administrative
+ access on the print server (i.e is not root or has granted the
+ SePrintOperatorPrivilege), the OpenPrinterEx()
+ call fails and the client makes another open call with a request for
+ a lower privilege level. This should succeed, however the APW
+ icon will not be displayed.
+ Disabling the show add printer wizard
+ parameter will always cause the OpenPrinterEx() on the server to fail. Thus the APW icon will never be displayed.
+
+This does not prevent the same user from having administrative privilege on an individual printer.</string>
+ <string id="POL_3CD8EF2C_23D9_58C5_A92C_3E1C2E4F3A4A">spoolss: architecture</string>
+ <string id="POL_3CD8EF2C_23D9_58C5_A92C_3E1C2E4F3A4A_Help">Windows spoolss print clients only allow association of server-side drivers with printers when the driver architecture matches the advertised print server architecture. Samba's spoolss print server architecture can be changed using this parameter.
+
+Example: Windows x64</string>
+ <string id="POL_DE5BD97B_EB5B_571A_98EE_814B2C006262">spoolss: os_major</string>
+ <string id="POL_DE5BD97B_EB5B_571A_98EE_814B2C006262_Help">Windows might require a new os version number. This option allows to modify the build number. The complete default version number is: 5.0.2195 (Windows 2000). The example is 6.1.7601 (Windows 2008 R2).
+
+Example: 6</string>
+ <string id="POL_5EB4315D_6DDE_50E9_A228_2F5062CB23B9">spoolss: os_minor</string>
+ <string id="POL_5EB4315D_6DDE_50E9_A228_2F5062CB23B9_Help">Windows might require a new os version number. This option allows to modify the build number. The complete default version number is: 5.0.2195 (Windows 2000). The example is 6.1.7601 (Windows 2008 R2).
+
+Example: 1</string>
+ <string id="POL_FEE2B5DC_E367_5173_8A6A_43EB82F22680">spoolss: os_build</string>
+ <string id="POL_FEE2B5DC_E367_5173_8A6A_43EB82F22680_Help">Windows might require a new os version number. This option allows to modify the build number. The complete default version number is: 5.0.2195 (Windows 2000). The example is 6.1.7601 (Windows 2008 R2).
+
+Example: 7601</string>
+ <string id="POL_6E7AC428_65F6_5006_97A7_B985AE445E43">spoolss_client: os_major</string>
+ <string id="POL_6E7AC428_65F6_5006_97A7_B985AE445E43_Help">Windows might require a new os version number. This option allows to modify the build number. The complete default version number is: 6.1.7007 (Windows 7 and Windows Server 2008 R2).</string>
+ <string id="POL_732E108C_5701_547E_903E_6112EDF3E999">spoolss_client: os_minor</string>
+ <string id="POL_732E108C_5701_547E_903E_6112EDF3E999_Help">Windows might require a new os version number. This option allows to modify the build number. The complete default version number is: 6.1.7007 (Windows 7 and Windows Server 2008 R2).</string>
+ <string id="POL_CBC8563A_7BEB_54F3_8554_74815EF130DF">spoolss_client: os_build</string>
+ <string id="POL_CBC8563A_7BEB_54F3_8554_74815EF130DF_Help">Windows might require a new os version number. This option allows to modify the build number. The complete default version number is: 6.1.7007 (Windows 7 and Windows Server 2008 R2).</string>
+ <string id="POL_A51777A2_FA82_5D61_B7E1_9B223537A750">cldap port</string>
+ <string id="POL_A51777A2_FA82_5D61_B7E1_9B223537A750_Help">This option controls the port used by the CLDAP protocol.
+
+Example: 3389</string>
+ <string id="POL_E2162FCB_2AF4_5BED_8254_84C87787CAA8">client ipc max protocol</string>
+ <string id="POL_E2162FCB_2AF4_5BED_8254_84C87787CAA8_Help">The value of the parameter (a string) is the highest
+ protocol level that will be supported for IPC$ connections as DCERPC transport.
+
+ Normally this option should not be set as the automatic
+ negotiation phase in the SMB protocol takes care of choosing
+ the appropriate protocol.
+
+ The value default refers to the latest
+ supported protocol, currently SMB3_11.
+
+ See for a full list
+ of available protocols. The values CORE, COREPLUS, LANMAN1, LANMAN2
+ are silently upgraded to NT1.
+
+Example: SMB2_10</string>
+ <string id="POL_86DD41DB_D3AE_5445_8E2D_335E8182ECDF">client ipc min protocol</string>
+ <string id="POL_86DD41DB_D3AE_5445_8E2D_335E8182ECDF_Help">This setting controls the minimum protocol version that the will be attempted to use for IPC$ connections as DCERPC transport.
+ Normally this option should not be set as the automatic negotiation phase in the SMB protocol takes care of choosing the appropriate protocol.
+ The value default refers to the higher value of NT1 and the effective value of .
+ See for a full list of available protocols. The values CORE, COREPLUS, LANMAN1, LANMAN2 are silently upgraded to NT1.
+
+Example: SMB3_11</string>
+ <string id="POL_8E18914D_E4D5_5B9E_8641_02F84DEA8092">client max protocol</string>
+ <string id="POL_8E18914D_E4D5_5B9E_8641_02F84DEA8092_Help">The value of the parameter (a string) is the highest
+ protocol level that will be supported by the client.
+
+ Possible values are :
+ CORE: Earliest version. No concept of user names. COREPLUS: Slight improvements on CORE for efficiency.
+ LANMAN1: First modern version of the protocol. Long filename support.
+ LANMAN2: Updates to Lanman1 protocol.
+ NT1: Current up to date version of the protocol. Used by Windows NT. Known as CIFS.
+ SMB2: Re-implementation of the SMB protocol. Used by Windows Vista and later versions of Windows. SMB2 has sub protocols available. SMB2_02: The earliest SMB2 version. SMB2_10: Windows 7 SMB2 version. By default SMB2 selects the SMB2_10 variant.
+ SMB3: The same as SMB2. Used by Windows 8. SMB3 has sub protocols available. SMB3_00: Windows 8 SMB3 version. SMB3_02: Windows 8.1 SMB3 version. SMB3_11: Windows 10 SMB3 version. By default SMB3 selects the SMB3_11 variant.
+
+
+ Normally this option should not be set as the automatic
+ negotiation phase in the SMB protocol takes care of choosing
+ the appropriate protocol.
+
+ The value default refers to SMB3_11.
+
+ IPC$ connections for DCERPC e.g. in winbindd, are handled by the
+ option.
+
+Example: LANMAN1</string>
+ <string id="POL_277C30D1_A2C2_5AB4_8748_A9ECC063AE91">client min protocol</string>
+ <string id="POL_277C30D1_A2C2_5AB4_8748_A9ECC063AE91_Help">This setting controls the minimum protocol version that the client will attempt to use.
+ Normally this option should not be set as the automatic negotiation phase in the SMB protocol takes care of choosing the appropriate protocol unless you connect to a legacy SMB1-only server.
+ See client max protocol for a full list of available protocols.
+ IPC$ connections for DCERPC e.g. in winbindd, are handled by the option.
+ Note that most command line tools support --option='client min protocol=NT1', so it may not be required to enable SMB1 protocols globally in smb.conf.
+
+Example: NT1</string>
+ <string id="POL_89A40B64_721B_55DF_841D_C3481F32C2FF">client use spnego</string>
+ <string id="POL_89A40B64_721B_55DF_841D_C3481F32C2FF_Help">This variable controls whether Samba clients will try
+ to use Simple and Protected NEGOtiation (as specified by rfc2478) with
+ supporting servers (including WindowsXP, Windows2000 and Samba
+ 3.0) to agree upon an authentication
+ mechanism. This enables Kerberos authentication in particular.
+
+ When is also set to
+ yes extended security (SPNEGO) is required
+ in order to use NTLMv2 only within NTLMSSP. This behavior was
+ introduced with the patches for CVE-2016-2111.</string>
+ <string id="POL_FCF4AF88_1B2D_5A6E_B630_7E88FA13F4EB">dcerpc endpoint servers</string>
+ <string id="POL_FCF4AF88_1B2D_5A6E_B630_7E88FA13F4EB_Help">Specifies which DCE/RPC endpoint servers should be run.
+
+Example: rpcecho</string>
+ <string id="POL_73CE9581_7CF3_5CD8_ABBD_3DD273E7ED10">defer sharing violations</string>
+ <string id="POL_73CE9581_7CF3_5CD8_ABBD_3DD273E7ED10_Help">Windows allows specifying how a file will be shared with other processes when it is opened. Sharing violations occur when a file is opened by a different process using options that violate the share settings specified by other processes. This parameter causes smbd to act as a Windows server does, and defer returning a &quot;sharing violation&quot; error message for up to one second, allowing the client to close the file causing the violation in the meantime.
+ UNIX by default does not have this behaviour.
+ There should be no reason to turn off this parameter, as it is designed to enable Samba to more correctly emulate Windows.</string>
+ <string id="POL_951C9DAC_2C21_58B0_8B22_D9D2CCEB1755">dgram port</string>
+ <string id="POL_951C9DAC_2C21_58B0_8B22_D9D2CCEB1755_Help">Specifies which ports the server should listen on for NetBIOS datagram traffic.</string>
+ <string id="POL_401F735E_7E1F_5EBC_A3E3_9642A9F023DA">disable netbios</string>
+ <string id="POL_401F735E_7E1F_5EBC_A3E3_9642A9F023DA_Help">Enabling this parameter will disable netbios support
+ in Samba. Netbios is the only available form of browsing in
+ all windows versions except for 2000 and XP.
+
+ Clients that only support netbios won't be able to
+ see your samba server when netbios support is disabled.</string>
+ <string id="POL_6BB5884D_D948_5765_B165_FCB496E3A64A">enable asu support</string>
+ <string id="POL_6BB5884D_D948_5765_B165_FCB496E3A64A_Help">Hosts running the &quot;Advanced Server for Unix (ASU)&quot; product
+ require some special accommodations such as creating a builtin [ADMIN$]
+ share that only supports IPC connections. The has been the default
+ behavior in smbd for many years. However, certain Microsoft applications
+ such as the Print Migrator tool require that the remote server support
+ an [ADMIN$] file share. Disabling this parameter allows for creating
+ an [ADMIN$] file share in smb.conf.</string>
+ <string id="POL_D389B35D_C2C8_5971_A195_FBD8C0AAC94C">eventlog list</string>
+ <string id="POL_D389B35D_C2C8_5971_A195_FBD8C0AAC94C_Help">This option defines a list of log names that Samba will
+ report to the Microsoft EventViewer utility. The listed
+ eventlogs will be associated with tdb file on disk in the
+ $(statedir)/eventlog.
+
+
+
+ The administrator must use an external process to parse the normal
+ Unix logs such as /var/log/messages
+ and write then entries to the eventlog tdb files. Refer to the
+ eventlogadm(8) utility for how to write eventlog entries.
+
+Example: Security Application Syslog Apache</string>
+ <string id="POL_04CE2D0D_386E_5CA3_B450_F1BC9FC9CC9B">large readwrite</string>
+ <string id="POL_04CE2D0D_386E_5CA3_B450_F1BC9FC9CC9B_Help">This parameter determines whether or not
+ smbd
+ 8 supports the new 64k
+ streaming read and write variant SMB requests introduced with
+ Windows 2000. Note that due to Windows 2000 client redirector bugs
+ this requires Samba to be running on a 64-bit capable operating
+ system such as IRIX, Solaris or a Linux 2.4 kernel. Can improve
+ performance by 10% with Windows 2000 clients. Defaults to on. Not as tested as some other Samba code paths.</string>
+ <string id="POL_63F5048E_6174_5012_8637_738DD79034E5">lsa over netlogon</string>
+ <string id="POL_63F5048E_6174_5012_8637_738DD79034E5_Help">Setting this deprecated option will allow the RPC server in the AD DC to answer the LSARPC interface on the \pipe\netlogon IPC pipe.
+ When enabled, this matches the behaviour of Microsoft's Windows, due to their internal implementation choices.
+ If it is disabled (the default), the AD DC can offer improved performance, as the netlogon server is decoupled and can run as multiple processes.</string>
+ <string id="POL_87E8C778_F6AC_5666_8855_D40F11853504">max mux</string>
+ <string id="POL_87E8C778_F6AC_5666_8855_D40F11853504_Help">This option controls the maximum number of
+ outstanding simultaneous SMB operations that Samba tells the client it will allow. You should never need to set this parameter.</string>
+ <string id="POL_E754670E_4295_5CAC_8817_8C848E31BA0B">max ttl</string>
+ <string id="POL_E754670E_4295_5CAC_8817_8C848E31BA0B_Help">This option tells nmbd
+ 8 what the default 'time to live'
+ of NetBIOS names should be (in seconds) when nmbd is
+ requesting a name using either a broadcast packet or from a WINS server. You should never need to change this parameter. The default is 3 days.</string>
+ <string id="POL_0AAACA11_DE41_5664_A306_F44D752598C5">max xmit</string>
+ <string id="POL_0AAACA11_DE41_5664_A306_F44D752598C5_Help">This option controls the maximum packet size
+ that will be negotiated by Samba's
+ smbd8
+ for the SMB1 protocol. The default is 16644, which
+ matches the behavior of Windows 2000. A value below 2048 is likely to cause problems.
+ You should never need to change this parameter from its default value.
+
+Example: 8192</string>
+ <string id="POL_24E58521_FFD2_5ADE_A9C8_4050EE408BC2">min receivefile size</string>
+ <string id="POL_24E58521_FFD2_5ADE_A9C8_4050EE408BC2_Help">This option changes the behavior of smbd
+8 when processing SMBwriteX calls. Any incoming
+SMBwriteX call on a non-signed SMB/CIFS connection greater than this value will not be processed in the normal way but will
+be passed to any underlying kernel recvfile or splice system call (if there is no such
+call Samba will emulate in user space). This allows zero-copy writes directly from network
+socket buffers into the filesystem buffer cache, if available. It may improve performance
+but user testing is recommended. If set to zero Samba processes SMBwriteX calls in the
+normal way. To enable POSIX large write support (SMB/CIFS writes up to 16Mb) this option must be
+nonzero. The maximum value is 128k. Values greater than 128k will be silently set to 128k.
+Note this option will have NO EFFECT if set on a SMB signed connection.
+The default is zero, which disables this option.</string>
+ <string id="POL_1DDE423B_1CCB_5179_87D3_1FEE7D4CA621">name resolve order</string>
+ <string id="POL_1DDE423B_1CCB_5179_87D3_1FEE7D4CA621_Help">This option is used by the programs in the Samba
+ suite to determine what naming services to use and in what order
+ to resolve host names to IP addresses. Its main purpose to is to
+ control how netbios name resolution is performed. The option takes a space
+ separated string of name resolution options.
+
+ The options are: &quot;lmhosts&quot;, &quot;host&quot;,
+ &quot;wins&quot; and &quot;bcast&quot;. They cause names to be
+ resolved as follows:
+
+ lmhosts : Lookup an IP address in the Samba lmhosts file. If the line in lmhosts has no name type attached to the NetBIOS name (see the manpage for lmhosts for details) then any name type matches for lookup.
+ host : Do a standard host name to IP address resolution, using the system /etc/hosts , NIS, or DNS lookups. This method of name resolution is operating system depended for instance on IRIX or Solaris this may be controlled by the /etc/nsswitch.conf file. Note that this method is used only if the NetBIOS name type being queried is the 0x20 (server) name type or 0x1c (domain controllers). The latter case is only useful for active directory domains and results in a DNS query for the SRV RR entry matching _ldap._tcp.domain.
+ wins : Query a name with the IP address listed in the wins server parameter. If no WINS server has been specified this method will be ignored.
+ bcast : Do a broadcast on each of the known local interfaces listed in the parameter. This is the least reliable of the name resolution methods as it depends on the target host being on a locally connected subnet.
+
+
+ The example below will cause the local lmhosts file to be examined
+ first, followed by a broadcast attempt, followed by a normal
+ system hostname lookup.
+
+ When Samba is functioning in ADS security mode (security = ads)
+ it is advised to use following settings for name resolve order:
+
+ name resolve order = wins bcast
+
+ DC lookups will still be done via DNS, but fallbacks to netbios names will not inundate your DNS servers with needless queries for DOMAIN&lt;0x1c&gt; lookups.
+
+Example: lmhosts bcast host</string>
+ <string id="POL_B1C3F6FC_E4FB_58A7_9CE4_50090EF8FF17">nbt port</string>
+ <string id="POL_B1C3F6FC_E4FB_58A7_9CE4_50090EF8FF17_Help">Specifies which port the server should use for NetBIOS over IP name services traffic.</string>
+ <string id="POL_E2A4C01A_1EFC_5826_9D3A_A4AD065518EF">nt pipe support</string>
+ <string id="POL_E2A4C01A_1EFC_5826_9D3A_A4AD065518EF_Help">This boolean parameter controls whether
+ smbd
+ 8 will allow Windows NT
+ clients to connect to the NT SMB specific IPC$
+ pipes. This is a developer debugging option and can be left alone.</string>
+ <string id="POL_C1F0941D_67B4_55EA_A915_6F5E9A945E57">nt status support</string>
+ <string id="POL_C1F0941D_67B4_55EA_A915_6F5E9A945E57_Help">This boolean parameter controls whether smbd
+ 8 will negotiate NT specific status
+ support with Windows NT/2k/XP clients. This is a developer debugging option and should be left alone.
+ If this option is set to no then Samba offers
+ exactly the same DOS error codes that versions prior to Samba 2.2.3
+ reported.
+
+ You should not need to ever disable this parameter.</string>
+ <string id="POL_CDB6A4B8_D076_5332_9EA2_CC994C8B45C7">read raw</string>
+ <string id="POL_CDB6A4B8_D076_5332_9EA2_CC994C8B45C7_Help">This is ignored if is set,
+ because this feature is incompatible with raw read SMB requests
+
+ If enabled, raw reads allow reads of 65535 bytes in
+ one packet. This typically provides a major performance benefit for some very, very old clients.
+
+
+ However, some clients either negotiate the allowable
+ block size incorrectly or are incapable of supporting larger block sizes, and for these clients you may need to disable raw reads.
+
+In general this parameter should be viewed as a system tuning tool and left severely alone.</string>
+ <string id="POL_F9AD06B5_1870_5BE4_87A9_08E3821667E4">rpc big endian</string>
+ <string id="POL_F9AD06B5_1870_5BE4_87A9_08E3821667E4_Help">Setting this option will force the RPC client and server to transfer data in big endian.
+ If it is disabled, data will be transferred in little endian.
+ The behaviour is independent of the endianness of the host machine.</string>
+ <string id="POL_380E7843_58D7_505E_9092_392FE1FC4BA2">rpc server port</string>
+ <string id="POL_380E7843_58D7_505E_9092_392FE1FC4BA2_Help">Specifies which port the server should listen on for DCE/RPC over TCP/IP traffic. This controls the default port for all protocols, except for NETLOGON. If unset, the first available port from is used, e.g. 49152. The NETLOGON server will use the next available port, e.g. 49153. To change this port use (eg) rpc server port:netlogon = 4000. Furthermore, all RPC servers can have the port they use specified independenty, with (for example) rpc server port:drsuapi = 5000.
+ This option applies currently only when samba 8 runs as an active directory domain controller.
+ The default value 0 causes Samba to select the first available port from .</string>
+ <string id="POL_D910FC29_975B_5105_97C8_BD75D68FDC5F">server max protocol</string>
+ <string id="POL_D910FC29_975B_5105_97C8_BD75D68FDC5F_Help">The value of the parameter (a string) is the highest
+ protocol level that will be supported by the server.
+
+ Possible values are :
+ LANMAN1: First modern version of the protocol. Long filename support.
+ LANMAN2: Updates to Lanman1 protocol.
+ NT1: Current up to date version of the protocol. Used by Windows NT. Known as CIFS.
+ SMB2: Re-implementation of the SMB protocol. Used by Windows Vista and later versions of Windows. SMB2 has sub protocols available. SMB2_02: The earliest SMB2 version. SMB2_10: Windows 7 SMB2 version. By default SMB2 selects the SMB2_10 variant.
+ SMB3: The same as SMB2. Used by Windows 8. SMB3 has sub protocols available. SMB3_00: Windows 8 SMB3 version. SMB3_02: Windows 8.1 SMB3 version. SMB3_11: Windows 10 SMB3 version. By default SMB3 selects the SMB3_11 variant.
+
+
+ Normally this option should not be set as the automatic
+ negotiation phase in the SMB protocol takes care of choosing
+ the appropriate protocol.
+
+Example: LANMAN1</string>
+ <string id="POL_98D56061_466A_5DDE_BFF3_8A194DE5FE2E">server min protocol</string>
+ <string id="POL_98D56061_466A_5DDE_BFF3_8A194DE5FE2E_Help">This setting controls the minimum protocol version that the server will allow the client to use.
+ Normally this option should not be set as the automatic negotiation phase in the SMB protocol takes care of choosing the appropriate protocol unless you have legacy clients which are SMB1 capable only.
+ See server max protocol for a full list of available protocols.
+
+Example: NT1</string>
+ <string id="POL_2A034462_D418_5914_B24C_6535DD368A66">share:fake_fscaps</string>
+ <string id="POL_2A034462_D418_5914_B24C_6535DD368A66_Help">This is needed to support some special application that makes QFSINFO calls to check whether we set the SPARSE_FILES bit (0x40). If this bit is not set that particular application refuses to work against Samba. With 64 the SPARSE_FILES file system capability flag is set. Use other decimal values to specify the bitmask you need to fake.</string>
+ <string id="POL_A3F9ABC7_494B_5007_B5A1_1DA0B9FC345D">smb2 max credits</string>
+ <string id="POL_A3F9ABC7_494B_5007_B5A1_1DA0B9FC345D_Help">This option controls the maximum number of outstanding simultaneous SMB2 operations
+that Samba tells the client it will allow. This is similar to the
+parameter for SMB1. You should never need to set this parameter.
+
+The default is 8192 credits, which is the same as a Windows 2008R2 SMB2 server.</string>
+ <string id="POL_209C2DE8_5843_50FC_9B61_A3F3EBFE95B5">smb2 max read</string>
+ <string id="POL_209C2DE8_5843_50FC_9B61_A3F3EBFE95B5_Help">This option specifies the protocol value that smbd
+8 will return to a client, informing the client of the largest
+size that may be returned by a single SMB2 read call.
+
+The maximum is 8388608 bytes (8MiB), which is the same as a Windows Server 2012 r2.
+Please note that the default is 8MiB, but it's limit is based on the
+smb2 dialect (64KiB for SMB == 2.0, 8MiB for SMB &gt;= 2.1 with LargeMTU).
+Large MTU is not supported over NBT (tcp port 139).</string>
+ <string id="POL_0696582B_7928_558B_B4DA_9A0C647CFBB8">smb2 max trans</string>
+ <string id="POL_0696582B_7928_558B_B4DA_9A0C647CFBB8_Help">This option specifies the protocol value that smbd
+8 will return to a client, informing the client of the largest
+size of buffer that may be used in querying file meta-data via QUERY_INFO and related SMB2 calls.
+
+The maximum is 8388608 bytes (8MiB), which is the same as a Windows Server 2012 r2.
+Please note that the default is 8MiB, but it's limit is based on the
+smb2 dialect (64KiB for SMB == 2.0, 1MiB for SMB &gt;= 2.1 with LargeMTU).
+Large MTU is not supported over NBT (tcp port 139).</string>
+ <string id="POL_DA17FE47_6637_50D0_9AD1_A95AAA49F717">smb2 max write</string>
+ <string id="POL_DA17FE47_6637_50D0_9AD1_A95AAA49F717_Help">This option specifies the protocol value that smbd
+8 will return to a client, informing the client of the largest
+size that may be sent to the server by a single SMB2 write call.
+
+The maximum is 8388608 bytes (8MiB), which is the same as a Windows Server 2012 r2.
+Please note that the default is 8MiB, but it's limit is based on the
+smb2 dialect (64KiB for SMB == 2.0, 8MiB for SMB =&gt; 2.1 with LargeMTU).
+Large MTU is not supported over NBT (tcp port 139).</string>
+ <string id="POL_97C2005C_F45B_5675_B450_75842A4139F0">smb ports</string>
+ <string id="POL_97C2005C_F45B_5675_B450_75842A4139F0_Help">Specifies which ports the server should listen on for SMB traffic.</string>
+ <string id="POL_5B8B1A0B_AC6B_5E89_8FDE_4CBE538A9CB8">svcctl list</string>
+ <string id="POL_5B8B1A0B_AC6B_5E89_8FDE_4CBE538A9CB8_Help">This option defines a list of init scripts that smbd
+ will use for starting and stopping Unix services via the Win32
+ ServiceControl API. This allows Windows administrators to
+ utilize the MS Management Console plug-ins to manage a
+ Unix server running Samba.
+
+ The administrator must create a directory
+ name svcctl in Samba's $(libdir)
+ and create symbolic links to the init scripts in
+ /etc/init.d/. The name of the links
+ must match the names given as part of the svcctl list.
+
+Example: cups postfix portmap httpd</string>
+ <string id="POL_0E701672_524B_56CE_9C43_D9DE631558EA">time server</string>
+ <string id="POL_0E701672_524B_56CE_9C43_D9DE631558EA_Help">This parameter determines if nmbd
+ 8 advertises itself as a time server to Windows
+clients.</string>
+ <string id="POL_B8322D3C_E4C4_5EAD_AE99_B912C35C56C8">unicode</string>
+ <string id="POL_B8322D3C_E4C4_5EAD_AE99_B912C35C56C8_Help">Specifies whether the server and client should support unicode.
+ If this option is set to false, the use of ASCII will be forced.</string>
+ <string id="POL_4A31BF60_B9E4_5E35_B979_A1C15754CA9A">unix extensions</string>
+ <string id="POL_4A31BF60_B9E4_5E35_B979_A1C15754CA9A_Help">This boolean parameter controls whether Samba
+ implements the CIFS UNIX extensions, as defined by HP.
+ These extensions enable Samba to better serve UNIX CIFS clients
+ by supporting features such as symbolic links, hard links, etc...
+ These extensions require a similarly enabled client, and are of
+ no current use to Windows clients.
+
+ Note if this parameter is turned on, the
+ parameter will automatically be disabled.
+
+
+ See the parameter
+ if you wish to change this coupling between the two parameters.</string>
+ <string id="POL_911349A8_68E0_5370_B0C8_1E5D4DD47DA4">write raw</string>
+ <string id="POL_911349A8_68E0_5370_B0C8_1E5D4DD47DA4_Help">This is ignored if is set,
+ because this feature is incompatible with raw write SMB requests
+
+ If enabled, raw writes allow writes of 65535 bytes in
+ one packet. This typically provides a major performance benefit for some very, very old clients.
+
+
+ However, some clients either negotiate the allowable
+ block size incorrectly or are incapable of supporting larger block sizes, and for these clients you may need to disable raw writes.
+
+In general this parameter should be viewed as a system tuning tool and left severely alone.</string>
+ <string id="POL_585034D0_C9E6_568C_AF40_354A01C24E02">server multi channel support</string>
+ <string id="POL_585034D0_C9E6_568C_AF40_354A01C24E02_Help">This boolean parameter controls whether
+ smbd
+ 8 will support
+ SMB3 multi-channel.
+
+ This parameter was added with version 4.4.
+
+ Warning: Note that this feature is still considered experimental.
+ Use it at your own risk: Even though it may seem to work well in testing,
+ it may result in data corruption under some race conditions.
+ Future releases may improve this situation.
+
+
+ Due to dependencies to kernel APIs of Linux or FreeBSD, it's only possible
+ to use this feature on Linux and FreeBSD for now. For testing this restriction
+ can be overwritten by specifying force:server multi channel support=yes
+ in addition.</string>
+ <string id="POL_4553EC0B_4966_52CE_83C6_948DAC67A281">smb2 disable lock sequence checking</string>
+ <string id="POL_4553EC0B_4966_52CE_83C6_948DAC67A281_Help">This boolean parameter controls whether
+ smbd
+ 8 will disable
+ lock sequence checking even for multi-channel connections
+ as well as durable handles.
+
+
+ The [MS-SMB2] specification (under 3.3.5.14 Receiving an SMB2 LOCK Request)
+ documents that a server should do lock sequence if Open.IsResilient or Open.IsDurable
+ or Open.IsPersistent is TRUE or if Connection.Dialect belongs to the SMB 3.x dialect
+ family and Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_MULTI_CHANNEL.
+
+
+ But Windows Server (at least up to v2004) only does these checks
+ for the Open.IsResilient and Open.IsPersistent.
+ That means they do not implement the behavior specified
+ in [MS-SMB2].
+
+ By default Samba behaves according to the specification
+ and sends smb2 oplock break notification retries.
+
+ Warning: Only enable this option if existing clients can't
+ handle lock sequence checking for handles without Open.IsResilient and Open.IsPersistent.
+ And it turns out that the Windows Server behavior is required.
+
+ Note: it's likely that this option will be removed again
+ if future Windows versions change their behavior.
+
+ Note: Samba does not implement Open.IsResilient and Open.IsPersistent yet.
+
+Example: yes</string>
+ <string id="POL_690A701E_D101_57E5_A180_30E9E54B8B38">smb2 disable oplock break retry</string>
+ <string id="POL_690A701E_D101_57E5_A180_30E9E54B8B38_Help">This boolean parameter controls whether
+ smbd
+ 8 will trigger
+ smb2 oplock break notification retries when using
+ yes.
+
+
+ The [MS-SMB2] specification documents that a server should
+ send smb2 oplock break notification retries on all available channel
+ to the given client.
+
+ But Windows Server versions (at least up to 2019) do not send
+ smb2 oplock break notification retries on channel failures.
+ That means they do not implement the behavior specified
+ in [MS-SMB2].
+
+ By default Samba behaves according to the specification
+ and send smb2 oplock break notification retries.
+
+ Warning: Only enable this option if existing clients can't
+ handle possible retries and it turns out that the Windows Server
+ behavior is required.
+
+ Note: it's likely that this option gets removed again
+ if future Windows versions change their behavior.
+
+ Note: this only applies to oplocks and not SMB2 leases.
+
+Example: yes</string>
+ <string id="POL_7564C5C4_88AA_576B_A9E8_091901A3D6E0">rpc server dynamic port range</string>
+ <string id="POL_7564C5C4_88AA_576B_A9E8_091901A3D6E0_Help">This parameter tells the RPC server which port range it is allowed to use to create a listening socket for LSA, SAM, Netlogon and others without wellknown tcp ports. The first value is the lowest number of the port range and the second the highest. This applies to RPC servers in all server roles.</string>
+ <string id="POL_8D3A68BB_46F0_55A8_B53F_A4AA70C39B46">algorithmic rid base</string>
+ <string id="POL_8D3A68BB_46F0_55A8_B53F_A4AA70C39B46_Help">This determines how Samba will use its
+ algorithmic mapping from uids/gid to the RIDs needed to construct
+ NT Security Identifiers.
+
+
+ Setting this option to a larger value could be useful to sites
+ transitioning from WinNT and Win2k, as existing user and
+ group rids would otherwise clash with system users etc.
+
+
+ All UIDs and GIDs must be able to be resolved into SIDs for
+ the correct operation of ACLs on the server. As such the algorithmic
+ mapping can't be 'turned off', but pushing it 'out of the way' should
+ resolve the issues. Users and groups can then be assigned 'low' RIDs
+ in arbitrary-rid supporting backends.
+
+Example: 100000</string>
+ <string id="POL_4A36DCFC_E9DB_5CD6_A67B_F94F3D95224F">allow dcerpc auth level connect</string>
+ <string id="POL_4A36DCFC_E9DB_5CD6_A67B_F94F3D95224F_Help">This option controls whether DCERPC services are allowed to be used with DCERPC_AUTH_LEVEL_CONNECT, which provides authentication, but no per message integrity nor privacy protection.
+ Some interfaces like samr, lsarpc and netlogon have a hard-coded default of no and epmapper, mgmt and rpcecho have a hard-coded default of yes.
+ The behavior can be overwritten per interface name (e.g. lsarpc, netlogon, samr, srvsvc, winreg, wkssvc ...) by using 'allow dcerpc auth level connect:interface = yes' as option.
+ This option yields precedence to the implementation specific restrictions. E.g. the drsuapi and backupkey protocols require DCERPC_AUTH_LEVEL_PRIVACY. The dnsserver protocol requires DCERPC_AUTH_LEVEL_INTEGRITY.
+
+Example: yes</string>
+ <string id="POL_F3A8A539_E774_5498_B8B7_5D295841A159">allow trusted domains</string>
+ <string id="POL_F3A8A539_E774_5498_B8B7_5D295841A159_Help">This option only takes effect when the option is set to
+ server, domain or ads.
+ If it is set to no, then attempts to connect to a resource from
+ a domain or workgroup other than the one which smbd is running
+ in will fail, even if that domain is trusted by the remote server
+ doing the authentication.
+ This is useful if you only want your Samba server to
+ serve resources to users in the domain it is a member of. As
+ an example, suppose that there are two domains DOMA and DOMB. DOMB
+ is trusted by DOMA, which contains the Samba server. Under normal
+ circumstances, a user with an account in DOMB can then access the
+ resources of a UNIX account with the same account name on the
+ Samba server even if they do not have an account in DOMA. This
+ can make implementing a security boundary difficult.</string>
+ <string id="POL_DF7112E5_5322_5A42_A1AD_45085CB6EC86">binddns dir</string>
+ <string id="POL_DF7112E5_5322_5A42_A1AD_45085CB6EC86_Help">This parameters defines the directory samba will use to store the configuration
+ files for bind, such as named.conf.
+
+ NOTE: The bind dns directory needs to be on the same mount point as the private
+ directory!</string>
+ <string id="POL_41C0408D_BF8C_5BA3_992E_6D58CF58FF84">check password script</string>
+ <string id="POL_41C0408D_BF8C_5BA3_992E_6D58CF58FF84_Help">The name of a program that can be used to check password
+ complexity. The password is sent to the program's standard input.
+
+ The program must return 0 on a good password, or any other value
+ if the password is bad.
+ In case the password is considered weak (the program does not return 0) the
+ user will be notified and the password change will fail.
+
+ In Samba AD, this script will be run AS ROOT by
+ samba 8
+ without any substitutions.
+
+ Note that starting with Samba 4.11 the following environment variables are exported to the script:
+
+ SAMBA_CPS_ACCOUNT_NAME is always present and contains the sAMAccountName of user, the is the same as the %u substitutions in the none AD DC case.
+ SAMBA_CPS_USER_PRINCIPAL_NAME is optional in the AD DC case if the userPrincipalName is present.
+ SAMBA_CPS_FULL_NAME is optional if the displayName is present.
+
+
+ Note: In the example directory is a sample program called crackcheck
+ that uses cracklib to check the password quality.
+
+Example: /usr/local/sbin/crackcheck</string>
+ <string id="POL_9869726F_8F58_512B_A708_C7360AC9146F">client ipc signing</string>
+ <string id="POL_9869726F_8F58_512B_A708_C7360AC9146F_Help">This controls whether the client is allowed or required to use SMB signing for IPC$
+ connections as DCERPC transport. Possible values
+ are auto, mandatory
+ and disabled.
+
+
+ When set to mandatory or default, SMB signing is required.
+
+ When set to auto, SMB signing is offered, but not enforced and if set
+ to disabled, SMB signing is not offered either.
+
+ Connections from winbindd to Active Directory Domain Controllers
+ always enforce signing.</string>
+ <string id="POL_309DB173_58D7_5326_B21D_8DF044225CB9">client lanman auth</string>
+ <string id="POL_309DB173_58D7_5326_B21D_8DF044225CB9_Help">This parameter determines whether or not smbclient
+ 8 and other samba client
+ tools will attempt to authenticate itself to servers using the
+ weaker LANMAN password hash. If disabled, only server which support NT
+ password hashes (e.g. Windows NT/2000, Samba, etc... but not
+ Windows 95/98) will be able to be connected from the Samba client.
+
+ The LANMAN encrypted response is easily broken, due to its
+ case-insensitive nature, and the choice of algorithm. Clients
+ without Windows 95/98 servers are advised to disable
+ this option.
+
+ Disabling this option will also disable the client plaintext auth option.
+
+ Likewise, if the client ntlmv2
+ auth parameter is enabled, then only NTLMv2 logins will be
+ attempted.</string>
+ <string id="POL_0F39ED01_BB64_5653_839C_CB26A70EC531">client NTLMv2 auth</string>
+ <string id="POL_0F39ED01_BB64_5653_839C_CB26A70EC531_Help">This parameter determines whether or not smbclient
+ 8 will attempt to
+ authenticate itself to servers using the NTLMv2 encrypted password
+ response.
+
+ If enabled, only an NTLMv2 and LMv2 response (both much more
+ secure than earlier versions) will be sent. Older servers
+ (including NT4 &lt; SP4, Win9x and Samba 2.2) are not compatible with
+ NTLMv2 when not in an NTLMv2 supporting domain
+
+ Similarly, if enabled, NTLMv1, client lanman auth and client plaintext auth
+ authentication will be disabled. This also disables share-level
+ authentication.
+
+ If disabled, an NTLM response (and possibly a LANMAN response)
+ will be sent by the client, depending on the value of client lanman auth.
+
+ Note that Windows Vista and later versions already use
+ NTLMv2 by default, and some sites (particularly those following
+ 'best practice' security polices) only allow NTLMv2 responses, and
+ not the weaker LM or NTLM.
+
+ When is also set to
+ yes extended security (SPNEGO) is required
+ in order to use NTLMv2 only within NTLMSSP. This behavior was
+ introduced with the patches for CVE-2016-2111.</string>
+ <string id="POL_94342D11_937E_5F14_BBEA_C9B370F6A523">client plaintext auth</string>
+ <string id="POL_94342D11_937E_5F14_BBEA_C9B370F6A523_Help">Specifies whether a client should send a plaintext password if the server does not support encrypted passwords.</string>
+ <string id="POL_DCB591D5_0F63_58EC_A0BB_F5F81064B714">client schannel</string>
+ <string id="POL_DCB591D5_0F63_58EC_A0BB_F5F81064B714_Help">This option is deprecated with Samba 4.8 and will be removed in future. At the same time the default changed to yes, which will be the hardcoded behavior in future.
+
+
+
+ This controls whether the client offers or even demands the use of the netlogon schannel.
+ no does not offer the schannel,
+ auto offers the schannel but does not
+ enforce it, and yes denies access
+ if the server is not able to speak netlogon schannel.
+
+
+ Note that for active directory domains this is hardcoded to
+ yes.
+
+ This option yields precedence to the option.
+
+Example: auto</string>
+ <string id="POL_F35419AB_2114_5382_8060_B1AAED24F2A1">client signing</string>
+ <string id="POL_F35419AB_2114_5382_8060_B1AAED24F2A1_Help">This controls whether the client is allowed or required to use SMB signing. Possible values
+ are auto, mandatory
+ and disabled.
+
+
+ When set to auto or default, SMB signing is offered, but not enforced.
+
+ When set to mandatory, SMB signing is required and if set
+ to disabled, SMB signing is not offered either.
+
+ IPC$ connections for DCERPC e.g. in winbindd, are handled by the
+ option.</string>
+ <string id="POL_F761A7A7_2852_560C_B6D7_A50C613C5431">client use spnego principal</string>
+ <string id="POL_F761A7A7_2852_560C_B6D7_A50C613C5431_Help">This parameter determines whether or not
+ smbclient
+ 8 and other samba components
+ acting as a client will attempt to use the server-supplied
+ principal sometimes given in the SPNEGO exchange.
+
+ If enabled, Samba can attempt to use Kerberos to contact
+ servers known only by IP address. Kerberos relies on names, so
+ ordinarily cannot function in this situation.
+
+ This is a VERY BAD IDEA for security reasons, and so this
+ parameter SHOULD NOT BE USED. It will be removed in a future
+ version of Samba.
+
+ If disabled, Samba will use the name used to look up the
+ server when asking the KDC for a ticket. This avoids situations
+ where a server may impersonate another, soliciting authentication
+ as one principal while being known on the network as another.
+
+
+ Note that Windows XP SP2 and later versions already follow
+ this behaviour, and Windows Vista and later servers no longer
+ supply this 'rfc4178 hint' principal on the server side.
+
+ This parameter is deprecated in Samba 4.2.1 and will be removed
+ (along with the functionality) in a later release of Samba.</string>
+ <string id="POL_158C42B4_685B_5FDE_BF9D_C42504E8C09C">debug encryption</string>
+ <string id="POL_158C42B4_685B_5FDE_BF9D_C42504E8C09C_Help">This option will make the smbd server and client code using
+ libsmb (smbclient, smbget, smbspool, ...) dump the Session Id,
+ the decrypted Session Key, the Signing Key, the Application Key,
+ the Encryption Key and the Decryption Key every time an SMB3+
+ session is established. This information will be printed in logs
+ at level 0.
+
+
+ Warning: access to these values enables the decryption of any
+ encrypted traffic on the dumped sessions. This option should
+ only be enabled for debugging purposes.</string>
+ <string id="POL_8853D1A2_6482_58E1_9748_192D92523750">dedicated keytab file</string>
+ <string id="POL_8853D1A2_6482_58E1_9748_192D92523750_Help">Specifies the absolute path to the kerberos keytab file when is set to &quot;dedicated keytab&quot;.
+
+Example: /usr/local/etc/krb5.keytab</string>
+ <string id="POL_3C1941B5_4894_501A_A7FD_F0C6BCE77DA9">encrypt passwords</string>
+ <string id="POL_3C1941B5_4894_501A_A7FD_F0C6BCE77DA9_Help">This parameter has been deprecated since Samba 4.11 and
+ support for plaintext (as distinct from NTLM, NTLMv2
+ or Kerberos authentication)
+ will be removed in a future Samba release.
+ That is, in the future, the current default of
+ encrypt passwords = yes
+ will be the enforced behaviour.
+ This boolean controls whether encrypted passwords
+ will be negotiated with the client. Note that Windows NT 4.0 SP3 and
+ above and also Windows 98 will by default expect encrypted passwords
+ unless a registry entry is changed. To use encrypted passwords in
+ Samba see the chapter &quot;User Database&quot; in the Samba HOWTO Collection.
+
+
+
+ MS Windows clients that expect Microsoft encrypted passwords and that
+ do not have plain text password support enabled will be able to
+ connect only to a Samba server that has encrypted password support
+ enabled and for which the user accounts have a valid encrypted password.
+ Refer to the smbpasswd command man page for information regarding the
+ creation of encrypted passwords for user accounts.
+
+
+
+ The use of plain text passwords is NOT advised as support for this feature
+ is no longer maintained in Microsoft Windows products. If you want to use
+ plain text passwords you must set this parameter to no.
+
+
+ In order for encrypted passwords to work correctly
+ smbd
+ 8 must either
+ have access to a local smbpasswd
+ 5 file (see the smbpasswd
+ 8 program for information on how to set up
+ and maintain this file), or set the [domain|ads] parameter which
+ causes smbd to authenticate against another server.</string>
+ <string id="POL_99472FC1_E6CE_5476_9EC3_EB2EF52862AE">guest account</string>
+ <string id="POL_99472FC1_E6CE_5476_9EC3_EB2EF52862AE_Help">This is a username which will be used for access
+ to services which are specified as (see below). Whatever privileges this
+ user has will be available to any client connecting to the guest service.
+ This user must exist in the password file, but does not require
+ a valid login. The user account &quot;ftp&quot; is often a good choice
+ for this parameter.
+
+
+ On some systems the default guest account &quot;nobody&quot; may not
+ be able to print. Use another account in this case. You should test
+ this by trying to log in as your guest user (perhaps by using the
+ su - command) and trying to print using the
+ system print command such as lpr(1) or
+ lp(1).
+
+ This parameter does not accept % macros, because
+ many parts of the system require this value to be constant for correct operation.
+
+Example: ftp</string>
+ <string id="POL_75BBDBCB_46D1_55DE_9A7C_9EEA7DD026BF">kerberos encryption types</string>
+ <string id="POL_75BBDBCB_46D1_55DE_9A7C_9EEA7DD026BF_Help">This parameter determines the encryption types to use when operating
+ as a Kerberos client. Possible values are all,
+ strong, and legacy.
+
+
+ Samba uses a Kerberos library (MIT or Heimdal) to obtain Kerberos
+ tickets. This library is normally configured outside of Samba, using
+ the krb5.conf file. This file may also include directives to configure
+ the encryption types to be used. However, Samba implements Active Directory
+ protocols and algorithms to locate a domain controller. In order to
+ force the Kerberos library into using the correct domain controller,
+ some Samba processes, such as
+ winbindd
+ 8 and
+ net
+ 8, build a private krb5.conf
+ file for use by the Kerberos library while being invoked from Samba.
+ This private file controls all aspects of the Kerberos library operation,
+ and this parameter controls how the encryption types are configured
+ within this generated file, and therefore also controls the encryption
+ types negotiable by Samba.
+
+
+ When set to all, all active directory
+ encryption types are allowed.
+
+
+ When set to strong, only AES-based encryption
+ types are offered. This can be used in hardened environments to prevent
+ downgrade attacks.
+
+
+ When set to legacy, only RC4-HMAC-MD5
+ is allowed. Avoiding AES this way has one a very specific use.
+ Normally, the encryption type is negotiated between the peers.
+ However, there is one scenario in which a Windows read-only domain
+ controller (RODC) advertises AES encryption, but then proxies the
+ request to a writeable DC which may not support AES encryption,
+ leading to failure of the handshake. Setting this parameter to
+ legacy would cause samba not to negotiate AES
+ encryption. It is assumed of course that the weaker legacy
+ encryption types are acceptable for the setup.</string>
+ <string id="POL_4AE746EE_4A10_55CC_8934_7E4FEF028E4D">kerberos method</string>
+ <string id="POL_4AE746EE_4A10_55CC_8934_7E4FEF028E4D_Help">Controls how kerberos tickets are verified.
+ Valid options are: secrets only - use only the secrets.tdb for ticket verification (default)
+ system keytab - use only the system keytab for ticket verification
+ dedicated keytab - use a dedicated keytab for ticket verification
+ secrets and keytab - use the secrets.tdb first, then the system keytab
+ The major difference between &quot;system keytab&quot; and &quot;dedicated keytab&quot; is that the latter method relies on kerberos to find the correct keytab entry instead of filtering based on expected principals.
+ When the kerberos method is in &quot;dedicated keytab&quot; mode, must be set to specify the location of the keytab file.</string>
+ <string id="POL_C0E75830_A92F_5E76_A2CF_8E864DF58497">kpasswd port</string>
+ <string id="POL_C0E75830_A92F_5E76_A2CF_8E864DF58497_Help">Specifies which ports the Kerberos server should listen on for password changes.</string>
+ <string id="POL_37987863_7B25_5531_81BE_8EB427F3D0E1">krb5 port</string>
+ <string id="POL_37987863_7B25_5531_81BE_8EB427F3D0E1_Help">Specifies which port the KDC should listen on for Kerberos traffic.</string>
+ <string id="POL_91CB69F0_B95B_565D_B50D_0BC441ED9E34">lanman auth</string>
+ <string id="POL_91CB69F0_B95B_565D_B50D_0BC441ED9E34_Help">This parameter has been deprecated since Samba 4.11 and
+ support for LanMan (as distinct from NTLM, NTLMv2 or
+ Kerberos authentication)
+ will be removed in a future Samba release.
+ That is, in the future, the current default of
+ lanman auth = no
+ will be the enforced behaviour.
+
+ This parameter determines whether or not smbd
+ 8 will attempt to
+ authenticate users or permit password changes
+ using the LANMAN password hash. If disabled, only clients which support NT
+ password hashes (e.g. Windows NT/2000 clients, smbclient, but not
+ Windows 95/98 or the MS DOS network client) will be able to
+ connect to the Samba host.
+
+ The LANMAN encrypted response is easily broken, due to its
+ case-insensitive nature, and the choice of algorithm. Servers
+ without Windows 95/98/ME or MS DOS clients are advised to disable
+ this option.
+
+ When this parameter is set to no this
+ will also result in sambaLMPassword in Samba's passdb being
+ blanked after the next password change. As a result of that
+ lanman clients won't be able to authenticate, even if lanman
+ auth is re-enabled later on.
+
+ Unlike the encrypt
+ passwords option, this parameter cannot alter client
+ behaviour, and the LANMAN response will still be sent over the
+ network. See the client lanman
+ auth to disable this for Samba's clients (such as smbclient)
+
+ This parameter is overridden by ntlm
+ auth, so unless that it is also set to
+ ntlmv1-permitted or yes,
+ then only NTLMv2 logins will be permitted and no LM hash will be
+ stored. All modern clients support NTLMv2, and but some older
+ clients require special configuration to use it.</string>
+ <string id="POL_89CBBE4F_9104_594C_88D1_F9C11246B21F">log nt token command</string>
+ <string id="POL_89CBBE4F_9104_594C_88D1_F9C11246B21F_Help">This option can be set to a command that will be called when new nt tokens are created.
+ This is only useful for development purposes.</string>
+ <string id="POL_6BE3D165_D5BE_5252_A0A2_31CD0E777478">map to guest</string>
+ <string id="POL_6BE3D165_D5BE_5252_A0A2_31CD0E777478_Help">This parameter can take four different values, which tell
+ smbd
+ 8 what to do with user
+ login requests that don't match a valid UNIX user in some way.
+
+ The four settings are :
+
+ Never - Means user login requests with an invalid password are rejected. This is the default. Bad User - Means user logins with an invalid password are rejected, unless the username does not exist, in which case it is treated as a guest login and mapped into the .
+ Bad Password - Means user logins with an invalid password are treated as a guest login and mapped into the . Note that this can cause problems as it means that any user incorrectly typing their password will be silently logged on as &quot;guest&quot; - and will not know the reason they cannot access files they think they should - there will have been no message given to them that they got their password wrong. Helpdesk services will hate you if you set the map to guest parameter this way :-). Bad Uid - Is only applicable when Samba is configured in some type of domain mode security (security = {domain|ads}) and means that user logins which are successfully authenticated but which have no valid Unix user account (and smbd is unable to create one) should be mapped to the defined guest account. This was the default behavior of Samba 2.x releases. Note that if a member server is running winbindd, this option should never be required because the nss_winbind library will export the Windows domain users and groups to the underlying OS via the Name Service Switch interface.
+
+
+ Note that this parameter is needed to set up &quot;Guest&quot;
+ share services. This is because in these modes the name of the resource being
+ requested is not sent to the server until after
+ the server has successfully authenticated the client so the server
+ cannot make authentication decisions at the correct time (connection
+ to the share) for &quot;Guest&quot; shares.
+
+Example: Bad User</string>
+ <string id="POL_56EEE2C2_6458_524A_95A8_C59B86A453E0">mit kdc command</string>
+ <string id="POL_56EEE2C2_6458_524A_95A8_C59B86A453E0_Help">This option specifies the path to the MIT kdc binary.
+
+ If the KDC is not installed in the default location and wasn't
+ correctly detected during build then you should modify this variable and
+ point it to the correct binary.
+
+Example: /opt/mit/sbin/krb5kdc</string>
+ <string id="POL_E82BE4E4_3F51_5B03_9809_03101186CE80">ntlm auth</string>
+ <string id="POL_E82BE4E4_3F51_5B03_9809_03101186CE80_Help">This parameter determines whether or not smbd
+ 8 will attempt to
+ authenticate users using the NTLM encrypted password response for
+ this local passdb (SAM or account database).
+
+ If disabled, both NTLM and LanMan authentication against the
+ local passdb is disabled.
+
+ Note that these settings apply only to local users,
+ authentication will still be forwarded to and NTLM authentication
+ accepted against any domain we are joined to, and any trusted
+ domain, even if disabled or if NTLMv2-only is enforced here. To
+ control NTLM authentiation for domain users, this must option must
+ be configured on each DC.
+
+ By default with ntlm auth set to
+ ntlmv2-only only NTLMv2 logins will be
+ permitted. All modern clients support NTLMv2 by default, but some older
+ clients will require special configuration to use it.
+
+ The primary user of NTLMv1 is MSCHAPv2 for VPNs and 802.1x.
+
+ The available settings are:
+
+
+
+ ntlmv1-permitted (alias yes) - Allow NTLMv1 and above for all clients.
+ This is the required setting for to enable the lanman auth parameter.
+
+
+
+
+ ntlmv2-only (alias no) - Do not allow NTLMv1 to be used, but permit NTLMv2.
+
+
+
+ mschapv2-and-ntlmv2-only - Only
+ allow NTLMv1 when the client promises that it is providing
+ MSCHAPv2 authentication (such as the ntlm_auth tool).
+
+
+
+ disabled - Do not accept NTLM (or
+ LanMan) authentication of any level, nor permit
+ NTLM password changes.
+
+
+
+
+ The default changed from yes to
+ no with Samba 4.5. The default changed again
+ to ntlmv2-only with Samba 4.7, however the
+ behaviour is unchanged.</string>
+ <string id="POL_BEB01EAD_B60E_5832_BDD5_5C8ACE276FD4">ntp signd socket directory</string>
+ <string id="POL_BEB01EAD_B60E_5832_BDD5_5C8ACE276FD4_Help">This setting controls the location of the socket that the NTP daemon uses to communicate with Samba for signing packets.
+ If a non-default path is specified here, then it is also necessary to make NTP aware of the new path using the ntpsigndsocket directive in ntp.conf.</string>
+ <string id="POL_C04AB7ED_DBC2_50A6_8082_AD0D6CCB758A">null passwords</string>
+ <string id="POL_C04AB7ED_DBC2_50A6_8082_AD0D6CCB758A_Help">Allow or disallow client access to accounts that have null passwords.
+
+ See also smbpasswd 5.</string>
+ <string id="POL_E305251F_7C82_54A6_8F9D_CFBB7934B1DF">obey pam restrictions</string>
+ <string id="POL_E305251F_7C82_54A6_8F9D_CFBB7934B1DF_Help">When Samba 3.0 is configured to enable PAM support
+ (i.e. --with-pam), this parameter will control whether or not Samba
+ should obey PAM's account and session management directives. The
+ default behavior is to use PAM for clear text authentication only
+ and to ignore any account or session management. Note that Samba
+ always ignores PAM for authentication in the case of yes. The reason
+ is that PAM modules cannot support the challenge/response
+ authentication mechanism needed in the presence of SMB password encryption.</string>
+ <string id="POL_DD8E3C33_F1AE_59CB_B2B6_3358FFBF41AF">old password allowed period</string>
+ <string id="POL_DD8E3C33_F1AE_59CB_B2B6_3358FFBF41AF_Help">Number of minutes to permit an NTLM login after a password change or reset using the old password. This allows the user to re-cache the new password on multiple clients without disrupting a network reconnection in the meantime.
+
+ This parameter only applies when is set to Active Directory Domain Controller</string>
+ <string id="POL_B65F086B_4235_5646_8C8B_AF4C16B6E4AD">pam password change</string>
+ <string id="POL_B65F086B_4235_5646_8C8B_AF4C16B6E4AD_Help">With the addition of better PAM support in Samba 2.2,
+ this parameter, it is possible to use PAM's password change control
+ flag for Samba. If enabled, then PAM will be used for password
+ changes when requested by an SMB client instead of the program listed in
+ .
+ It should be possible to enable this without changing your
+ parameter for most setups.</string>
+ <string id="POL_755D3500_5D11_5DF0_82AC_E5E964C7707B">passdb backend</string>
+ <string id="POL_755D3500_5D11_5DF0_82AC_E5E964C7707B_Help">This option allows the administrator to chose which backend
+ will be used for storing user and possibly group information. This allows
+ you to swap between different storage mechanisms without recompile.
+
+ The parameter value is divided into two parts, the backend's name, and a 'location'
+ string that has meaning only to that particular backed. These are separated
+ by a : character.
+
+ Available backends can include: smbpasswd - The old plaintext passdb backend. Some Samba features will not work if this passdb backend is used. Takes a path to the smbpasswd file as an optional argument. tdbsam - The TDB based password storage
+ backend. Takes a path to the TDB as an optional argument (defaults to passdb.tdb
+ in the directory. ldapsam - The LDAP based passdb
+ backend. Takes an LDAP URL as an optional argument (defaults to
+ ldap://localhost) LDAP connections should be secured where possible. This may be done using either
+ Start-TLS (see ) or by
+ specifying ldaps:// in
+ the URL argument.
+
+ Multiple servers may also be specified in double-quotes. Whether multiple servers are supported or not and the exact syntax depends on the LDAP library you use.
+
+
+ Examples of use are:
+
+passdb backend = tdbsam:/etc/samba/private/passdb.tdb
+
+or multi server LDAP URL with OpenLDAP library:
+
+passdb backend = ldapsam:&quot;ldap://ldap-1.example.com ldap://ldap-2.example.com&quot;
+
+or multi server LDAP URL with Netscape based LDAP library:
+
+passdb backend = ldapsam:&quot;ldap://ldap-1.example.com ldap-2.example.com&quot;</string>
+ <string id="POL_2F42A35D_FAD2_545A_9ACE_84CD88BEBDB4">passdb expand explicit</string>
+ <string id="POL_2F42A35D_FAD2_545A_9ACE_84CD88BEBDB4_Help">This parameter controls whether Samba substitutes %-macros in the passdb fields if they are explicitly set. We used to expand macros here, but this turned out to be a bug because the Windows client can expand a variable %G_osver% in which %G would have been substituted by the user's primary group.</string>
+ <string id="POL_87D22064_A317_506A_8057_62D7EB06E246">passwd chat</string>
+ <string id="POL_87D22064_A317_506A_8057_62D7EB06E246_Help">This string controls the &quot;chat&quot;
+ conversation that takes places between smbd
+ 8 and the local password changing
+ program to change the user's password. The string describes a
+ sequence of response-receive pairs that smbd
+ 8 uses to determine what to send to the
+ and what to expect back. If the expected output is not
+ received then the password is not changed.
+
+ This chat sequence is often quite site specific, depending
+ on what local methods are used for password control (such as NIS
+ etc).
+
+ Note that this parameter only is used if the parameter is set to yes. This sequence is
+ then called AS ROOT when the SMB password in the
+ smbpasswd file is being changed, without access to the old password
+ cleartext. This means that root must be able to reset the user's password without
+ knowing the text of the previous password. In the presence of
+ NIS/YP, this means that the must
+ be executed on the NIS master.
+
+
+ The string can contain the macro %n which is substituted
+ for the new password. The old password (%o) is only available when
+ has been disabled.
+ The chat sequence can also contain the standard macros
+ \n, \r, \t and \s to give line-feed, carriage-return, tab
+ and space. The chat sequence string can also contain
+ a '*' which matches any sequence of characters. Double quotes can
+ be used to collect strings with spaces in them into a single
+ string.
+
+ If the send string in any part of the chat sequence is a full
+ stop &quot;.&quot;, then no string is sent. Similarly, if the
+ expect string is a full stop then no string is expected.
+
+ If the parameter is set to yes, the chat pairs may be matched in any order, and success is determined by the PAM result, not any particular output. The \n macro is ignored for PAM conversions.
+
+Example: &quot;*Enter NEW password*&quot; %n\n &quot;*Reenter NEW password*&quot; %n\n &quot;*Password changed*&quot;</string>
+ <string id="POL_FB5B5BAF_88EA_547F_B6C1_C26EF698C89B">passwd chat debug</string>
+ <string id="POL_FB5B5BAF_88EA_547F_B6C1_C26EF698C89B_Help">This boolean specifies if the passwd chat script
+ parameter is run in debug mode. In this mode the
+ strings passed to and received from the passwd chat are printed
+ in the smbd
+ 8 log with a
+
+ of 100. This is a dangerous option as it will allow plaintext passwords
+ to be seen in the smbd log. It is available to help
+ Samba admins debug their passwd chat scripts
+ when calling the passwd program and should
+ be turned off after this has been done. This option has no effect if the
+ parameter is set. This parameter is off by default.</string>
+ <string id="POL_885CA09B_77E8_5E63_85E8_108397557B0B">passwd chat timeout</string>
+ <string id="POL_885CA09B_77E8_5E63_85E8_108397557B0B_Help">This integer specifies the number of seconds smbd will wait for an initial
+ answer from a passwd chat script being run. Once the initial answer is received
+ the subsequent answers must be received in one tenth of this time. The default it
+ two seconds.</string>
+ <string id="POL_E710453F_700A_5430_BE8D_5364117F7E85">passwd program</string>
+ <string id="POL_E710453F_700A_5430_BE8D_5364117F7E85_Help">The name of a program that can be used to set
+ UNIX user passwords. Any occurrences of %u
+ will be replaced with the user name. The user name is checked for
+ existence before calling the password changing program.
+
+ Also note that many passwd programs insist in reasonable
+ passwords, such as a minimum length, or the inclusion
+ of mixed case chars and digits. This can pose a problem as some clients
+ (such as Windows for Workgroups) uppercase the password before sending
+ it.
+
+ Note that if the unix
+ password sync parameter is set to yes
+ then this program is called AS ROOT
+ before the SMB password in the smbpasswd
+ file is changed. If this UNIX password change fails, then
+ smbd will fail to change the SMB password also
+ (this is by design).
+
+ If the unix password sync parameter
+ is set this parameter MUST USE ABSOLUTE PATHS
+ for ALL programs called, and must be examined
+ for security implications. Note that by default unix
+ password sync is set to no.
+
+Example: /bin/passwd %u</string>
+ <string id="POL_77F6400F_03D4_53F9_AB7B_E0464F72E61F">password hash gpg key ids</string>
+ <string id="POL_77F6400F_03D4_53F9_AB7B_E0464F72E61F_Help">If samba is running as an active directory domain controller, it is possible to store the cleartext password of accounts in a PGP/OpenGPG encrypted form.
+ You can specify one or more recipients by key id or user id. Note that 32bit key ids are not allowed, specify at least 64bit.
+ The value is stored as 'Primary:SambaGPG' in the supplementalCredentials attribute.
+ As password changes can occur on any domain controller, you should configure this on each of them. Note that this feature is currently available only on Samba domain controllers.
+ This option is only available if samba was compiled with gpgme support.
+ You may need to export the GNUPGHOME environment variable before starting samba. It is strongly recommended to only store the public key in this location. The private key is not used for encryption and should be only stored where decryption is required.
+ Being able to restore the cleartext password helps, when they need to be imported into other authentication systems later (see samba-tool user getpassword) or you want to keep the passwords in sync with another system, e.g. an OpenLDAP server (see samba-tool user syncpasswords).
+ While this option needs to be configured on all domain controllers, the samba-tool user syncpasswords command should run on a single domain controller only (typically the PDC-emulator).
+
+Example: 4952E40301FAB41A
+
+Example: selftest@samba.example.com
+
+Example: selftest@samba.example.com, 4952E40301FAB41A</string>
+ <string id="POL_5EA8345D_5B61_554F_AAF5_2C069A37DFCA">password hash userPassword schemes</string>
+ <string id="POL_5EA8345D_5B61_554F_AAF5_2C069A37DFCA_Help">This parameter determines whether or not
+samba
+8 acting as an Active
+Directory Domain Controller will attempt to store additional
+passwords hash types for the user
+
+The values are stored as 'Primary:userPassword' in the
+supplementalCredentials
+attribute. The value of this option is a hash type.
+
+The currently supported hash types are:
+
+
+ CryptSHA256
+
+
+ CryptSHA512
+
+
+
+Multiple instances of a hash type may be computed and stored.
+The password hashes are calculated using the
+crypt
+3 call.
+The number of rounds used to compute the hash can be specified by adding
+':rounds=xxxx' to the hash type, i.e. CryptSHA512:rounds=4500 would calculate
+an SHA512 hash using 4500 rounds. If not specified the Operating System
+defaults for
+crypt
+3 are used.
+
+
+As password changes can occur on any domain controller,
+you should configure this on each of them. Note that this feature is
+currently available only on Samba domain controllers.
+
+Currently the NT Hash of the password is recorded when these hashes
+are calculated and stored. When retrieving the hashes the current value of the
+NT Hash is checked against the stored NT Hash. This detects password changes
+that have not updated the password hashes. In this case
+samba-tool user will ignore the stored
+hash values.
+
+
+Being able to obtain the hashed password helps, when
+they need to be imported into other authentication systems
+later (see samba-tool user
+getpassword) or you want to keep the passwords in
+sync with another system, e.g. an OpenLDAP server (see
+samba-tool user
+syncpasswords).
+
+unix password sync
+
+Example: CryptSHA256
+
+Example: CryptSHA256 CryptSHA512
+
+Example: CryptSHA256:rounds=5000 CryptSHA512:rounds=7000</string>
+ <string id="POL_1D36B51B_8AB7_593A_95D8_93B12C9F9EFA">password server</string>
+ <string id="POL_1D36B51B_8AB7_593A_95D8_93B12C9F9EFA_Help">By specifying the name of a domain controller with this option,
+ and using security = [ads|domain]
+ it is possible to get Samba
+ to do all its username/password validation using a specific remote server.
+
+ Ideally, this option
+ should not be used, as the default '*' indicates to Samba
+ to determine the best DC to contact dynamically, just as all other hosts in an
+ AD domain do. This allows the domain to be maintained (addition
+ and removal of domain controllers) without modification to
+ the smb.conf file. The cryptographic protection on the authenticated RPC calls
+ used to verify passwords ensures that this default is safe.
+
+ It is strongly recommended that you use the
+ default of '*', however if in your particular
+ environment you have reason to specify a particular DC list, then
+ the list of machines in this option must be a list of names or IP
+ addresses of Domain controllers for the Domain. If you use the
+ default of '*', or list several hosts in the password server option then smbd will try each in turn till it
+ finds one that responds. This is useful in case your primary
+ server goes down.
+
+ If the list of servers contains both names/IP's and the '*'
+ character, the list is treated as a list of preferred
+ domain controllers, but an auto lookup of all remaining DC's
+ will be added to the list as well. Samba will not attempt to optimize
+ this list by locating the closest DC.
+ If parameter is a name, it is looked up using the
+ parameter and so may resolved
+ by any method and order described in that parameter.
+
+Example: NT-PDC, NT-BDC1, NT-BDC2, *
+
+Example: windc.mydomain.com:389 192.168.1.101 *</string>
+ <string id="POL_4605CA34_85F3_51DB_8BCE_C56B51AA39BF">preload modules</string>
+ <string id="POL_4605CA34_85F3_51DB_8BCE_C56B51AA39BF_Help">This is a list of paths to modules that should be loaded into smbd before a client connects. This improves the speed of smbd when reacting to new connections somewhat.
+
+Example: /usr/lib/samba/passdb/mysql.so</string>
+ <string id="POL_5103CDE2_436D_5FB9_8633_6BB5EBB59406">private dir</string>
+ <string id="POL_5103CDE2_436D_5FB9_8633_6BB5EBB59406_Help">This parameters defines the directory
+ smbd will use for storing such files as smbpasswd
+ and secrets.tdb.</string>
+ <string id="POL_7DB136EF_7DAD_5A4F_8C40_F3079FCB925F">raw NTLMv2 auth</string>
+ <string id="POL_7DB136EF_7DAD_5A4F_8C40_F3079FCB925F_Help">This parameter determines whether or not smbd
+ 8 will allow SMB1 clients without
+ extended security (without SPNEGO) to use NTLMv2 authentication.
+
+ If this option, lanman auth
+ and ntlm auth are all disabled,
+ then only clients with SPNEGO support will be permitted.
+ That means NTLMv2 is only supported within NTLMSSP.</string>
+ <string id="POL_E4D542FC_3D67_5397_9AC3_3868BB017F03">rename user script</string>
+ <string id="POL_E4D542FC_3D67_5397_9AC3_3868BB017F03_Help">This is the full pathname to a script that will be run as root by smbd 8 under special circumstances described below.
+ When a user with admin authority or SeAddUserPrivilege rights renames a user (e.g.: from the NT4 User Manager for Domains), this script will be run to rename the POSIX user. Two variables, %uold and %unew, will be substituted with the old and new usernames, respectively. The script should return 0 upon successful completion, and nonzero otherwise.
+ The script has all responsibility to rename all the necessary data that is accessible in this posix method. This can mean different requirements for different backends. The tdbsam and smbpasswd backends will take care of the contents of their respective files, so the script is responsible only for changing the POSIX username, and other data that may required for your circumstances, such as home directory. Please also consider whether or not you need to rename the actual home directories themselves. The ldapsam backend will not make any changes, because of the potential issues with renaming the LDAP naming attribute. In this case the script is responsible for changing the attribute that samba uses (uid) for locating users, as well as any data that needs to change for other applications using the same directory.</string>
+ <string id="POL_7D42E3F0_DE0E_57E0_8EAF_F56111560EA3">restrict anonymous</string>
+ <string id="POL_7D42E3F0_DE0E_57E0_8EAF_F56111560EA3_Help">The setting of this parameter determines whether SAMR and LSA DCERPC services can be accessed anonymously. This corresponds to the following Windows Server registry options:
+ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\RestrictAnonymous
+ The option also affects the browse option which is required by legacy clients which rely on Netbios browsing. While modern Windows version should be fine with restricting the access there could still be applications relying on anonymous access.
+ Setting 1 will disable anonymous SAMR access.
+ Setting 2 will, in addition to restricting SAMR access, disallow anonymous connections to the IPC$ share in general. Setting yes on any share will remove the security advantage.</string>
+ <string id="POL_6745DAC3_A866_5519_83C8_8086C063AAB7">root directory</string>
+ <string id="POL_6745DAC3_A866_5519_83C8_8086C063AAB7_Help">The server will chroot() (i.e.
+ Change its root directory) to this directory on startup. This is
+ not strictly necessary for secure operation. Even without it the
+ server will deny access to files not in one of the service entries.
+ It may also check for, and deny access to, soft links to other
+ parts of the filesystem, or attempts to use &quot;..&quot; in file names
+ to access other directories (depending on the setting of the parameter).
+
+
+ Adding a root directory entry other
+ than &quot;/&quot; adds an extra level of security, but at a price. It
+ absolutely ensures that no access is given to files not in the
+ sub-tree specified in the root directory
+ option, including some files needed for
+ complete operation of the server. To maintain full operability
+ of the server you will need to mirror some system files
+ into the root directory tree. In particular
+ you will need to mirror /etc/passwd (or a
+ subset of it), and any binaries or configuration files needed for
+ printing (if required). The set of files that must be mirrored is
+ operating system dependent.
+
+Example: /homes/smb</string>
+ <string id="POL_9218F54E_BE22_57C0_BEF2_489F89B7D3BA">samba kcc command</string>
+ <string id="POL_9218F54E_BE22_57C0_BEF2_489F89B7D3BA_Help">This option specifies the path to the Samba KCC command. This script is used for replication topology replication.
+ It should not be necessary to modify this option except for testing purposes or if the samba_kcc was installed in a non-default location.
+
+Example: /usr/local/bin/kcc</string>
+ <string id="POL_86AEEBA8_5181_54A2_A436_FD35443F7C03">security</string>
+ <string id="POL_86AEEBA8_5181_54A2_A436_FD35443F7C03_Help">This option affects how clients respond to
+ Samba and is one of the most important settings in the
+ smb.conf file.
+
+ The default is security = user, as this is
+ the most common setting, used for a standalone file server or a DC.
+
+ The alternatives are
+ security = ads or security = domain
+ , which support joining Samba to a Windows domain
+
+ You should use security = user and
+ if you
+ want to mainly setup shares without a password (guest shares). This
+ is commonly used for a shared printer server.
+ The different settings will now be explained.
+
+
+ SECURITY = AUTO
+
+ This is the default security setting in Samba, and causes Samba to consult
+ the parameter (if set) to determine the security mode.
+
+ SECURITY = USER
+
+ If is not specified, this is the default security setting in Samba.
+ With user-level security a client must first &quot;log-on&quot; with a
+ valid username and password (which can be mapped using the
+ parameter). Encrypted passwords (see the parameter) can also
+ be used in this security mode. Parameters such as and if set are then applied and
+ may change the UNIX user to use on this connection, but only after
+ the user has been successfully authenticated.
+
+ Note that the name of the resource being
+ requested is not sent to the server until after
+ the server has successfully authenticated the client. This is why
+ guest shares don't work in user level security without allowing
+ the server to automatically map unknown users into the .
+ See the parameter for details on doing this.
+
+ SECURITY = DOMAIN
+
+ This mode will only work correctly if net
+ 8 has been used to add this
+ machine into a Windows NT Domain. It expects the parameter to be set to yes. In this
+ mode Samba will try to validate the username/password by passing
+ it to a Windows NT Primary or Backup Domain Controller, in exactly
+ the same way that a Windows NT Server would do.
+
+ Note that a valid UNIX user must still
+ exist as well as the account on the Domain Controller to allow
+ Samba to have a valid UNIX account to map file access to.
+
+ Note that from the client's point
+ of view security = domain is the same
+ as security = user. It only
+ affects how the server deals with the authentication,
+ it does not in any way affect what the client sees.
+
+ Note that the name of the resource being
+ requested is not sent to the server until after
+ the server has successfully authenticated the client. This is why
+ guest shares don't work in user level security without allowing
+ the server to automatically map unknown users into the .
+ See the parameter for details on doing this.
+
+ See also the parameter and the parameter.
+ SECURITY = ADS In this mode, Samba will act as a domain member in an ADS realm. To operate in this mode, the machine running Samba will need to have Kerberos installed and configured and Samba will need to be joined to the ADS realm using the net utility. Note that this mode does NOT make Samba operate as a Active Directory Domain Controller.
+ Note that this forces yes and yes for the primary domain.
+ Read the chapter about Domain Membership in the HOWTO for details.
+
+Example: DOMAIN</string>
+ <string id="POL_925F9081_BDD3_5BE8_BB73_89EBE3A0A8F0">server role</string>
+ <string id="POL_925F9081_BDD3_5BE8_BB73_89EBE3A0A8F0_Help">This option determines the basic operating mode of a Samba
+ server and is one of the most important settings in the smb.conf file.
+
+ The default is server role = auto, as causes
+ Samba to operate according to the setting, or if not
+ specified as a simple file server that is not connected to any domain.
+
+ The alternatives are
+ server role = standalone or server role = member server
+ , which support joining Samba to a Windows domain, along with server role = domain controller, which run Samba as a Windows domain controller.
+
+ You should use server role = standalone and
+ if you
+ want to mainly setup shares without a password (guest shares). This
+ is commonly used for a shared printer server.
+ SERVER ROLE = AUTO
+
+ This is the default server role in Samba, and causes Samba to consult
+ the parameter (if set) to determine the server role, giving compatible behaviours to previous Samba versions.
+
+ SERVER ROLE = STANDALONE
+
+ If is also not specified, this is the default security setting in Samba.
+ In standalone operation, a client must first &quot;log-on&quot; with a
+ valid username and password (which can be mapped using the
+ parameter) stored on this machine. Encrypted passwords (see the parameter) are by default
+ used in this security mode. Parameters such as and if set are then applied and
+ may change the UNIX user to use on this connection, but only after
+ the user has been successfully authenticated.
+
+ SERVER ROLE = MEMBER SERVER
+
+ This mode will only work correctly if net
+ 8 has been used to add this
+ machine into a Windows Domain. It expects the parameter to be set to yes. In this
+ mode Samba will try to validate the username/password by passing
+ it to a Windows or Samba Domain Controller, in exactly
+ the same way that a Windows Server would do.
+
+ Note that a valid UNIX user must still
+ exist as well as the account on the Domain Controller to allow
+ Samba to have a valid UNIX account to map file access to. Winbind can provide this.
+
+ SERVER ROLE = CLASSIC PRIMARY DOMAIN CONTROLLER
+
+ This mode of operation runs a classic Samba primary domain
+ controller, providing domain logon services to Windows and Samba
+ clients of an NT4-like domain. Clients must be joined to the domain to
+ create a secure, trusted path across the network. There must be
+ only one PDC per NetBIOS scope (typically a broadcast network or
+ clients served by a single WINS server).
+
+ SERVER ROLE = CLASSIC BACKUP DOMAIN CONTROLLER
+
+ This mode of operation runs a classic Samba backup domain
+ controller, providing domain logon services to Windows and Samba
+ clients of an NT4-like domain. As a BDC, this allows
+ multiple Samba servers to provide redundant logon services to a
+ single NetBIOS scope.
+
+ SERVER ROLE = ACTIVE DIRECTORY DOMAIN CONTROLLER
+
+ This mode of operation runs Samba as an active directory
+ domain controller, providing domain logon services to Windows and
+ Samba clients of the domain. This role requires special
+ configuration, see the Samba4
+ HOWTO
+
+Example: ACTIVE DIRECTORY DOMAIN CONTROLLER</string>
+ <string id="POL_6B0930DB_3CC7_57DB_8798_A6B6D3AF05B9">server schannel</string>
+ <string id="POL_6B0930DB_3CC7_57DB_8798_A6B6D3AF05B9_Help">This option is deprecated with Samba 4.8 and will be removed in future. At the same time the default changed to yes, which will be the hardcoded behavior in future. If you have the need for the behavior of &quot;auto&quot; to be kept, please file a bug at https://bugzilla.samba.org.
+
+
+ This controls whether the server offers or even demands the use of the netlogon schannel. no does not offer the schannel, auto offers the schannel but does not enforce it, and yes denies access if the client is not able to speak netlogon schannel. This is only the case for Windows NT4 before SP4.
+
+ Please note that with this set to no, you will have to apply the WindowsXP WinXP_SignOrSeal.reg registry patch found in the docs/registry subdirectory of the Samba distribution tarball.
+
+Example: auto</string>
+ <string id="POL_6DC4F5E8_3493_5D3C_8E35_D928C38C2604">server signing</string>
+ <string id="POL_6DC4F5E8_3493_5D3C_8E35_D928C38C2604_Help">This controls whether the client is allowed or required to use SMB1 and SMB2 signing. Possible values
+ are default, auto, mandatory
+ and disabled.
+
+
+ By default, and when smb signing is set to
+ default, smb signing is required when
+ is active directory
+ domain controller and disabled otherwise.
+
+ When set to auto, SMB1 signing is offered, but not enforced.
+ When set to mandatory, SMB1 signing is required and if set
+ to disabled, SMB signing is not offered either.
+
+ For the SMB2 protocol, by design, signing cannot be disabled. In the case
+ where SMB2 is negotiated, if this parameter is set to disabled,
+ it will be treated as auto. Setting it to mandatory
+ will still require SMB2 clients to use signing.</string>
+ <string id="POL_7C0D1957_E0F4_5B60_805D_FBA7399D8737">smb passwd file</string>
+ <string id="POL_7C0D1957_E0F4_5B60_805D_FBA7399D8737_Help">This option sets the path to the encrypted smbpasswd file. By
+ default the path to the smbpasswd file is compiled into Samba.
+
+
+ An example of use is:
+
+smb passwd file = /etc/samba/smbpasswd</string>
+ <string id="POL_94D60BE2_185E_5EC1_8E58_146C4B17C1E7">tls cafile</string>
+ <string id="POL_94D60BE2_185E_5EC1_8E58_146C4B17C1E7_Help">This option can be set to a file (PEM format) containing CA certificates of root CAs to trust to sign certificates or intermediate CA certificates. This path is relative to if the path does not start with a /.</string>
+ <string id="POL_A9FA5D2E_2052_5A81_812D_83A2952DF38B">tls certfile</string>
+ <string id="POL_A9FA5D2E_2052_5A81_812D_83A2952DF38B_Help">This option can be set to a file (PEM format) containing the RSA certificate. This path is relative to if the path does not start with a /.</string>
+ <string id="POL_C3E30BBB_123E_55E6_9693_7FF6CCF7488D">tls crlfile</string>
+ <string id="POL_C3E30BBB_123E_55E6_9693_7FF6CCF7488D_Help">This option can be set to a file containing a certificate revocation list (CRL). This path is relative to if the path does not start with a /.</string>
+ <string id="POL_ABFC90A0_6AA2_5372_85E6_FCD989E458EE">tls dh params file</string>
+ <string id="POL_ABFC90A0_6AA2_5372_85E6_FCD989E458EE_Help">This option can be set to a file with Diffie-Hellman parameters which will be used with DH ciphers. This path is relative to if the path does not start with a /.</string>
+ <string id="POL_0F91E806_ADD5_59A1_B4FA_E99A51FED659">tls enabled</string>
+ <string id="POL_0F91E806_ADD5_59A1_B4FA_E99A51FED659_Help">If this option is set to yes, then Samba will use TLS when possible in communication.</string>
+ <string id="POL_D245CE57_C525_5967_A452_F28BFDB9509B">tls keyfile</string>
+ <string id="POL_D245CE57_C525_5967_A452_F28BFDB9509B_Help">This option can be set to a file (PEM format) containing the RSA private key. This file must be accessible without a pass-phrase, i.e. it must not be encrypted. This path is relative to if the path does not start with a /.</string>
+ <string id="POL_6DB833DB_F8B8_5A20_8E2A_6B7D8E298B9D">tls verify peer</string>
+ <string id="POL_6DB833DB_F8B8_5A20_8E2A_6B7D8E298B9D_Help">This controls if and how strict the client will verify the peer's certificate and name. Possible values are (in increasing order): no_check, ca_only, ca_and_name_if_available, ca_and_name and as_strict_as_possible.
+ When set to no_check the certificate is not verified at all, which allows trivial man in the middle attacks.
+ When set to ca_only the certificate is verified to be signed from a ca specified in the option. Setting to a valid file is required. The certificate lifetime is also verified. If the option is configured, the certificate is also verified against the ca crl.
+ When set to ca_and_name_if_available all checks from ca_only are performed. In addition, the peer hostname is verified against the certificate's name, if it is provided by the application layer and not given as an ip address string.
+ When set to ca_and_name all checks from ca_and_name_if_available are performed. In addition the peer hostname needs to be provided and even an ip address is checked against the certificate's name.
+ When set to as_strict_as_possible all checks from ca_and_name are performed. In addition the needs to be configured. Future versions of Samba may implement additional checks.</string>
+ <string id="POL_82913C09_64C3_59C3_8303_3A815661F70E">unix password sync</string>
+ <string id="POL_82913C09_64C3_59C3_8303_3A815661F70E_Help">This boolean parameter controls whether Samba
+ attempts to synchronize the UNIX password with the SMB password
+ when the encrypted SMB password in the smbpasswd file is changed.
+ If this is set to yes the program specified in the passwd
+ program parameter is called AS ROOT -
+ to allow the new UNIX password to be set without access to the
+ old UNIX password (as the SMB password change code has no
+ access to the old password cleartext, only the new).
+
+ This option has no effect if samba
+ is running as an active directory domain controller, in that case have a
+ look at the option and the
+ samba-tool user syncpasswords command.</string>
+ <string id="POL_37EE4890_B571_50D5_B6D7_3462FF89BCE1">username level</string>
+ <string id="POL_37EE4890_B571_50D5_B6D7_3462FF89BCE1_Help">This option helps Samba to try and 'guess' at
+ the real UNIX username, as many DOS clients send an all-uppercase
+ username. By default Samba tries all lowercase, followed by the
+ username with the first letter capitalized, and fails if the
+ username is not found on the UNIX machine.
+
+ If this parameter is set to non-zero the behavior changes.
+ This parameter is a number that specifies the number of uppercase
+ combinations to try while trying to determine the UNIX user name. The
+ higher the number the more combinations will be tried, but the slower
+ the discovery of usernames will be. Use this parameter when you have
+ strange usernames on your UNIX machine, such as AstrangeUser
+ .
+
+ This parameter is needed only on UNIX systems that have case
+ sensitive usernames.
+
+Example: 5</string>
+ <string id="POL_086EBC7E_1D72_5C67_9447_F5F6E36EFA8F">username map</string>
+ <string id="POL_086EBC7E_1D72_5C67_9447_F5F6E36EFA8F_Help">This option allows you to specify a file containing a mapping of usernames from the clients to the server. This can be used for several purposes. The most common is to map usernames that users use on DOS or Windows machines to those that the UNIX box uses. The other is to map multiple users to a single username so that they can more easily share files.
+
+ Please note that for user mode security, the username map is applied prior to validating the user credentials. Domain member servers (domain or ads) apply the username map after the user has been successfully authenticated by the domain controller and require fully qualified entries in the map table (e.g. biddle = DOMAIN\foo).
+
+ The map file is parsed line by line. Each line should contain a single UNIX username on the left then a '=' followed by a list of usernames on the right. The list of usernames on the right may contain names of the form @group in which case they will match any UNIX username in that group. The special client name '*' is a wildcard and matches any name. Each line of the map file may be up to 1023 characters long.
+
+ The file is processed on each line by taking the supplied username and comparing it with each username on the right hand side of the '=' signs. If the supplied name matches any of the names on the right hand side then it is replaced with the name on the left. Processing then continues with the next line.
+
+ If any line begins with a '#' or a ';' then it is ignored.
+
+ If any line begins with an '!' then the processing will stop after that line if a mapping was done by the line. Otherwise mapping continues with every line being processed. Using '!' is most useful when you have a wildcard mapping line later in the file.
+
+ For example to map from the name admin or administrator to the UNIX name root you would use:
+
+root = admin administrator
+ Or to map anyone in the UNIX group system to the UNIX name sys you would use:
+
+sys = @system
+
+
+ You can have as many mappings as you like in a username map file.
+
+
+ If your system supports the NIS NETGROUP option then the netgroup database is checked before the /etc/group database for matching groups.
+
+ You can map Windows usernames that have spaces in them by using double quotes around the name. For example:
+
+tridge = &quot;Andrew Tridgell&quot;
+
+ would map the windows username &quot;Andrew Tridgell&quot; to the unix username &quot;tridge&quot;.
+
+ The following example would map mary and fred to the unix user sys, and map the rest to guest. Note the use of the
+ '!' to tell Samba to stop processing if it gets a match on that line:
+
+!sys = mary fred
+guest = *
+
+
+
+ Note that the remapping is applied to all occurrences of usernames. Thus if you connect to \\server\fred and fred is remapped to mary then you will actually be connecting to \\server\mary and will need to supply a password suitable for mary not fred. The only exception to this is the username passed to a Domain Controller (if you have one). The DC will receive whatever username the client supplies without modification.
+
+
+ Also note that no reverse mapping is done. The main effect this has is with printing. Users who have been mapped may have trouble deleting print jobs as PrintManager under WfWg will think they don't own the print job.
+
+ Samba versions prior to 3.0.8 would only support reading the fully qualified username (e.g.: DOMAIN\user) from the username map when performing a kerberos login from a client. However, when looking up a map entry for a user authenticated by NTLM[SSP], only the login name would be used for matches. This resulted in inconsistent behavior sometimes even on the same server.
+
+
+
+ The following functionality is obeyed in version 3.0.8 and later:
+
+
+
+ When performing local authentication, the username map is applied to the login name before attempting to authenticate
+ the connection.
+
+
+
+ When relying upon a external domain controller for validating authentication requests, smbd will apply the username map
+ to the fully qualified username (i.e. DOMAIN\user) only after the user has been successfully authenticated.
+
+
+
+ An example of use is:
+
+username map = /usr/local/samba/lib/users.map</string>
+ <string id="POL_0FE7956E_5744_5658_A2ED_8433C45918D7">username map cache time</string>
+ <string id="POL_0FE7956E_5744_5658_A2ED_8433C45918D7_Help">Mapping usernames with the or features of Samba can be relatively expensive. During login of a user, the mapping is done several times. In particular, calling the can slow down logins if external databases have to be queried from the script being called.
+ The parameter controls a mapping cache. It specifies the number of seconds a mapping from the username map file or script is to be efficiently cached. The default of 0 means no caching is done.
+
+Example: 60</string>
+ <string id="POL_7C2B49D9_45DE_5D97_B844_9F509F86D211">username map script</string>
+ <string id="POL_7C2B49D9_45DE_5D97_B844_9F509F86D211_Help">This script is a mutually exclusive alternative to the parameter. This parameter specifies and external program or script that must accept a single command line option (the username transmitted in the authentication request) and return a line on standard output (the name to which the account should mapped). In this way, it is possible to store username map tables in an LDAP or NIS directory services.
+
+Example: /etc/samba/scripts/mapusers.sh</string>
+ <string id="POL_22AAB8AC_4E62_5B51_BC38_C9340E8AC56E">tls priority</string>
+ <string id="POL_22AAB8AC_4E62_5B51_BC38_C9340E8AC56E_Help">This option can be set to a string describing the TLS protocols
+ to be supported in the parts of Samba that use GnuTLS, specifically
+ the AD DC.
+
+ The string is appended to the default priority list of GnuTLS.
+ The valid options are described in the
+ GNUTLS
+ Priority-Strings documentation at http://gnutls.org/manual/html_node/Priority-Strings.html
+
+ The SSL3.0 protocol will be disabled.</string>
+ <string id="POL_08DDB9FE_1D88_5264_BEB0_6D60420CE12B">aio max threads</string>
+ <string id="POL_08DDB9FE_1D88_5264_BEB0_6D60420CE12B_Help">The integer parameter specifies the maximum number of
+ threads each smbd process will create when doing parallel asynchronous IO
+ calls. If the number of outstanding calls is greater than this
+ number the requests will not be refused but go onto a queue
+ and will be scheduled in turn as outstanding requests complete.
+
+
+ aio read size
+ aio write size</string>
+ <string id="POL_0F98F240_9B2D_5788_AC7C_7B2ECDAE60A2">deadtime</string>
+ <string id="POL_0F98F240_9B2D_5788_AC7C_7B2ECDAE60A2_Help">The value of the parameter (a decimal integer)
+ represents the number of minutes of inactivity before a connection
+ is considered dead, and it is disconnected. The deadtime only takes
+ effect if the number of open files is zero.
+ This is useful to stop a server's resources being
+ exhausted by a large number of inactive connections.
+
+ Most clients have an auto-reconnect feature when a
+ connection is broken so in most cases this parameter should be
+ transparent to users.
+
+ Using this parameter with a timeout of a few minutes
+ is recommended for most systems.
+
+ A deadtime of zero indicates that no auto-disconnection should be performed.
+
+Example: 15</string>
+ <string id="POL_BAC6D3CB_A32D_5702_93FD_289B714016C3">getwd cache</string>
+ <string id="POL_BAC6D3CB_A32D_5702_93FD_289B714016C3_Help">This is a tuning option. When this is enabled a
+ caching algorithm will be used to reduce the time taken for getwd()
+ calls. This can have a significant impact on performance, especially
+ when the parameter is set to no.</string>
+ <string id="POL_0FB07FB9_33B4_5ECF_9725_9B7A38F863AF">hostname lookups</string>
+ <string id="POL_0FB07FB9_33B4_5ECF_9725_9B7A38F863AF_Help">Specifies whether samba should use (expensive)
+ hostname lookups or use the ip addresses instead. An example place
+ where hostname lookups are currently used is when checking
+ the hosts deny and hosts allow.
+
+Example: yes</string>
+ <string id="POL_C2D014CF_45D1_5A08_9727_3F2B500A4D58">keepalive</string>
+ <string id="POL_C2D014CF_45D1_5A08_9727_3F2B500A4D58_Help">The value of the parameter (an integer) represents
+ the number of seconds between keepalive
+ packets. If this parameter is zero, no keepalive packets will be
+ sent. Keepalive packets, if sent, allow the server to tell whether
+ a client is still present and responding.
+
+ Keepalives should, in general, not be needed if the socket
+ has the SO_KEEPALIVE attribute set on it by default. (see ).
+Basically you should only use this option if you strike difficulties.
+
+ Please note this option only applies to SMB1 client connections, and
+ has no effect on SMB2 clients.
+
+Example: 600</string>
+ <string id="POL_AF4738EE_230C_5D39_A4CE_F270B28FE9AB">max disk size</string>
+ <string id="POL_AF4738EE_230C_5D39_A4CE_F270B28FE9AB_Help">This option allows you to put an upper limit
+ on the apparent size of disks. If you set this option to 100
+ then all shares will appear to be not larger than 100 MB in
+ size.
+
+ Note that this option does not limit the amount of
+ data you can put on the disk. In the above case you could still
+ store much more than 100 MB on the disk, but if a client ever asks
+ for the amount of free disk space or the total disk size then the
+ result will be bounded by the amount specified in max
+ disk size.
+
+ This option is primarily useful to work around bugs
+ in some pieces of software that can't handle very large disks,
+ particularly disks over 1GB in size.
+
+ A max disk size of 0 means no limit.
+
+Example: 1000</string>
+ <string id="POL_21C3BE22_42E5_544F_97AB_732B2163839B">max open files</string>
+ <string id="POL_21C3BE22_42E5_544F_97AB_732B2163839B_Help">This parameter limits the maximum number of
+ open files that one smbd
+ 8 file
+ serving process may have open for a client at any one time.
+ This parameter can be set very high (16384) as Samba uses
+ only one bit per unopened file. Setting this parameter lower than
+ 16384 will cause Samba to complain and set this value back to
+ the minimum of 16384, as Windows 7 depends on this number of
+ open file handles being available.
+
+ The limit of the number of open files is usually set
+ by the UNIX per-process file descriptor limit rather than
+ this parameter so you should never need to touch this parameter.</string>
+ <string id="POL_67BA8388_A439_54EA_8A1B_B6D2CCD8BB9B">max smbd processes</string>
+ <string id="POL_67BA8388_A439_54EA_8A1B_B6D2CCD8BB9B_Help">This parameter limits the maximum number of smbd
+ 8 processes concurrently running on a system and is intended
+ as a stopgap to prevent degrading service to clients in the event that the server has insufficient
+ resources to handle more than this number of connections. Remember that under normal operating
+ conditions, each user will have an smbd
+ 8 associated with him or her to handle connections to all
+ shares from a given host.
+
+ For a Samba ADDC running the standard process model this option
+ limits the number of processes forked to handle requests.
+ Currently new processes are only forked for ldap and netlogon
+ requests.
+
+Example: 1000</string>
+ <string id="POL_7CB978B4_3314_5AE7_9821_574DC024294B">name cache timeout</string>
+ <string id="POL_7CB978B4_3314_5AE7_9821_574DC024294B_Help">Specifies the number of seconds it takes before
+ entries in samba's hostname resolve cache time out. If
+ the timeout is set to 0. the caching is disabled.
+
+Example: 0</string>
+ <string id="POL_93A78BFD_8C1E_5643_8329_A90FF5CE5A6B">socket options</string>
+ <string id="POL_93A78BFD_8C1E_5643_8329_A90FF5CE5A6B_Help">Modern server operating systems are tuned for high
+ network performance in the majority of situations; when you set socket
+ options you are overriding those settings. Linux in particular has an
+ auto-tuning mechanism for buffer sizes that will be disabled if you
+ specify a socket buffer size. This can potentially cripple your
+ TCP/IP stack.
+
+ Getting the socket options correct can make a big difference to
+ your performance, but getting them wrong can degrade it by just as
+ much. As with any other low level setting, if you must make changes
+ to it, make small changes and test the effect
+ before making any large changes.
+
+
+
+ This option allows you to set socket options
+ to be used when talking with the client.
+
+ Socket options are controls on the networking layer
+ of the operating systems which allow the connection to be
+ tuned.
+
+ This option will typically be used to tune your Samba server
+ for optimal performance for your local network. There is no way
+ that Samba can know what the optimal parameters are for your net,
+ so you must experiment and choose them yourself. We strongly
+ suggest you read the appropriate documentation for your operating
+ system first (perhaps man
+ setsockopt will help).
+
+ You may find that on some systems Samba will say
+ &quot;Unknown socket option&quot; when you supply an option. This means you
+ either incorrectly typed it or you need to add an include file
+ to includes.h for your OS. If the latter is the case please
+ send the patch to
+ samba-technical@lists.samba.org.
+
+ Any of the supported socket options may be combined
+ in any way you like, as long as your OS allows it.
+
+ This is the list of socket options currently settable
+ using this option:
+
+
+ SO_KEEPALIVE
+ SO_REUSEADDR
+ SO_BROADCAST
+ TCP_NODELAY TCP_KEEPCNT * TCP_KEEPIDLE * TCP_KEEPINTVL *
+ IPTOS_LOWDELAY
+ IPTOS_THROUGHPUT SO_REUSEPORT
+ SO_SNDBUF *
+ SO_RCVBUF *
+ SO_SNDLOWAT *
+ SO_RCVLOWAT * SO_SNDTIMEO * SO_RCVTIMEO * TCP_FASTACK * TCP_QUICKACK TCP_NODELAYACK TCP_KEEPALIVE_THRESHOLD * TCP_KEEPALIVE_ABORT_THRESHOLD * TCP_DEFER_ACCEPT * TCP_USER_TIMEOUT *
+
+
+ Those marked with a '*' take an integer
+ argument. The others can optionally take a 1 or 0 argument to enable
+ or disable the option, by default they will be enabled if you
+ don't specify 1 or 0.
+
+ To specify an argument use the syntax SOME_OPTION = VALUE
+ for example SO_SNDBUF = 8192. Note that you must
+ not have any spaces before or after the = sign.
+
+ If you are on a local network then a sensible option
+ might be:
+
+ socket options = IPTOS_LOWDELAY
+
+ If you have a local network then you could try:
+
+ socket options = IPTOS_LOWDELAY TCP_NODELAY
+
+ If you are on a wide area network then perhaps try
+ setting IPTOS_THROUGHPUT.
+
+ Note that several of the options may cause your Samba server to fail completely. Use these options with caution!
+
+Example: IPTOS_LOWDELAY</string>
+ <string id="POL_3FD02174_8A27_5426_848C_B3123EA8C4C3">use mmap</string>
+ <string id="POL_3FD02174_8A27_5426_848C_B3123EA8C4C3_Help">This global parameter determines if the tdb internals of Samba can
+ depend on mmap working correctly on the running system. Samba requires a coherent
+ mmap/read-write system memory cache. Currently only OpenBSD and HPUX do not have such a
+ coherent cache, and on those platforms this parameter is overridden internally
+ to be effectively no. On all systems this parameter should be left alone. This
+ parameter is provided to help the Samba developers track down problems with
+ the tdb internal code.</string>
+ <string id="POL_77FC1090_5D4B_587E_BD3B_DAE9F7A9682F">get quota command</string>
+ <string id="POL_77FC1090_5D4B_587E_BD3B_DAE9F7A9682F_Help">The get quota command should only be used whenever there is no operating system API available from the OS that samba can use.
+ This option is only available Samba was compiled with quotas support.
+ This parameter should specify the path to a script that queries the quota information for the specified user/group for the partition that the specified directory is on.
+ Such a script is being given 3 arguments:
+ directory type of query uid of user or gid of group
+ The directory is actually mostly just &quot;.&quot; - It needs to be treated relatively to the current working directory that the script can also query.
+ The type of query can be one of:
+ 1 - user quotas 2 - user default quotas (uid = -1) 3 - group quotas 4 - group default quotas (gid = -1)
+ This script should print one line as output with spaces between the columns. The printed columns should be:
+ 1 - quota flags (0 = no quotas, 1 = quotas enabled, 2 = quotas enabled and enforced) 2 - number of currently used blocks 3 - the softlimit number of blocks 4 - the hardlimit number of blocks 5 - currently used number of inodes 6 - the softlimit number of inodes 7 - the hardlimit number of inodes 8 (optional) - the number of bytes in a block(default is 1024)
+
+Example: /usr/local/sbin/query_quota</string>
+ <string id="POL_B093DF52_6C77_5327_AC90_AAC6AF6CB126">host msdfs</string>
+ <string id="POL_B093DF52_6C77_5327_AC90_AAC6AF6CB126_Help">If set to yes, Samba will act as a Dfs server, and allow Dfs-aware clients to browse Dfs trees hosted on the server.
+ See also the share level parameter. For more information on setting up a Dfs tree on Samba, refer to the MSFDS chapter in the book Samba3-HOWTO.</string>
+ <string id="POL_6B9A8C91_49AF_58C8_931C_0304B60491D2">set quota command</string>
+ <string id="POL_6B9A8C91_49AF_58C8_931C_0304B60491D2_Help">The set quota command should only be used whenever there is no operating system API available from the OS that samba can use.
+ This option is only available if Samba was compiled with quota support.
+ This parameter should specify the path to a script that can set quota for the specified arguments.
+ The specified script should take the following arguments:
+ 1 - path to where the quota needs to be set. This needs to be interpreted relative to the current working directory that the script may also check for. 2 - quota type 1 - user quotas 2 - user default quotas (uid = -1) 3 - group quotas 4 - group default quotas (gid = -1) 3 - id (uid for user, gid for group, -1 if N/A) 4 - quota state (0 = disable, 1 = enable, 2 = enable and enforce) 5 - block softlimit 6 - block hardlimit 7 - inode softlimit 8 - inode hardlimit 9(optional) - block size, defaults to 1024
+ The script should output at least one line of data on success. And nothing on failure.
+
+Example: /usr/local/sbin/set_quota</string>
+ <string id="POL_6A683A86_8075_55FF_B1E6_D7874A3539AA">apply group policies</string>
+ <string id="POL_6A683A86_8075_55FF_B1E6_D7874A3539AA_Help">This option controls whether winbind will execute the gpupdate command defined in on the Group Policy update interval. The Group Policy update interval is defined as every 90 minutes, plus a random offset between 0 and 30 minutes. This applies Group Policy Machine polices to the client or KDC and machine policies to a server.
+
+Example: yes</string>
+ <string id="POL_0471CC71_51D5_58F6_A00A_6E8B283C3AF5">create krb5 conf</string>
+ <string id="POL_0471CC71_51D5_58F6_A00A_6E8B283C3AF5_Help">Setting this parameter to no prevents winbind from creating custom krb5.conf files. Winbind normally does this because the krb5 libraries are not AD-site-aware and thus would pick any domain controller out of potentially very many. Winbind is site-aware and makes the krb5 libraries use a local DC by creating its own krb5.conf files. Preventing winbind from doing this might become necessary if you have to add special options into your system-krb5.conf that winbind does not see.</string>
+ <string id="POL_46FF92BD_F484_5B2C_A639_ACBE73F15F3A">idmap backend</string>
+ <string id="POL_46FF92BD_F484_5B2C_A639_ACBE73F15F3A_Help">The idmap backend provides a plugin interface for Winbind to use varying backends to store SID/uid/gid mapping tables.
+ This option specifies the default backend that is used when no special configuration set, but it is now deprecated in favour of the new spelling .</string>
+ <string id="POL_309434B4_68BA_53E0_BDF9_CA589711EA29">idmap cache time</string>
+ <string id="POL_309434B4_68BA_53E0_BDF9_CA589711EA29_Help">This parameter specifies the number of seconds that Winbind's idmap interface will cache positive SID/uid/gid query results. By
+ default, Samba will cache these results for one week.</string>
+ <string id="POL_066B06D4_3BC0_5CFA_80A9_D2B1C046B5B0">idmap gid</string>
+ <string id="POL_066B06D4_3BC0_5CFA_80A9_D2B1C046B5B0_Help">The idmap gid parameter specifies the range of group ids for the default idmap configuration. It is now deprecated in favour of .
+ See the option.
+
+Example: 10000-20000</string>
+ <string id="POL_9B5D009F_1EBE_5E94_A46B_8644157A6061">idmap negative cache time</string>
+ <string id="POL_9B5D009F_1EBE_5E94_A46B_8644157A6061_Help">This parameter specifies the number of seconds that Winbind's idmap interface will cache negative SID/uid/gid query results.</string>
+ <string id="POL_37D1856A_CAF9_5395_AC8E_8E0F3E9C03E4">idmap uid</string>
+ <string id="POL_37D1856A_CAF9_5395_AC8E_8E0F3E9C03E4_Help">The idmap uid parameter specifies the range of user ids for the default idmap configuration. It is now deprecated in favour of .
+ See the option.
+
+Example: 10000-20000</string>
+ <string id="POL_283F0A5F_5841_5D1D_8EE3_D2715805A463">include system krb5 conf</string>
+ <string id="POL_283F0A5F_5841_5D1D_8EE3_D2715805A463_Help">Setting this parameter to no will prevent winbind to include the system /etc/krb5.conf file into the krb5.conf file it creates. See also . This option only applies to Samba built with MIT Kerberos.</string>
+ <string id="POL_61C9E6AE_96EF_5E8D_9AB8_7598584D391E">neutralize nt4 emulation</string>
+ <string id="POL_61C9E6AE_96EF_5E8D_9AB8_7598584D391E_Help">This option controls whether winbindd sends the NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION flag in order to bypass the NT4 emulation of a domain controller.
+ Typically you should not need set this. It can be useful for upgrades from NT4 to AD domains.
+ The behavior can be controlled per netbios domain by using 'neutralize nt4 emulation:NETBIOSDOMAIN = yes' as option.</string>
+ <string id="POL_D8459DE9_6E91_58A6_8E4E_83BFBB41AE4E">reject md5 servers</string>
+ <string id="POL_D8459DE9_6E91_58A6_8E4E_83BFBB41AE4E_Help">This option controls whether winbindd requires support for aes support for the netlogon secure channel.
+ The following flags will be required NETLOGON_NEG_ARCFOUR, NETLOGON_NEG_SUPPORTS_AES, NETLOGON_NEG_PASSWORD_SET2 and NETLOGON_NEG_AUTHENTICATED_RPC.
+ You can set this to yes if all domain controllers support aes. This will prevent downgrade attacks.
+ The behavior can be controlled per netbios domain by using 'reject md5 servers:NETBIOSDOMAIN = yes' as option.
+ This option takes precedence to the option.</string>
+ <string id="POL_E3A88031_AF89_5D12_9F48_5BD36B25F58C">require strong key</string>
+ <string id="POL_E3A88031_AF89_5D12_9F48_5BD36B25F58C_Help">This option controls whether winbindd requires support for md5 strong key support for the netlogon secure channel.
+ The following flags will be required NETLOGON_NEG_STRONG_KEYS, NETLOGON_NEG_ARCFOUR and NETLOGON_NEG_AUTHENTICATED_RPC.
+ You can set this to no if some domain controllers only support des. This might allows weak crypto to be negotiated, may via downgrade attacks.
+ The behavior can be controlled per netbios domain by using 'require strong key:NETBIOSDOMAIN = no' as option.
+ Note for active directory domain this option is hardcoded to 'yes'
+ This option yields precedence to the option.
+ This option takes precedence to the option.</string>
+ <string id="POL_D55FF104_CF84_512D_9962_D01784923C49">template homedir</string>
+ <string id="POL_D55FF104_CF84_512D_9962_D01784923C49_Help">When filling out the user information for a Windows NT user, the winbindd 8 daemon uses this parameter to fill in the home directory for that user. If the string %D is present it is substituted with the user's Windows NT domain name. If the string %U is present it is substituted with the user's Windows NT user name.</string>
+ <string id="POL_A317595E_2C79_5B73_9043_CEB7525F6692">template shell</string>
+ <string id="POL_A317595E_2C79_5B73_9043_CEB7525F6692_Help">When filling out the user information for a Windows NT user, the winbindd 8 daemon uses this parameter to fill in the login shell for that user.</string>
+ <string id="POL_F8F9B8BF_2D26_5079_928E_7168BBCA91BE">winbind cache time</string>
+ <string id="POL_F8F9B8BF_2D26_5079_928E_7168BBCA91BE_Help">This parameter specifies the number of seconds the winbindd 8 daemon will cache user and group information before querying a Windows NT server again.
+
+ This does not apply to authentication requests, these are always evaluated in real time unless the option has been enabled.</string>
+ <string id="POL_07E24EA1_B340_5215_BDBB_5248537F9540">winbindd socket directory</string>
+ <string id="POL_07E24EA1_B340_5215_BDBB_5248537F9540_Help">This setting controls the location of the winbind daemon's socket. Except within automated test scripts, this should not be altered, as the client tools (nss_winbind etc) do not honour this parameter. Client tools must then be advised of the altered path with the WINBINDD_SOCKET_DIR environment variable.</string>
+ <string id="POL_8FEAD8B9_8097_5BA2_BD78_7BB0AA8691C1">winbind enum groups</string>
+ <string id="POL_8FEAD8B9_8097_5BA2_BD78_7BB0AA8691C1_Help">On large installations using winbindd 8 it may be necessary to suppress the enumeration of groups through the setgrent(), getgrent() and endgrent() group of system calls. If the winbind enum groups parameter is no, calls to the getgrent() system call will not return any data.
+
+Turning off group enumeration may cause some programs to behave oddly.</string>
+ <string id="POL_FAB1BAAD_85CD_5FE6_B0AA_AC48B77ACCCC">winbind enum users</string>
+ <string id="POL_FAB1BAAD_85CD_5FE6_B0AA_AC48B77ACCCC_Help">On large installations using winbindd 8 it may be necessary to suppress the enumeration of users through the setpwent(), getpwent() and endpwent() group of system calls. If the winbind enum users parameter is no, calls to the getpwent system call will not return any data.
+
+Turning off user enumeration may cause some programs to behave oddly. For example, the finger program relies on having access to the full user list when searching for matching usernames.</string>
+ <string id="POL_2B331ECE_5A4A_5DE9_8DBF_EFBCE108F070">winbind expand groups</string>
+ <string id="POL_2B331ECE_5A4A_5DE9_8DBF_EFBCE108F070_Help">This option controls the maximum depth that winbindd
+ will traverse when flattening nested group memberships of Windows domain groups. This is different from the option
+ which implements the Windows NT4 model of local group nesting. The &quot;winbind expand groups&quot;
+ parameter specifically applies to the membership of domain groups.
+ This option also affects the return of non nested group memberships of Windows domain users. With the new default &quot;winbind expand groups = 0&quot; winbind does not query group memberships at all.
+ Be aware that a high value for this parameter can result in system slowdown as the main parent winbindd daemon must perform the group unrolling and will be unable to answer incoming NSS or authentication requests during this time.
+ The default value was changed from 1 to 0 with Samba 4.2. Some broken applications (including some implementations of newgrp and sg) calculate the group memberships of users by traversing groups, such applications will require &quot;winbind expand groups = 1&quot;. But the new default makes winbindd more reliable as it doesn't require SAMR access to domain controllers of trusted domains.</string>
+ <string id="POL_7F3A4DCD_923C_5586_AFFB_1BA559F399CB">winbind:ignore domains</string>
+ <string id="POL_7F3A4DCD_923C_5586_AFFB_1BA559F399CB_Help">Allows one to enter a list of trusted domains winbind should
+ ignore (untrust). This can avoid the overhead of resources from
+ attempting to login to DCs that should not be communicated with.
+
+Example: DOMAIN1, DOMAIN2</string>
+ <string id="POL_FE5A1763_2311_55A2_AB2E_10D92C3A7FC4">winbind max clients</string>
+ <string id="POL_FE5A1763_2311_55A2_AB2E_10D92C3A7FC4_Help">This parameter specifies the maximum number of clients the winbindd 8 daemon can connect with. The parameter is not a hard limit. The winbindd 8 daemon configures itself to be able to accept at least that many connections, and if the limit is reached, an attempt is made to disconnect idle clients.</string>
+ <string id="POL_57855ED8_E596_52E6_A8F8_B710E76BD0F6">winbind max domain connections</string>
+ <string id="POL_57855ED8_E596_52E6_A8F8_B710E76BD0F6_Help">This parameter specifies the maximum number of simultaneous connections that the winbindd 8 daemon should open to the domain controller of one domain. Setting this parameter to a value greater than 1 can improve scalability with many simultaneous winbind requests, some of which might be slow. Note that if is set to Yes, then only one DC connection is allowed per domain, regardless of this setting.
+
+Example: 10</string>
+ <string id="POL_6C096F2D_4DB1_5E05_84BB_9E9E3E0708BB">winbind nested groups</string>
+ <string id="POL_6C096F2D_4DB1_5E05_84BB_9E9E3E0708BB_Help">If set to yes, this parameter activates the support for nested
+ groups. Nested groups are also called local groups or
+ aliases. They work like their counterparts in Windows: Nested
+ groups are defined locally on any machine (they are shared
+ between DC's through their SAM) and can contain users and
+ global groups from any trusted SAM. To be able to use nested
+ groups, you need to run nss_winbind.</string>
+ <string id="POL_7C9859FE_6BA0_526D_A308_9454D3063550">winbind normalize names</string>
+ <string id="POL_7C9859FE_6BA0_526D_A308_9454D3063550_Help">This parameter controls whether winbindd will replace whitespace in user and group names with an underscore (_) character. For example, whether the name &quot;Space Kadet&quot; should be replaced with the string &quot;space_kadet&quot;. Frequently Unix shell scripts will have difficulty with usernames contains whitespace due to the default field separator in the shell. If your domain possesses names containing the underscore character, this option may cause problems unless the name aliasing feature is supported by your nss_info plugin.
+
+ This feature also enables the name aliasing API which can be used to make domain user and group names to a non-qualified version. Please refer to the manpage for the configured idmap and nss_info plugin for the specifics on how to configure name aliasing for a specific configuration. Name aliasing takes precedence (and is mutually exclusive) over the whitespace replacement mechanism discussed previously.
+
+Example: yes</string>
+ <string id="POL_3D3D280A_1D60_58AA_A7BD_54D13DDBE1A6">winbind nss info</string>
+ <string id="POL_3D3D280A_1D60_58AA_A7BD_54D13DDBE1A6_Help">This parameter is designed to control how Winbind retrieves Name Service Information to construct a user's home directory and login shell. Currently the following settings are available:
+ template - The default, using the parameters of template shell and template homedir)
+ &lt;sfu | sfu20 | rfc2307 &gt; - When Samba is running in security = ads and your Active Directory Domain Controller does support the Microsoft &quot;Services for Unix&quot; (SFU) LDAP schema, winbind can retrieve the login shell and the home directory attributes directly from your Directory Server. For SFU 3.0 or 3.5 simply choose &quot;sfu&quot;, if you use SFU 2.0 please choose &quot;sfu20&quot;. Note that for the idmap backend idmap_ad you need to configure those settings in the idmap configuration section. Make sure to consult the documentation of the idmap backend that you are using.
+
+Example: sfu</string>
+ <string id="POL_34B48F10_7723_5E77_A57B_AE606BBB43B7">winbind offline logon</string>
+ <string id="POL_34B48F10_7723_5E77_A57B_AE606BBB43B7_Help">This parameter is designed to control whether Winbind should allow one to login with the pam_winbind module using Cached Credentials. If enabled, winbindd will store user credentials from successful logins encrypted in a local cache.
+
+Example: yes</string>
+ <string id="POL_05A14875_99EE_5000_A1E2_100D2F7B079F">winbind reconnect delay</string>
+ <string id="POL_05A14875_99EE_5000_A1E2_100D2F7B079F_Help">This parameter specifies the number of seconds the winbindd 8 daemon will wait between attempts to contact a Domain controller for a domain that is determined to be down or not contactable.</string>
+ <string id="POL_98A94538_AA09_51C8_A96D_ACB0B314F5F4">winbind refresh tickets</string>
+ <string id="POL_98A94538_AA09_51C8_A96D_ACB0B314F5F4_Help">This parameter is designed to control whether Winbind should refresh Kerberos Tickets retrieved using the pam_winbind module.
+
+Example: yes</string>
+ <string id="POL_96B1E9F8_5418_5EA0_8B87_614B45822D92">winbind request timeout</string>
+ <string id="POL_96B1E9F8_5418_5EA0_8B87_614B45822D92_Help">This parameter specifies the number of seconds the winbindd 8 daemon will wait before disconnecting either a client connection with no outstanding requests (idle) or a client connection with a request that has remained outstanding (hung) for longer than this number of seconds.</string>
+ <string id="POL_FEC015B1_6B0B_5D76_B23D_71363578FAF7">winbind rpc only</string>
+ <string id="POL_FEC015B1_6B0B_5D76_B23D_71363578FAF7_Help">Setting this parameter to yes forces winbindd to use RPC instead of LDAP to retrieve information from Domain
+ Controllers.</string>
+ <string id="POL_412B470E_EC88_556F_B9DE_1952C70E45B1">winbind scan trusted domains</string>
+ <string id="POL_412B470E_EC88_556F_B9DE_1952C70E45B1_Help">This option only takes effect when the option is set to
+ domain or ads.
+ If it is set to yes (the default), winbindd periodically tries to scan for new
+ trusted domains and adds them to a global list inside of winbindd.
+ The list can be extracted with wbinfo --trusted-domains --verbose.
+ This matches the behaviour of Samba 4.7 and older.
+
+ The construction of that global list is not reliable and often
+ incomplete in complex trust setups. In most situations the list is
+ not needed any more for winbindd to operate correctly.
+ E.g. for plain file serving via SMB using a simple idmap setup
+ with autorid, tdb or ad.
+ However some more complex setups require the list, e.g.
+ if you specify idmap backends for specific domains.
+ Some pam_winbind setups may also require the global list.
+
+ If you have a setup that doesn't require the global list, you should set
+ no.</string>
+ <string id="POL_6247DEB4_05CC_51B8_A8CB_1FF7DEDA741C">winbind sealed pipes</string>
+ <string id="POL_6247DEB4_05CC_51B8_A8CB_1FF7DEDA741C_Help">This option controls whether any requests from winbindd to domain controllers pipe will be sealed. Disabling sealing can be useful for debugging purposes.
+ The behavior can be controlled per netbios domain by using 'winbind sealed pipes:NETBIOSDOMAIN = no' as option.</string>
+ <string id="POL_7E1E179F_7E0D_5CB4_BDAA_B8EDF41428CC">winbind separator</string>
+ <string id="POL_7E1E179F_7E0D_5CB4_BDAA_B8EDF41428CC_Help">This parameter allows an admin to define the character used when listing a username of the form of DOMAIN \user. This parameter is only applicable when using the pam_winbind.so and nss_winbind.so modules for UNIX services.
+ Please note that setting this parameter to + causes problems with group membership at least on glibc systems, as the character + is used as a special character for NIS in /etc/group.
+
+Example: +</string>
+ <string id="POL_1780A1A5_0535_5D0B_8105_2129879E3C40">winbind use default domain</string>
+ <string id="POL_1780A1A5_0535_5D0B_8105_2129879E3C40_Help">This parameter specifies whether the winbindd 8 daemon should operate on users without domain component in their username. Users without a domain component are treated as is part of the winbindd server's own domain. While this does not benefit Windows users, it makes SSH, FTP and e-mail function in a way much closer to the way they would in a native unix system. This option should be avoided if possible. It can cause confusion about responsibilities for a user or group. In many situations it is not clear whether winbind or /etc/passwd should be seen as authoritative for a user, likewise for groups.
+
+Example: yes</string>
+ <string id="POL_71A1842A_9526_5BF9_A0FC_07322D2C6C81">winbind use krb5 enterprise principals</string>
+ <string id="POL_71A1842A_9526_5BF9_A0FC_07322D2C6C81_Help">winbindd is able to get kerberos tickets for pam_winbind with krb5_auth or wbinfo -K/--krb5auth=.
+ winbindd (at least on a domain member) is never be able to have a complete picture of the trust topology (which is managed by the DCs). There might be uPNSuffixes and msDS-SPNSuffixes values, which don't belong to any AD domain at all.
+ With no winbindd don't even get an incomplete picture of the topology.
+ It is not really required to know about the trust topology. We can just rely on the [K]DCs of our primary domain (e.g. PRIMARY.A.EXAMPLE.COM) and use enterprise principals e.g. upnfromB@B.EXAMPLE.COM@PRIMARY.A.EXAMPLE.COM and follow the WRONG_REALM referrals in order to find the correct DC. The final principal might be userfromB@INTERNALB.EXAMPLE.PRIVATE.
+ With yes winbindd enterprise principals will be used.
+
+Example: yes</string>
+ <string id="POL_B05D0593_B0CE_52A9_977C_E7A897EEA307">dns proxy</string>
+ <string id="POL_B05D0593_B0CE_52A9_977C_E7A897EEA307_Help">Specifies that nmbd 8 when acting as a WINS server and finding that a NetBIOS name has not been registered, should treat the NetBIOS name word-for-word as a DNS name and do a lookup with the DNS server for that name on behalf of the name-querying client.
+ Note that the maximum length for a NetBIOS name is 15 characters, so the DNS name (or DNS alias) can likewise only be 15 characters, maximum.
+ nmbd spawns a second copy of itself to do the DNS name lookup requests, as doing a name lookup is a blocking action.</string>
+ <string id="POL_C1A54865_BE76_5627_B737_BBB708AEC44C">max wins ttl</string>
+ <string id="POL_C1A54865_BE76_5627_B737_BBB708AEC44C_Help">This option tells smbd
+ 8 when acting as a WINS server (yes) what the maximum
+ 'time to live' of NetBIOS names that nmbd
+ will grant will be (in seconds). You should never need to change this parameter. The default is 6 days (518400 seconds).</string>
+ <string id="POL_BEE0A696_13BD_578B_B448_1E0A01AB915A">min wins ttl</string>
+ <string id="POL_BEE0A696_13BD_578B_B448_1E0A01AB915A_Help">This option tells nmbd
+ 8
+ when acting as a WINS server (yes) what the minimum 'time to live'
+ of NetBIOS names that nmbd will grant will be (in
+ seconds). You should never need to change this parameter. The default
+ is 6 hours (21600 seconds).</string>
+ <string id="POL_890DE0DC_C0FC_565A_A1D3_AD06EFAC41ED">nbtd:wins_prepend1Bto1Cqueries</string>
+ <string id="POL_890DE0DC_C0FC_565A_A1D3_AD06EFAC41ED_Help">Normally queries for 0x1C names (all logon servers for a domain) will return the first address of the 0x1B names (domain master browser and PDC) as first address in the result list. As many client only use the first address in the list by default, all clients will use the same server (the PDC). Windows servers have an option to disable this behavior (since Windows 2000 Service Pack 2).</string>
+ <string id="POL_06F0FFB1_F595_57BB_B964_6D419A02F468">nbtd:wins_wins_randomize1Clist</string>
+ <string id="POL_06F0FFB1_F595_57BB_B964_6D419A02F468_Help">Normally queries for 0x1C names will return the addresses in the same order as they're stored in the database, that means first all addresses which have been directly registered at the local wins server and then all addresses registered at other servers. Windows servers have an option to change this behavior and randomize the returned addresses. Set this parameter to &quot;yes&quot; and Samba will sort the address list depending on the client address and the matching bits of the addresses, the first address is randomized based on depending on the &quot;nbtd:wins_randomize1Clist_mask&quot; parameter.</string>
+ <string id="POL_F63D2A1E_D6BA_516E_995D_F9FEE05D49DB">nbtd:wins_randomize1Clist_mask</string>
+ <string id="POL_F63D2A1E_D6BA_516E_995D_F9FEE05D49DB_Help">If the &quot;nbtd:wins_randomize1Clist&quot; parameter is set to &quot;yes&quot;, then randomizing of the first returned address is based on the specified netmask. If there are addresses which are in the same subnet as the client address, the first returned address is randomly chosen out them. Otherwise the first returned address is randomly chosen out of all addresses.</string>
+ <string id="POL_D0A83CCC_07AF_553B_84AE_4824377AE692">winsdb:local_owner</string>
+ <string id="POL_D0A83CCC_07AF_553B_84AE_4824377AE692_Help">This specifies the address that is stored in the winsOwner attribute, of locally registered winsRecord-objects. The default is to use the ip-address of the first network interface.</string>
+ <string id="POL_06442D20_4739_5DE0_820F_516416AD0ECF">winsdb:dbnosync</string>
+ <string id="POL_06442D20_4739_5DE0_820F_516416AD0ECF_Help">This parameter disables fsync() after changes of the WINS database.</string>
+ <string id="POL_F7271C08_2949_53E0_809D_9B976AB9DE2E">wins hook</string>
+ <string id="POL_F7271C08_2949_53E0_809D_9B976AB9DE2E_Help">When Samba is running as a WINS server this allows you to call an external program for all changes to the WINS database. The primary use for this option is to allow the dynamic update of external name resolution databases such as dynamic DNS.
+ The wins hook parameter specifies the name of a script or executable that will be called as follows:
+ wins_hook operation name nametype ttl IP_list
+ The first argument is the operation and is one of &quot;add&quot;, &quot;delete&quot;, or &quot;refresh&quot;. In most cases the operation can be ignored as the rest of the parameters provide sufficient information. Note that &quot;refresh&quot; may sometimes be called when the name has not previously been added, in that case it should be treated as an add.
+ The second argument is the NetBIOS name. If the name is not a legal name then the wins hook is not called. Legal names contain only letters, digits, hyphens, underscores and periods.
+ The third argument is the NetBIOS name type as a 2 digit hexadecimal number.
+ The fourth argument is the TTL (time to live) for the name in seconds. The fifth and subsequent arguments are the IP addresses currently registered for that name. If this list is empty then the name should be deleted.
+ An example script that calls the BIND dynamic DNS update program nsupdate is provided in the examples directory of the Samba source code.</string>
+ <string id="POL_A1E6C0E7_38BA_5583_816D_73C91FCAADB4">wins proxy</string>
+ <string id="POL_A1E6C0E7_38BA_5583_816D_73C91FCAADB4_Help">This is a boolean that controls if nmbd 8 will respond to broadcast name queries on behalf of other hosts. You may need to set this to yes for some older clients.</string>
+ <string id="POL_31C40FB1_1B0A_5AA3_80F9_7914AC38FD99">wins server</string>
+ <string id="POL_31C40FB1_1B0A_5AA3_80F9_7914AC38FD99_Help">This specifies the IP address (or DNS name: IP address for preference) of the WINS server that nmbd 8 should register with. If you have a WINS server on your network then you should set this to the WINS server's IP.
+ You should point this at your WINS server if you have a multi-subnetted network.
+ If you want to work in multiple namespaces, you can give every wins server a 'tag'. For each tag, only one (working) server will be queried for a name. The tag should be separated from the ip address by a colon.
+ You need to set up Samba to point to a WINS server if you have multiple subnets and wish cross-subnet browsing to work correctly. See the chapter in the Samba3-HOWTO on Network Browsing.
+
+Example: mary:192.9.200.1 fred:192.168.3.199 mary:192.168.2.61
+
+
+Example: 192.9.200.1 192.168.2.61</string>
+ <string id="POL_44517D2D_845B_5F7B_90F2_F7BD0DA063A9">wins support</string>
+ <string id="POL_44517D2D_845B_5F7B_90F2_F7BD0DA063A9_Help">This boolean controls if the nmbd 8 process in Samba will act as a WINS server. You should not set this to yes unless you have a multi-subnetted network and you wish a particular nmbd to be your WINS server. Note that you should NEVER set this to yes on more than one machine in your network.</string>
+ <string id="POL_8A035569_9C85_59DC_9BF8_241994D4E947">wreplsrv:periodic_interval</string>
+ <string id="POL_8A035569_9C85_59DC_9BF8_241994D4E947_Help">This maximum interval in seconds between 2 periodically scheduled runs where we check for wins.ldb changes and do push notifications to our push partners. Also wins_config.ldb changes are checked in that interval and partner configuration reloads are done.</string>
+ <string id="POL_186864AE_CE31_5628_BA4E_6B9F06F087E5">wreplsrv:propagate name releases</string>
+ <string id="POL_186864AE_CE31_5628_BA4E_6B9F06F087E5_Help">If this parameter is enabled, then explicit (from the client) and implicit (via the scavenging) name releases are propagated to the other servers directly, even if there are still other addresses active, this applies to SPECIAL GROUP (2) and MULTIHOMED (3) entries. Also the replication conflict merge algorithm for SPECIAL GROUP (2) entries discards replica addresses where the address owner is the local server, if the address was not stored locally before. The merge result is propagated directly in case an address was discarded. A Windows servers doesn't propagate name releases of SPECIAL GROUP (2) and MULTIHOMED (3) entries directly, which means that Windows servers may return different results to name queries for SPECIAL GROUP (2) and MULTIHOMED (3) names. The option doesn't have much negative impact if Windows servers are around, but be aware that they might return unexpected results.</string>
+ <string id="POL_8DC9CC59_A490_5F52_8C69_A9EEC802C48C">wreplsrv:scavenging_interval</string>
+ <string id="POL_8DC9CC59_A490_5F52_8C69_A9EEC802C48C_Help">This is the interval in s between 2 scavenging runs which clean up the WINS database and changes the states of expired name records. Defaults to half of the value of wreplsrv:renew_interval.</string>
+ <string id="POL_DB737BF2_9B47_5895_A3F8_D51BBD764222">wreplsrv:tombstone_extra_timeout</string>
+ <string id="POL_DB737BF2_9B47_5895_A3F8_D51BBD764222_Help">This is the time in s the server needs to be up till we'll remove tombstone records from our database. Defaults to 3 days.</string>
+ <string id="POL_30D1C3B2_BDCD_5A5C_A131_11E1E6DA2A76">wreplsrv:tombstone_interval</string>
+ <string id="POL_30D1C3B2_BDCD_5A5C_A131_11E1E6DA2A76_Help">This is the interval in s till released records of the WINS server become tombstone. Defaults to 6 days.</string>
+ <string id="POL_F19C445A_AFD5_51B6_B87A_E42499C3C5D8">wreplsrv:tombstone_timeout</string>
+ <string id="POL_F19C445A_AFD5_51B6_B87A_E42499C3C5D8_Help">This is the interval in s till tombstone records are deleted from the WINS database. Defaults to 1 day.</string>
+ <string id="POL_8CF1FEA3_BD3E_53C0_9F73_34050187A91E">wreplsrv:verify_interval</string>
+ <string id="POL_8CF1FEA3_BD3E_53C0_9F73_34050187A91E_Help">This is the interval in s till we verify active replica records with the owning WINS server. Unfortunately not implemented yet. Defaults to 24 days.</string>
+ <string id="CAT_9DEF582D_447A_47E9_A1F5_363558D03FA9">Messages</string>
+ <string id="POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07">Message of the day</string>
+ <string id="POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07_Help"> The contents of /etc/motd are displayed after a successful login but just before it executes the login shell.</string>
+ <string id="POL_68E9155C_CB49_428E_AFE0_B89316FFD948">Login Prompt Message</string>
+ <string id="POL_68E9155C_CB49_428E_AFE0_B89316FFD948_Help"> The issue file may contain certain escape codes to display the system name, date, time etc. All escape codes consist of a backslash (\) immediately followed by one of the characters listed below.
+
+ 4 or 4{interface}
+ Insert the IPv4 address of the specified network interface (for example: \4{eth0}). If the interface argument is not specified, then select the first fully configured (UP, non-LOCALBACK, RUNNING) interface. If not any configured interface is found, fall back to the IP address of the machine's hostname.
+
+ 6 or 6{interface}
+ The same as \4 but for IPv6.
+
+ b Insert the baudrate of the current line.
+
+ d Insert the current date.
+
+ e or e{name}
+ Translate the human-readable name to an escape sequence and insert it (for example: \e{red}Alert text.\e{reset}). If the name argument is not specified, then insert \033. The currently supported names are: black, blink, blue, bold, brown, cyan, darkgray, gray, green, halfbright, lightblue, lightcyan, lightgray, lightgreen, lightmagenta, lightred, magenta, red, reset, reverse, and yellow. All unknown names are silently ignored.
+
+ s Insert the system name (the name of the operating system). Same as 'uname -s'. See also the \S escape code.
+
+ S or S{VARIABLE}
+ Insert the VARIABLE data from /etc/os-release. If this file does not exist then fall back to /usr/lib/os-release. If the VARIABLE argument is not specified, then use PRETTY_NAME from the file or the system name (see \s). This escape code allows to keep /etc/issue distribution and release independent. Note that \S{ANSI_COLOR} is converted to the real terminal escape sequence.
+
+ l Insert the name of the current tty line.
+
+ m Insert the architecture identifier of the machine. Same as 'uname -m'.
+
+ n Insert the nodename of the machine, also known as the hostname. Same as 'uname -n'.
+
+ o Insert the NIS domainname of the machine. Same as 'hostname -d'.
+
+ O Insert the DNS domainname of the machine.
+
+ r Insert the release number of the OS. Same as 'uname -r'.
+
+ t Insert the current time.
+
+ u Insert the number of current users logged in.
+
+ U Insert the string "1 user" or "&lt;n&gt; users" where &lt;n&gt; is the number of current users logged in.
+
+ v Insert the version of the OS, that is, the build-date and such.</string>
+ <string id="CAT_371A8FF5_990F_47DD_B200_D436AC28A4F9">Firewalld</string>
+ <string id="POL_ADABE9E0_FFF9_4FFE_A105_03E646C79978">Zones</string>
+ <string id="POL_ADABE9E0_FFF9_4FFE_A105_03E646C79978_Help">A list of zones to create. Existing zones on the host will be unaffected.
+
+Rule creation for zones is handled in the Rules setting.</string>
+ <string id="POL_B21F349F_4BF6_473E_8452_047D714F156C">Rules</string>
+ <string id="POL_B21F349F_4BF6_473E_8452_047D714F156C_Help">A JSON dictionary, containing zones paired with a list of rules.
+
+For example, to create rules for the Work and Home zones, specify the following JSON:
+
+{
+ "work": [
+ {"rule": {"family": "ipv4"}, "source address": "172.25.1.7", "service name": "ftp", "reject": {}},
+ {"rule": {}, "source address": "172.25.1.8", "service name": "ftp", "reject": {}}
+ ],
+ "home": [
+ {"rule": {}, "protocol value": "icmp", "reject": {}},
+ {"rule": {"family": "ipv4"}, "source address": "192.168.1.2/32", "service name": "telnet", "accept": {"limit value": "1/m"}}
+ ]
+}
+
+An improperly formatted JSON will be ignored.
+
+The rule structure loosely follows the Firewalld Rich Language Documentation.
+
+General rule structure:
+{
+ "rule": {
+ "family": "ipv4 | ipv6",
+ "priority": "priority"
+ },
+ "source [not] address | mac | ipset": "address[/mask] | mac-address | ipset",
+ "destination [not] address": "address[/mask]",
+ "service name": "service name",
+ "port": {
+ "port": "port value",
+ "protocol": "tcp | udp"
+ }
+ "protocol value": "protocol value",
+ "icmp-block name": "icmptype name",
+ "Masquerade": true|false,
+ "icmp-type": "icmptype name",
+ "forward-port": {
+ "port": "port value",
+ "protocol": "tcp | udp",
+ "to-port": "port value",
+ "to-addr": "address"
+ },
+ "source-port": {
+ "port": "port value",
+ "protocol": "tcp | udp"
+ },
+ "log": {
+ "prefix": "prefix text",
+ "level": "emerg | alert | crit | error | warning | notice | info | debug",
+ "limit value": "rate/duration"
+ },
+ "audit": {
+ "limit value": "rate/duration"
+ },
+ "accept" : {
+ "limit value": "rate/duration"
+ } | "reject": {
+ "type": "reject type",
+ "limit value": "rate/duration"
+ } | "drop": {
+ "limit value": "rate/duration"
+ } | "mark": {
+ "set": "mark[/mask]",
+ "limit value": "rate/duration"
+ }
+}</string>
+ </stringTable>
+ <presentationTable>
+ <presentation id="POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061">
+ <listBox refId="LST_2E9A4684_3C0E_415B_8FD6_D4AF68BC8AC6">Script and arguments</listBox>
+ </presentation>
+ <presentation id="POL_825D441F_905E_4C7E_9E4B_03013697C6C1">
+ <listBox refId="LST_1AA93D59_6372_4F1E_90BB_D4CBBBB77238">Script and arguments</listBox>
+ </presentation>
+ <presentation id="POL_D298F3BD_44D9_426D_AF11_3163D31582F6">
+ <listBox refId="LST_8BC6757D_B1FB_4780_83B4_F85F27BF6E60">Script and arguments</listBox>
+ </presentation>
+ <presentation id="POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674">
+ <listBox refId="LST_1E7198A6_7850_4CAB_B656_BC18752564FC">Script and arguments</listBox>
+ </presentation>
+ <presentation id="POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3">
+ <listBox refId="LST_4F4BA073_4F7B_4B64_A61D_8E75257A4B9F">Sudoers commands</listBox>
+ </presentation>
+ <presentation id="POL_A3D6C2F2_2798_527E_861E_FA8BADBBE6E6">
+ <textBox refId="TXT_F940E18B_16AE_594B_9669_96417E695AC9">
+ <label>additional dns hostnames</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_AC8777B4_88D7_5A1A_BB7E_E47AB5DBD6AA">
+ <checkBox refId="CHK_5C837672_BFBB_592A_907C_E378BEEDA2E4">bind interfaces only</checkBox>
+ </presentation>
+ <presentation id="POL_D03F1811_D0CA_56CF_9D18_B480E9B5AFAD">
+ <textBox refId="TXT_03C82812_CCD0_5E35_8FA1_2704BAF796E9">
+ <label>config backend</label>
+ <defaultValue>file</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DE840DAF_58CD_5B21_A76B_70740BD125A1">
+ <textBox refId="TXT_CF5594A6_FA4A_5AB4_881B_AD9270CE3523">
+ <label>dos charset</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3783DBBE_7F1F_52B4_BECB_6176E8D43AE1">
+ <checkBox defaultChecked="true" refId="CHK_A51834ED_BBB9_52C3_A7C5_A566ABE7AB3D">enable core files</checkBox>
+ </presentation>
+ <presentation id="POL_5EE2E645_A509_5C51_94FE_4F84668AC869">
+ <textBox refId="TXT_3E2FB206_740F_580E_889D_B53C2540732C">
+ <label>mdns name</label>
+ <defaultValue>netbios</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_32EB220A_5721_51EC_810C_0BEF4B9EA706">
+ <checkBox defaultChecked="true" refId="CHK_03FFDBD4_C185_5951_954F_189B0D4C40DA">multicast dns register</checkBox>
+ </presentation>
+ <presentation id="POL_51EEB44F_42B8_5CEA_8DA6_CB78139F4804">
+ <textBox refId="TXT_6A12C17F_F8CF_56F3_8D82_43CAB3C57F55">
+ <label>netbios aliases</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_4AEFFAC4_3FBE_5DFA_9D3F_D78B50416B7C">
+ <textBox refId="TXT_34827D8A_E97C_590B_BD8A_6DEA6A354BE8">
+ <label>netbios name</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_24E6BE64_5FEA_56A1_83AF_844C8A96E96D">
+ <textBox refId="TXT_0ED12914_E653_5CDA_9F46_E1C3AB2FC32E">
+ <label>netbios scope</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0901DFB6_7C73_5D10_82CC_5D77CD14685D">
+ <decimalTextBox defaultValue="10" refId="DXT_F0896598_D8F1_579A_B01D_09A48282AC76"/>
+ </presentation>
+ <presentation id="POL_26F4B846_C66B_5649_AA7E_B06E899017CA">
+ <decimalTextBox defaultValue="4" refId="DXT_BD459D8F_47F9_558D_A641_97892C9E577E"/>
+ </presentation>
+ <presentation id="POL_9C3E188A_07B9_5354_A206_DD0FA0B4A235">
+ <decimalTextBox defaultValue="120" refId="DXT_16991D04_74C7_54C3_9E4F_52EF9C9AEDB4"/>
+ </presentation>
+ <presentation id="POL_609F7E6F_9AAC_56B4_B098_4E63BBBB98B4">
+ <textBox refId="TXT_5B075596_6622_5C89_A426_B9DA3F43AC3A">
+ <label>realm</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_68ED4DED_E13E_5C54_BD04_23E499D77D51">
+ <textBox refId="TXT_E2BF4D58_613E_5C2D_850A_C3585BC311C2">
+ <label>server services</label>
+ <defaultValue>s3fs, rpc, nbt, wrepl, ldap, cldap, kdc, drepl, winbindd, ntp_signd, kcc, dnsupdate, dns</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_584FF155_77A9_5209_AC2F_071DEAB5FA42">
+ <textBox refId="TXT_EC20B2FC_7658_536F_A876_F0B61196042C">
+ <label>server string</label>
+ <defaultValue>Samba %v</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3D10A56C_5C5B_516D_8718_0112384056DB">
+ <textBox refId="TXT_682410E7_F583_5A97_BB60_6BBAA190DA1C">
+ <label>share backend</label>
+ <defaultValue>classic</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A64B2059_EC1C_5759_94E8_CD95EEB42F35">
+ <textBox refId="TXT_3F03354B_7221_5D54_8D25_FA3229D9A026">
+ <label>unix charset</label>
+ <defaultValue>UTF-8</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_38764DE0_53DC_587E_A94B_7C03323B0C69">
+ <textBox refId="TXT_A1CD4626_197B_582B_9C09_E35945F84ECF">
+ <label>workgroup</label>
+ <defaultValue>WORKGROUP</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DD5ADDCF_E8DF_50F9_9847_E821787C2C3C">
+ <textBox refId="TXT_18F101C1_8754_5052_8D12_3D4B3755A739">
+ <label>interfaces</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EECBA792_3D9C_5624_A01E_F5876EF8224D">
+ <checkBox defaultChecked="true" refId="CHK_1D40EF50_9DF5_5D95_B5EF_406C4F3774B8">browse list</checkBox>
+ </presentation>
+ <presentation id="POL_414481A1_7B9D_551A_96F0_B235A226F141">
+ <textBox refId="TXT_69092348_8194_5EA4_9EB2_AFFFF4A2A6C8">
+ <label>domain master</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_25D5E28F_5847_5A16_8CF5_01E528D1807D">
+ <checkBox defaultChecked="true" refId="CHK_7A02FE2C_82BF_50CE_91F0_14B1191E7258">enhanced browsing</checkBox>
+ </presentation>
+ <presentation id="POL_7356F015_5915_5A1E_9154_AEE48849DC85">
+ <textBox refId="TXT_9C07BE5E_EF60_51EC_B26C_CEA97CD41C69">
+ <label>lm announce</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_37CB9A35_D06B_581B_8BBC_96F636F2DF0D">
+ <decimalTextBox defaultValue="60" refId="DXT_6B8EAB54_6B9E_5EE3_BBB3_286F512AC0F9"/>
+ </presentation>
+ <presentation id="POL_00BB67E5_7846_53BF_990A_8B7D03F9D88E">
+ <checkBox defaultChecked="true" refId="CHK_CFD7EF58_DD73_5465_B0CE_4C6B4E35F416">local master</checkBox>
+ </presentation>
+ <presentation id="POL_99809647_A4DC_5363_8E8B_A27B51B90E87">
+ <decimalTextBox defaultValue="20" refId="DXT_3DF3E95D_2453_53C1_A98D_DB040E45E676"/>
+ </presentation>
+ <presentation id="POL_69BB8325_FE45_56C0_8D34_F23EC38D2107">
+ <textBox refId="TXT_82D47B73_2C75_5779_A283_E9A39FD54705">
+ <label>preferred master</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F664E709_2422_5047_BD55_E95C422B6B33">
+ <textBox refId="TXT_BEC7C085_5840_5531_9E64_A727E258569A">
+ <label>allow dns updates</label>
+ <defaultValue>secure only</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C69048CD_ABF0_5333_B5CB_7455D5F226FF">
+ <textBox refId="TXT_64C9BBC7_F73A_5844_A613_08685212F33C">
+ <label>dns forwarder</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F9D5C585_21FD_5990_BE36_3A58B7AF326B">
+ <textBox refId="TXT_05BC3827_6AE7_54BF_8E0C_008D698CC732">
+ <label>dns update command</label>
+ <defaultValue>/samba_dnsupdate</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2363A474_4143_52A2_A69B_05285C98E4CF">
+ <checkBox refId="CHK_3104780C_9730_550D_8DF9_5C5A226B2AAE">dns zone scavenging</checkBox>
+ </presentation>
+ <presentation id="POL_F2F11B02_D190_5766_95DC_FDB846EEEB13">
+ <textBox refId="TXT_A8FD53BD_1ED7_54DB_9A7C_159348F47A6D">
+ <label>gpo update command</label>
+ <defaultValue>/samba-gpupdate</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A83B176D_D2FE_5F41_9977_9A16F5B8C5ED">
+ <decimalTextBox defaultValue="604800" refId="DXT_E5687DEB_DB51_5266_ACDB_2E619982BAD7"/>
+ </presentation>
+ <presentation id="POL_5BD73E55_C69F_5CCF_8D91_2513716FB1C6">
+ <textBox refId="TXT_3BA3F934_5C9D_5EAB_BAEB_7FBDAE0268F5">
+ <label>nsupdate command</label>
+ <defaultValue>/usr/bin/nsupdate -g</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E38856B0_C9B1_5577_9055_C48A4CCE499C">
+ <textBox refId="TXT_041114D6_313A_501F_BFC9_FD004546248B">
+ <label>spn update command</label>
+ <defaultValue>/samba_spnupdate</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C2FCADD1_1EF0_5726_9CDE_0E155B0B6575">
+ <decimalTextBox defaultValue="1" refId="DXT_0BA0C537_293A_525C_AC5C_9BB5C0524277"/>
+ </presentation>
+ <presentation id="POL_620B56BA_84B7_5E72_AC2D_4F0574FBB199">
+ <textBox refId="TXT_241061E9_3BDA_5AFE_87CB_13C53A164649">
+ <label>mangling method</label>
+ <defaultValue>hash2</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E59D859C_7C78_5AB6_8DE3_27F672637189">
+ <decimalTextBox defaultValue="512" refId="DXT_EA859956_0483_500A_9962_8A26A8B81BB4"/>
+ </presentation>
+ <presentation id="POL_6BB5939F_7CE6_588E_A6E2_B114EF17F60F">
+ <checkBox defaultChecked="true" refId="CHK_45471F8A_D0BD_53A3_B51F_393DE6CC03D2">stat cache</checkBox>
+ </presentation>
+ <presentation id="POL_BE2B9E4A_5ABE_543F_8564_4CBDD1AF9179">
+ <textBox refId="TXT_4A85EF32_894F_50AF_9917_B7F431720A82">
+ <label>client ldap sasl wrapping</label>
+ <defaultValue>sign</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F4937393_B88E_5B26_89F5_F9933BEBEF8B">
+ <textBox refId="TXT_4B00C10F_7EBB_52D5_9AD1_C893F9C094C5">
+ <label>ldap admin dn</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_5187BD6B_3008_59FC_887D_1C89E807B11E">
+ <decimalTextBox defaultValue="2" refId="DXT_87AD8E93_91B6_5439_B928_9776BF986ED0"/>
+ </presentation>
+ <presentation id="POL_96311867_A4DE_5B57_BD8C_3D25B5084F68">
+ <checkBox refId="CHK_2BC96AC0_ECEF_55D4_AEA4_039FDD24C999">ldap delete dn</checkBox>
+ </presentation>
+ <presentation id="POL_193E7C6B_E70E_55EB_AB50_3788B93F4607">
+ <textBox refId="TXT_FCC83065_2F1A_585B_A998_85AA52D99537">
+ <label>ldap deref</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E6D23CDA_DABC_5749_BEF1_D15FF80E02BF">
+ <textBox refId="TXT_DEC758B4_6B3C_5882_B0B8_386473EECFD3">
+ <label>ldap follow referral</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_6C44A469_31FA_512A_AB08_ACDADD5B7238">
+ <textBox refId="TXT_B51FB55F_3A49_539E_A77A_7F7F2AF2CC39">
+ <label>ldap group suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_83D7A344_AE69_5DCA_A3D9_A79DF817A7D4">
+ <textBox refId="TXT_E49CAB56_E62A_5930_99DE_EEC0B04DBCF4">
+ <label>ldap idmap suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_07D748C7_B6EA_558D_B652_62F9BC2E9A1B">
+ <textBox refId="TXT_2B9911E2_33DC_5CB0_A9CC_E7DD7B2A5799">
+ <label>ldap machine suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F831F898_66A7_53D3_B6EA_B90065F7EF41">
+ <decimalTextBox defaultValue="1000" refId="DXT_1C52332B_FC98_54CA_8C3D_64E63D450DD7"/>
+ </presentation>
+ <presentation id="POL_068B0430_6CF2_5CAC_BDC8_F7074411AA6C">
+ <textBox refId="TXT_03529C2D_378A_5BE4_A342_9FF088AC8396">
+ <label>ldap passwd sync</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DC0C1ABD_D8CE_5175_A9AB_D58661AACFB1">
+ <decimalTextBox defaultValue="1000" refId="DXT_B21A5F63_507D_5407_B582_DA64138C6B97"/>
+ </presentation>
+ <presentation id="POL_F12B9752_4939_52A6_9A5E_52FFF53FC34F">
+ <textBox refId="TXT_3ADB0A83_AA24_5C68_BD2E_3723FC2F2268">
+ <label>ldapsam:editposix</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_90ECE51D_8CF8_50F9_809F_87A024DDCAAE">
+ <textBox refId="TXT_B10770E9_1959_5A4A_8D44_F070923C2A12">
+ <label>ldapsam:trusted</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B58FAA75_79BA_53E3_A895_69D6DE3E547E">
+ <textBox refId="TXT_9F11612E_1A6E_5CF7_BC96_4ADBD123A76D">
+ <label>ldap server require strong auth</label>
+ <defaultValue>yes</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D6465FAC_2205_59C0_A3E6_1F1DE4C50A58">
+ <textBox refId="TXT_950B2F92_3A19_5FC4_839A_3226C858811C">
+ <label>ldap ssl</label>
+ <defaultValue>start tls</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EAF3D0F1_C7E5_5864_AE5D_FBF9F6102FF4">
+ <checkBox refId="CHK_0D06C9D8_3A6A_509E_9B4A_DE497AFA6B58">ldap ssl ads</checkBox>
+ </presentation>
+ <presentation id="POL_208E2789_E8A9_53CA_B756_2694096B8DAF">
+ <textBox refId="TXT_ABB81954_F41C_5FAD_BD35_873007549C27">
+ <label>ldap suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D76D653B_C2A3_5939_BF95_9BAE0CF6C88C">
+ <decimalTextBox defaultValue="15" refId="DXT_8B73DF13_A7A3_57B4_A4BE_AC816E59EBAB"/>
+ </presentation>
+ <presentation id="POL_B3FBC8E2_DD5D_5CEA_9FC5_44687CF36BB5">
+ <textBox refId="TXT_B9F4F586_8F61_53D2_AFEE_B2011D0DFF43">
+ <label>ldap user suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_94ABA1F3_F411_52AE_ADAA_72B53F9198CA">
+ <decimalTextBox defaultValue="256000" refId="DXT_B7AEDDC2_0B5A_5C1C_AFA0_7518773C5F5F"/>
+ </presentation>
+ <presentation id="POL_A2C8FD60_A284_5409_B130_B135DEE4B615">
+ <decimalTextBox defaultValue="16777216" refId="DXT_1B597D08_FFDB_5BA4_ABD9_31A8446A3625"/>
+ </presentation>
+ <presentation id="POL_695C7E25_8C69_519C_907E_9A71D1FE2EC3">
+ <decimalTextBox defaultValue="256000" refId="DXT_6FA557BE_E2D9_54CC_9A8D_FAA4BFCD552A"/>
+ </presentation>
+ <presentation id="POL_60E126C5_9E79_54DC_B201_A3E643352D00">
+ <decimalTextBox defaultValue="200" refId="DXT_8D517C10_BE65_5D58_AC86_8A21017F479A"/>
+ </presentation>
+ <presentation id="POL_6B50B6B6_D038_54C5_BD82_9D377C2E8C0C">
+ <decimalTextBox defaultValue="0" refId="DXT_14C326D8_5326_5883_95FA_D903E07A457A"/>
+ </presentation>
+ <presentation id="POL_D9E75BB0_F19B_5F72_A58E_22718E614EB3">
+ <checkBox defaultChecked="true" refId="CHK_8649286E_DE5D_5DE7_A836_AA15E736A911">smb2 leases</checkBox>
+ </presentation>
+ <presentation id="POL_D7003A7B_D00A_51AE_8D40_7446533B2974">
+ <checkBox refId="CHK_4915975F_60D1_5187_9E6A_F835D1086622">debug class</checkBox>
+ </presentation>
+ <presentation id="POL_CF714212_43A8_52ED_BDAD_B1D6F82A6EF9">
+ <checkBox defaultChecked="true" refId="CHK_ADDEF100_7619_5056_B632_ECEF204DBEC8">debug hires timestamp</checkBox>
+ </presentation>
+ <presentation id="POL_CF524D7E_11CA_5027_9777_5398DD2804B4">
+ <checkBox refId="CHK_6D39A340_480D_596C_A9F5_3412FC28765D">debug pid</checkBox>
+ </presentation>
+ <presentation id="POL_BDF671C9_3811_5B19_AB78_5F12B25CEC84">
+ <checkBox refId="CHK_2367747B_4E47_503A_A92C_1EA98AC3D5CC">debug prefix timestamp</checkBox>
+ </presentation>
+ <presentation id="POL_B76DE893_21E7_5B6A_81AB_23B8F00D782D">
+ <checkBox refId="CHK_5BD4217F_5C51_59D6_9582_3037FB4B6E4F">debug uid</checkBox>
+ </presentation>
+ <presentation id="POL_BACB061C_C7A0_5830_80FE_15FA009DEAA2">
+ <decimalTextBox defaultValue="0" refId="DXT_DBF1992F_D735_55E7_9029_AE5D9EBA66FB"/>
+ </presentation>
+ <presentation id="POL_B51CE2D4_7EFD_577E_97EC_8EEA650C0F0F">
+ <decimalTextBox defaultValue="10" refId="DXT_2D488F55_5DE8_5AC6_85AE_F77BE4429364"/>
+ </presentation>
+ <presentation id="POL_1C03B9BE_5E74_58CF_A649_CDFD9E91F6CC">
+ <textBox refId="TXT_2C83A41B_5CDA_5130_8343_1278307321CD">
+ <label>log file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_FA6B22DA_628C_5C5E_8BAD_97BBCE0E4F1F">
+ <textBox refId="TXT_2533346E_4C1C_5ACB_9355_B40495EB63CD">
+ <label>logging</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C4E11396_B289_5D98_9F39_6BD19BBB4330">
+ <textBox refId="TXT_60E8D3F6_8EC7_5FDC_8645_3E4E3EF85512">
+ <label>log level</label>
+ <defaultValue>0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EA5127A5_4C6A_5B8A_9D52_D5D17D9E8AFE">
+ <decimalTextBox defaultValue="5000" refId="DXT_60E6F44F_5185_576D_91C2_9B10FB853416"/>
+ </presentation>
+ <presentation id="POL_69FD7A6B_0BA2_570F_9BB1_B869C7404630">
+ <decimalTextBox defaultValue="1" refId="DXT_FCD3912D_FD93_54A5_91E4_A834457B8F2E"/>
+ </presentation>
+ <presentation id="POL_FD3A0B38_1664_58B4_983A_3A21EC4A76EA">
+ <checkBox refId="CHK_88778A4E_D102_588A_A01C_E930BEE81D6C">syslog only</checkBox>
+ </presentation>
+ <presentation id="POL_AB153BC2_9291_51D0_81AC_1A78B1A0DE6F">
+ <checkBox defaultChecked="true" refId="CHK_16FD7E9E_1FCF_58D9_940E_42D45860825B">timestamp logs</checkBox>
+ </presentation>
+ <presentation id="POL_7C7A3857_7762_5F1F_BDB5_A621FEBD0E99">
+ <textBox refId="TXT_6716C37B_3C84_5AB4_8A8D_B6D070787CEB">
+ <label>abort shutdown script</label>
+ <defaultValue>&quot;&quot;</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A6105481_F59A_5B08_8B4C_B100EF112BD9">
+ <textBox refId="TXT_BB6CFFBF_3E2F_5FDF_A2CC_E255231A3370">
+ <label>add group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_01C79ED8_2727_54DF_AF75_96E5A25722DD">
+ <textBox refId="TXT_C3FD37B5_A643_57DF_AE57_048E75B21BDF">
+ <label>add machine script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_BA7787E8_0D26_5963_8F44_498B278A4703">
+ <textBox refId="TXT_56C28546_216A_5AFF_B212_FFEC207F3FFD">
+ <label>add user script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_077466DB_CB4D_5489_8934_C2F22592D94A">
+ <textBox refId="TXT_218549FC_FD8A_5036_8199_9B2AB628624F">
+ <label>add user to group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8F632169_4F0C_500B_BE8B_88960312C345">
+ <checkBox refId="CHK_61299541_E6C3_50AD_9CCD_409DBABC3DA2">allow nt4 crypto</checkBox>
+ </presentation>
+ <presentation id="POL_5A6DC206_1A48_5FFE_8B2D_897EF95CCBAD">
+ <checkBox refId="CHK_F34DA878_4D45_5E26_8454_77BAE0D9FCAA">auth event notification</checkBox>
+ </presentation>
+ <presentation id="POL_3152501B_87A8_5907_AAD5_00B3F7752516">
+ <textBox refId="TXT_F75A550B_6B11_57A4_9EAD_27361359E4CB">
+ <label>delete group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_676F211D_0B27_54F6_9FF0_1B6F6CC88CA6">
+ <textBox refId="TXT_E6287F6E_CDD6_57CC_A6CF_59E26391473A">
+ <label>delete user from group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3033EDC8_8938_5A64_A8B9_1F7349DC1149">
+ <textBox refId="TXT_1FC62BD1_6541_5C03_B233_B5DE1B987775">
+ <label>delete user script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_27365CD7_D0DF_5A41_9140_A1C6970CB3D0">
+ <checkBox refId="CHK_B67618DB_ED7B_5A2E_AC14_C2E808E1A927">domain logons</checkBox>
+ </presentation>
+ <presentation id="POL_49526C11_2F64_5D85_A25D_A90D2152195E">
+ <checkBox defaultChecked="true" refId="CHK_A6532133_05F0_5D5F_983E_8924AB2334D5">enable privileges</checkBox>
+ </presentation>
+ <presentation id="POL_026CF0E2_B95C_5B67_BBAA_E95C5F809B28">
+ <decimalTextBox defaultValue="100" refId="DXT_1FD373A1_8A61_5884_9208_07A886F6334F"/>
+ </presentation>
+ <presentation id="POL_B9587C82_562E_5CA5_8BBD_835B3940D00D">
+ <textBox refId="TXT_633A0D2D_C7E6_54EF_BCE0_46ECFB6B2C1E">
+ <label>init logon delayed hosts</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_84F161E0_6C65_55C2_9DB5_CC61E66CEA9F">
+ <textBox refId="TXT_8F910181_D80D_58A5_937D_186E347E6433">
+ <label>logon drive</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_508CD547_53D7_59ED_BB1F_E6EE939C1AF2">
+ <textBox refId="TXT_3C94DDFB_94DD_598E_BC0D_B70465DA9C0C">
+ <label>logon home</label>
+ <defaultValue>\\%N\%U</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_204A522A_CF55_5E96_A2AD_B58E105AA80C">
+ <textBox refId="TXT_05B40781_B875_53DD_B1DD_4CA590B56E4A">
+ <label>logon path</label>
+ <defaultValue>\\%N\%U\profile</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A1B5FFEC_19C2_5415_ACE0_38E5D118E369">
+ <textBox refId="TXT_C1B894A7_BDF5_52B8_AC59_900953D453AC">
+ <label>logon script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DD7A32CE_6F63_596B_8E15_43B11C82E2AF">
+ <checkBox refId="CHK_805FD143_5242_56DE_BD51_0B514A588E9F">reject md5 clients</checkBox>
+ </presentation>
+ <presentation id="POL_2AD85924_5D09_571B_B048_E996EC819C57">
+ <textBox refId="TXT_B00F123E_2430_5EA0_A543_92D22A0F5FD4">
+ <label>set primary group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A8F30942_8D30_583F_8C0F_877BD20D9B26">
+ <textBox refId="TXT_74A021FE_F97F_5D54_9C4E_023D1964D37E">
+ <label>shutdown script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F0D581AB_54B4_58AA_9B84_6794FB8D3D55">
+ <textBox refId="TXT_C77D6CE7_BED5_52A8_BD8C_0259439992FA">
+ <label>add share command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_91CEEB79_E73B_563E_84CC_0C1483141142">
+ <decimalTextBox defaultValue="604800" refId="DXT_FBB1DAD6_26B9_5FB1_9678_EB499E48CC26"/>
+ </presentation>
+ <presentation id="POL_77D04206_AF73_51DE_9BE8_63524E440826">
+ <textBox refId="TXT_22E4592F_8119_5A26_AF4F_0624F1AC5E0E">
+ <label>afs username map</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_5FA91D1E_B675_5681_9FE8_E14B3E1BA737">
+ <checkBox refId="CHK_AC4E2E8E_74FE_5FD1_B6F4_3637B4582348">allow insecure wide links</checkBox>
+ </presentation>
+ <presentation id="POL_153D9711_80CD_56CD_8A51_DDA71A3800C0">
+ <checkBox refId="CHK_D36441A8_7E2F_5174_8483_4DFE0503C16D">allow unsafe cluster upgrade</checkBox>
+ </presentation>
+ <presentation id="POL_DFD4B19F_8874_5AE7_83CE_F8F507F26D51">
+ <checkBox refId="CHK_E37B6C82_F04E_5025_B457_01D9296753BE">async smb echo handler</checkBox>
+ </presentation>
+ <presentation id="POL_AA42E677_62D1_5408_A8B7_98222854E79B">
+ <textBox refId="TXT_34B124B0_A219_5575_BFDC_EAC426D7A3A5">
+ <label>auto services</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2099F7FC_F033_5E2F_B2D0_17E1CCB2969A">
+ <textBox refId="TXT_07FAF490_385F_5A63_8A03_BF34531D019D">
+ <label>cache directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2CD315A0_5DDA_5123_A973_79C1DE40BC82">
+ <checkBox defaultChecked="true" refId="CHK_1A966B04_20C5_5E97_8C75_71519DB4783C">change notify</checkBox>
+ </presentation>
+ <presentation id="POL_2D514759_876D_5B59_B854_8DC51888BB02">
+ <textBox refId="TXT_B8991748_9729_56D2_8DAD_5BAFEC5A7A8A">
+ <label>change share command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_239BABBB_C9C7_538A_B6CF_0FA2FC980562">
+ <textBox refId="TXT_E05A6480_11BB_5FF4_8E6E_37E281DA95F6">
+ <label>cluster addresses</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_92925554_781D_56B7_958E_DD33A753ED22">
+ <checkBox refId="CHK_D800E6F3_FB17_5561_9C47_88EB4384129D">clustering</checkBox>
+ </presentation>
+ <presentation id="POL_F2210D02_1B94_561B_9B05_1C5B896AF6D4">
+ <textBox refId="TXT_EB6161C1_BF92_5E6F_A106_AAE90FBD9EBD">
+ <label>config file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2EED8B7C_AF41_514A_A33D_8100A5F831AC">
+ <textBox refId="TXT_E56A7A49_B6A1_502F_AF0E_A3944A5DBFFA">
+ <label>ctdbd socket</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0DE178AC_0A5A_5CDD_8BE6_0E24150CF2BA">
+ <decimalTextBox defaultValue="0" refId="DXT_BB942009_69C3_5BAD_8507_AF692DF05CA1"/>
+ </presentation>
+ <presentation id="POL_026C959C_5371_5698_903A_03F46EEDEBE9">
+ <decimalTextBox defaultValue="0" refId="DXT_8A4C2887_09B3_542A_A22B_EEC3404DBEF8"/>
+ </presentation>
+ <presentation id="POL_C16447B8_9E34_57E6_A1F7_A6F87E66CF73">
+ <textBox refId="TXT_70112D53_C921_5D1F_9AFC_15D4890131CE">
+ <label>default service</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_41887133_D321_5526_B73E_2D5BEDA6B644">
+ <textBox refId="TXT_7B81ED14_1277_5697_B4DE_2CCFB8F79BC3">
+ <label>delete share command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B93F17F1_6F2A_5D04_AC96_EA043AC87144">
+ <checkBox refId="CHK_3D317248_E078_5FDD_B3C7_B7051C10506D">dsdb event notification</checkBox>
+ </presentation>
+ <presentation id="POL_ED5A8D54_C086_5C46_985E_746D4ED62FEA">
+ <checkBox refId="CHK_F76A8EFA_4388_54E3_B283_976BA2DD2A2E">dsdb group change notification</checkBox>
+ </presentation>
+ <presentation id="POL_5B2313F4_5239_57E8_88E9_822DBB4C0E77">
+ <checkBox refId="CHK_4B61A9A1_8E18_56CF_9B9E_6904A78328A0">dsdb password event notification</checkBox>
+ </presentation>
+ <presentation id="POL_B86BF972_B64C_57B2_9E82_96C5EECFAFA7">
+ <textBox refId="TXT_7AB84D08_FB4A_5676_B106_B4DB68C5F577">
+ <label>elasticsearch:mappings</label>
+ <defaultValue>/elasticsearch_mappings.json</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_444019F3_369A_5807_805C_AB00E59CDD4B">
+ <checkBox refId="CHK_9EA28A80_4AA6_5D4A_8A14_E22205D488CD">fss: prune stale</checkBox>
+ </presentation>
+ <presentation id="POL_472F0591_240C_5E5D_827C_49E760A75B8E">
+ <decimalTextBox refId="DXT_D5D56481_74EE_5D10_8476_B3FDB82AE518"/>
+ </presentation>
+ <presentation id="POL_DADF0887_C19B_5B14_9CEF_6721596557EB">
+ <textBox refId="TXT_B001AD6C_7FA0_5EE0_8C4D_D506EECFF497">
+ <label>homedir map</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_AFF4FEEA_8C88_5AED_9414_F4A320074A99">
+ <checkBox defaultChecked="true" refId="CHK_F273132D_C805_596F_A0E1_B6ECB4752ADB">kernel change notify</checkBox>
+ </presentation>
+ <presentation id="POL_4F279322_30AA_564B_844F_7827454574D2">
+ <textBox refId="TXT_A384C210_BD62_5E63_B7EB_BC26844F51C8">
+ <label>lock directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1120E96A_0F8E_5827_A6D2_3CA7AD66D689">
+ <checkBox refId="CHK_EB18668D_E754_524B_B2D7_CC74BA90421D">log writeable files on exit</checkBox>
+ </presentation>
+ <presentation id="POL_63067D3C_4F00_5193_92FE_A58651D4BACC">
+ <textBox refId="TXT_18DDFF0D_D5DB_5617_AE32_D93BE7E38C4B">
+ <label>message command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8765A188_6EFA_515B_B602_8F67140CFE7F">
+ <textBox refId="TXT_C551A0C4_E3B9_5985_9492_C7F42D10E75C">
+ <label>nbt client socket address</label>
+ <defaultValue>0.0.0.0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D7C62F7B_B1B6_57B3_AE48_34D09A88ECFE">
+ <textBox refId="TXT_1A090CE6_58F5_56F0_A29C_175CADD196D7">
+ <label>ncalrpc dir</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_CCC72421_6131_58BC_BFE1_D9EC7399CD57">
+ <checkBox refId="CHK_8E5A65B4_42A2_5F00_8558_E69C28758E1B">NIS homedir</checkBox>
+ </presentation>
+ <presentation id="POL_3E9DEECC_9015_5720_9251_CF804FAB2602">
+ <checkBox defaultChecked="true" refId="CHK_49457A99_B4CF_594B_B796_916B9AB74838">nmbd bind explicit broadcast</checkBox>
+ </presentation>
+ <presentation id="POL_5A63DA17_F433_5414_A47F_26C5B9BE57C2">
+ <textBox refId="TXT_A21115E3_D3E1_505B_9D2C_84A3DC428246">
+ <label>panic action</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_50CDC71F_7927_5631_A40A_C0BD12899CA1">
+ <textBox refId="TXT_6C7D4E2F_9ABE_5C67_9A8C_18D11AEF6038">
+ <label>perfcount module</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A02E7761_E359_5528_A160_F2B67024244F">
+ <textBox refId="TXT_DC19A229_4604_5CC9_8C83_CA2A1323653A">
+ <label>pid directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C030CCF1_08E7_5B6F_9239_F19B792C2157">
+ <checkBox refId="CHK_0200BA53_C2E5_5136_8A69_D8561A556A50">registry shares</checkBox>
+ </presentation>
+ <presentation id="POL_ADE18BC6_D01E_58CF_98FA_BCDCC7CDDC37">
+ <textBox refId="TXT_D765EA37_D1F5_50B2_91CE_49E66F462943">
+ <label>remote announce</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2D35EC75_4D7A_533F_96C8_3A331BDEDF34">
+ <textBox refId="TXT_F44D8D8A_1E1F_5BEE_AB4F_B3DAAFB7DBA9">
+ <label>remote browse sync</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2594A0C3_CF98_5B89_B182_1BB9C275B742">
+ <checkBox refId="CHK_57B96280_EA3D_5DAC_83DE_13338587A0D6">reset on zero vc</checkBox>
+ </presentation>
+ <presentation id="POL_17837A58_88D4_5F29_8D41_479688BD8CBD">
+ <textBox refId="TXT_90158AA7_C0BE_5650_9204_2AFC0BD9D5E8">
+ <label>rpc_daemon:DAEMON</label>
+ <defaultValue>disabled</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_AC41C088_31DF_569D_8FC8_8747C4A30548">
+ <textBox refId="TXT_31E1741F_829C_5B90_9A2F_B0E0DC5F1E75">
+ <label>rpc_server:SERVER</label>
+ <defaultValue>embedded</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1233682B_A71D_5081_9CF1_F5112A62EE3B">
+ <textBox refId="TXT_B5965925_60A9_5A4E_B348_80C590F7AF7A">
+ <label>smbd profiling level</label>
+ <defaultValue>off</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C2788566_CBC3_59A3_80A2_72D92E42C276">
+ <textBox refId="TXT_58CF9CC7_1A14_55B0_8E4E_52E962A10EE4">
+ <label>state directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_6AF97A17_10D7_553C_8CEC_09C8466A2AA4">
+ <checkBox refId="CHK_2D14A430_BA96_5B3F_970F_CE1AE9F7E8AA">usershare allow guests</checkBox>
+ </presentation>
+ <presentation id="POL_35B0CCC2_C387_5AED_9345_A2E4DE654F5F">
+ <decimalTextBox defaultValue="0" refId="DXT_AD83F27E_4FF7_5E8D_A441_0A8925C9D917"/>
+ </presentation>
+ <presentation id="POL_4E1A7DA3_3014_5C3C_9B0B_1919ECADACFB">
+ <checkBox defaultChecked="true" refId="CHK_950CF79D_4898_55EB_A6A8_24F2A6867B1D">usershare owner only</checkBox>
+ </presentation>
+ <presentation id="POL_F2D66EF9_F99C_5347_A075_E8733603E83D">
+ <textBox refId="TXT_D24709D9_FFEF_5871_AF49_5E3A3466761C">
+ <label>usershare path</label>
+ <defaultValue>/usershares</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_568D23D8_683D_5E32_96B8_5CCF81F0BDEC">
+ <textBox refId="TXT_C0DF82DC_7C0A_5B7F_9B93_19D517976672">
+ <label>usershare prefix allow list</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8A095F7E_AF4C_5F23_8C6D_327CF9225A8E">
+ <textBox refId="TXT_0CE59443_3FA6_5849_9671_8D70B1EA7E50">
+ <label>usershare prefix deny list</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_ABD81045_A7F0_5D9D_93E5_0D96C0BD7AA8">
+ <textBox refId="TXT_029600AB_FD39_52B7_AE5D_AE0D7138153A">
+ <label>usershare template share</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_238B28BE_5F6B_5251_B47B_4932EA213DAE">
+ <checkBox refId="CHK_651BA339_0B8E_5456_99AA_E4CD4BE64F51">utmp</checkBox>
+ </presentation>
+ <presentation id="POL_BB0E4D55_D6E9_5FDD_A75B_59F7403CF67C">
+ <textBox refId="TXT_C85A703E_0428_51EF_8A2A_D4803BE9446E">
+ <label>utmp directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2AD1815C_5DBC_5A7E_8DC9_CEE194030C59">
+ <textBox refId="TXT_CF0F4D90_5001_57CB_A6C8_58575659305D">
+ <label>wtmp directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_63B9016C_EBE5_5EA7_85B0_493E3155F943">
+ <textBox refId="TXT_63999B72_41DB_5A45_A6DE_66574F1F442F">
+ <label>addport command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_778F868C_7119_5059_9D0D_62B468410A7D">
+ <textBox refId="TXT_5581F365_D9D7_535E_A25B_A58F2FBABCBB">
+ <label>addprinter command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E4EA6E76_DFE6_5C90_8D2F_544185E10581">
+ <decimalTextBox defaultValue="30" refId="DXT_21FF9D0E_70B9_5790_9877_F218D435CAA2"/>
+ </presentation>
+ <presentation id="POL_5A6F3F97_C655_501A_8A1D_D3B96E22D189">
+ <textBox refId="TXT_90A3BD2E_13EF_5BC9_970F_32A3CE582200">
+ <label>cups encrypt</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_713C453D_7C4E_5446_99F0_93FDC97CBD6E">
+ <textBox refId="TXT_E3EF87B6_2525_530F_96D9_36770179DBEF">
+ <label>cups server</label>
+ <defaultValue>&quot;&quot;</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_7801A389_C366_5376_9D03_631BD51C46C4">
+ <textBox refId="TXT_6477B02C_3AE4_5724_B00B_0A11F16A1ECD">
+ <label>deleteprinter command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8AEEC70D_CC12_55A5_A39F_ED0C3A3B652E">
+ <checkBox refId="CHK_BA883BE5_77CE_5478_BBC8_10B796EF09C2">disable spoolss</checkBox>
+ </presentation>
+ <presentation id="POL_D8A14125_4BEE_575E_B7A2_A6D2809A0CC9">
+ <checkBox defaultChecked="true" refId="CHK_76C31A1A_3CCA_54F4_A09B_01ED9C31465A">enable spoolss</checkBox>
+ </presentation>
+ <presentation id="POL_E95AFA3E_7680_5281_88E1_BC2B9DE7C60D">
+ <textBox refId="TXT_9B7FB891_910F_5AB1_96BC_432F871E50AA">
+ <label>enumports command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D0CE14C7_93FC_54DA_84A8_FB6579A01A95">
+ <textBox refId="TXT_CEDD5E8E_4BCB_515F_B962_7C06E9E4EBE6">
+ <label>iprint server</label>
+ <defaultValue>&quot;&quot;</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2AA9A3C9_2D35_5140_AAFD_5A6D4A8B46A9">
+ <checkBox defaultChecked="true" refId="CHK_01150395_D329_542B_8848_2D352BA599CA">load printers</checkBox>
+ </presentation>
+ <presentation id="POL_CB7375CD_3BD9_5AFF_885F_5CD41077D92A">
+ <decimalTextBox defaultValue="30" refId="DXT_86697EF6_0F2B_59EA_AC0A_2A6B16860DC2"/>
+ </presentation>
+ <presentation id="POL_6C573DCA_ADF2_503D_86F1_167FB4B20390">
+ <textBox refId="TXT_60176F30_80AE_5289_8984_1213DB736520">
+ <label>os2 driver map</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_4E996FBA_21B1_54D2_AF3E_0290231D9225">
+ <decimalTextBox defaultValue="750" refId="DXT_30FEC2C2_FB9E_59DC_86AC_0952A9904B2F"/>
+ </presentation>
+ <presentation id="POL_9E502331_FC16_56A6_BAA2_8A4F8CD7403E">
+ <textBox refId="TXT_8288D727_1C29_5CDF_A162_3F5701E803B2">
+ <label>printcap name</label>
+ <defaultValue>/etc/printcap</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_63DFC41F_0FA5_52C6_95CC_071B309E09A9">
+ <checkBox defaultChecked="true" refId="CHK_21859C56_D5DA_5C2E_9215_BA75864C9B4B">show add printer wizard</checkBox>
+ </presentation>
+ <presentation id="POL_C105B217_101D_5080_B2F2_28F453585AF3">
+ <textBox refId="TXT_C9E18177_8584_5290_8B40_37D46546DDB1">
+ <label>spoolss: architecture</label>
+ <defaultValue>Windows NT x86</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B7405490_DE98_5CC9_A096_8B6F690536A5">
+ <decimalTextBox defaultValue="5" refId="DXT_1D4352B8_DB79_5551_A486_7D4D33F8D4D9"/>
+ </presentation>
+ <presentation id="POL_5049AEF7_B2E3_5F11_BB76_CD05A0F405D1">
+ <decimalTextBox defaultValue="0" refId="DXT_6F51D95E_66DD_50B2_B62F_7665EF471B52"/>
+ </presentation>
+ <presentation id="POL_52B0D644_BD3A_5C9D_873F_3DF18D2FDB60">
+ <decimalTextBox defaultValue="2195" refId="DXT_B21A8651_347B_5648_94FA_37B943B6A547"/>
+ </presentation>
+ <presentation id="POL_4B72C056_F162_529E_A137_1F557D5FDFCE">
+ <decimalTextBox defaultValue="6" refId="DXT_6188EEA1_529A_508D_B9D5_378CAB822D89"/>
+ </presentation>
+ <presentation id="POL_1855B435_5BFA_512B_A805_E30B09CFD23F">
+ <decimalTextBox defaultValue="1" refId="DXT_A21AB0C1_D47D_5B8C_8609_171B9D2F4C27"/>
+ </presentation>
+ <presentation id="POL_F173249E_078E_531E_A8DC_85931745FBF9">
+ <decimalTextBox defaultValue="7007" refId="DXT_EC7D7A9D_C0D7_5665_9030_9C85D402BDB1"/>
+ </presentation>
+ <presentation id="POL_A3C35AAF_A7F5_5DCD_B328_C7ABD0F2FDFF">
+ <decimalTextBox defaultValue="389" refId="DXT_BCC54168_D5A8_5014_903F_D0689B350906"/>
+ </presentation>
+ <presentation id="POL_7D6BFF26_946F_5B18_B213_0B9EE147C3C9">
+ <textBox refId="TXT_BC8B7A29_65FA_5B55_BC11_A7574ECD0AA8">
+ <label>client ipc max protocol</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_4D5635CC_F944_5F32_83F0_7730FC9DE680">
+ <textBox refId="TXT_2FAFBF21_5429_5CF1_9152_921CF9CEEC6C">
+ <label>client ipc min protocol</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_79B1D2DB_C2F7_57FA_8D6F_83D756A43A40">
+ <textBox refId="TXT_6E173477_D6E4_5C47_BC6C_5961404DB0CD">
+ <label>client max protocol</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E5D3402E_7A4B_555E_AC54_E5C7AE196EF2">
+ <textBox refId="TXT_30573924_1A09_5202_8DF8_9B24FA69C14E">
+ <label>client min protocol</label>
+ <defaultValue>SMB2_02</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B86463E0_7A50_5BD1_9CD5_A43C20A5E087">
+ <checkBox defaultChecked="true" refId="CHK_5549EDCC_940D_5AEA_8465_B771FEE013BC">client use spnego</checkBox>
+ </presentation>
+ <presentation id="POL_F0990CDC_21DF_538D_9282_2749E00AF99E">
+ <textBox refId="TXT_E8C89EE3_FF60_5216_A5C7_803A3AA8D790">
+ <label>dcerpc endpoint servers</label>
+ <defaultValue>epmapper, wkssvc, rpcecho, samr, netlogon, lsarpc, drsuapi, dssetup, unixinfo, browser, eventlog6, backupkey, dnsserver</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_BD3F8921_7AF6_57F8_894A_9C73D40C6202">
+ <checkBox defaultChecked="true" refId="CHK_AA0DA4CF_4431_509C_8E2D_27BD0DD5CCAB">defer sharing violations</checkBox>
+ </presentation>
+ <presentation id="POL_0C775437_E6FD_5657_9A04_AF137F18FACE">
+ <decimalTextBox defaultValue="138" refId="DXT_8E6D975D_6C56_56F9_9853_60394A2CEFA7"/>
+ </presentation>
+ <presentation id="POL_614DA2E7_D77F_5434_9C73_137D1D89D086">
+ <checkBox refId="CHK_D433FDEC_A984_5B75_AD88_924962077009">disable netbios</checkBox>
+ </presentation>
+ <presentation id="POL_35845C32_CE1D_5395_A07C_142BCFD9744C">
+ <checkBox refId="CHK_31A76B18_E56F_57E6_BBC1_A5988C8D731C">enable asu support</checkBox>
+ </presentation>
+ <presentation id="POL_000AF517_65A2_5220_B1DD_7187EFC59AAB">
+ <textBox refId="TXT_3A3CA4FB_B0F0_5D20_AA43_D6CAECA189E1">
+ <label>eventlog list</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B4BFA8D2_FF42_5E4A_ADE8_D7829A2CC94A">
+ <checkBox defaultChecked="true" refId="CHK_21EE7A7A_DF8F_56F7_85FB_6EC5DD083DD6">large readwrite</checkBox>
+ </presentation>
+ <presentation id="POL_644A4C74_3ECB_5A01_8E2B_1FA9E74EC778">
+ <checkBox refId="CHK_52E0D939_4722_5165_AAFE_A5FD7584E12C">lsa over netlogon</checkBox>
+ </presentation>
+ <presentation id="POL_EAE8C258_343E_522B_A09C_69E9FD81B535">
+ <decimalTextBox defaultValue="50" refId="DXT_549D41B9_4692_55A3_B8C0_11D91DBCC133"/>
+ </presentation>
+ <presentation id="POL_2BAFBEFD_9CEA_53C2_9E78_04807EA6531F">
+ <decimalTextBox defaultValue="259200" refId="DXT_F5E2AC7A_E892_5316_81C3_368BC6F5E4C4"/>
+ </presentation>
+ <presentation id="POL_7D30022C_3DDE_56D1_8D07_D90741127527">
+ <decimalTextBox defaultValue="16644" refId="DXT_8A171231_CF95_5684_B665_9B1F5B046ABD"/>
+ </presentation>
+ <presentation id="POL_02E42B0E_C3F3_5E0B_83C1_6F3ABFEEF251">
+ <decimalTextBox defaultValue="0" refId="DXT_0B40F1AE_EF9C_58E0_9E35_6D119671AAE1"/>
+ </presentation>
+ <presentation id="POL_9AA4C867_EE0B_5742_94F0_4D2243C2E368">
+ <textBox refId="TXT_7C9CF069_5856_5D63_94DD_AF9530B8D495">
+ <label>name resolve order</label>
+ <defaultValue>lmhosts wins host bcast</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0EAD5917_3B68_5B59_92E1_69BD263150EA">
+ <decimalTextBox defaultValue="137" refId="DXT_F06BA6AF_533A_520F_B2E1_EA508FF26E55"/>
+ </presentation>
+ <presentation id="POL_3FA711F7_BD87_5CF6_9A5A_77CF771AAFF2">
+ <checkBox defaultChecked="true" refId="CHK_DAAC7C86_8FD9_55BF_9125_9C95E2D52AFE">nt pipe support</checkBox>
+ </presentation>
+ <presentation id="POL_85D402BD_4D59_5CE0_8EA2_3331CABD23CA">
+ <checkBox defaultChecked="true" refId="CHK_95DD62AA_03E3_5679_AD11_D5616CD25255">nt status support</checkBox>
+ </presentation>
+ <presentation id="POL_9045A4F7_5DED_5A70_B01D_D92B419B6634">
+ <checkBox defaultChecked="true" refId="CHK_B11F35D5_3196_5D92_9B1D_9C746F9162FA">read raw</checkBox>
+ </presentation>
+ <presentation id="POL_9926B5F8_3F22_569B_BB6C_06F2CDF21381">
+ <checkBox refId="CHK_CCA3E37C_1A5F_5493_BFC6_AD75B7AEF1D7">rpc big endian</checkBox>
+ </presentation>
+ <presentation id="POL_56DBEBB2_3508_5C9E_91B2_3E55EF357FFB">
+ <decimalTextBox defaultValue="0" refId="DXT_9489E35C_10BA_57DF_BCA8_E482D719B220"/>
+ </presentation>
+ <presentation id="POL_738E8CDC_C229_5926_8153_E0009CC07424">
+ <textBox refId="TXT_B22408B0_8FF5_5F41_BB61_F89CF80FB1C4">
+ <label>server max protocol</label>
+ <defaultValue>SMB3</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_00778E7A_F34D_546E_9FA8_3968A937392B">
+ <textBox refId="TXT_633970D9_6038_55ED_856F_A39492AE0173">
+ <label>server min protocol</label>
+ <defaultValue>SMB2_02</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B33A00A2_B848_59D9_9C41_582F886C008A">
+ <textBox refId="TXT_3C8506A1_3A67_58AF_BB1F_DD3A931A7FBE">
+ <label>share:fake_fscaps</label>
+ <defaultValue>0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0BC6C240_419F_5F72_9A24_DA191CFFE18E">
+ <decimalTextBox defaultValue="8192" refId="DXT_4FCC3712_A2B7_5C65_933A_621697E78E8F"/>
+ </presentation>
+ <presentation id="POL_908FC006_7CE8_5B56_A049_A3E582C281F3">
+ <decimalTextBox defaultValue="8388608" refId="DXT_8D17E70E_8AA1_5DEC_86C2_154031314317"/>
+ </presentation>
+ <presentation id="POL_84ED1A25_58B9_5C00_8261_11A7D387EAB9">
+ <decimalTextBox defaultValue="8388608" refId="DXT_0923E7AF_8C15_54FD_A360_41E09D67D24C"/>
+ </presentation>
+ <presentation id="POL_A1955D87_2287_524B_9A8C_454C8218F590">
+ <decimalTextBox defaultValue="8388608" refId="DXT_AC8EA085_B897_5581_8260_25EC8761048F"/>
+ </presentation>
+ <presentation id="POL_796581A5_F65E_5D31_BB5C_2CC641B8D03C">
+ <textBox refId="TXT_07CA0480_16BB_5E14_B1E8_716E293305F7">
+ <label>smb ports</label>
+ <defaultValue>445 139</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C141D92D_B912_54D7_88D6_CC3A12A4739D">
+ <textBox refId="TXT_7312B2B6_2E91_5D9E_BE33_A1C73675950E">
+ <label>svcctl list</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_747C776B_2150_5FD4_9A47_9832FD35EBC5">
+ <checkBox refId="CHK_838A32D7_1BA5_55CB_9FA4_95280DFB26F6">time server</checkBox>
+ </presentation>
+ <presentation id="POL_69C69BCA_D38B_54E1_817C_E6993FF1AB91">
+ <checkBox defaultChecked="true" refId="CHK_2280B94E_EB17_5A5E_80F0_B48BE0CBC2CB">unicode</checkBox>
+ </presentation>
+ <presentation id="POL_063DDC7C_E490_5F1B_866D_06D25ABAED90">
+ <checkBox defaultChecked="true" refId="CHK_E429FAE8_6D3B_5B56_8EFF_B3B7C25B3DE1">unix extensions</checkBox>
+ </presentation>
+ <presentation id="POL_CC4C4C4D_0BA2_52C2_A510_1C4F669856F3">
+ <checkBox defaultChecked="true" refId="CHK_4FD77295_65FD_5553_AB18_D6CF04394DAB">write raw</checkBox>
+ </presentation>
+ <presentation id="POL_D1D0620C_FFC1_5C7D_9733_4005F5F61A8D">
+ <checkBox refId="CHK_82B2446C_9CAB_5880_AF33_2803AE49B294">server multi channel support</checkBox>
+ </presentation>
+ <presentation id="POL_D0AC80B8_9AFD_5848_B779_1E43C144D7B3">
+ <checkBox refId="CHK_B6B60597_42F0_58D3_98BB_DB6B75D07112">smb2 disable lock sequence checking</checkBox>
+ </presentation>
+ <presentation id="POL_85DD283F_59E2_5E1D_A694_D52FD7C7627A">
+ <checkBox refId="CHK_B83E6646_94FD_5882_B57A_15B4BA0AABFD">smb2 disable oplock break retry</checkBox>
+ </presentation>
+ <presentation id="POL_9E9B6ADB_2118_5108_9C2D_9899DDDC59AF">
+ <textBox refId="TXT_28520FBC_2959_5800_B0C5_FE205973260B">
+ <label>rpc server dynamic port range</label>
+ <defaultValue>49152-65535</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_9B792D3F_06B3_5683_92D9_45D323276228">
+ <decimalTextBox defaultValue="1000" refId="DXT_9EFB50AC_B3B6_51C1_AD40_298F546733DC"/>
+ </presentation>
+ <presentation id="POL_F30A212E_4A35_5E67_8902_5D28B4E37CE7">
+ <checkBox refId="CHK_EAA911EE_CB2D_5459_AF50_DC1CA4719686">allow dcerpc auth level connect</checkBox>
+ </presentation>
+ <presentation id="POL_2725BCA8_877C_519D_A248_D6EE701DAD53">
+ <checkBox defaultChecked="true" refId="CHK_83FBBE91_8F41_5C06_BD1D_9A47A10B07FE">allow trusted domains</checkBox>
+ </presentation>
+ <presentation id="POL_92DB14AD_A920_5D74_BA74_0C51B13AECBF">
+ <textBox refId="TXT_D70FDB73_012F_5168_8371_B68B4B2FF60E">
+ <label>binddns dir</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C95900AB_E4E2_5313_9EF5_9AC181CD63A7">
+ <textBox refId="TXT_D6E02483_EC02_52E1_AB5A_E65E2C7FD5C8">
+ <label>check password script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0DDAC1B2_5E35_5770_B177_333E21EF2A80">
+ <textBox refId="TXT_28B76952_9A9C_5E2D_89C6_28CA8ABBEFD4">
+ <label>client ipc signing</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_045DA01B_9A96_5BB1_A5AD_9EA38ECFC199">
+ <checkBox refId="CHK_5203727D_209F_5E8A_AA94_F9DC1BB27027">client lanman auth</checkBox>
+ </presentation>
+ <presentation id="POL_B1954186_3F6B_5F1F_B066_9105058C20A6">
+ <checkBox defaultChecked="true" refId="CHK_B6DB6C5E_8C6F_5288_B469_0C54B947EA2F">client NTLMv2 auth</checkBox>
+ </presentation>
+ <presentation id="POL_676B4751_B95E_5720_A513_203DC3A33B5C">
+ <checkBox refId="CHK_3DCC027B_9C81_5EDE_A64D_D6F956AFE5B8">client plaintext auth</checkBox>
+ </presentation>
+ <presentation id="POL_C3248F39_498F_5B9B_B82D_E99AB08FD0AF">
+ <textBox refId="TXT_4A77A711_9230_5D41_A77C_97123E4789B7">
+ <label>client schannel</label>
+ <defaultValue>yes</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0A922D59_F39C_57B5_82CE_E08DB4EFC5F9">
+ <textBox refId="TXT_E3513F2F_1C85_5D8C_8DEE_741059C1F393">
+ <label>client signing</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_952DF975_FF04_55BD_8C6B_1D0CF167106B">
+ <checkBox refId="CHK_E5D1CBBE_5B07_5559_8885_E8F6DBA75A18">client use spnego principal</checkBox>
+ </presentation>
+ <presentation id="POL_D9E8EB33_0AE9_5DA5_BA48_00221DCE75EB">
+ <checkBox refId="CHK_711A458E_DC58_57EC_B315_0FEF0D2354BF">debug encryption</checkBox>
+ </presentation>
+ <presentation id="POL_B7875E95_FF94_5579_956F_6E2CEB41AB91">
+ <textBox refId="TXT_F17E81EB_DEBF_56F4_B372_D6F61F5516E3">
+ <label>dedicated keytab file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1EE4C27C_051F_55A6_8385_E55B6776D7E4">
+ <checkBox defaultChecked="true" refId="CHK_EC390E59_1CA4_5C42_960E_B0EEA3B0C1F4">encrypt passwords</checkBox>
+ </presentation>
+ <presentation id="POL_59E14991_089B_550D_A563_8FB90A8333FB">
+ <textBox refId="TXT_92855060_EFF4_5BCA_B30B_10C364F30E2E">
+ <label>guest account</label>
+ <defaultValue>nobody</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_772B9223_59BD_57E8_8FA7_17AF0E0EC8EC">
+ <textBox refId="TXT_751BA79F_27EA_55BE_B787_D424CBD47CED">
+ <label>kerberos encryption types</label>
+ <defaultValue>all</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F11FAFDE_22DF_5BB6_9F63_007597D313BD">
+ <textBox refId="TXT_30977E18_9746_5A78_A6DC_82AC5157781F">
+ <label>kerberos method</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F37DD404_E28E_50F2_BFF4_90142620EA2F">
+ <decimalTextBox defaultValue="464" refId="DXT_3E0E91A2_1877_54F2_AFFE_13F912C4B534"/>
+ </presentation>
+ <presentation id="POL_E6FCD1B7_7104_5EF9_BAA7_73E15CC49EE2">
+ <decimalTextBox defaultValue="88" refId="DXT_41AD8F69_347F_58D1_9DA4_B9A600C32EAE"/>
+ </presentation>
+ <presentation id="POL_F77B9807_0B1E_5EA5_A1CB_62B310FE5034">
+ <checkBox refId="CHK_7460D4AE_3934_5090_9E10_BBF60CD5A983">lanman auth</checkBox>
+ </presentation>
+ <presentation id="POL_3D0B6848_AEF7_54A0_8FA0_B6EAD987D449">
+ <textBox refId="TXT_E576122E_9E34_5B1D_9362_2EF751F22E3F">
+ <label>log nt token command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_32F00B99_2861_5EFE_B961_1F52B4FC0530">
+ <textBox refId="TXT_12B82358_1926_5FEC_B016_946E52DDC7A7">
+ <label>map to guest</label>
+ <defaultValue>Never</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_6D23275C_279D_571C_8835_3DA99356979C">
+ <textBox refId="TXT_4C14ACC2_4652_5801_BF08_1D9E81090E16">
+ <label>mit kdc command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3AE05749_32F8_5D7C_BEF0_D0DFB206EA34">
+ <textBox refId="TXT_E71B9BA6_F3A9_510D_AE73_34CC2E7AF19F">
+ <label>ntlm auth</label>
+ <defaultValue>ntlmv2-only</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_7A4CC1D5_FF89_5D5A_9711_B783227B92CE">
+ <textBox refId="TXT_9AB44C0C_849E_55AD_BF88_30862CC83464">
+ <label>ntp signd socket directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1F95F2F6_790E_5946_8F22_F93441D1B91D">
+ <checkBox refId="CHK_905844C6_A433_5422_9020_A275A062AB6F">null passwords</checkBox>
+ </presentation>
+ <presentation id="POL_4B855392_C467_5D42_B793_3EC858462C02">
+ <checkBox refId="CHK_FFDDD176_BDAB_58E3_A455_F60861FD2C63">obey pam restrictions</checkBox>
+ </presentation>
+ <presentation id="POL_F388E520_9E19_53AC_9AFA_D6DAAE139BFE">
+ <decimalTextBox defaultValue="60" refId="DXT_1D580B43_F65E_5F39_A938_BE0D03A04F2B"/>
+ </presentation>
+ <presentation id="POL_FC62DA5F_6B94_5AD6_B9E6_51A9F5F52E2E">
+ <checkBox refId="CHK_49F56502_4B93_5C98_A4BB_327120E5F7D8">pam password change</checkBox>
+ </presentation>
+ <presentation id="POL_6F5A4F7B_B2BC_50D0_84F6_64202749462B">
+ <textBox refId="TXT_38925248_C56C_5F67_959E_45860FA3CEDE">
+ <label>passdb backend</label>
+ <defaultValue>tdbsam</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F3E8ECEA_80D4_529F_8F7B_97B8847E3101">
+ <checkBox refId="CHK_4D782AF0_E6B7_5C3E_AE8F_90D07527724B">passdb expand explicit</checkBox>
+ </presentation>
+ <presentation id="POL_EE00148B_DAEA_5039_B087_B342E865E3AE">
+ <textBox refId="TXT_9E734663_521F_5654_A01C_E8B5C19A4684">
+ <label>passwd chat</label>
+ <defaultValue>*new*password* %n\n *new*password* %n\n *changed*</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A0D04F58_1760_5152_AE42_748ABA7B15D8">
+ <checkBox refId="CHK_6F2AD6B8_489E_512B_A7CC_EDB6FA628D1E">passwd chat debug</checkBox>
+ </presentation>
+ <presentation id="POL_0F8503B0_2D17_54A4_AECA_C8954FC2F1B3">
+ <decimalTextBox defaultValue="2" refId="DXT_849C03F3_A9CF_5B20_81B9_D4EEE2435447"/>
+ </presentation>
+ <presentation id="POL_484C71CF_D856_514E_A645_C94805B51752">
+ <textBox refId="TXT_97FDEF1F_BA9C_5995_BB37_93AF59ADB59C">
+ <label>passwd program</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DE8AED8D_92DF_5DC8_A412_F374508B2DF2">
+ <textBox refId="TXT_DF9C4D42_5129_5D7A_A155_18F2DBB5B2E7">
+ <label>password hash gpg key ids</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E57A4D09_C62A_5ACB_BA14_A52FB3A14D54">
+ <textBox refId="TXT_8F89431E_D922_5610_8770_40BD094BA98D">
+ <label>password hash userPassword schemes</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8DF1C787_4DD3_5769_981D_AD98697D5FAB">
+ <textBox refId="TXT_2BD70FBF_B577_55F7_B757_5DE68D1ECB4B">
+ <label>password server</label>
+ <defaultValue>*</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_576D7547_5317_5D19_9105_4BFD5714D591">
+ <textBox refId="TXT_799A2EBA_FC4C_53C2_B724_0838399601DF">
+ <label>preload modules</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0B74AC8D_E102_5E02_9B21_D264A6662698">
+ <textBox refId="TXT_97A88495_3A90_5773_AF8C_5D35B63E672A">
+ <label>private dir</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_84F44316_118C_5460_A9E9_022AE89D6BC7">
+ <checkBox refId="CHK_C2793981_4BCD_5CDF_8F7B_7AD01E207D2C">raw NTLMv2 auth</checkBox>
+ </presentation>
+ <presentation id="POL_81A0C9F8_E865_532F_8FF6_EA55C23E6417">
+ <textBox refId="TXT_3697BE5E_8DCE_5701_A121_A7E36F07CE6C">
+ <label>rename user script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_61F81501_C5C3_5F3F_8A89_4490F25812D1">
+ <decimalTextBox defaultValue="0" refId="DXT_B5114D77_9A2D_5FB4_8862_313764FA836F"/>
+ </presentation>
+ <presentation id="POL_82E70187_3C79_5C38_837A_F6F7660F7D10">
+ <textBox refId="TXT_00392C71_F9D4_5A75_8082_F7806B6B7564">
+ <label>root directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_487E924D_1F5E_52FA_9DD7_7C893DC03299">
+ <textBox refId="TXT_98D641EC_FAA9_546B_A032_3D7D3D0B28E2">
+ <label>samba kcc command</label>
+ <defaultValue>/samba_kcc</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1D7DD262_FBC1_53B0_8981_D664D2793B98">
+ <textBox refId="TXT_94515E41_3367_514F_978D_FB02F7C7ABD1">
+ <label>security</label>
+ <defaultValue>AUTO</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E94725FD_24A2_5499_9793_E27F2E3D82AB">
+ <textBox refId="TXT_7688CBD7_E2F8_573B_AA8D_9EF8C47630F8">
+ <label>server role</label>
+ <defaultValue>AUTO</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_51A99ED6_90F2_5884_904E_FBB01AE99010">
+ <textBox refId="TXT_0DC074F0_E1DE_5232_B834_889409466FB7">
+ <label>server schannel</label>
+ <defaultValue>yes</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_5FCA2961_E0AB_5E89_8361_C30A3FBAB1EC">
+ <textBox refId="TXT_90F5A286_21F2_5FE7_97F9_88EF3C9B636C">
+ <label>server signing</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_619FBE76_46C6_5CD4_8FAB_F6031B681197">
+ <textBox refId="TXT_A5857127_9668_5119_9FB1_28989C19BE29">
+ <label>smb passwd file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F01FFF92_4BCB_5309_8B5C_3910D8E2EE4D">
+ <textBox refId="TXT_18E2AB7A_7B3D_5588_8E22_91549B53719E">
+ <label>tls cafile</label>
+ <defaultValue>tls/ca.pem</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2D715716_887A_5F22_B8BF_F4D8239F9576">
+ <textBox refId="TXT_24A9FF35_91AF_50B7_9C8B_DCB8815A3B19">
+ <label>tls certfile</label>
+ <defaultValue>tls/cert.pem</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_823C796B_2B4A_5733_B90D_9179CA58C03D">
+ <textBox refId="TXT_3B707725_83FA_511D_BBC2_69122D141655">
+ <label>tls crlfile</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EE10300D_C58D_5AF3_819F_6707ACE727E9">
+ <textBox refId="TXT_EB8D2F6A_9929_5004_BD04_03EB0F381453">
+ <label>tls dh params file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D1A081CF_40D1_5505_9E0F_1DF2B67DC69F">
+ <checkBox defaultChecked="true" refId="CHK_FBD1856B_6C06_5CF4_9A53_DDF372A2250F">tls enabled</checkBox>
+ </presentation>
+ <presentation id="POL_686F2495_B4CA_5D83_95E3_BF372A1857A3">
+ <textBox refId="TXT_45D2AB07_CCD6_5350_A04D_DB915B7B79A3">
+ <label>tls keyfile</label>
+ <defaultValue>tls/key.pem</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_869E3C32_6369_5FB5_B149_F982FB872384">
+ <textBox refId="TXT_09331402_B0D6_59B2_8C69_2758849398CE">
+ <label>tls verify peer</label>
+ <defaultValue>as_strict_as_possible</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_6B1AC895_029E_5686_B072_4BD0BD8B7C4D">
+ <checkBox refId="CHK_1E20CD87_5BB4_5449_9E0C_BFFBE014C934">unix password sync</checkBox>
+ </presentation>
+ <presentation id="POL_821FE87C_398B_5051_A106_BB4C41475FA2">
+ <decimalTextBox defaultValue="0" refId="DXT_55E19EF4_DFB4_5F5F_8DF5_D88E4874D090"/>
+ </presentation>
+ <presentation id="POL_4A737F54_FE8F_5996_AE22_5AD683E96F64">
+ <textBox refId="TXT_F413607F_E22F_5652_B367_376C260376CF">
+ <label>username map</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B01C544C_C17F_58BE_A8C5_B8B93A5D6D6B">
+ <decimalTextBox defaultValue="0" refId="DXT_54B979EE_6AB6_5CFA_9EE0_CAF728D8EC17"/>
+ </presentation>
+ <presentation id="POL_D6C75311_EF00_56FB_BB7E_2AED9360F004">
+ <textBox refId="TXT_C8B62E8A_0311_5EC2_A8CF_70B60E1BD044">
+ <label>username map script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D915E5DA_6227_5AF7_84CC_C5FF9079D441">
+ <textBox refId="TXT_55A11C3A_195F_55F9_852D_0D62FD18327B">
+ <label>tls priority</label>
+ <defaultValue>NORMAL:-VERS-SSL3.0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_5413F647_D5E0_5620_B00D_101274974D25">
+ <decimalTextBox defaultValue="100" refId="DXT_8BBF5B06_26CE_5BCE_B851_7B1D4E5BA791"/>
+ </presentation>
+ <presentation id="POL_B9BCD3D7_045F_57C2_9347_4258B5841D4B">
+ <decimalTextBox defaultValue="10080" refId="DXT_1C7D2B97_728C_587E_880B_EDEF41300FAB"/>
+ </presentation>
+ <presentation id="POL_29E85EE4_9F4B_5824_AAD0_B71BC3AD529A">
+ <checkBox defaultChecked="true" refId="CHK_18CC19EE_D0BD_5776_9816_F100799183AB">getwd cache</checkBox>
+ </presentation>
+ <presentation id="POL_9FC38F18_A498_5A48_A001_E1C9DF302BAD">
+ <checkBox refId="CHK_04B2F1DF_E88E_5792_B491_793217A0C8C8">hostname lookups</checkBox>
+ </presentation>
+ <presentation id="POL_A09855DC_589A_515D_B123_3846F60F4908">
+ <decimalTextBox defaultValue="300" refId="DXT_3DAC248C_C8A8_5C1C_8CFB_443894213FC9"/>
+ </presentation>
+ <presentation id="POL_8C101F96_8BD1_5E91_ACA0_813AA7EB6F03">
+ <decimalTextBox defaultValue="0" refId="DXT_4DAE2123_2535_5E0D_BCD1_D5D819A750B9"/>
+ </presentation>
+ <presentation id="POL_571D0589_CE6E_50D9_A04F_4070993911D4">
+ <decimalTextBox defaultValue="16384" refId="DXT_E36137FA_C613_5FBE_B6FE_1A0554C4130E"/>
+ </presentation>
+ <presentation id="POL_4B0BF94D_F644_5874_9963_FB1DB672DFCF">
+ <decimalTextBox defaultValue="0" refId="DXT_3DC584F7_71D3_5762_BB59_FB55D524AF1D"/>
+ </presentation>
+ <presentation id="POL_CCB2A269_DED1_5A89_B0EA_AC8B9A248E01">
+ <decimalTextBox defaultValue="660" refId="DXT_23802D96_34E6_5E30_BB47_2839CFF09E5E"/>
+ </presentation>
+ <presentation id="POL_D0EACF0A_A7EC_5114_84E9_A119EAB06054">
+ <textBox refId="TXT_9F944C4E_3CCB_5C34_AC11_84D5E8AE9675">
+ <label>socket options</label>
+ <defaultValue>TCP_NODELAY</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0BEE9D62_728C_5BEC_B208_C6413ACB23CA">
+ <checkBox defaultChecked="true" refId="CHK_AE0F9277_9994_5245_9AF5_2FE2694EADB3">use mmap</checkBox>
+ </presentation>
+ <presentation id="POL_F0BBD72A_2F52_5518_978A_E4DE80EA63A7">
+ <textBox refId="TXT_1299FC9B_B974_5807_B85B_96EF03DF6E7E">
+ <label>get quota command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1B9A680B_C7D9_5909_A73A_4A88884B1A1A">
+ <checkBox defaultChecked="true" refId="CHK_D8B6A576_57BD_5C1B_8503_D7514BF9A79A">host msdfs</checkBox>
+ </presentation>
+ <presentation id="POL_23841534_EA5C_5066_9A34_A81201DFA255">
+ <textBox refId="TXT_CB4EB282_B71E_5E88_AAD0_CBE322ED1354">
+ <label>set quota command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A8D8A049_7017_5627_B698_79DB288ACF3D">
+ <checkBox refId="CHK_E3F6F2BF_E5EF_5ECD_B4EF_525C704252CE">apply group policies</checkBox>
+ </presentation>
+ <presentation id="POL_322C552E_7DC6_57F9_845A_F76107A65059">
+ <checkBox defaultChecked="true" refId="CHK_4D19E247_9D41_57FC_A81B_7AAA3DA70D22">create krb5 conf</checkBox>
+ </presentation>
+ <presentation id="POL_D65A78B4_B284_51E5_86B8_548907E5B99E">
+ <textBox refId="TXT_E8A538AD_C502_5298_A571_D37AF30908B1">
+ <label>idmap backend</label>
+ <defaultValue>tdb</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D9437864_AD98_5DE6_A280_76BF74DF6241">
+ <decimalTextBox defaultValue="604800" refId="DXT_9707658F_1F28_5859_A19A_74FA303C63FD"/>
+ </presentation>
+ <presentation id="POL_DADA8FE7_2FB0_5AFE_AE6F_5CDE2F6C835A">
+ <textBox refId="TXT_8E0B0FA4_3946_55DD_9AD6_B31C5AC79265">
+ <label>idmap gid</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_595CE1B7_F379_543C_99B1_DDF5DCBB2034">
+ <decimalTextBox defaultValue="120" refId="DXT_DB0243EE_0466_539F_8844_6C0FFDEC6AA3"/>
+ </presentation>
+ <presentation id="POL_1493AE04_9E17_51E3_BF56_61A594C41065">
+ <textBox refId="TXT_5BC5E3D4_DCD5_5F0A_92C3_74C651DE0CEA">
+ <label>idmap uid</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_BFD4E3E9_B3CF_5703_95C9_D5AF443628EC">
+ <checkBox defaultChecked="true" refId="CHK_09A137C2_9429_5D4A_A327_A5F475E367AE">include system krb5 conf</checkBox>
+ </presentation>
+ <presentation id="POL_B2DF30E2_2C79_5DB4_BDD4_2A72F3AAE4D1">
+ <checkBox refId="CHK_5CF9E5FF_8158_5689_9FD3_E408D710EC13">neutralize nt4 emulation</checkBox>
+ </presentation>
+ <presentation id="POL_D5D3240F_0956_5A05_8847_1B20DF57BEC8">
+ <checkBox refId="CHK_25E7D915_B85C_5F5B_9A60_056A326ED8F5">reject md5 servers</checkBox>
+ </presentation>
+ <presentation id="POL_5D72D99B_EFA5_5B2F_8616_2FBE8DBBCF81">
+ <checkBox defaultChecked="true" refId="CHK_C103A13B_7017_50F6_A337_C2A90DAE4419">require strong key</checkBox>
+ </presentation>
+ <presentation id="POL_A7D4A2B5_A2CB_5BE6_A7D2_111FFC0BB9C5">
+ <textBox refId="TXT_A6A67F77_1744_5905_9C6F_A3468BBFC424">
+ <label>template homedir</label>
+ <defaultValue>/home/%D/%U</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D7A44478_576C_554E_B31A_5316A836F68E">
+ <textBox refId="TXT_73F5972B_1879_58A0_9815_A627E1F6D5BC">
+ <label>template shell</label>
+ <defaultValue>/bin/false</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EE40BE14_5D1D_5ED4_845C_E7E51C529C2B">
+ <decimalTextBox defaultValue="300" refId="DXT_22E52F9D_8E44_59CE_ACC2_916D022CDFA6"/>
+ </presentation>
+ <presentation id="POL_76E2E87A_908A_5F9A_AA09_FF096575D9A7">
+ <textBox refId="TXT_C06A3052_6AD2_53D9_BD21_2A738D8BB155">
+ <label>winbindd socket directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_91508E50_D468_5787_B9AD_BD8160522742">
+ <checkBox refId="CHK_F53BC663_D7A1_5D33_8C57_9EC32E71DC68">winbind enum groups</checkBox>
+ </presentation>
+ <presentation id="POL_F4AED7E2_E1E5_50C5_BBCA_C543EB5E383E">
+ <checkBox refId="CHK_08E1CF79_DDA7_588B_B86D_590B4967C1C0">winbind enum users</checkBox>
+ </presentation>
+ <presentation id="POL_FE94B125_13A6_5560_A963_34F8F6C8F4D6">
+ <decimalTextBox defaultValue="0" refId="DXT_B28BA151_1969_59E2_B275_C81CA16B5A23"/>
+ </presentation>
+ <presentation id="POL_7548D0E2_C166_5A7A_9701_063C15E4172D">
+ <textBox refId="TXT_3C8A3138_1C1C_5FFF_A3F7_513DEA315389">
+ <label>winbind:ignore domains</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DD3D412F_8AD9_54B9_8D5A_A0501DF3AB07">
+ <decimalTextBox defaultValue="200" refId="DXT_C2980001_BA2C_57BA_8C1B_F973C067028B"/>
+ </presentation>
+ <presentation id="POL_BE09D431_FA6A_5383_994E_1AEA3E9EEC4A">
+ <decimalTextBox defaultValue="1" refId="DXT_6F41A5F1_F003_54F4_88AF_9CC14C5B64F0"/>
+ </presentation>
+ <presentation id="POL_2ABFD1ED_23F7_5C67_8ECD_3F7EE2752B7D">
+ <checkBox defaultChecked="true" refId="CHK_EE309E41_F404_5CE1_AC86_5E795D0C979A">winbind nested groups</checkBox>
+ </presentation>
+ <presentation id="POL_4542EFF0_F19C_5215_92F8_0B006803D437">
+ <checkBox refId="CHK_E9249CF9_4820_553B_B406_5560E8B3DEFF">winbind normalize names</checkBox>
+ </presentation>
+ <presentation id="POL_62688BAF_1F03_5CF4_888F_4B88677FF4AC">
+ <textBox refId="TXT_B2B0FF5C_C714_52AC_BAFE_846EC003D31E">
+ <label>winbind nss info</label>
+ <defaultValue>template</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_053CBE3D_DD33_522A_9B34_9AFF4044D454">
+ <checkBox refId="CHK_5945AB58_D8F0_5BA1_9964_D8E69AF19CBB">winbind offline logon</checkBox>
+ </presentation>
+ <presentation id="POL_3BF15158_B942_5458_999E_4FEBCA3A2290">
+ <decimalTextBox defaultValue="30" refId="DXT_BEC37822_5BBB_56AE_B122_DFA48B55FF4A"/>
+ </presentation>
+ <presentation id="POL_46E902CB_4766_50A8_8A8A_86893347E86F">
+ <checkBox refId="CHK_9DDF19FA_7129_5F46_82E2_FED21BCF9048">winbind refresh tickets</checkBox>
+ </presentation>
+ <presentation id="POL_9F679274_5E36_5B71_BBB3_880590FFB5A4">
+ <decimalTextBox defaultValue="60" refId="DXT_542C16F7_4011_5AFF_A127_7A773681E95B"/>
+ </presentation>
+ <presentation id="POL_B5754213_7C07_59E8_BE54_44BD0B64A8ED">
+ <checkBox refId="CHK_2EB29672_8B33_566A_AFE5_41BFDBE0F72E">winbind rpc only</checkBox>
+ </presentation>
+ <presentation id="POL_923523CB_9B7D_5261_93D6_B5FD86FC39E4">
+ <checkBox defaultChecked="true" refId="CHK_3CAC88EA_556D_5AA8_8A29_282B574B2743">winbind scan trusted domains</checkBox>
+ </presentation>
+ <presentation id="POL_FFF6590E_C5E7_5680_9A62_61DC88079555">
+ <checkBox defaultChecked="true" refId="CHK_E93252A7_06C7_566B_B7E6_8D4D7AADFB8D">winbind sealed pipes</checkBox>
+ </presentation>
+ <presentation id="POL_A55D34ED_E614_5500_9F7B_A07E0EE1F7BE">
+ <textBox refId="TXT_25CC57B6_941F_525A_99F8_1C041F206D9B">
+ <label>winbind separator</label>
+ <defaultValue>\</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_14AE5941_E62F_53FC_95AE_441E7EF43F56">
+ <checkBox refId="CHK_BF4DA096_841C_5A0D_A5E3_CD564122C924">winbind use default domain</checkBox>
+ </presentation>
+ <presentation id="POL_4B5E805D_7C7A_5CCE_AAB2_FBD0B9CC6D2E">
+ <checkBox refId="CHK_7E9390CD_05D9_570F_A761_7B5A605BA1F9">winbind use krb5 enterprise principals</checkBox>
+ </presentation>
+ <presentation id="POL_DBC0E447_01F4_5B72_BA4E_E9248006FD96">
+ <checkBox defaultChecked="true" refId="CHK_243E92BD_CBA1_50BC_BD4D_87B750B6FABB">dns proxy</checkBox>
+ </presentation>
+ <presentation id="POL_2E4CDFD7_AB3A_5898_B4A1_44EDABBEE713">
+ <decimalTextBox defaultValue="518400" refId="DXT_761AB0AD_EED6_5734_BC07_88D6599EF57F"/>
+ </presentation>
+ <presentation id="POL_584FFB0D_E6B4_51B1_B65D_FBFD4D40C4D9">
+ <decimalTextBox defaultValue="21600" refId="DXT_153EA1D4_FC29_50AF_878D_5695C6C186CD"/>
+ </presentation>
+ <presentation id="POL_6D6BFEF8_655A_59B7_B17E_050ADA0FAD0F">
+ <textBox refId="TXT_4B630740_3B6C_5FCF_9B93_46CD46767198">
+ <label>nbtd:wins_prepend1Bto1Cqueries</label>
+ <defaultValue>yes</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F145528D_6177_5DA0_9730_05420DF91116">
+ <textBox refId="TXT_A7D6BC38_6BF1_56CF_85B2_FEEA5DAB1A45">
+ <label>nbtd:wins_wins_randomize1Clist</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1D8649CE_6826_507E_A697_A06B2B693295">
+ <textBox refId="TXT_845EC4E4_224C_5FE8_B43E_3F417E26E1F8">
+ <label>nbtd:wins_randomize1Clist_mask</label>
+ <defaultValue>255.255.255.0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8A6CF1A8_12F0_5EC4_B588_658C72C10C4B">
+ <textBox refId="TXT_5A9C87F1_E213_5A53_AD54_9B3AFAB13F9C">
+ <label>winsdb:local_owner</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_4B068333_B3F0_5408_A84F_05BFDB2AD521">
+ <textBox refId="TXT_DE8267A0_F6DE_5043_AFDA_3D98B6494A6D">
+ <label>winsdb:dbnosync</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_61D06DDC_5FC1_5A27_9953_0522C71D3C81">
+ <textBox refId="TXT_7AC86D1C_8F55_5202_9960_E3F76BE03021">
+ <label>wins hook</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DA957F88_D7CE_566D_A902_4CCDEF755586">
+ <checkBox refId="CHK_F6AECF98_9DF6_5B4D_8F4C_1A262B314282">wins proxy</checkBox>
+ </presentation>
+ <presentation id="POL_8F4113F9_15A6_5E26_9F02_7CA7971BE6C9">
+ <textBox refId="TXT_C1395789_AF99_5B0A_89F7_DD274EC794EA">
+ <label>wins server</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0F35BC3D_B809_53E1_9BFD_1765E5E4E934">
+ <checkBox refId="CHK_BE0D6F0B_4FEE_5580_AD27_507FBCC53AB5">wins support</checkBox>
+ </presentation>
+ <presentation id="POL_1009764B_DAB3_56F8_A766_B45CFC524A5E">
+ <textBox refId="TXT_A8EC94D1_CDB1_5E5B_A2D7_D4FDDD78655D">
+ <label>wreplsrv:periodic_interval</label>
+ <defaultValue>15</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_17929B31_DDBB_5B79_AD9D_F0C7EB54BFFA">
+ <textBox refId="TXT_C4483400_9388_5705_BB16_A9CD61B3FC01">
+ <label>wreplsrv:propagate name releases</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E9361CA3_1260_52FE_AD12_742A86788475">
+ <textBox refId="TXT_7E454192_9281_5588_8F18_A4C13837C555">
+ <label>wreplsrv:scavenging_interval</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D3F0B860_C5A4_5E2A_983F_90B40B5AEF46">
+ <textBox refId="TXT_C4470E01_F859_5E45_B342_290D5974C4D0">
+ <label>wreplsrv:tombstone_extra_timeout</label>
+ <defaultValue>259200</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0CA9F8A3_6092_57F4_8CCC_114358C3B9EB">
+ <textBox refId="TXT_D81F8827_96DE_500F_B1B8_D6EF10D165FE">
+ <label>wreplsrv:tombstone_interval</label>
+ <defaultValue>518400</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B06D59DA_A8FC_53AF_AB8F_9C00812D8832">
+ <textBox refId="TXT_B8A345EA_EAA9_524C_A511_8121FD7A5EA1">
+ <label>wreplsrv:tombstone_timeout</label>
+ <defaultValue>86400</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3F2ADB29_E0AE_5723_BC18_0B7ABC97BBE7">
+ <textBox refId="TXT_F35F7924_DBD3_5F6F_B247_7F4893C63844">
+ <label>wreplsrv:verify_interval</label>
+ <defaultValue>2073600</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07">
+ <textBox refId="TXT_609C208A_3B4D_48F1_8A15_C0DF08EAD4D6">
+ <label>Message of the day</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_68E9155C_CB49_428E_AFE0_B89316FFD948">
+ <textBox refId="TXT_8075D9EA_6E15_4B2A_833A_B918EE90856F">
+ <label>Login Prompt Message</label>
+ <defaultValue>Welcome to \s \r \l</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_ADABE9E0_FFF9_4FFE_A105_03E646C79978">
+ <listBox refId="LST_5B9AE80A_6529_4313_A9A1_764DF5320930">Firewalld Zones</listBox>
+ </presentation>
+ <presentation id="POL_B21F349F_4BF6_473E_8452_047D714F156C">
+ <textBox refId="TXT_76109A0B_AA79_4F69_ADFC_2B3CA52763D2">
+ <label>Firewalld Rules</label>
+ <defaultValue>{}</defaultValue>
+ </textBox>
+ </presentation>
+ </presentationTable>
+ </resources>
+</policyDefinitionResources>
diff --git a/libgpo/admx/ru-RU/GNOME_Settings.adml b/libgpo/admx/ru-RU/GNOME_Settings.adml
new file mode 100644
index 0000000..491bf45
--- /dev/null
+++ b/libgpo/admx/ru-RU/GNOME_Settings.adml
@@ -0,0 +1,110 @@
+<policyDefinitionResources revision="1.0" schemaVersion="1.0">
+ <displayName>
+ </displayName>
+ <description>
+ </description>
+ <resources>
+ <stringTable>
+ <string id="SUPPORTED_SAMBA_4_15">Samba 4.15</string>
+ <string id="CAT_351B0FDF_55F3_4904_AC71_D3A6CF8DB323">Настройки GNOME</string>
+ <string id="POL_541A888A_A96D_4A21_9A8F_1021EF6D2F25">Разрешить использовать онлайн-аккаунты</string>
+ <string id="POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC">Онлайн-аккаунты только из белого списка</string>
+ <string id="POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC_Help">Учетные записи GNOME Online (GOA) используются для интеграции песональных сетевых учетных записей с GNOME Desktop и приложениями. Пользователь может добавить свои онлайн-аккаунты, такие как Google, Facebook, Flickr, ownCloud и другие, с помощью приложения Online Accounts.
+Как системный администратор вы можете:
+выборочно включить несколько онлайн-аккаунтов.</string>
+ <string id="POL_541A888A_A96D_4A21_9A8F_1021EF6D2F25_Help">Учетные записи GNOME Online (GOA) используются для интеграции песональных сетевых учетных записей с GNOME Desktop и приложениями. Пользователь может добавить свои онлайн-аккаунты, такие как Google, Facebook, Flickr, ownCloud и другие, с помощью приложения Online Accounts.
+Как системный администратор вы можете:
+включить все онлайн-аккаунты;
+выключить все онлайн-аккаунты.</string>
+ <string id="POL_6307C5EA_766A_4D39_BBAE_B1F9A651F08C">Отключить доступ к коммандной строке</string>
+ <string id="POL_6307C5EA_766A_4D39_BBAE_B1F9A651F08C_Help">Чтобы отключить доступ к командной строке для пользователя рабочего стола, вам необходимо внести изменения в конфигурацию в различных контекстах. Имейте в виду, что следующие шаги не удаляют разрешения пользователя рабочего стола на доступ к командной строке, а скорее удаляют способы, которыми пользователь рабочего стола может получить доступ к командной строке.
+
+Установите ключ GSettings org.gnome.desktop.lockdown.disable-command-line, который запрещает пользователю доступ к терминалу или указание командной строки для выполнения (командная строка Alt + F2).
+
+Запретить пользователям доступ к командной строке Alt + F2.
+
+Отключите переключение на виртуальные терминалы (VT) с помощью сочетаний клавиш Ctrl + Alt + "функциональная клавиша", изменив конфигурацию X-сервера.
+
+Удалите Терминал и все другие терминальные приложения из обзора действий в оболочке GNOME. Вам также необходимо запретить пользователю устанавливать новое приложение терминала.</string>
+ <string id="POL_373CCAD2_D0BC_49A3_A078_10CB073AA949">Отключить сохранение файлов</string>
+ <string id="POL_373CCAD2_D0BC_49A3_A078_10CB073AA949_Help">Вы можете отключить диалоговые окна «Сохранить» и «Сохранить как». Это может быть полезно, если вы предоставляете временный доступ пользователю или не хотите, чтобы пользователь сохранял файлы на компьютер.
+
+ВНИМАНИЕ: эта функция будет работать только в приложениях, которые ее поддерживают! Эта функция включена не во всех приложениях GNOME и сторонних разработчиков. Эти изменения не повлияют на приложения, которые не поддерживают эту функцию.</string>
+ <string id="POL_2B71227C_C44B_4F77_B32A_FF92F312BCE2">Отключить печать</string>
+ <string id="POL_2B71227C_C44B_4F77_B32A_FF92F312BCE2_Help">Вы можете отключить отображение диалогового окна печати для пользователей. Это может быть полезно, если вы предоставляете временный доступ пользователю или не хотите, чтобы пользователь печатал на сетевых принтерах.
+
+ВНИМАНИЕ: эта функция будет работать только в приложениях, которые ее поддерживают! Эта функция включена не во всех приложениях GNOME и сторонних разработчиков. Эти изменения не повлияют на приложения, которые не поддерживают эту функцию.</string>
+ <string id="POL_F5785112_422C_4426_BF69_164FED2D6075">Отключить повторное разбиение дискового пространства</string>
+ <string id="POL_F5785112_422C_4426_BF69_164FED2D6075_Help">polkit позволяет вам устанавливать разрешения для отдельных операций. Для udisks2, утилиты для служб управления дисками, конфигурация находится по адресу /usr/share/polkit-1/actions/org.freedesktop.udisks2.policy. Этот файл содержит набор действий и значений по умолчанию, которые могут быть изменены системным администратором.
+
+СОВЕТ: Конфигурация polkit в /etc переопределяет те, которые поставляются пакетами в /usr/share.</string>
+ <string id="POL_DBD5262E_1014_4778_92C8_C3258C0D8EEE">Отключить выход пользователя из системы</string>
+ <string id="POL_DBD5262E_1014_4778_92C8_C3258C0D8EEE_Help">Предотвращение выхода пользователя из системы полезно для особых типов развертываний GNOME (автоматические киоски, общедоступные терминалы доступа в Интернет и т.д.).
+
+ВАЖНО: Пользователи могут избежать блокировки выхода из системы, переключившись на другого пользователя. По этой причине рекомендуется также отключить переключение пользователей при настройке системы.</string>
+ <string id="POL_E5211A0E_F684_4E93_B62B_4F6B8BE5BBAD">Отключить переключение пользователей</string>
+ <string id="POL_E5211A0E_F684_4E93_B62B_4F6B8BE5BBAD_Help">Предотвращение выхода пользователя из системы полезно для особых типов развертываний GNOME (автоматические киоски, общедоступные терминалы доступа в Интернет и т. Д.).
+
+ВАЖНО: Пользователи могут избежать блокировки выхода из системы, переключившись на другого пользователя. По этой причине рекомендуется также отключить переключение пользователей при настройке системы.</string>
+ <string id="POL_942D0D38_C946_4805_8339_92B661BE64E7">Запретить вход по отпечатку пальца</string>
+ <string id="POL_942D0D38_C946_4805_8339_92B661BE64E7_Help">Пользователи со сканером отпечатков пальцев могут использовать свои отпечатки пальцев вместо пароля для входа в систему. Пользователь должен настроить вход по отпечатку пальца, прежде чем его можно будет использовать.
+
+Считыватели отпечатков пальцев не всегда надежны, поэтому вы можете отключить вход в систему с помощью считывателя по соображениям безопасности.
+ </string>
+ <string id="POL_0906773B_31CA_48E7_B173_A2A8435FA31C">Заблокировать включенные расширения</string>
+ <string id="POL_0906773B_31CA_48E7_B173_A2A8435FA31C_Help">В оболочке GNOME вы можете запретить пользователю включать или отключать расширения, заблокировав ключи org.gnome.shell.enabled-extensions и org.gnome.shell.development-tools. Это позволяет вам предоставить набор расширений, которые должен использовать пользователь.
+
+Блокировка ключа org.gnome.shell.development-tools гарантирует, что пользователь не сможет использовать встроенный отладчик и инспектор GNOME Shell (Looking Glass) для отключения любых обязательных расширений.</string>
+ <string id="POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B">Заблокировать определенные настройки</string>
+ <string id="POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B_Help">Используя режим блокировки в dconf, вы можете запретить пользователям изменять определенные настройки. Без блокировки системных настроек, пользовательские настройки имеют приоритет над настройками системы.
+
+Чтобы заблокировать ключ или подпуть dconf, вам необходимо создать подкаталог locks в каталоге ключевых файлов. Файлы внутри этого каталога содержат список ключей или подкаталогов для блокировки. Как и в случае с ключевыми файлами, вы можете добавить любое количество файлов в этот каталог.</string>
+ <string id="CAT_7E067B4B_2FE1_4AAD_8D76_54209466A491">Пользовательские настройки</string>
+ <string id="POL_1F00D0C9_3190_42E1_870F_33A0E560E873">Тёмный экран, когда пользователь бездействует</string>
+ <string id="POL_1F00D0C9_3190_42E1_870F_33A0E560E873_Help">Вы можете сделать экран компьютера тёмным после того, как компьютер не используется (простаивает) в течение некоторого времени.</string>
+ <string id="POL_05BFA99F_C8C1_4486_AA35_CFB72EF94CAE">Создать ключ</string>
+ <string id="POL_93280789_E7BA_4EB8_924B_61BA1EEB0437">Включенные расширения</string>
+ <string id="POL_93280789_E7BA_4EB8_924B_61BA1EEB0437_Help">Ключ enabled-extensions указывает включенные расширения с помощью uuid расширений.</string>
+ </stringTable>
+ <presentationTable>
+ <presentation id="POL_B00E46C8_3837_4FE2_91EF_3C13D50B0BDC">
+ <listBox refId="LST_B2FA2836_7FE0_4C2D_9D40_073E4BBDF0F3">
+ </listBox>
+ </presentation>
+ <presentation id="POL_1DE280F7_3BE5_4DDD_BE10_5A31D6E7ED9B">
+ <listBox refId="LST_19198E2B_79A2_4263_B09E_CC40151A265B">Настройки</listBox>
+ </presentation>
+ <presentation id="POL_1F00D0C9_3190_42E1_870F_33A0E560E873">
+ <decimalTextBox refId="DXT_B46B9503_767D_43E6_8844_8852AC9211C9" defaultValue="300">Время задержки, после которого включается режим ожидания</decimalTextBox>
+ <decimalTextBox refId="DXT_C652079A_D03D_4DE0_A43A_F5AC3F416F4D" defaultValue="30">Яркость в режиме ожидания</decimalTextBox>
+ </presentation>
+ <presentation id="POL_05BFA99F_C8C1_4486_AA35_CFB72EF94CAE">
+ <comboBox refId="CMB_F3CCB880_E12B_4068_8B8A_66DE04211F69">
+ <label>Создать ключ</label>
+ <default>Правый Alt</default>
+ <suggestion>Правый Alt</suggestion>
+ <suggestion>Левый Win</suggestion>
+ <suggestion>3rd level of Left Win</suggestion>
+ <suggestion>Правый Win</suggestion>
+ <suggestion>3rd level of Right Win</suggestion>
+ <suggestion>Меню</suggestion>
+ <suggestion>3rd level of Menu</suggestion>
+ <suggestion>Левый Ctrl</suggestion>
+ <suggestion>3rd level of Left Ctrl</suggestion>
+ <suggestion>Правый Ctrl</suggestion>
+ <suggestion>3rd level of Right Ctrl</suggestion>
+ <suggestion>Caps Lock</suggestion>
+ <suggestion>3rd level of Caps Lock</suggestion>
+ <suggestion>The "&lt; &gt;" key</suggestion>
+ <suggestion>3rd level of the "&lt; &gt;" key</suggestion>
+ <suggestion>Pause</suggestion>
+ <suggestion>PrtSc</suggestion>
+ <suggestion>Scroll Lock</suggestion>
+ </comboBox>
+ </presentation>
+ <presentation id="POL_93280789_E7BA_4EB8_924B_61BA1EEB0437">
+ <listBox refId="LST_FAD2DD29_CDD9_45BC_99CA_1C47084D09A8">Включенные расширения</listBox>
+ </presentation>
+ </presentationTable>
+ </resources>
+</policyDefinitionResources>
diff --git a/libgpo/admx/ru-RU/samba.adml b/libgpo/admx/ru-RU/samba.adml
new file mode 100644
index 0000000..7ecec41
--- /dev/null
+++ b/libgpo/admx/ru-RU/samba.adml
@@ -0,0 +1,5403 @@
+<?xml version="1.0" ?>
+<policyDefinitionResources revision="1.0" schemaVersion="1.0">
+ <displayName>
+ </displayName>
+ <description>
+ </description>
+ <resources>
+ <stringTable>
+ <string id="CAT_3338C1DD_8A00_4273_8547_158D8B8C19E9">Samba</string>
+ <string id="CAT_7D8D7DC8_5A9D_4BE1_8227_F09CDD5AFFC6">Настройки Unix</string>
+ <string id="CAT_2B6D622C_5721_4C23_A2D6_5C70D6E059BA">Скрипты</string>
+ <string id="POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061">Ежедневно</string>
+ <string id="POL_825D441F_905E_4C7E_9E4B_03013697C6C1">Ежечасно</string>
+ <string id="POL_D298F3BD_44D9_426D_AF11_3163D31582F6">Ежемесячно</string>
+ <string id="POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674">Еженедельно</string>
+ <string id="POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3">Управление разрешениями Sudo</string>
+ <string id="POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061_Help">Этот параметр политики позволяет выполнять команды, локальные или удаленные, ежедневно.</string>
+ <string id="POL_825D441F_905E_4C7E_9E4B_03013697C6C1_Help">Этот параметр политики позволяет выполнять команды, локальные или удаленные, ежечасно.</string>
+ <string id="POL_D298F3BD_44D9_426D_AF11_3163D31582F6_Help">Этот параметр политики позволяет выполнять команды, локальные или удаленные, ежемесячно.</string>
+ <string id="POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674_Help">Этот параметр политики позволяет выполнять команды, локальные или удаленные, еженедельно.</string>
+ <string id="POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3_Help">Эта политика настраивает файл sudoers со специальными строками.</string>
+ <string id="CAT_10827749_64ED_5052_87F7_E81AD421856A">smb.conf</string>
+ <string id="POL_33AAE399_07A8_5CC8_882A_393E4B96B259">additional dns hostnames</string>
+ <string id="POL_33AAE399_07A8_5CC8_882A_393E4B96B259_Help">Список дополнительных DNS-имен, по которым можно идентифицировать этот хост.
+
+Значение по умолчанию:
+пустая строка (нет дополнительных DNS-имен)
+
+Пример:
+host2.example.com host3.other.com</string>
+ <string id="POL_3CD2A970_826E_518E_B5F0_5E6725FF354D">bind interfaces only</string>
+ <string id="POL_3CD2A970_826E_518E_B5F0_5E6725FF354D_Help">Этот глобальный параметр позволяет администратору Samba ограничивать интерфейсы на машине, обслуживающие запросы SMB. Это по-разному затрагивает файловую службу smbd(8) и службу имён nmbd(8).
+
+Если установить этот параметр, то служба имён nmbd связывается по портам 137 и 138 на интерфейсах, перечисленных в параметре 'interfaces'. А также c интерфейсом «все адреса» (0.0.0.0) на портах 137 и 138 для чтения широковещательных сообщений. Если этот параметр не установлен, то служба nmbd будет обслуживать запросы имён на всех этих сокетах. Если параметр установлен, то nmbd проверит исходный адрес любых входящих пакетов на широковещательных сокетах и откажется от любого, который не соответствует широковещательным адресам интерфейсов в списке параметра 'interfaces'. Поскольку одноадресные пакеты принимаются другими сокетами, это позволяет nmbd отказывать в обслуживании имен машинам, которые посылают пакеты с интерфейсов, не перечисленных в списке параметра 'interfaces'. Однако подделка IP-адреса источника обходит эту простую проверку защиты nmbd, поэтому этот параметр не следует серьезно использовать в качестве средства безопасности для nmbd.
+
+Для службы файлов эта опция заставляет smbd(8) связываться только с теми интерфейсами, которые перечисленны в параметре 'interfaces'. Таким образом, ограничиваются сети, которые будет обслуживать smbd, до пакетов, поступающих через эти интерфейсы. Обратите внимание, что нельзя использовать этот параметр для машин, которые обслуживаются через PPP или другие непостоянные или нешироковещательные сетевые интерфейсы, поскольку эта опция не справится с непостоянными интерфейсами.
+
+Если установлена эта опция и в список интерфейсов не добавлен адрес 127.0.0.1 (параметр 'interfaces'), то smbpasswd(8) не будет работать, как ожидалось, т.к. для изменения пользователем SMB пароля, smbpasswd по умолчанию подключается к адресу localhost 127.0.0.1 в качестве SMB клиента для отправки запроса на изменение пароля. Нужно либо добавить адрес 127.0.0.1 в параметре 'interfaces', либо заставить smbpasswd использовать IP-адрес основного интерфейса локального хоста с помощью параметра smbpasswd(8): -r remote machine (при этом, в качестве remote machine указывается IP-адрес основного интерфейса локального хоста).
+
+Значение по умолчанию:
+bind interfaces only = no</string>
+ <string id="POL_109FA3A4_0F92_5052_A7D9_D4BBCA75F765">config backend</string>
+ <string id="POL_109FA3A4_0F92_5052_A7D9_D4BBCA75F765_Help">Этот параметр определяет бэкэнд для хранения конфигурации. Возможные значения: file (по умолчанию) или registry (реестр). Когда при загрузке smb.conf обнаруживается значение 'config backend = registry', то прочитанная конфигурация отбрасывается, и вместо этого читаются глобальные параметры из реестра. Таким образом, считывается только конфигурация реестра. Параметры общих ресурсов не читаются сразу, но устанавливается параметр 'registry shares = yes'.
+
+Примечание. Этот параметр нельзя установить в самой конфигурации реестра.
+
+Значение по умолчанию:
+file
+
+Пример:
+registry</string>
+ <string id="POL_08734B25_7265_5D0B_B857_B2E831B624F1">dos charset</string>
+ <string id="POL_08734B25_7265_5D0B_B857_B2E831B624F1_Help">DOS SMB клиенты предполагают, что сервер имеет ту же кодировку, что и они. Эта опция определяет кодировку Samba для работы с DOS клиентами.
+
+Значение по умолчанию зависит от того, какие кодировки были установлены. Samba попробует использовать кодировку 850, но снизит скорость передачи данных до ASCII, если кодировка 850 не доступна. Выполните testparm(1), чтобы проверить значение по умолчанию в вашей системе.
+
+Значения по умолчанию нет</string>
+ <string id="POL_4CCDFFB7_07DF_58F9_904E_13A024A3F54A">enable core files</string>
+ <string id="POL_4CCDFFB7_07DF_58F9_904E_13A024A3F54A_Help">Этот параметр указывает, должны ли дампы ядра записываться во внутренние выходы. Обычно этот параметр установлен (enable core files = yes). Никогда не нужно менять значение этого параметра.
+
+Значение по умолчанию:
+enable core files = yes</string>
+ <string id="POL_5B751E57_31A9_5EC2_A3CD_A8511D74FCFB">mdns name</string>
+ <string id="POL_5B751E57_31A9_5EC2_A3CD_A8511D74FCFB_Help">Этот параметр управляет именем, которое multicast DNS поддерживает как свой hostname.
+
+У этого параметра есть два специальных значения: netbios и mdns.
+
+По умолчанию используется имя NetBIOS, которое обычно представляет собой имя хоста, написанное заглавными буквами.
+
+Если параметр имеет значение mdns, будут использованы настройки имени хоста из используемой библиотеки MDNS.
+
+Значение по умолчанию:
+netbios
+</string>
+ <string id="POL_461A8AAF_F51E_5FF5_9433_A8D25BBCF783">multicast dns register</string>
+ <string id="POL_461A8AAF_F51E_5FF5_9433_A8D25BBCF783_Help">Если Samba скомпилирована с соответствующей поддержкой и если эта опция включена, Samba станет анонсировать сведения о себе с помощью служб multicast DNS, например, предоставляемых демоном Avahi.
+
+Значение по умолчанию:
+multicast dns register = yes</string>
+ <string id="POL_04F98D09_4223_5390_B66F_A6DA05F97FCC">netbios aliases</string>
+ <string id="POL_04F98D09_4223_5390_B66F_A6DA05F97FCC_Help">Это список имен NetBIOS, которые объявит демон nmbd как дополнительные имена, которые известны серверу Samba. Это позволяет одному компьютеру, на котором запущен сервер Samba, быть объявленным под несколькими именами. Если машина выполняет роль сервера просмотра (browse server) или сервера входа в систему (logon server), ни одно из этих имен не будет объявлено ни как сервер просмотра, ни как сервер входа в систему, только основное имя машины будет объявлено с этими возможностями.
+
+Значение по умолчанию:
+пустая строка (без дополнительных имен)
+
+Пример:
+TEST TEST1 TEST2</string>
+ <string id="POL_90CE7832_31B7_51D8_9EF2_92FEF396F49B">netbios name</string>
+ <string id="POL_90CE7832_31B7_51D8_9EF2_92FEF396F49B_Help">Эта опция устанавливает имя NetBIOS, по которому будет доступен сервер Samba. По умолчанию используется первая часть доменного имени хоста. Если машина является сервером просмотра (browse server) или сервером входа в систему (logon server), это имя (или первая часть доменного имени) будет использоваться в качестве имени и этих сервисов.
+
+Обратите внимание, что максимальная длина имени NetBIOS составляет 15 символов.
+
+В Samba имеется ошибка, из-за которой нарушается процедура просмотра и доступа к общим ресурсам, если NetBIOS-имя имеет значение "PIPE".
+
+Значение по умолчанию:
+netbios name = #DNS-имя хоста
+
+Пример:
+MYNAME</string>
+ <string id="POL_3B93FDE1_6461_572C_AD2E_6AEEAE4EA949">netbios scope</string>
+ <string id="POL_3B93FDE1_6461_572C_AD2E_6AEEAE4EA949_Help">Эта опция устанавливает диапазон NetBIOS, в котором будет работать Samba. Значение этого параметра не следует изменять, если только на каждом компьютере в локальной сети также не установлено такое же значение.
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_E633B0BE_9CF3_5D79_A9F1_CB782C82A19C">prefork backoff increment</string>
+ <string id="POL_E633B0BE_9CF3_5D79_A9F1_CB782C82A19C_Help">Эта опция указывает количество секунд, добавленных к задержке перед перезапуском мастера prefork или рабочего процесса. Первоначальная задержка при перезапуске равна нулю, значение параметра 'prefork backoff increment' добавляется к задержке при каждом перезапуске, до значения указанного в параметре 'prefork maximum backoff'.
+
+Кроме того, можно задать отсрочку для отдельного сервиса, используя параметр 'prefork backoff increment: service name'. Например, если 'prefork backoff increment:ldap = 2', то отсрочка каждый раз увеличивается на 2.
+
+Если 'prefork backoff increment = 2' и prefork 'maximum backoff = 5', то первый перезапуск будет с нулевой задержкой, второй перезапуск будет с задержкой в 2 секунды, а третий и последующие перезапуски будут с задержкой в 4 секунды.
+
+Значение по умолчанию:
+10
+</string>
+ <string id="POL_B4E848BD_E606_552C_8C9F_3F8CC1AEF191">prefork children</string>
+ <string id="POL_B4E848BD_E606_552C_8C9F_3F8CC1AEF191_Help">Эта опция контролирует количество рабочих процессов, которые запускаются для каждой службы при включенной модели процесса prefork (см. samba(8) -M). Потомки prefork запускаются только для тех служб, которые поддерживают prefork (в настоящее время это ldap, kdc и netlogon). Для процессов, которые не поддерживают предварительную загрузку, все запросы обрабатываются одним процессом для этой службы.
+
+Значение этого параметра должно быть кратно количеству ЦП, доступных на сервере.
+
+Кроме того, количество дочерних элементов prefork можно указать для отдельной службы с помощью параметра 'prefork children: service name', например, для установки количества рабочих процессов ldap: 'prefork children:ldap = 8'.
+
+Значение по умолчанию:
+4</string>
+ <string id="POL_D721EFAF_A53D_57B7_9639_3859CF9CE31E">prefork maximum backoff</string>
+ <string id="POL_D721EFAF_A53D_57B7_9639_3859CF9CE31E_Help">Эта опция контролирует максимальную задержку перед перезапуском упавшего prefork процесса.
+
+Значение по умолчанию:
+120</string>
+ <string id="POL_1630255E_61BA_5686_B3E0_995F8C4DAA5E">realm</string>
+ <string id="POL_1630255E_61BA_5686_B3E0_995F8C4DAA5E_Help">Эта опция определяет используемую область Kerberos. Область используется в качестве эквивалента ADS домена NT4. Обычно это DNS-имя сервера Kerberos.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+mysambabox.mycompany.com</string>
+ <string id="POL_E1D45258_0E70_5AF8_AE28_DAB6B318BB8A">server services</string>
+ <string id="POL_E1D45258_0E70_5AF8_AE28_DAB6B318BB8A_Help">Этот параметр содержит службы, которые будет запускать демон Samba.
+
+Запись в файле smb.conf может либо полностью переопределить предыдущее значение, либо можно добавить или удалить записи к предыдущему значению, путём добавления к ним префикса «+» или «-».
+
+Значение по умолчанию:
+s3fs, rpc, nbt, wrepl, ldap, cldap, kdc, drepl, winbindd, ntp_signd, kcc, dnsupdate, dns
+
+Пример:
+-s3fs, +smb</string>
+ <string id="POL_351CFFDA_9DC3_54FB_BE9A_E434F0DB9955">server string</string>
+ <string id="POL_351CFFDA_9DC3_54FB_BE9A_E434F0DB9955_Help">Эта опция определяет, какая строка будет отображаться в поле для комментариев к принтеру в диспетчере печати и рядом с IPC-соединением в сетевом представлении. Это может быть любая строка, которую следует показать пользователям.
+
+Также опция устанавливает, что будет отображаться в списках просмотра рядом с именем машины.
+
+Переменные подстановки:
+ * %v будет заменен номером версии Samba.
+
+ * %h будет заменено на имя компьютера (hostname).
+
+Значение по умолчанию:
+Samba %v
+
+Пример:
+University of GNUs Samba Server</string>
+ <string id="POL_32A7428D_00FC_5203_9943_2BDCDC3D9E0D">share backend</string>
+ <string id="POL_32A7428D_00FC_5203_9943_2BDCDC3D9E0D_Help">Этот параметр указывает бэкенд, который будет использоваться для доступа к конфигурации общих файловых ресурсов.
+
+По умолчанию общие файловые ресурсы Samba настраиваются в файле smb.conf.
+
+На данный момент других поддерживаемых бэкендов нет.
+
+Значение по умолчанию:
+classic</string>
+ <string id="POL_ABDCEE90_90DE_55C2_A2DC_1C7D017F4B2B">unix charset</string>
+ <string id="POL_ABDCEE90_90DE_55C2_A2DC_1C7D017F4B2B_Help">Эта опция задает кодировку, которую использует Samba на unix-машине. Samba необходимо знать кодировку, чтобы иметь возможность преобразовывать текст в кодировки, которые используют другие клиенты SMB.
+
+Также эта кодировка будет использована в аргументах скриптов, используемых Samba.
+
+Значение по умолчанию:
+UTF-8
+
+Пример:
+ASCII</string>
+ <string id="POL_D1FAAF87_1E1E_596F_A915_BE72D67A5DC5">workgroup</string>
+ <string id="POL_D1FAAF87_1E1E_596F_A915_BE72D67A5DC5_Help">Эта настройка указывает, в какой рабочей группе будет находиться сервер при запросе клиентов. Обратите внимание, что этот параметр также управляет доменным именем, используемым с параметром 'security = domain'.
+
+Значение по умолчанию:
+WORKGROUP
+
+Пример:
+MYGROUP</string>
+ <string id="POL_163183B9_195A_5290_927E_08FBB6C76AA0">interfaces</string>
+ <string id="POL_163183B9_195A_5290_927E_08FBB6C76AA0_Help">Параметр позволяет переопределить список сетевых интерфейсов по умолчанию, которые Samba будет использовать для просмотра ресурсов сети, регистрации имён и другого трафика NetBIOS через TCP/IP (NBT). По умолчанию Samba запрашивает ядро для получения списка всех активных интерфейсов и использует любые интерфейсы, которые поддерживают широковещательную рассылку, кроме 127.0.0.1.
+
+Параметр принимает список интерфейсов в виде строки. Каждая строка может быть в любой из следующих форм:
+
+ * Имя сетевого интерфейса (например, eth0). Эта форма может включать подстановочные знаки, например, eth* будет соответствовать любому интерфейсу, начинающемуся с подстроки «eth».
+
+ * IP-адрес. Маска подсети определяется из списка интерфейсов полученного у ядра.
+
+ * пара IP-адрес/маска;
+
+ * пара адрес сети/маска.
+
+Параметр «маска» может быть представлен в битовой размерности (например, 24 для сети класса C) или в виде полной маски подсети с разделителями в виде десятичной точки.
+
+Параметр «IP-адрес» может указываться либо полным десятичным IP-адресом, разделённым точками или указанием имени хоста (hostname), которое будет разрешено с помощью обычных механизмов разрешения имени хоста ОС.
+
+По умолчанию Samba включает все активные интерфейсы, поддерживающие широковещательную передачу, за исключением адаптера обратной связи (IP-адрес 127.0.0.1).
+
+Чтобы поддерживать многоканальные конфигурации SMB3, smbd понимает некоторые дополнительные параметры, которые могут быть добавлены после фактического интерфейса с помощью расширенного синтаксиса (обратите внимание, что кавычки важны для обработки символов «;» и «,»):
+
+ &quot;interface[;key1=value1[,key2=value2[...]]]&quot;
+
+Возможные ключи — speed (скорость), capability (пропускная способность) и if_index. Скорость указывается в битах в секунду. Пропускная способность — RSS и RDMA. If_index следует использовать с осторожностью: значения не должны совпадать с индексами, используемыми ядром. Обратите внимание, что эти параметры в основном предназначены для тестирования и разработки, а не для промышленного использования. По крайней мере, в системах Linux эти значения должны определяться автоматически, но настройки могут служить последним средством, когда автоопределение не работает или недоступно. Указанные значения заменяют автоматически обнаруженные значения.
+
+Значение по умолчанию:
+пустая строка
+
+Ниже приведены примеры. В первых двух примерах настраиваются три сетевых интерфейса, соответствующие устройству eth0 и IP-адресам 192.168.2.10 и 192.168.3.10. Сетевая маска двух последних интерфейсов будет установлена на 255.255.255.0.
+
+В остальных примерах показано, как можно указать дополнительные параметры для каждого интерфейса. Обратите внимание на возможное использование символов «;» и «,», что делает необходимым использование двойных кавычек.
+
+Пример:
+eth0 192.168.2.10/24 192.168.3.10/255.255.255.0
+
+Пример:
+eth0, 192.168.2.10/24; 192.168.3.10/255.255.255.0
+
+Пример:
+&quot;eth0;if_index=65,speed=1000000000,capability=RSS&quot;
+
+Пример:
+&quot;lo;speed=1000000000&quot; &quot;eth0;capability=RSS&quot;
+
+Пример:
+&quot;lo;speed=1000000000&quot; , &quot;eth0;capability=RSS&quot;
+
+Пример:
+&quot;eth0;capability=RSS&quot; , &quot;rdma1;capability=RDMA&quot; ; &quot;rdma2;capability=RSS,capability=RDMA&quot;</string>
+ <string id="POL_25731B61_FC84_5A83_93AE_296F7D6311C4">browse list</string>
+ <string id="POL_25731B61_FC84_5A83_93AE_296F7D6311C4_Help">Параметр устанавливает, обслужит ли smbd(8) список просмотра клиенту, выполняющему вызов NetServerEnum. Обычно 'browse list = yes'. Никогда не следует изменять значение этого параметра.
+
+Значение по умолчанию:
+browse list = yes</string>
+ <string id="POL_3E9E3188_6F1A_54F8_8E13_265E2AD1BE71">domain master</string>
+ <string id="POL_3E9E3188_6F1A_54F8_8E13_265E2AD1BE71_Help">Разрешает smbd(8) сопоставлять список просмотра WAN сети. Включение этой области заставляет nmbd требовать NetBIOS имя домена, идентифицирующее его как мастер браузер домена для данной рабочей группы. Местные мастер браузеры в изолированных подсетях передадут этому nmbd свои локальные списки просмотра и потом запросят у smbd законченную копию списка для всей глобальной сети. Клиенты локальных мастер браузеров получат от своих изолированных мастер браузеров списки всей глобальной сети, вместо списка изолированной подсети.
+
+Обратите внимание, что Windows NT Primary Domain Controllers ожидают, что у них есть возможность требовать NetBIOS имя домена, которое идентифицирует их как мастер браузер домена по умолчанию (и нет способа заставить Windows NT PDC не требовать этого). Это означает, что если этот параметр установлен, и nmbd запрашивает специальное имя для рабочей группы раньше, чем Windows NT PDC, то перекрёстный просмотр подсети будет вести себя странно, и может потерпеть неудачу.
+
+Если 'domain logons' включен, то по умолчанию включается параметр 'domain master'. Если 'domain logons' не включен (по умолчанию), тогда ни один 'domain master' не включен по умолчанию.
+
+Если 'domain logons = yes' и 'domain master = yes', в результате Samba — PDC. Если 'domain master = no', Samba — BDC. Как правило, этот параметр должен быть иметь значение no только на резервном контроллере домена.
+
+Значение по умолчанию:
+auto</string>
+ <string id="POL_E14519D2_9B84_5A1B_B4A4_89F6151BFCE2">enhanced browsing</string>
+ <string id="POL_E14519D2_9B84_5A1B_B4A4_89F6151BFCE2_Help">Эта опция включает перекрестный обзор подсетей, добавленный в Samba, но не являющийся стандартным для Windows.
+
+Сначала Samba просматривает WINS-сервер для всех Domain Master Browsers, сопровождаемых синхронизацией обзора с каждым из возвращенных DMBs (Domain Master Browsers). Потом синхронизируются списки просмотра со всеми известными DMBs.
+
+Можно отключить эту опцию, если есть проблема с пустыми рабочими группами, не исчезающими из списков просмотра. Из-за ограничений протоколов обзора эти расширения могут заставить пустую рабочую группу оставаться в сетевом окружении навсегда, что может раздражать.
+
+В основном, лучше оставить эту опцию включенной, поскольку она делает перекрестный обзор намного более надежным.
+
+По умолчанию:
+enhanced browsing = yes
+ </string>
+ <string id="POL_7E8FBFDB_CBDD_5CE7_B101_07AB8AA71209">lm announce</string>
+ <string id="POL_7E8FBFDB_CBDD_5CE7_B101_07AB8AA71209_Help">Этот параметр отвечает за рассылку демоном nmbd широковещательных пакетов lanman, которые требуются клиентам OS/2 для того, чтобы увидеть Samba в их сетевом окружении. Этот параметр может принимать три значения yes, no, или auto. Значение по умолчанию auto. Если выставлено no, Samba никогда не будет посылать широковещательные пакеты lanman. Если выставлено yes, Samba будет посылать пакеты с интервалом, указанным в параметре 'lm interval'. Если выставлено auto, Samba не будет посылать такие пакеты, но будет слушать сеть на предмет таких пакетов. Если в сети появится такой пакет, то Samba тоже начнет рассылать такие пакеты с интервалом, указанным в параметре 'lm interval'.
+
+По умолчанию:
+auto
+
+Пример:
+yes
+</string>
+ <string id="POL_6D665B21_1F08_5183_B9CD_CFD712C1D4AB">lm interval</string>
+ <string id="POL_6D665B21_1F08_5183_B9CD_CFD712C1D4AB_Help">Если серверу Samba указано посылать широковещательные пакеты lanman, необходимые клиентам OS/2 (см. параметр 'lm announce'), тогда параметр 'lm interval' указывает интервал в секундах, через который следует посылать такие пакеты. Если этот параметр равен 0, то такие пакеты не будут рассылаться вовсе, даже не смотря на значение параметра 'lm announce'.
+
+Значение по умолчанию:
+60
+
+Пример:
+120</string>
+ <string id="POL_40EA4C73_20A7_580A_A830_0EDA7FC72B7D">local master</string>
+ <string id="POL_40EA4C73_20A7_580A_A830_0EDA7FC72B7D_Help">Эта опция разрешает демону nmbd попытаться стать локальным мастер-браузером в этой подсети. Если параметр выключен (local master = no), то nmbd даже не будет пытаться стать мастер-браузером в этой подсети и будет проигрывать все выборы мастер-браузера. По умолчанию, этот параметр установлен (local master = yes), но это не значит, что Samba станет мастер-браузером в подсети. Это означает лишь, что nmbd будет участвовать в выборах мастер-браузера.
+
+Выключение этого параметра (local master = no) приведет к тому, что nmbd никогда не станет мастер-браузером.
+
+Значение по умолчанию:
+local master = yes
+</string>
+ <string id="POL_95C311BC_3067_5654_A978_70326D928F48">os level</string>
+ <string id="POL_95C311BC_3067_5654_A978_70326D928F48_Help">Значение этого параметра (целое число) устанавливает уровень сервера Samba, который используется в выборах обозревателя. Значение этого параметра определяет, имеет ли шансы демон nmbd(8) стать мастер-браузером (master browser) для 'workgroup' в пределах действия широковещательных запросов.
+
+Заметьте, что по умолчанию, Samba будет выигрывать все выборы у всех операционных систем кроме контроллера домена Windows NT 4.0/2000. Это означает, что неправильно сконфигурированная Samba может эффективно изолировать подсеть для просмотра. Этот параметр, в основном, конфигурируется автоматически в Samba-3 и очень редко требуется переопределять его значение. См. раздел «Network Browsing» руководства Samba3-HOWTO для получения более детальной информации, относящейся к этому параметру. Заметьте, что максимальное значение этого параметра 255. Если поставить значение большее 255, то отсчет начнется с 0!
+
+Значение по умолчанию:
+20
+
+Пример:
+65</string>
+ <string id="POL_516D10CE_AECD_50DE_B4F5_D9DBF85FA582">preferred master</string>
+ <string id="POL_516D10CE_AECD_50DE_B4F5_D9DBF85FA582_Help">Этот параметр указывает на то, будет ли демон nmbd(8) предпочитаемым мастер-браузером (master browser) для его рабочей группы или нет.
+
+Если значение этого параметра установлено в yes, то при загрузке, демон nmbd будет форсировать выборы, при этом у него будет небольшое преимущество в победе на выборах. Рекомендуется устанавливать этот параметр совместно с параметром 'domain master = yes', тогда nmbd точно станет доменным мастером (domain master).
+
+Используйте эту опцию с осторожностью, потому что если несколько компьютеров (неважно Samba, Win 95 или NT) будут предпочитаемыми обозревателями в одной сети, они будут постоянно пытаться стать мастер браузерами (master browser). Это вызовет излишний широковещательный трафик и создаст задержки при обращении к сетевому окружению.
+
+Значение по умолчанию:
+auto</string>
+ <string id="POL_E468B4EF_D43C_572D_9A57_390D5D22F485">allow dns updates</string>
+ <string id="POL_E468B4EF_D43C_572D_9A57_390D5D22F485_Help">Этот параметр определяет, какие обновления DNS разрешены.
+
+Обновления DNS можно полностью запретить, установив значение disabled, можно разрешить только для безопасных подключений, установив значение secure only (безопасное соединение), либо разрешить во всех случаях, установив значение nonsecure (небезопасный режим).
+
+Значение по умолчанию:
+secure only
+
+Пример:
+disabled</string>
+ <string id="POL_7E805DF0_F3AD_55F6_AC1E_B13987AE73FC">dns forwarder</string>
+ <string id="POL_7E805DF0_F3AD_55F6_AC1E_B13987AE73FC_Help">Эта опция указывает список DNS-серверов, на которые будут перенаправляться DNS-запросы, если они не могут быть обработаны самой Samba.
+
+Сервер пересылки DNS используется только в том случае, если используется внутренний DNS-сервер в Samba.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+192.168.0.1 192.168.0.2</string>
+ <string id="POL_DE5786B0_C694_53AA_85F2_F9B4EB2F9923">dns update command</string>
+ <string id="POL_DE5786B0_C694_53AA_85F2_F9B4EB2F9923_Help">Этот параметр устанавливает команду, которая вызывается при обновлении DNS. Она должна обновить DNS-имена локальных машин с помощью TSIG-GSS.
+
+Значение по умолчанию:
+/samba_dnsupdate
+
+Пример:
+/usr/local/sbin/dnsupdate</string>
+ <string id="POL_C5C16F87_0017_5CC1_810B_398855115BC9">dns zone scavenging</string>
+ <string id="POL_C5C16F87_0017_5CC1_810B_398855115BC9_Help">При включении (по умолчанию выключено) неиспользуемые динамические DNS-записи периодически удаляются.
+
+Этот параметр не следует включать для установок, созданных с помощью версий Samba до 4.9, так как это приведет к потере статических записей DNS. Это связано с ошибкой в предыдущих версиях Samba (BUG 12451), которая помечала динамические записи DNS как статические, а статические записи как динамические.
+
+Если одна запись для DNS-имени является статической (без устаревания), никакая другая запись для этого DNS-имени не будет очищена.
+
+Значение по умолчанию:
+dns zone scavenging = no</string>
+ <string id="POL_23A4E426_BE59_5616_849E_94C825DDFC5B">gpo update command</string>
+ <string id="POL_23A4E426_BE59_5616_849E_94C825DDFC5B_Help">Этот параметр устанавливает команду, которая вызывается для применения политик GPO. Сценарий samba-gpupdate применяет политики доступа к системе и политики Kerberos к KDC. Политики доступа к системе устанавливают следующие параметры samdb: в minPwdAge, maxPwdAge, minPwdLength и pwdProperties. Политики Kerberos устанавливают следующие параметры в smb.conf: kdc:время жизни билета службы, kdc:время жизни билета пользователя и kdc:время продления.
+
+Значение по умолчанию:
+/samba-gpupdate
+
+Пример:
+/usr/local/sbin/gpoupdate</string>
+ <string id="POL_D32F3D0B_74B1_5C8F_81B4_CC9574EAB9B7">machine password timeout</string>
+ <string id="POL_D32F3D0B_74B1_5C8F_81B4_CC9574EAB9B7_Help">Если Samba является членом домена Windows NT (см. параметры 'security = domain' и 'security = ads'), в таком случае процесс smbd будет пытаться через определенный интервал времени изменить значение переменной MACHINE ACCOUNT PASSWORD, хранимой в TDB файле private/secrets.tdb. Этот параметр указывает на то, как часто будет меняться пароль (значение в секундах). Значение по умолчанию — одна неделя (время, записанное в секундах), точно такое же, как у доменного сервера WinNT.
+
+См. также: smbpasswd(8) и параметры 'security = domain' и 'security = ads'.
+
+Значение по умолчанию:
+604800
+</string>
+ <string id="POL_07339CF8_68F5_5B5F_9207_93D2E4526C44">nsupdate command</string>
+ <string id="POL_07339CF8_68F5_5B5F_9207_93D2E4526C44_Help">Эта опция устанавливает путь к команде nsupdate, которая используется для динамических обновлений DNS GSS-TSIG.
+
+Значение по умолчанию:
+/usr/bin/nsupdate -g</string>
+ <string id="POL_D0F6F805_6160_55CF_9B8B_F5AD874B1E2C">spn update command</string>
+ <string id="POL_D0F6F805_6160_55CF_9B8B_F5AD874B1E2C_Help">Этот параметр устанавливает команду для обновления имен servicePrincipalName из spn_update_list.
+
+Значение по умолчанию:
+/samba_spnupdate
+
+Пример:
+/usr/local/sbin/spnupdate</string>
+ <string id="POL_6FFBB02C_6B3E_5D0E_9193_15F9B38E487D">mangle prefix</string>
+ <string id="POL_6FFBB02C_6B3E_5D0E_9193_15F9B38E487D_Help">Управляет количеством префиксных символов, берущимися из оригинального имени для генерации преобразованного имени. Большее значение даст более слабый хэш и будет вызывать больше коллизий. Минимальное значение — 1, а максимальное — 6.
+
+Параметр 'mangle prefix' имеет смысл только тогда когда для параметра 'mangling method' установлено значение hash2.
+
+Значение по умолчанию:
+1
+
+Пример:
+4</string>
+ <string id="POL_BE8F8AE7_99AC_582E_8105_00326D511339">mangling method</string>
+ <string id="POL_BE8F8AE7_99AC_582E_8105_00326D511339_Help">Устанавливает алгоритм, используемый для генерации переопределяемых имен. Может принимать два значения «hash» и «hash2». «hash» это алгоритм, который использовался в Samba много лет и был параметром по умолчанию для Samba 2.2.х. «hash2» это новый улучшенный алгоритм (меньше вероятность ошибки). Множество Win32 программ хранят измененные имена, поэтому переключение между этими алгоритмами должно быть выполнено быстро, потому что такие приложения могут быть повреждены.
+
+Значение по умолчанию:
+hash2
+
+Пример:
+hash
+</string>
+ <string id="POL_62095050_5FA9_5E4F_8792_595D30BEF047">max stat cache size</string>
+ <string id="POL_62095050_5FA9_5E4F_8792_595D30BEF047_Help">Этот параметр ограничивает размер статического буфера (stat cache), который используется для ускорения ресурсоемких операций преобразования имен. Указывает количество килобайт, которые может использовать статический буфер. Ноль означает «не ограничено». Не рекомендуется использовать такое значение, потому что оно влечет за собой повышенное использование памяти. Не следует изменять значение этого параметра.
+
+Значение по умолчанию:
+512
+
+Пример:
+100</string>
+ <string id="POL_63F6A053_E2E9_57D0_A0F8_003024AD6470">stat cache</string>
+ <string id="POL_63F6A053_E2E9_57D0_A0F8_003024AD6470_Help">Этот параметр определяет будет ли демон smbd(8) использовать буфер для увеличения скорости преобразования имен. Вам скорее всего никогда не потребуется изменять значение этого параметра.
+
+Значение по умолчанию:
+stat cache = yes</string>
+ <string id="POL_FBDCB316_EDD2_526C_AE9F_32F50A97A72F">client ldap sasl wrapping</string>
+ <string id="POL_FBDCB316_EDD2_526C_AE9F_32F50A97A72F_Help">Эта опция определяет, будет ли трафик ldap подписан или подписан и зашифрован (запечатан). Возможные значения: plain, sign и seal (обычная, подпись, печать).
+
+Значения sign и seal доступны только в том случае, если Samba была скомпилирована для современной версии OpenLDAP (2.3.x или выше).
+
+Эта опция необходима в случае, если контроллеры домена принудительно используют подписанные соединения LDAP (например, Windows 2000 SP3 или выше). Подпись и печать LDAP можно контролировать с помощью ключа реестра «HKLM\System\CurrentControlSet\Services\ NTDS\Parameters\LDAPServerIntegrity» на стороне сервера Windows.
+
+В зависимости от используемой библиотеки KRB5 (MIT и более старые версии Heimdal) возможно, что сообщение «только целостность» («integrity only») не поддерживается. В этом случае sign — это всего лишь псевдоним для seal.
+
+Значение по умолчанию — sign, что подразумевает синхронизацию времени с KDC в случае использования Kerberos.
+
+Значение по умолчанию:
+sign</string>
+ <string id="POL_712CFB73_7887_55DD_975B_48DEDBDB9441">ldap admin dn</string>
+ <string id="POL_712CFB73_7887_55DD_975B_48DEDBDB9441_Help">Параметр определяет отличительное имя (Distinguished Name (DN)) используемое Samba для подключения к LDAP-серверу при запросе информации о пользователе. 'ldap admin dn' используется совместно с admin dn паролем, сохраненным в файле private/secrets.tdb. О том, как это сделать смотрите справку по smbpasswd(8). 'ldap admin dn' включает полный DN. 'ldap suffix' не добавляется к 'ldap admin dn'.
+
+Нет умолчания.</string>
+ <string id="POL_CEAB52CA_95EB_5DE5_863B_2399BEF5C727">ldap connection timeout</string>
+ <string id="POL_CEAB52CA_95EB_5DE5_863B_2399BEF5C727_Help">Этот параметр сообщает вызовам библиотеки LDAP, какой тайм-аут в секундах они должны соблюдать во время первоначального установления соединения с серверами LDAP. Это очень полезно, в частности, в сценариях аварийного переключения. Если один или несколько серверов LDAP вообще недоступны, не нужно ждать, пока истечет время ожидания TCP. Эта функция должна поддерживаться библиотекой LDAP.
+
+Этот параметр отличается от 'ldap timeout', который влияет на операции на серверах LDAP, использующих существующее соединение и не устанавливающих начальное соединение.
+
+Значение по умолчанию:
+2</string>
+ <string id="POL_4750A945_176C_5FFF_AB50_DF2BE31C3FBB">ldap delete dn</string>
+ <string id="POL_4750A945_176C_5FFF_AB50_DF2BE31C3FBB_Help">Этот параметр определяет, разрешены ли операции удаления записей в ldapsam или разрешены только операции изменения конкретных атрибутов для Samba.
+
+Значение по умолчанию:
+ldap delete dn = no
+ </string>
+ <string id="POL_27BBF4DB_E2AE_58D3_8018_E83C4B185A3C">ldap deref</string>
+ <string id="POL_27BBF4DB_E2AE_58D3_8018_E83C4B185A3C_Help">Эта опция определяет, должна ли Samba указывать библиотеке LDAP, использовать определенный метод разыменования псевдонимов. Значение по умолчанию — auto, что означает, что настройки по умолчанию клиентской библиотеки ldap будут сохранены. Другие возможные значения: never, finding, searching и always. Для получения дополнительной информации см. руководство по LDAP.
+
+Значение по умолчанию:
+auto
+
+Пример:
+searching</string>
+ <string id="POL_B383A7ED_F6A4_5BD3_B85E_E6B6527D8D79">ldap follow referral</string>
+ <string id="POL_B383A7ED_F6A4_5BD3_B85E_E6B6527D8D79_Help">Эта опция определяет, следует ли следовать ссылкам LDAP при поиске записей в базе данных LDAP. Возможные значения: on, чтобы включить следующие отсылки, off, чтобы отключить, и auto, чтобы использовать настройки libldap по умолчанию. Выбор libldap для следующих отсылок или нет устанавливается в /etc/openldap/ldap.conf с параметром REFERRALS, как описано в ldap.conf(5).
+
+Значение по умолчанию:
+auto
+
+Пример:
+off</string>
+ <string id="POL_E31CD0A8_5A4A_5657_8ACA_123A200C6E06">ldap group suffix</string>
+ <string id="POL_E31CD0A8_5A4A_5657_8ACA_123A200C6E06_Help">Параметр определяет суффикс, используемый для групп, добавляемых в каталог LDAP. Если параметр не установлен, используется значение параметра 'ldap suffix'. Этот суффикс идет перед 'ldap suffix', поэтому лучше использовать частичные DN.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+ou=Groups</string>
+ <string id="POL_FC4495FC_4C6E_50C8_9B37_08D9955A883B">ldap idmap suffix</string>
+ <string id="POL_FC4495FC_4C6E_50C8_9B37_08D9955A883B_Help">Параметр определяет суффикс, используемый для хранения idmap сопоставлений. Если параметр не установлен, используется значение параметра 'ldap suffix'. Этот суффикс идет перед 'ldap suffix', поэтому лучше использовать частичные DN.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+ou=Idmap</string>
+ <string id="POL_2ED1402F_4CF6_5CED_BE40_9B112E1238DC">ldap machine suffix</string>
+ <string id="POL_2ED1402F_4CF6_5CED_BE40_9B112E1238DC_Help">Параметр определяет, как компьютеры будут добавлены в дерево ldap. Если параметр не установлен, используется значение параметра 'ldap suffix'. Этот суффикс идет перед 'ldap suffix', поэтому лучше использовать частичные DN.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+ldap machine suffix = ou=Computers</string>
+ <string id="POL_12C5B04D_D734_576A_99F1_7475BC9E90D7">ldap page size</string>
+ <string id="POL_12C5B04D_D734_576A_99F1_7475BC9E90D7_Help">Этот параметр указывает количество записей на странице.
+
+Если сервер LDAP поддерживает результаты с разбивкой на страницы, клиенты могут запрашивать подмножества результатов поиска (страницы) вместо всего списка. Этот параметр определяет размер этих страниц.
+
+Значение по умолчанию:
+1000
+
+Пример:
+512</string>
+ <string id="POL_DB427B53_CF02_5410_AE37_5BD4E8B968CE">ldap passwd sync</string>
+ <string id="POL_DB427B53_CF02_5410_AE37_5BD4E8B968CE_Help">Параметр определяет, должна ли Samba синхронизировать LDAP пароль с хэшами NT и LM для обычных учетных записей пользователей (не для компьютеров, серверов и доверенных доменов) при смене пароля через Samba.
+
+Параметр может быть установлен в одно из трех значений:
+
+ * yes — попробовать обновить LDAP, NT и LM пароли и обновить время pwdLastSet (атрибут времени последнего изменения пароля).
+ * no — обновить NT и LM пароли и обновить время pwdLastSet.
+ * only — обновить только LDAP пароль, а все остальное сделает LDAP-сервер.
+
+Значение по умолчанию:
+no</string>
+ <string id="POL_0C51A40C_E06E_5A0A_B160_5EB21289B17D">ldap replication sleep</string>
+ <string id="POL_0C51A40C_E06E_5A0A_B160_5EB21289B17D_Help">Если Sabma пытается записать на LDAP сервер, сконфигурированный только для чтения, запрос перенаправляется на мастер-сервер чтения-записи. Этот сервер потом синхронизирует изменения на наш локальный сервер, однако это может занять несколько секунд, особенно на медленных соединениях. Этот параметр задает время ожидания для Samba, чтобы LDAP сервера успели синхронизироваться. Определенные действия клиентов, например, присоединение к домену, могут сбить с толку из-за «успешно выполненного действия», который не приводит к немедленному изменению данных серверной части LDAP.
+
+Этот параметр задает время ожидания для Samba, чтобы LDAP сервера успели синхронизироваться. Если сеть с особенно высокой задержкой, то можно захотеть синхронизировать репликацию LDAP с помощью сетевого сниффера и соответственно увеличить это значение. Однако надо учитывать, что проверка фактической репликации данных не выполняется.
+
+Значение определяется в миллисекундах, максимальная величина составляет 5000 (5 секунд).
+
+Значение по умолчанию:
+1000
+</string>
+ <string id="POL_763BAFE2_3FE0_5C25_B3DC_34AE48F2F569">ldapsam:editposix</string>
+ <string id="POL_763BAFE2_3FE0_5C25_B3DC_34AE48F2F569_Help">Этот параметр дополняет параметр 'ldapsam:trusted' и позволяет упростить управление контроллером домена, дает возможность не создавать пользовательские скрипты по добавлению и управлению posix пользователями и группами. Этот параметр позволяет изменять ldap, создавать, удалять и изменять пользователей и группы. Необходимо, чтобы работал winbindd, так как он используется для выделения новых uids/gids при создании пользователей/групп. Следовательно, необходимо настроить диапазон распределения.
+
+Чтобы использовать эту опцию, необходимо настроить базовое ldap дерево, параметры ldap suffix так же должны быть правильно настроены. На вновь установленных серверах, группы и пользователи по умолчанию (Administrator, Guest, Domain Users, Domain Admins, Domain Guests) могут быть вновь созданы командой net sam provision. Чтобы запустить эту команду должны быть запущены ldap-сервер и Winbindd, а так же ldap вариант файла smb.conf должен быть настроен соответствующим образом. Типовая установка ldap использует параметр 'ldapsam:trusted = yes' с параметром 'ldapsam:editposix = yes'.
+
+Значение по умолчанию:
+ldapsam:editposix = no
+
+Пример конфигурации:
+encrypt passwords = true
+passdb backend = ldapsam
+ldapsam:trusted=yes
+ldapsam:editposix=yes
+ldap admin dn = cn=admin,dc=samba,dc=org
+ldap delete dn = yes
+ldap group suffix = ou=groups
+ldap idmap suffix = ou=idmap
+ldap machine suffix = ou=computers
+ldap user suffix = ou=users
+ldap suffix = dc=samba,dc=org
+idmap backend = ldap:&quot;ldap://localhost&quot;
+idmap uid = 5000-50000
+idmap gid = 5000-50000
+
+
+Эта конфигурация LDAP-сервера предполагает структуру каталогов, подобную описанной в следующем ldif:
+dn: dc=samba,dc=org
+objectClass: top
+objectClass: dcObject
+objectClass: organization
+o: samba.org
+dc: samba
+dn: cn=admin,dc=samba,dc=org
+objectClass: simpleSecurityObject
+objectClass: organizationalRole
+cn: admin
+description: LDAP administrator
+userPassword: secret
+dn: ou=users,dc=samba,dc=org
+objectClass: top
+objectClass: organizationalUnit
+ou: users
+dn: ou=groups,dc=samba,dc=org
+objectClass: top
+objectClass: organizationalUnit
+ou: groups
+dn: ou=idmap,dc=samba,dc=org
+objectClass: top
+objectClass: organizationalUnit
+ou: idmap
+dn: ou=computers,dc=samba,dc=org
+objectClass: top
+objectClass: organizationalUnit
+ou: computers</string>
+ <string id="POL_F7979912_0010_5656_BC3A_08876A56418C">ldapsam:trusted</string>
+ <string id="POL_F7979912_0010_5656_BC3A_08876A56418C_Help">По умолчанию Samba, действующая как контроллер домена Active Directory с LDAP бэкэндом, должна использовать NSS подсистему в стиле UNIX для доступа к информации о пользователях и группах. Из-за того, что Unix хранит информацию в файлах /etc/passwd и /etc/group это неэффективно. Пользователю обычно важно знать список групп, членом которых он является. UNIX имеет оптимизированные функции для определения принадлежности пользователя группе (файл /etc/group). К сожалению, другие функции, которые используются для работы с атрибутами пользователей и групп, не имеют такой оптимизации.
+
+Чтобы Samba хорошо масштабировалась в больших средах, параметр 'ldapsam:trusted = yes' предполагает, что полная база данных пользователей и групп, имеющих отношение к Samba, хранится в LDAP со стандартными атрибутами posixAccount/posixGroup. Кроме того, предполагается, что классы вспомогательных объектов Samba хранятся вместе с данными POSIX в одном объекте LDAP. Если эти предположения соблюдены, можно активировать 'ldapsam:trusted = yes', и Samba может обойти систему NSS для запроса членства в группах пользователей. Samba будет работать быстрее с LDAP, чем с локальными файлами /etc/passwd и /etc/group. Оптимизированные запросы LDAP значительно ускоря��т вход в домен и административные задачи. В зависимости от размера базы данных LDAP легко достигается коэффициент 100 или более для общих запросов.
+
+Значение по умолчанию:
+ldapsam:trusted = no
+</string>
+ <string id="POL_04D79AF3_042D_5ABC_BE8F_4C6628E0F703">ldap server require strong auth</string>
+ <string id="POL_04D79AF3_042D_5ABC_BE8F_4C6628E0F703_Help">Опция определяет, требует ли сервер LDAP подписанный или подписанный и зашифрованный (запечатанный) трафик ldap. Возможные значения: no, allow_sasl_over_tls и yes.
+
+Значение no позволяет выполнять простые и sasl-привязки для всех транспортов.
+
+Значение allow_sasl_over_tls разрешает простые и sasl-привязки (без подписи и печати) через зашифрованные TLS-соединения. Незашифрованные соединения допускают привязку sasl только подписанные или запечатанные.
+
+Значение yes разрешает только простые привязки через зашифрованные TLS-соединения. Незашифрованные соединения допускают привязку sasl только со знаком или печатью.
+
+Значение по умолчанию:
+yes</string>
+ <string id="POL_5B8B9520_4858_5C2F_AA85_F972FF86784A">ldap ssl</string>
+ <string id="POL_5B8B9520_4858_5C2F_AA85_F972FF86784A_Help">Этот параметр определяет, использует ли Samba SSL при подключении к LDAP серверу. Этот параметр не связан с параметром --with-ssl команды configure. По возможности, соединения LDAP должны быть защищены. Это можно сделать, либо установив для этого параметра значение start tls, либо указав ldaps:// в аргументе URL-адреса 'passdb backend'.
+
+Параметр может быть установлен в одно из следующих значений:
+
+ * off — не использовать SSL при запросах к каталогу.
+ * start tls — Использовать LDAPv3 StartTLS расширенные операции (RFC2830) при подключении к серверу каталога.
+
+Обратите внимание, что этот параметр влияет только на методы rpc. Чтобы включить расширенную операцию LDAPv3 StartTLS (RFC2830) для ads, установите 'ldap ssl = start tls' и 'ldap ssl ads = yes'. См. smb.conf(5) для получения дополнительной информации о 'ldap ssl ads'.
+
+Значение по умолчанию:
+start_tls
+</string>
+ <string id="POL_42494B88_7254_5F5F_B738_D5D10BCFBC6C">ldap ssl ads</string>
+ <string id="POL_42494B88_7254_5F5F_B738_D5D10BCFBC6C_Help">Этот параметр используется для определения, следует ли Samba использовать SSL при подключении к серверу LDAP с использованием методов ads. Этот параметр не влияет на методы RPC. Обратите внимание, что этот параметр не будет иметь никакого эффекта, если установлен в no.
+
+См. smb.conf(5) для получения дополнительной информации.</string>
+ <string id="POL_9B071174_FBD3_5CA8_82AA_3BD1EB7BCF45">ldap suffix</string>
+ <string id="POL_9B071174_FBD3_5CA8_82AA_3BD1EB7BCF45_Help">Определяет базу для всех суффиксов LDAP и для хранения объекта sambaDomain. Этот параметр добавляется к значениям определенным в параметрах 'ldap user suffix', 'ldap group suffix', 'ldap machine suffix', и 'ldap idmap suffix'. Каждый из них должен быть представлен как DN к 'ldap suffix'.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+dc=samba,dc=org
+</string>
+ <string id="POL_40F4D046_B9E1_53B0_9DC9_1AE4DE9B1976">ldap timeout</string>
+ <string id="POL_40F4D046_B9E1_53B0_9DC9_1AE4DE9B1976_Help">Этот параметр определяет количество секунд, которые Samba ожидает для выполнения LDAP операций.
+
+Значение по умолчанию:
+15</string>
+ <string id="POL_26984E46_7C64_57A4_B4BF_C2C2B13C330E">ldap user suffix</string>
+ <string id="POL_26984E46_7C64_57A4_B4BF_C2C2B13C330E_Help">Параметр определяет, как пользователи будут добавлены в дерево LDAP. Если параметр не установлен, будет использоваться значение 'ldap suffix'. Строка суффикса будет предшествовать строке 'ldap suffix', так что используйте частичный DN.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+ou=people</string>
+ <string id="POL_AB95F2C5_BFBC_5955_8062_8B446AF7E84C">ldap max anonymous request size</string>
+ <string id="POL_AB95F2C5_BFBC_5955_8062_8B446AF7E84C_Help">Этот параметр указывает максимально допустимый размер (в байтах) для запроса LDAP, полученного по анонимному соединению.
+
+Если размер запроса превышает этот предел, запрос будет отклонен.
+
+Значение по умолчанию:
+256000
+
+Пример:
+500000</string>
+ <string id="POL_23FFECD5_A3C4_566C_AEB3_015F25B1A978">ldap max authenticated request size</string>
+ <string id="POL_23FFECD5_A3C4_566C_AEB3_015F25B1A978_Help">Этот параметр указывает максимально допустимый размер (в байтах) для запроса LDAP, полученного при аутентифицированном соединении.
+
+Если размер запроса превышает этот предел, запрос будет отклонен.
+
+Значение по умолчанию:
+16777216
+
+Пример:
+4194304</string>
+ <string id="POL_F7C651B1_70B4_5047_BC65_2E4D382CBD15">ldap max search request size</string>
+ <string id="POL_F7C651B1_70B4_5047_BC65_2E4D382CBD15_Help">Этот параметр указывает максимально допустимый размер (в байтах) для поискового запроса LDAP.
+
+Если размер запроса превышает этот предел, запрос будет отклонен.
+
+Значение по умолчанию:
+256000
+
+Пример:
+4194304</string>
+ <string id="POL_B3B2B9CC_3DBC_5C45_AA31_7C1E52AFEFAF">lock spin time</string>
+ <string id="POL_B3B2B9CC_3DBC_5C45_AA31_7C1E52AFEFAF_Help">Время в микросекундах, которое smbd следует ожидать для того, чтобы оценить может ли быть удовлетворен запрос на блокировку. Этот параметр изменился в Samba 3.0.23 с 10 до 200. Ассоциированный параметр 'lock spin count' начиная с Samba 3.0.24 больше не используется. Не следует изменять значение этого параметра.
+
+Значение по умолчанию:
+200</string>
+ <string id="POL_4A0366F2_6815_5654_8DC2_F68E840E53F4">oplock break wait time</string>
+ <string id="POL_4A0366F2_6815_5654_8DC2_F68E840E53F4_Help">Это параметр тонкой настройки добавлен из-за ошибок в Windows 9x и WinNT. Если Samba отвечает клиенту слишком быстро, в момент, когда клиент отправляет SMB запрос, который может повлечь за собой запрос прерывания блокировки, то сетевой клиент может выйти из строя и не ответить на запрос прерывания (break request). Этот параметр тонкой настройки (в миллисекундах) — количество времени, которое будет ждать Samba, прежде чем послать запрос прерывания таким (дефектным) клиентам.
+
+Предупреждение
+НЕ МЕНЯЙТЕ ДАННЫЙ ПАРАМЕТР, ЕСЛИ ВЫ НЕ ПРОЧИТАЛИ И НЕ ПОНЯЛИ КОД SAMBA OPLOCK.
+
+Значение по умолчанию:
+0</string>
+ <string id="POL_B49FAE41_B4C1_5AFA_870E_9E1C35F9A96F">smb2 leases</string>
+ <string id="POL_B49FAE41_B4C1_5AFA_870E_9E1C35F9A96F_Help">Этот логический параметр сообщает smbd, следует ли глобально согласовывать аренду SMB2 для запросов на открытие файлов. Аренда — это функция только для SMB2, которая позволяет клиентам агрессивно кэшировать файлы локально сверх кэширования, разрешенного блокировками SMB1.
+
+Доступны только значения yes и no.
+
+Обратите внимание, что кэш записи не будет использоваться для дескрипторов файлов с арендой smb2 для записи.
+
+Значение по умолчанию:
+smb2 leases = yes</string>
+ <string id="POL_1E9B5BE6_8C81_5141_88CD_B5AC0E8D964B">debug class</string>
+ <string id="POL_1E9B5BE6_8C81_5141_88CD_B5AC0E8D964B_Help">Если этот логический параметр включен, класс отладки (DBGC_CLASS) будет отображаться в заголовке отладки.
+
+Дополнительные сведения о доступных в настоящее время классах отладки см. в описании параметра 'log level'.
+
+Значение по умолчанию:
+debug class = no</string>
+ <string id="POL_07D2E039_C5A0_5123_BD71_0C74E2569310">debug hires timestamp</string>
+ <string id="POL_07D2E039_C5A0_5123_BD71_0C74E2569310_Help">Иногда метки времени в сообщениях журнала необходимы с разрешением выше, чем секунды, этот логический параметр добавляет разрешение в микросекундах к заголовку сообщения метки времени при включении.
+
+Обратите внимание, что параметр 'debug timestamp' также должен быть включен ('debug timestamp = yes').
+
+Значение по умолчанию:
+debug hires timestamp = yes</string>
+ <string id="POL_E066DF4A_5BA1_5B35_A96F_90DE6CF27132">debug pid</string>
+ <string id="POL_E066DF4A_5BA1_5B35_A96F_90DE6CF27132_Help">При использовании только одного файла журнала для более чем одного разветвленного smbd(8)-процесса может быть трудно проследить, какой процесс, какое сообщение выводит. Этот логический параметр добавляет идентификатор процесса к заголовкам сообщений с отметкой времени в файле журнала при включении.
+
+Обратите внимание, что параметр 'debug timestamp' также должен быть включен ('debug timestamp = yes').
+
+Значение по умолчанию:
+debug pid = no</string>
+ <string id="POL_4B4EF8B5_3526_5583_8174_E3E332727970">debug prefix timestamp</string>
+ <string id="POL_4B4EF8B5_3526_5583_8174_E3E332727970_Help">Если этот параметр включен, заголовок сообщения с меткой времени ставится перед сообщением отладки без имени файла и информации о функциях, которые включены в параметр. Это дает временные метки сообщениям без добавления дополнительной строки.
+
+Обратите внимание, что параметр 'debug timestamp' также должен быть включен ('debug timestamp = yes').
+
+Значение по умолчанию:
+debug prefix timestamp = no</string>
+ <string id="POL_571A8B87_3CCC_5725_BA33_BDEE367BB740">debug uid</string>
+ <string id="POL_571A8B87_3CCC_5725_BA33_BDEE367BB740_Help">Samba иногда запускается от имени пользователя root, а иногда от имени подключенного пользователя, этот логический параметр, если он включен, вставляет текущий euid, egid, uid и gid в заголовки сообщений с отметками времени в файлы журнала.
+
+Обратите внимание, что параметр 'debug timestamp' также должен быть включен ('debug timestamp = yes').
+
+Значение по умолчанию:
+debug uid = no</string>
+ <string id="POL_2167CEE9_B2C9_5574_8F7D_F38DA9EBBFF1">ldap debug level</string>
+ <string id="POL_2167CEE9_B2C9_5574_8F7D_F38DA9EBBFF1_Help">Этот параметр управляет уровнем отладки вызовов библиотеки LDAP. В случае OpenLDAP это то же битовое поле, которое понимается сервером и задокументировано на странице руководства slapd.conf(5). Типичное полезное значение будет 1 для отслеживания вызовов функций. Выходные данные отладки из библиотек LDAP отображаются с префиксом [LDAP] в выходных данных журнала Samba. Уровень, на котором печатается журнал LDAP, контролируется параметром 'ldap debug threshold'.
+
+Значение по умолчанию:
+0
+
+Пример:
+1</string>
+ <string id="POL_F324946B_9B0D_53F0_AD4F_56800DD63085">ldap debug threshold</string>
+ <string id="POL_F324946B_9B0D_53F0_AD4F_56800DD63085_Help">Этот параметр управляет уровнем отладки Samba, на котором выходные данные отладки библиотеки LDAP печатаются в журналах Samba. См. подробности в описании опции 'ldap debug level'.
+
+Значение по умолчанию:
+10
+
+Пример:
+5</string>
+ <string id="POL_3A601C55_A5EB_5E86_817B_38DACFD45CF9">log file</string>
+ <string id="POL_3A601C55_A5EB_5E86_817B_38DACFD45CF9_Help">Эта опция позволяет переопределить имя файла журнала Samba (также известный как файл отладки).
+
+Эта опция принимает стандартные подстановки, позволяя иметь отдельные файлы журнала для каждого пользователя или машины.
+
+Значения по умолчанию нет.
+
+Пример:
+/usr/local/samba/var/log.%m</string>
+ <string id="POL_A3E0303F_93B5_5C1F_8C01_362881F843CC">logging</string>
+ <string id="POL_A3E0303F_93B5_5C1F_8C01_362881F843CC_Help">Этот параметр позволяет конфигурировать логирование серверной части. Одновременно можно указывать несколько бэкендов с разным уровнем логирования. Параметр представляет собой список бэкендов, где для каждого бэкенда заданы специфичные опции [:option][@loglevel].
+
+Параметр 'option' может использоваться для передачи опций, специфичных для каждой серверной части.
+
+Уровень логирования для бэкенда является опциональным. Если уровень логирования не установлен, то логироваться будут все сообщения.
+Параметр 'log level' определяет общий уровень логирования, в то время как, указанные здесь уровни логирования определяют, что конкретно будет отправлено на каждый бэкенд.
+Когда опция установлена, она имеет приоритет над параметрами 'syslog' и 'syslog only'.
+
+Некоторые бэкенды доступны только тогда, когда Samba скомпилирована с дополнительными библиотеками. Общий список бэкэндов для логирования:
+ * syslog
+ * file
+ * systemd
+ * lttng
+ * gpfs
+ * ringbuf
+
+Бэкэнд ringbuf поддерживает необязательный аргумент size (размер) для изменения размера используемого буфера, значение по умолчанию — 1 МБ:
+ ringbuf:size=NBYTES
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+syslog@1 file</string>
+ <string id="POL_E077BD91_3587_5DBA_A7CB_13044D97E451">log level</string>
+ <string id="POL_E077BD91_3587_5DBA_A7CB_13044D97E451_Help">Значение параметра (строка) позволяет указать уровень отладки (уровень ведения журнала) в файле smb.conf.
+
+Этот параметр был расширен, начиная с серии 2.2.x, теперь он позволяет указывать уровень отладки для нескольких классов отладки и отдельных файлов журнала для классов отладки. Это сделано для большей гибкости конфигурации системы. В настоящее время реализованы следующие классы отладки:
+
+ all
+ tdb
+ printdrivers
+ lanman
+ smb
+ smb2
+ smb2_credits
+ rpc_parse
+ rpc_srv
+ rpc_cli
+ passdb
+ sam
+ auth
+ winbind
+ vfs
+ idmap
+ quota
+ acls
+ locking
+ msdfs
+ dmapi
+ registry
+ scavenger
+ dns
+ ldb
+ tevent
+ auth_audit
+ auth_json_audit
+ kerberos
+ dsdb_audit
+ dsdb_json_audit
+ dsdb_password_audit
+ dsdb_password_json_audit
+ dsdb_transaction_audit
+ dsdb_transaction_json_audit
+
+Чтобы перенаправить ведение журнала для определенных классов в другой файл, можно добавить @PATH к классу, например, log level = 1 full_audit: 1@/var/log/audit.log.
+
+Информация аудита аутентификации и авторизации регистрируется в auth_audit, и если Samba не была скомпилирована с --without-json, представление JSON регистрируется в auth_json_audit.
+
+Поддержка является всеобъемлющей для любой аутентификации и авторизации учетных записей пользователей в Samba Active Directory Domain Controller, а также неявной аутентификации при смене пароля. В файловом сервере предусмотрена проверка подлинности NTLM, авторизация SMB и RPC.
+
+Уровни журнала для auth_audit и auth_audit_json:
+ * 2: Authentication Failure (Ошибки Аутентификации)
+ * 3: Authentication Success (Успешная Аутентификация)
+ * 4: Authorization Success (Успешная Авторизация)
+ * 5: Anonymous Authentication and Authorization Success (Анонимная Аутентификация и Успешная Авторизация)
+
+Изменения в базе данных sam.ldb регистрируются в dsdb_audit, а представление JSON регистрируется в dsdb_json_audit.
+
+Изменения пароля и сброс пароля регистрируются в dsdb_password_audit, а представление JSON регистрируется в файле dsdb_password_json_audit.
+
+Откаты транзакций и сбои при подготовке фиксации регистрируются в dsdb_transaction_audit, а представление JSON регистрируется в файле password_json_audit. Регистрация сведений о транзакции позволяет идентифицировать операции с паролями и sam.ldb, для которых был выполнен откат.
+
+Значение по умолчанию:
+0
+
+Пример:
+3 passdb:5 auth:10 winbind:2
+
+Пример:
+1 full_audit:1@/var/log/audit.log winbind:2</string>
+ <string id="POL_7E7EB779_098F_5383_A0B3_66216F434918">max log size</string>
+ <string id="POL_7E7EB779_098F_5383_A0B3_66216F434918_Help">Эта опция (целое число в килобайтах) указывает максимальный размер файла журнала. Samba периодически проверяет размер и, если размер превысит указанный, то переименовывает файл, добавляя расширение .old.
+
+Значение 0 означает отсутствие ограничений.
+
+Значение по умолчанию:
+5000
+
+Пример:
+1000</string>
+ <string id="POL_57C1D731_63A4_519D_BD0B_05683B94BFDB">syslog</string>
+ <string id="POL_57C1D731_63A4_519D_BD0B_05683B94BFDB_Help">Этот параметр указывает уровень отладки журналов событий, которые будут записываться в системный syslog.
+
+Соответствие значения параметра и событий, который попадают в системный syslog:
+
+0 — LOG_ERR,
+1 — LOG_WARNING,
+2 — LOG_NOTICE,
+3 — LOG_INFO.
+Все значения выше соответствуют LOG_DEBUG.
+
+Этот параметр выступает в роли ограничителя для сообщений, которые будут попадать в системный syslog. Только сообщения с уровнем отладки ниже, чем значение этого параметра будут записываться в syslog. Тем не менее, некоторые отладочные файлы все же будут создаваться, это касается файлов log.[sn]mbd.
+
+Значение по умолчанию:
+syslog = 1</string>
+ <string id="POL_07C28AF5_BA9B_5B55_A018_28B10E803B26">syslog only</string>
+ <string id="POL_07C28AF5_BA9B_5B55_A018_28B10E803B26_Help">Если этот параметр включен (syslog only = yes), то отладочные сообщения Samba будут записываться в системный syslog, но не в отладочные файлы Samba. Но даже при такой установке, некоторые отладочные файлы все же будут создаваться, это касается файлов log.[sn]mbd.
+
+Значение по умолчанию:
+syslog only = no</string>
+ <string id="POL_C2541812_F829_51FC_93D7_75BA34C1F487">timestamp logs</string>
+ <string id="POL_C2541812_F829_51FC_93D7_75BA34C1F487_Help">Сообщения журнала отладки Samba по умолчанию имеют отметку времени. Если вы работаете на высоком уровне, эти временные метки могут отвлекать. Этот логический параметр позволяет отключить отметку времени.
+
+Значение по умолчанию:
+timestamp logs = yes</string>
+ <string id="POL_3B7BF4ED_04E2_5466_9368_8610A5657F8F">abort shutdown script</string>
+ <string id="POL_3B7BF4ED_04E2_5466_9368_8610A5657F8F_Help">В этом параметре определяется полный путь к сценарию, вызываемому демоном smbd(8), запускающему процедуру выключения сервера.
+
+Если подключенный пользователь обладает правами SeRemoteShutdownPrivilege, то эта команда будет им запущена с правами пользователя root.
+
+Значение по умолчанию:
+""
+
+Пример:
+/sbin/shutdown -c</string>
+ <string id="POL_7EEBACBA_ED90_5C68_826F_737212B364EF">add group script</string>
+ <string id="POL_7EEBACBA_ED90_5C68_826F_737212B364EF_Help">В этом параметре определяется полный путь к сценарию, который будет запускать smbd(8) от имени пользователя root, при запросе создания новой группы. Аргумент %g будет заменен преданным именем группы. Этот скрипт полезен только для установки с использованием инструментов администрирования домена Windows NT. Скрипт может создать группу с произвольным именем, чтобы обойти Unix ограничения на имена групп. В этом случае скрипт должен вывести числовой идентификатор созданной группы на стандартный вывод (stdout).
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/sbin/groupadd %g</string>
+ <string id="POL_96F9DA59_163C_56B8_9F66_40CAAD868F91">add machine script</string>
+ <string id="POL_96F9DA59_163C_56B8_9F66_40CAAD868F91_Help">В этом параметре определяется путь к сценарию, запускаемому smbd(8) при добавлении учетной записи компьютера в домен Samba. Учетная запись Unix, соответствующая имени компьютера с добавленным в конец знаком «$» не должна существовать.
+
+Этот параметр очень похож на сценарий по добавлению пользователя (параметр 'add user script'), и аналогично использует замену аргумента %u именем учетной записи. Не используйте аргумент %m.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/sbin/adduser -n -g machines -c Machine -d /var/lib/nobody -s /bin/false %u
+</string>
+ <string id="POL_4AEC4EDA_3303_57E2_BC12_784F40DACA8F">add user script</string>
+ <string id="POL_4AEC4EDA_3303_57E2_BC12_784F40DACA8F_Help">В этом параметре определяется путь к сценарию, который будет выполнен демоном smbd(8) от имени пользователя root при специальных обстоятельствах, описанных ниже.
+
+Обычно, сервер Samba требует, чтобы пользователи UNIX были созданы для всех пользователей, обращающихся к файлам на этом сервере. Для сайтов, которые используют базы данных учетных записей Windows NT в качестве своей основной базы данных пользователей, создание этих пользователей и поддержание синхронизации списка пользователей с Windows NT PDC является тяжелой задачей. Этот параметр позволяет smbd создавать требуемых пользователей UNIX ПО ТРЕБОВАНИЮ, когда пользователь обращается к серверу Samba.
+
+Когда пользователь Windows при входе в систему (установка сессии в SMB протоколе) пытается обратиться к серверу Samba, smbd(8) соединяется с сервером паролей и пытается подтвердить подлинность данного пользователя с данным паролем. Если аутентификация прошла успешно, smbd пытается найти пользователя UNIX в базе данных паролей UNIX, чтобы сопоставить его пользователю Windows. Если происходит сбой поиска, и параметр 'add user script' установлен, тогда smbd вызовет указанный сценарий от имени пользователя root, преобразуя аргумент %u в имя пользователя, которого нужно создать. Если этот сценарий успешно создаст пользователя, тогда smbd продолжит работу, как если бы пользователь UNIX уже существовал. Таким образом, пользователи UNIX создаются динамически, чтобы соответствовать существующим учетным записям Windows NT.
+
+См. также параметры 'security', 'password server', 'delete user script'.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/local/samba/bin/add_user %u</string>
+ <string id="POL_5268249C_58BD_59DA_B44F_DA9109370C58">add user to group script</string>
+ <string id="POL_5268249C_58BD_59DA_B44F_DA9109370C58_Help">В этом параметре определяется полный путь к сценарию, который будет вызываться, когда пользователь добавляется к группе при помощи административных средств домена Windows NT. Скрипт будет выполнен демоном smbd(8) от имени пользователя root. Аргумент %g будет заменен именем группы, а аргумент %u — именем пользователя.
+
+Обратите внимание, что команда adduser, используемая в примере ниже, не поддерживает используемый синтаксис на всех системах.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/sbin/adduser %u %g</string>
+ <string id="POL_89206841_7524_5BFF_872C_444F45C82318">allow nt4 crypto</string>
+ <string id="POL_89206841_7524_5BFF_872C_444F45C82318_Help">Эта опция определяет, будет ли netlogon server (в настоящее время только в режиме «контроллер домена AD») отклонять клиентов, которые не поддерживают NETLOGON_NEG_STRONG_KEYS или NETLOGON_NEG_SUPPORTS_AES.
+
+Эта опция была добавлена в Samba 4.2.0. Эта опция может заблокировать клиентов, которые успешно работали с версиями Samba ниже 4.1.x., т.к. по умолчанию в старых версиях этот параметр был установлен ('allow nt4 crypto = yes'), а в новых по умолчанию не установлен ('allow nt4 crypto = no').
+
+Если в сети есть клиенты без RequireStrongKey = 1 в реестре, то может потребоваться установить параметр 'allow nt4 crypto', пока не будут исправлены все клиенты.
+
+Значение 'allow nt4 crypto = yes' позволяет договариваться о слабой криптографии, возможно, через понижении уровня атаки.
+
+Опция 'reject md5 clients' имеет приоритет перед этой опцией.
+
+Значение по умолчанию:
+allow nt4 crypto = no</string>
+ <string id="POL_9A41AF51_88E9_5566_B12E_36DEA5C42D49">auth event notification</string>
+ <string id="POL_9A41AF51_88E9_5566_B12E_36DEA5C42D49_Help">Если этот параметр включен (auth event notification = yes), Samba (действующая как контроллер домена Active Directory) передает события аутентификации по внутренней шине сообщений. Скрипты, созданные с использованием привязок Python к Samba, могут прослушивать эти события, зарегистрировавшись в качестве службы auth_event.
+
+Этот параметр следует рассматривать как инструмент разработчика (он помогает в наборе тестов Samba), а не как средство для внешнего аудита, поскольку доставка сообщений не гарантируется (функция, которую позволяет использовать набор тестов). Кроме того, Samba должна быть скомпилирована с поддержкой jansson, чтобы эта опция была эффективной.
+
+События аутентификации также регистрируются с помощью обычных методов ведения журнала, если установлен параметр 'log level'.
+
+Значение по умолчанию:
+auth event notification = no</string>
+ <string id="POL_1CAC5DAB_3CB5_586A_AB6F_84E39DDF4796">delete group script</string>
+ <string id="POL_1CAC5DAB_3CB5_586A_AB6F_84E39DDF4796_Help">В этом параметре указан полный путь к сценарию, выполняющемуся от имени пользователя root при удалении пользовательской группы. Этот сценарий полезен для инсталляций, использующих Windows NT domain administration tools.
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_789E0632_E8D7_5FD6_86C6_0EBD079D28C4">delete user from group script</string>
+ <string id="POL_789E0632_E8D7_5FD6_86C6_0EBD079D28C4_Help">В этом параметре указан полный путь к сценарию, который будут вызываться утилитой Windows NT domain administration tools при удалении пользователя из группы. smbd(8) выполнит этот сценарий от имени пользователя root. ргумент %g будет заменен именем группы, а аргумент %u — именем пользователя.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/sbin/deluser %u %g</string>
+ <string id="POL_A399CF3E_C0C6_594B_8F31_F2AA4A18B5AC">delete user script</string>
+ <string id="POL_A399CF3E_C0C6_594B_8F31_F2AA4A18B5AC_Help">В этом параметре указан полный путь к сценарию, выполняемому smbd(8) при управлении пользователями с помощью удаленных RPC (NT) утилит. Этот сценарий вызывается при удалении пользователя с сервера утилитами 'User Manager for Domains' или rpcclient. Этот сценарий должен удалить имя пользователя UNIX.
+
+По умолчанию:
+пустая строка
+
+Пример:
+/usr/local/samba/bin/del_user %u
+ </string>
+ <string id="POL_B35B056A_EEB8_5B89_9FCC_127565F4A6AC">domain logons</string>
+ <string id="POL_B35B056A_EEB8_5B89_9FCC_127565F4A6AC_Help">Этот параметр устарел, начиная с Samba 4.13, и поддержка входа в домен в стиле NT4 (в отличие от Samba AD DC) будет удалена в следующем выпуске Samba.
+
+То есть в будущем значение по умолчанию для 'domain logons' = no будет принудительным поведением.
+
+Если этот параметр установлен, Samba поддерживает службу входа в сеть для Windows 9X для рабочей группы. Это также заставит Samba действовать как контроллер домена NT4. Более подробно см. раздел «Domain Control» руководства Samba-HOWTO.
+
+Значение по умолчанию:
+domain logons = no</string>
+ <string id="POL_3B3E3AD6_FB80_5225_8EDA_6066E5987CE1">enable privileges</string>
+ <string id="POL_3B3E3AD6_FB80_5225_8EDA_6066E5987CE1_Help">Этот параметр управляет, действительно ли smbd будет соблюдать привилегии, назначенные на определенный SIDs утилитой net rpc rights или через одну из утилит Windows user and group manager. Этот параметр включен по умолчанию. Необходимо отключить параметр, чтобы запретить членам группы Domain Admins назначать привилегии пользователям или группам, что может привести к некоторым smbd операциям, выполняющимся от имени пользователя root, которые обычно работали бы под контекстом связанным с подключенным пользователем.
+
+Примером того, как можно использовать привилегии, является назначение права добавлять клиентов к домену Samba, не имея root доступа к серверу через smbd.
+
+Пожалуйста, прочитайте расширенное описание в руководстве Samba-HOWTO.
+
+Значение по умолчанию:
+enable privileges = yes</string>
+ <string id="POL_130E1C0E_9AED_52F5_B1AB_20FD88C999E8">init logon delay</string>
+ <string id="POL_130E1C0E_9AED_52F5_B1AB_20FD88C999E8_Help">Этот параметр определяет задержку в миллисекундах, для хостов, сконфигурированных с параметром 'init logon delayed hosts' для initial samlogon.
+
+Значение по умолчанию:
+100</string>
+ <string id="POL_EEBDC4C9_64BA_58DF_B7A3_C384D6972690">init logon delayed hosts</string>
+ <string id="POL_EEBDC4C9_64BA_58DF_B7A3_C384D6972690_Help">Этот параметр принимает список имен хостов, адресов или сетей, для которых должен быть отложен начальный ответ на samlogon (поэтому рабочие станции XP предпочитают другие контроллеры домена, если таковые имеются).
+
+Продолжительность задержки может быть указана с помощью параметра 'init logon delay'.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+150.203.5. myhost.mynet.de</string>
+ <string id="POL_2FCE2207_11A6_5B55_9ECC_49D171438176">logon drive</string>
+ <string id="POL_2FCE2207_11A6_5B55_9ECC_49D171438176_Help">Параметр указывает путь присоединения домашнего каталога (см. параметр 'logon home') и используется только рабочими станциями Windows NT. Этот параметр имеет смысл только в том случае, если Samba настроена как сервер авторизации (logon server).
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+h:</string>
+ <string id="POL_12DCA5BB_14ED_5BC6_AB9D_E6A57E943B24">logon home</string>
+ <string id="POL_12DCA5BB_14ED_5BC6_AB9D_E6A57E943B24_Help">Параметр указывает домашний каталог при авторизации клиента Windows95/98/NT, что, например, позволит выполнить команду:
+
+C:\&gt;NET USE H: /HOME
+
+Эта опция позволяет использовать отдельный сценарий запуска для различных пользователей компьютера. Параметр может быть использован с рабочими станциями Win9X для того, чтобы профиль пользователя хранился в домашнем каталоге пользователя независимо от того, за каким компьютером работает пользователь. Это делается следующим способом:
+
+logon home = \\%N\%U\profile
+
+Этот параметр для Samba означает, что нужно вернуть вышеописанную строку с изменениями когда клиент запрашивает информацию, преимущественно при запросе NetUserGetInfo. Клиенты Win9X перенаправляются в каталог \servershare, в том случае когда указано net use /home, тем не менее, использует полную строку, когда оперирует профилями.
+
+Обратите внимание на то, что в предыдущих версиях Samba возвращался 'logon path' вместо 'logon home'. Это не позволяло выполнить net use /home, но разрешало профили вне домашнего каталога. В текущей версии все нормально и вышеприведенные примеры работоспособны.
+
+Запретить использование этой опции можно, указав: 'logon home = ""' (пустая строка).
+
+Этот параметр имеет смысл только в том случае, если Samba настроена как сервер авторизации (logon server).
+
+Значение по умолчанию:
+\\%N\%U\
+
+Пример:
+\\remote_smb_server\%U
+</string>
+ <string id="POL_6C04D9F3_27E3_51A9_82B5_BEB5265E1236">logon path</string>
+ <string id="POL_6C04D9F3_27E3_51A9_82B5_BEB5265E1236_Help">Параметр указывает каталог, где будут храниться пользовательские профили (Рабочий стол, NTuser.dat и т.д.). В отличие от предыдущих версий этих справочных страниц, этот параметр никак не связан с перемещаемыми профилями Win 9X. Чтобы узнать, как обрабатывать перемещаемые профили для системы Win 9X, см. параметр logon home.
+
+Эта опция принимает подставновочные символы, что позволяет использовать отдельный сценарий запуска для различных пользователей компьютера. Она также указывает каталог, в котором хранятся «Application Data», рабочий стол, меню пуск, сетевое окружение, программы и другие папки вместе с их содержимым, отображаемым в клиентах WindowsNT.
+
+Каталог, открытый для доступа («шара») и путь должны быть доступны пользователю для чтения. Этот каталог должен быть доступен для записи, когда пользователь заходит в систему впервые, для того чтобы клиенты WinNT могли создать NTuser.dat и другие каталоги. Впоследствии, права на каталоги вместе с их содержимым могут быть изменены на «только для чтения». Тем не менее, не рекомендуется делать файл NTuser.dat доступным только для чтения — переименуйте его в NTuser.man для достижения желаемого эффекта (принудительного профиля — MANdatory profile).
+
+Клиенты Windows иногда могут поддерживать подключение к домашним каталогам [homes], даже если пользователь не прошел авторизацию. Т.е. очень важно чтобы путь 'logon path' НЕ включал в себя путь к домашнему каталогу (т.е. установка значения параметра \\%N\homes\profile_path вызовет проблемы).
+
+Предупреждение:
+ Не заключайте значение этой переменной в кавычки. Установка, например, такого значения “\\%N\profile\%U” нарушит работу профилей. Если используется tdbsam или ldapsam passdb, то во время создания пользовательской учетной записи, значение, установленное для этого параметра, пишется в passdb и в smb.conf. Любые ошибки в passdb должны быть исправлены, с использованием соответствующего инструментария (например, консольный pdbedit).
+
+Эта опция имеет смысл только в том случае, когда Samba работает в режиме домен-контроллера.
+
+Запретить использование перемещаемых профилей можно с помощью установки параметра 'logon path = ""'. Обратите внимание на то, что даже если в конфигурационном файле smb.conf установлена пустая строка, любое значение, установленное в профиле пользователя в passbd переопределит значение этого параметра. Таким образом, полный запрет перемещаемых профилей требует, чтобы в свойствах пользовательского профиля было тоже пусто.
+
+Значение по умолчанию:
+\\%N\%U\profile
+
+Пример использования:
+\\PROFILESERVER\PROFILE\%U
+ </string>
+ <string id="POL_D354C217_6C18_5AD8_B0A2_DDC89463D0C6">logon script</string>
+ <string id="POL_D354C217_6C18_5AD8_B0A2_DDC89463D0C6_Help">Этот параметр указывает пакетный файл запуска (.bat) или файл сценария NT (.cmd), который будет скачан и выполнен на клиентском компьютере, когда пользователь войдет в систему. Файл должен содержать перевод строки в стиле DOS (CR/LF). Для написания таких файлов рекомендуется использовать редактор, поддерживающий переводы строк в стиле DOS.
+
+Файл сценария должен иметь отношение к сервису [netlogon]. Если [netlogon] указывает на 'path' /usr/local/samba/netlogon и имя 'logon script = STARTUP.BAT', тогда файл, который будет скачан должен лежать в /usr/local/samba/netlogon/STARTUP.BAT.
+
+Содержимое .bat файла полностью зависит от вас. Предлагается использовать команду 'NET TIME \SERVER /SET /YES' для синхронизации времени всех компьютеров с сервером времени.
+Еще можно посоветовать использовать 'NET USE U: \SERVERUTILS' для утилит общего пользования или, к примеру 'NET USE Q: \SERVERISO9001_QA'
+
+Обратите внимание на то, что в целях безопасности нужно запрещать запись в [netlogon] или снимать право записи с файла пакетного запуска, т.к. если этого не сделать, то в файл могут написать всё что угодно и безопасность всей системы будет под угрозой.
+
+Этот параметр позволяет иметь разные сценарии запуска для разных пользователей или компьютеров.
+
+Этот параметр полезен только в том случае, если Samba настроена как сервер авторизации (logon server) с ролью классического контроллера домена. Если Samba настроена как контроллер домена Active Directory, вместо этого используется атрибут LDAP scriptPath. Для конфигураций, в которых используется 'passdb backend = ldapsam', этот параметр определяет значение по умолчанию только в случае отсутствия атрибута LDAP sambaLogonScript.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+scripts\%U.bat</string>
+ <string id="POL_0AABECB8_5A60_50DA_973A_7EED1138DB0C">reject md5 clients</string>
+ <string id="POL_0AABECB8_5A60_50DA_973A_7EED1138DB0C_Help">Этот параметр определяет, будет ли сервер netlogon (в настоящее время только в режиме «контроллер домена AD»), отклонять клиентов, которые не поддерживают NETLOGON_NEG_SUPPORTS_AES.
+
+Можно установить этот параметр (reject md5 clientst = yes), если все члены домена поддерживают AES. Это предотвратит попытки перехода на более раннюю версию.
+
+Эта опция имеет приоритет перед опцией 'allow nt4 crypto'.
+
+Значение по умолчанию:
+reject md5 clientst = no</string>
+ <string id="POL_68A94D8F_DA35_5CEC_90E6_4FB245FF32D3">set primary group script</string>
+ <string id="POL_68A94D8F_DA35_5CEC_90E6_4FB245FF32D3_Help">Благодаря использованию системы Posix в WinNT, у пользователя есть основная группа в дополнение к вспомогательным группам. Это сценарий устанавливает основную группу в базе данных пользователей UNIX, когда администратор устанавливает первичную группу пользователя Windows, в диспетчере пользователей или при получении SAM с помощью 'net rpc vampire'. Аргумент %u будет заменен пользователем, первичную группу которого нужно будет установить. Аргумент %g будет заменен группой, которую нужно установить.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+set primary group script = /usr/sbin/usermod -g ‘%g’ ‘%u’</string>
+ <string id="POL_5CDF89E1_F318_5495_BEA0_DA44F0542D49">shutdown script</string>
+ <string id="POL_5CDF89E1_F318_5495_BEA0_DA44F0542D49_Help">Полный путь к сценарию, вызываемому smbd(8), который должен запустить процедуру завершения работы.
+
+Если подключенный пользователь обладает SeRemoteShutdownPrivilege, то эта команда будет выполнена от имени пользователя root.
+
+Переменные %z %t %r %f раскрываются следующим образом:
+
+ * %z — сообщение, которое будет послано серверу.
+ * %t — число секунд ожидания перед запуском процедуры завершения работы.
+ * %r — будет заменен ключом -r, который для NT означает перезагрузку после завершения работы.
+ * %f — будет заменен ключом -f, который для NT означает завершение работы, даже в том случае, если есть не отвечающие приложения.
+
+Процесс завершения работы «не отдает» консоль, поэтому нужно запустить его в фоновом режиме.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/local/samba/sbin/shutdown %m %t %r %f
+
+Пример сценария:
+#!/bin/bash
+
+$time=0
+let &quot;time/60&quot;
+let &quot;time++&quot;
+
+/sbin/shutdown $3 $4 +$time $1 &amp;</string>
+ <string id="POL_3F1B0630_F3F0_5FDE_B66B_1A315CC059B3">add share command</string>
+ <string id="POL_3F1B0630_F3F0_5FDE_B66B_1A315CC059B3_Help">В Samba 2.2.0 добавлена возможность динамически добавлять и удалять общие ресурсы через Диспетчер серверов Windows NT 4.0. Параметр 'add share command' используется, чтобы определить внешнюю программу или сценарий, который добавит определения для нового общего ресурса в smb.conf.
+
+Для успешного выполнения команды добавления общего ресурса, smbd требует, чтобы администратор был подключен с правами root (uid == 0) или имел привилегии SeDiskOperatorPrivilege. Сценарии, определенные в параметре 'add share command', выполняются от имени пользователя root.
+
+После запуска, smbd автоматически вызовет команду, добавляющую общий ресурс с пятью параметрами:
+
+ * configFile — местоположение глобального файла smb.conf.
+
+ * shareName — имя нового общего ресурса.
+
+ * pathName — путь к существующему каталогу на диске.
+
+ * comment — комментарий, связанный с новым общим ресурсом.
+
+ * max connections — максимальное количество одновременных подключений к общему ресурсу.
+
+Этот параметр используется только при создании файлового общего ресурса. Для добавления общего ресурса принтеров см. параметр 'addprinter command'.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/local/bin/addshare</string>
+ <string id="POL_66A8EC32_6235_5E7C_A085_189166239268">afs token lifetime</string>
+ <string id="POL_66A8EC32_6235_5E7C_A085_189166239268_Help">Этот параметр контролирует время жизни токенов, заявленных AFS fake-kaserver. На самом деле они никогда не истекают, но это время жизни контролирует, когда клиент afs забудет токен.
+
+Установите для этого параметра значение 0, чтобы получить NEVERDATE.
+
+Значение по умолчанию:
+604800</string>
+ <string id="POL_78946CAB_73BD_507E_96D5_C643814290D0">afs username map</string>
+ <string id="POL_78946CAB_73BD_507E_96D5_C643814290D0_Help">Если вы используете особенность AFS fake-kaserver, можно вручную создать имена пользователей, для которых всоздаются токены (tokens). Например, это необходимо, если у вас есть пользователи из нескольких доменов в базе данных AFS Protection. Одна из возможных схем кодирования пользователей — это DOMAIN + User, это сделано в winbind со знаком «+» в качестве разделителя.
+
+Отображаемое имя пользователя должно содержать имя ячейки для входа, так как если не настроить этот параметр не создастся никакого маркера (token).
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+%u@afs.samba.org</string>
+ <string id="POL_DEF84B6C_B415_56EB_B3E7_1ED683BFEDE5">allow insecure wide links</string>
+ <string id="POL_DEF84B6C_B415_56EB_B3E7_1ED683BFEDE5_Help">При нормальной работе опция 'wide links', которая позволяет серверу следовать символическим ссылкам за пределами общего пути, автоматически отключается, если они включена опция 'unix extensions' на сервере Samba. Это сделано в целях безопасности, чтобы клиенты UNIX не создавали символические ссылки на области файловой системы сервера, которые администратор не желает экспортировать.
+
+Установка параметра 'allow insecure wide links' отключает связь между этими двумя параметрами, снимая эту защиту и позволяя сайту настраивать сервер для следования символическим ссылкам (путем установки опции 'wide links'), даже если включена опция 'unix extensions'.
+
+Не рекомендуется включать эту опцию, если вы полностью не понимаете последствия разрешения серверу следовать символическим ссылкам, созданным клиентами UNIX. Для большинства обычных конфигураций Samba это будет считаться дырой в безопасности, и установка этого параметра не рекомендуется.
+
+Эта опция была добавлена по просьбе сайтов, которые намеренно настроили Samba таким образом, и которым необходимо было продолжать поддерживать эту функциональность без необходимости исправлять код Samba.
+
+Значение по умолчанию:
+allow insecure wide links = no</string>
+ <string id="POL_8539DC0B_8971_5145_8173_C77681F13A94">allow unsafe cluster upgrade</string>
+ <string id="POL_8539DC0B_8971_5145_8173_C77681F13A94_Help">Если этот параметр не установлен ('allow unsafe cluster upgrade = no' по умолчанию), smbd проверяет при запуске, запущены ли в кластере другие версии smbd, и отказывается запускаться, если это так. Это сделано для защиты от повреждения данных во внутренних структурах из-за несовместимых версий Samba, работающих одновременно в одном кластере. Установка этого параметра ('allow unsafe cluster upgrade = yes') отключает эту проверку безопасности.
+
+Значение по умолчанию:
+allow unsafe cluster upgrade = no</string>
+ <string id="POL_A05EAA54_C6F4_567A_8DE6_7541F9B11046">async smb echo handler</string>
+ <string id="POL_A05EAA54_C6F4_567A_8DE6_7541F9B11046_Help">Этот параметр определяет должна ли Samba создавать отдельный процесс обработчика smb echo. Порождение этого обработчика может быть удобно, если операционная система выполняет длительные блокирующие вызовы. В некоторых случаях это увеличивает тайм-аут, который Windows использует для определения того, разорвано ли соединение. Этот параметр подходит только для SMB1. Для SMB2 и выше вместо этого можно использовать пакеты TCP keepalives.
+
+Значение по умолчанию:
+async smb echo handler = no</string>
+ <string id="POL_087EEAB6_7F83_50CF_A3D0_97B4C6F94F67">auto services</string>
+ <string id="POL_087EEAB6_7F83_50CF_A3D0_97B4C6F94F67_Help">Это список служб, которые необходимо автоматически добавлять в списки просмотра. Это наиболее полезно для дома и служб принтеров, которые в противном случае были бы невидимы.
+
+Обратите внимание: если нужно только, чтобы все принтеры из файла настройки принтеров были загружены, то проще использовать опцию 'load printers'.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+fred lp colorlp</string>
+ <string id="POL_5518624A_7DB9_51BA_A891_F00A40152354">cache directory</string>
+ <string id="POL_5518624A_7DB9_51BA_A891_F00A40152354_Help">Обычно большая часть файлов TDB хранится в 'lock directory'. Начиная с Samba 3.4.0, можно различать файлы TDB с постоянными данными и файлы TDB с непостоянными данными, используя параметры 'state directory' и 'cache directory'.
+
+Этот параметр указывает каталог для хранения файлов TDB, содержащих непостоянные данные, которые будут сохраняться при перезапусках службы. Каталог должен быть помещен в постоянное хранилище, но данные могут быть безопасно удалены администратором.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/var/run/samba/locks/cache</string>
+ <string id="POL_3E23F826_A699_511F_9370_F79DBB4977A9">change notify</string>
+ <string id="POL_3E23F826_A699_511F_9370_F79DBB4977A9_Help">Этот параметр определяет, должна ли Samba ответить запросом уведомления на изменение файла клиента. Никогда не изменяйте этот параметр.
+
+Значение по умолчанию:
+change notify = yes</string>
+ <string id="POL_3EF254FF_4CC2_58A5_9A1B_4E0655610DCA">change share command</string>
+ <string id="POL_3EF254FF_4CC2_58A5_9A1B_4E0655610DCA_Help">В Samba 2.2.0 была добавлена возможность динамически добавлять и удалять общие ресурсы через Windows NT 4.0 Server Manager. Опция 'change share command' используется, чтобы определить внешнюю программу или сценарий, который изменит существующие настройки сервиса в smb.conf.
+
+Чтобы успешно выполнять команду изменения общего ресурса, smbd требует, чтобы администратор был подключен с правами root (uid == 0) или имел SeDiskOperatorPrivilege. Скрипты, определённые в параметре 'change share command', выполняются от имени пользователя root.
+
+При выполнении smbd автоматически вызовет команду 'change share command' с шестью параметрами:
+
+ * configFile — местоположение глобального файла smb.conf.
+ * shareName — имя нового общего ресурса.
+ * pathName — путь к существующему каталогу на диске.
+ * comment — комментарий, связанный с новым общим ресурсом.
+ * max connections — максимальное количество одновременных подключений к общему ресурсу.
+ * CSC policy — политика кэширования на стороне клиента в строковой форме. Допустимые значения: manual, documents, programs, disable.
+
+Этот параметр используется только для изменения существующих определений файлового ресурса. Чтобы изменить общие принтеры, используйте папку «Принтеры…» («Printers…»), которую видно при просмотре хоста Samba.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/local/bin/changeshare</string>
+ <string id="POL_93ADB149_A45A_56A2_9462_0BE437084E47">cluster addresses</string>
+ <string id="POL_93ADB149_A45A_56A2_9462_0BE437084E47_Help">С помощью этого параметра можно добавить дополнительные адреса, которые nmbd зарегистрирует на WINS-сервере. Точно так же эти адреса будут зарегистрированы по умолчанию, когда 'net ads dns register' вызывается с установленным параметром 'clustering'.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+10.0.0.1 10.0.0.2 10.0.0.3</string>
+ <string id="POL_306A8E87_1400_5208_8ABF_B9802BFA685B">clustering</string>
+ <string id="POL_306A8E87_1400_5208_8ABF_B9802BFA685B_Help">Этот параметр указывает, должна ли Samba связываться с ctdb для доступа к своим tdb-файлам и использовать ctdb в качестве серверной части для своей системы обмена сообщениями.
+
+Установите этот параметр, только если у вас есть установка кластера с запущенным ctdb.
+
+Значение по умолчанию:
+clustering = no</string>
+ <string id="POL_2D29302D_8AD7_5BC3_B681_8C54D0A61E68">config file</string>
+ <string id="POL_2D29302D_8AD7_5BC3_B681_8C54D0A61E68_Help">Этот параметр позволяет переопределить используемый файл конфигурации вместо файла по умолчанию (обычно smb.conf). При этом существует проблема, как с курицей и яйцом (что раньше?), поскольку этот параметр установлен в файле конфигурации!
+
+По этой причине, если имя файла конфигурации изменилось при загрузке параметров, он перезагрузит их из нового файла конфигурации.
+
+Эта опция принимает обычные подстановки, которые могут быть очень полезны.
+
+Если файл конфигурации не существует, он не будет загружен (что позволяет в особых случаях использовать файлы конфигурации только нескольких клиентов).
+
+Значения по умолчанию нет.
+
+Пример:
+/usr/local/samba/lib/smb.conf.%m</string>
+ <string id="POL_3838911B_D4E6_50BD_B168_85F113E29165">ctdbd socket</string>
+ <string id="POL_3838911B_D4E6_50BD_B168_85F113E29165_Help">Если установлен параметр 'clustering', нужно указать Samba, где ctdbd прослушивает свой сокет домена Unix. Путь по умолчанию для ctdb 1.0 — /tmp/ctdb.socket, который необходимо явно указать для Samba в smb.conf.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/tmp/ctdb.socket</string>
+ <string id="POL_57D6924C_3F94_5C29_8F63_39808A84FA0F">ctdb locktime warn threshold</string>
+ <string id="POL_57D6924C_3F94_5C29_8F63_39808A84FA0F_Help">В кластерах, где используется Samba и ctdb, важно, чтобы блокировки на центральных базах данных ctdb-hosted таких как locking.tdb не удерживались надолго. В текущей архитектуре Samba случается, что Samba принимает блокировку и, удерживая эту блокировку, выполняет вызовы файловой системы в общую файловую систему кластера. Эта опция заставляет Samba предупреждать, если обнаруживает, что она удерживала блокировки в течение указанного количества миллисекунд. Если это произойдет, smbd выдаст сообщение уровня отладки 0 в свои журналы и, возможно, в системный журнал. Наиболее вероятная причина появления такого сообщения в журнале заключается в том, что операция экспорта Samba файловой системы кластера занимает больше времени, чем ожидалось. Сообщения предназначены для помощи в отладке потенциальных проблем кластера.
+
+Значение 0 (по умолчанию) отключает ведение этого журнала.
+
+Значение по умолчанию:
+0</string>
+ <string id="POL_6392B974_5997_5E87_916F_FCDCCCCA6069">ctdb timeout</string>
+ <string id="POL_6392B974_5997_5E87_916F_FCDCCCCA6069_Help">Этот параметр указывает время ожидания в миллисекундах для соединения между Samba и ctdb. Этот параметр действителен только в том случае, если Samba скомпилирована с кластеризацией и если установлен параметр 'clustering'.
+
+Когда что-то в кластере блокируется, может случиться так, что мы будем бесконечно долго ждать ctdb, просто добавляя условие блокировки. В хорошо работающем кластере этого никогда не должно происходить, но в кластере слишком много компонентов, которые могут давать сбои. Выбор правильного баланса для этого значения очень сложен, потому что в загруженном кластере может быть допустимо длительное время обслуживания для передачи чего-либо через кластер. Установка слишком короткого значения ухудшит качество обслуживания, которое предоставляет кластер, а установка слишком большого значения может привести к тому, что сам кластер слишком долго не восстановится после того, как что-то серьезно сломалось.
+
+Имейте в виду, что если установить этот параметр, он должен быть указан в файле smb.conf, а не в конфигурации реестра (типично для кластера), потому что для доступа к реестру требуется контакт ctdb.
+
+Установка для 'ctdb timeout' значения n заставляет любой процесс ждать ответа от паники кластера дольше n миллисекунд. Установка его в 0 (по умолчанию) приводит к блокировке Samba навсегда, что настоятельно рекомендуется по умолчанию.
+
+Значение по умолчанию:
+0</string>
+ <string id="POL_65E02D5E_EC95_5CD1_9976_6FF4E023ADDD">default service</string>
+ <string id="POL_65E02D5E_EC95_5CD1_9976_6FF4E023ADDD_Help">Этот параметр определяет имя сервиса, который будет подключен в случае невозможности найти запрашиваемый сервис. Обратите внимание, что квадратные скобки не нужны в значении параметра (см. пример ниже).
+Для этого параметра нет значения по умолчанию. Если параметр не установлен, попытка соединения с несуществующей службой приведет к ошибке.
+
+Обычно службой по умолчанию будет 'guest ok', 'read-only'.
+
+Обратите внимание на то, что имя сервиса будет заменено на требуемое. Это очень полезно, так как позволяет использовать макрос типа %S, чтобы использовать подстановку.
+
+Обратите внимание также на то, что любой символ «_» в имени службы, используемой в заданной по умолчанию службе будет приведен к «/». Это позволяет делать интересные вещи.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+pub
+</string>
+ <string id="POL_6CD86A19_3EBF_5E3B_A686_462CA044C5D8">delete share command</string>
+ <string id="POL_6CD86A19_3EBF_5E3B_A686_462CA044C5D8_Help">В Samba 2.2.0 была добавлена возможность динамически добавлять и удалять общие ресурсы через Windows NT 4.0 Server Manager. Параметр 'delete share command' запускает внешнюю программу или сценарий, удаляющий существующий общий ресурс из smb.conf.
+
+Для успешного выполнения этой программы, smbd требует, чтобы администратор был подключен с правами root (uid == 0) или с правами SeDiskOperatorPrivilege. После запуска, smbd автоматически вызовет внешнюю программу с двумя параметрами:
+
+ * configFile — местоположение глобального smb.conf файла.
+ * shareName — имя общего ресурса.
+
+Этот параметр используется только для удаления общих файловых ресурсов. Чтобы удалять общие принтеры, см. параметр 'deleteprinter command'.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/local/bin/delshare
+
+</string>
+ <string id="POL_EA272781_6D7D_5FD5_96BF_069193C67F65">dsdb event notification</string>
+ <string id="POL_EA272781_6D7D_5FD5_96BF_069193C67F65_Help">Если этот параметр включен (dsdb event notification = yes), Samba (действующая как контроллер домена Active Directory) передает события базы данных Samba по внутренней шине сообщений. Сценарии, созданные с использованием привязок Python к Samba, могут прослушивать эти события, зарегистрировавшись в качестве службы dsdb_event.
+
+Этот параметр следует рассматривать как инструмент разработчика (он помогает в наборе тестов Samba), а не как средство для внешнего аудита, поскольку доставка сообщений не гарантируется (функция, которую позволяет использовать набор тестов).
+
+События базы данных Samba также регистрируются с помощью обычных методов ведения журнала, если установлен соответствующий параметр 'log level'.
+
+Значение по умолчанию:
+dsdb event notification = no
+</string>
+ <string id="POL_560BC356_6AEC_5D1A_9859_6479FE0F97C0">dsdb group change notification</string>
+ <string id="POL_560BC356_6AEC_5D1A_9859_6479FE0F97C0_Help">Если этот параметр включен, Samba (действующая как контроллер домена Active Directory) передает события изменения членства в группе по внутренней шине сообщений. Сценарии, созданные с использованием привязок Python к Samba, могут прослушивать эти события, зарегистрировавшись в качестве службы dsdb_group_event.
+
+Этот параметр следует рассматривать как инструмент разработчика (он помогает в наборе тестов Samba), а не как средство для внешнего аудита, поскольку доставка сообщений не гарантируется (функция, которую позволяет использовать набор тестов).
+
+Групповые события также регистрируются с помощью обычных методов ведения журнала, если установлен соответствующий параметр 'log level'.
+
+Значение по умолчанию:
+dsdb group change notification = no</string>
+ <string id="POL_2CF8E791_3F03_5CE3_AC93_0B8078E9667D">dsdb password event notification</string>
+ <string id="POL_2CF8E791_3F03_5CE3_AC93_0B8078E9667D_Help">Если этот параметр включен, Samba (действующая как контроллер домена Active Directory) будет передавать события смены пароля и сброса по внутренней шине сообщений. Сценарии, созданные с использованием привязок Python к Samba, могут прослушивать эти события, зарегистрировавшись в качестве службы password_event.
+
+Этот параметр следует рассматривать как инструмент разработчика (он помогает в наборе тестов Samba), а не как средство для внешнего аудита, поскольку доставка сообщений не гарантируется (функция, которую позволяет использовать набор тестов).
+
+События паролей также регистрируются с помощью обычных методов ведения журнала, если установлен соответствующий параметр 'log level'.
+
+Значение по умолчанию:
+dsdb password event notification = no</string>
+ <string id="POL_C8A040D9_B798_5FE4_A736_BAD9C81CE976">elasticsearch:mappings</string>
+ <string id="POL_C8A040D9_B798_5FE4_A736_BAD9C81CE976_Help">Путь к файлу, определяющий сопоставления атрибутов метаданных в формате JSON. Используется серверной частью Elasticsearch службы Spotlight RPC.
+
+Значение по умолчанию:
+/elasticsearch_mappings.json
+
+Пример:
+/usr/share/foo/mymappings.json</string>
+ <string id="POL_66C9072D_C818_5DFB_AB72_5EDDD4CAE999">fss: prune stale</string>
+ <string id="POL_66C9072D_C818_5DFB_AB72_5EDDD4CAE999_Help">Если этот параметр включен (fss: prune stale = yes), сервер Samba File Server Remote VSS Protocol (FSRVP) проверяет все моментальные снимки, инициированные FSRVP, при запуске и удаляет любое соответствующее состояние (включая определения общих ресурсов) для несуществующих путей к моментальным снимкам.
+
+Значение по умолчанию:
+fss: prune stale = no</string>
+ <string id="POL_A7F4325A_910F_5437_B911_6D94050EF882">fss: sequence timeout</string>
+ <string id="POL_A7F4325A_910F_5437_B911_6D94050EF882_Help">Сервер удаленного протокола VSS (FSRVP) файлового сервера включает таймер последовательности сообщений для обеспечения очистки при неожиданном отключении клиента. Этот параметр отменяет тайм-аут по умолчанию между операциями FSRVP. Таймауты FSRVP можно полностью отключить, установив значение 0.
+
+Значение по умолчанию:
+1
+
+Пример:
+0</string>
+ <string id="POL_529A6287_1697_57CA_A6D0_811F61A441A0">homedir map</string>
+ <string id="POL_529A6287_1697_57CA_A6D0_811F61A441A0_Help">Если установлен параметр 'nis homedir', и smbd(8) используется в качестве сервера входа в Win95/98, то этот параметр определяет NIS (или YP) соответствие, из которого должны быть извлечены домашние каталоги пользователей. В настоящее время принимаются только соответствия формата Sun auto.home.
+
+Формат соответствия:
+username server:/some/file/system
+
+Программа будет извлекать servername до первого символа «:». Вероятно, следует передать разбор системе, которая лучше справляется с соответствиями разных форматов, например, с такими как AMD (еще один automounter) соответствие.
+
+Заметьте, что в системе должен быть запущен NIS клиент.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+amd.homedir</string>
+ <string id="POL_3EE25C0A_C920_54B4_8B7B_D0A91CF3E3F1">kernel change notify</string>
+ <string id="POL_3EE25C0A_C920_54B4_8B7B_D0A91CF3E3F1_Help">Параметр определяет, должен ли сервер Samba запрашивать у ядра уведомление об изменениях произошедших в каталогах, для того чтобы SMB клиент смог обновить состояние каталогов при изменении данных на сервере. Этот параметр используется, только если ядро поддерживает уведомления об изменении данных с помощью inotify интерфейса.
+
+Значение по умолчанию:
+kernel change notify = yes</string>
+ <string id="POL_15EAB330_0CF4_537E_AD96_8FCECB55194F">lock directory</string>
+ <string id="POL_15EAB330_0CF4_537E_AD96_8FCECB55194F_Help">Эта опция указывает каталог для хранения файлов блокировок. Файлы блокировок используются для реализации опции 'max connections'.
+
+Примечание. Этот параметр нельзя установить в настройках реестра.
+
+Файлы, помещенные в этот каталог, не требуются при перезапуске службы и могут быть безопасно помещены в энергозависимое хранилище (например, tmpfs в Linux).
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/var/run/samba/locks</string>
+ <string id="POL_A53007F8_7951_51F3_9753_B6FA4B38B9B7">log writeable files on exit</string>
+ <string id="POL_A53007F8_7951_51F3_9753_B6FA4B38B9B7_Help">Когда сетевое соединение между клиентом CIFS и Samba прерывается, у Samba нет другого выбора, кроме как просто отключить серверную часть сетевого соединения. В этом случае существует риск повреждения данных, поскольку клиент Windows не выполнил все операции записи, запрошенные приложением Windows. Если этот параметр включен (log writeable files on exit = yes), в журнал smbd будет записано сообщение уровня 0 со списком всех файлов, которые были открыты для записи, когда сетевое соединение оборвалось. Это файлы, которые потенциально повреждены. Параметр предназначен для помощи администратору, чтобы дать ему список файлов для проверки согласованности.
+
+Значение по умолчанию:
+log writeable files on exit = no</string>
+ <string id="POL_7DD9B43E_A2B8_59F8_9927_2B56698E65B6">message command</string>
+ <string id="POL_7DD9B43E_A2B8_59F8_9927_2B56698E65B6_Help">Эта опция указывает какую команду следует выполнить, когда сервером будет получено сообщение WinPopup. Обычно это команда, которая каким-то образом доставляет сообщение. Как это сделать — зависит от вас и вашего воображения.
+
+Пример:
+
+message command = csh -c 'xedit %s;rm %s' &amp;
+
+Эта команда доставляет сообщение используя xedit и впоследствии удаляет сообщение. ОЧЕНЬ ВАЖНО ЧТОБЫ ЭТА КОМАНДА «ОТДАВАЛА» КОНСОЛЬ МГНОВЕННО. Именно поэтому в примере используется '&amp;' в конце. Если команда сразу не «отдаст» консоль, то ПК могут зависнуть при отправке сообщений (они должны восстановиться через 30 секунд).
+
+Все сообщения доставляются от имени гостевого пользователя. Эта команда расширяет стандартное поведение (или стандартную функциональность), хотя подстановка %u не будет работать (%U может быть и будет).
+
+К стандартной функциональности добавлены кое-какие дополнительные параметры. В частности:
+
+ * %s = имя файла, содержащего сообщение
+ * %t = пункт назначения, куда было послано сообщение (вероятно имя сервера).
+ * %f = от кого сообщение.
+
+Можно назначить этой команде все что угодно, например, отправку письма (e-mail). Сообщите нам, если у вас будут какие-то интересные идеи.
+
+Здесь показано как отправлять письмо пользователю root:
+
+message command = /bin/mail -s 'message from %f on %m' root &lt; %s; rm %s
+
+Если у параметр 'message command' не установлен, то сообщение не будет доставлено и Samba сообщит получателю об ошибке. К сожалению Windows для рабочих групп игнорирует код ошибки и в любом случае сообщает об успешной доставке.
+
+Для удаления без уведомления, попробуйте:
+
+message command = rm %s
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+csh -c 'xedit %s; rm %s' &amp;</string>
+ <string id="POL_3BDFEE33_A965_5CA9_BC8C_7E5FDA1BB1D5">nbt client socket address</string>
+ <string id="POL_3BDFEE33_A965_5CA9_BC8C_7E5FDA1BB1D5_Help">Эта опция позволяет контролировать, с какого адреса Samba будет отправлять клиентские пакеты NBT, и обрабатывать ответы с их помощью, в том числе в nmbd.
+
+Установка этой опции никогда не должна быть обязательной на обычных серверах Samba, на которых работает только один nmbd.
+
+По умолчанию Samba отправляет UDP-пакеты с адреса ОС по умолчанию для пункта назначения и принимает ответы на 0.0.0.0.
+
+Этот параметр устарел. См. параметры 'bind interfaces only = yes' и 'interfaces' для предыдущего поведения по управлению обычными прослушивающими сокетами.
+
+Значение по умолчанию:
+0.0.0.0
+
+Пример:
+192.168.2.20</string>
+ <string id="POL_C4D98472_F115_59FD_A3E6_A7984D662B99">ncalrpc dir</string>
+ <string id="POL_C4D98472_F115_59FD_A3E6_A7984D662B99_Help">Этот каталог будет содержать серию именованных каналов, позволяющих RPC через межпроцессное взаимодействие.
+
+Это позволит Samba и другим процессам Unix взаимодействовать через DCE/RPC без использования TCP/IP. Кроме того, подкаталог np имеет ограниченные разрешения и обеспечивает надежный канал связи между процессами Samba.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/var/run/samba/ncalrpc</string>
+ <string id="POL_4308D035_8B4B_575A_8984_BAC33A169EBA">nis homedir</string>
+ <string id="POL_4308D035_8B4B_575A_8984_BAC33A169EBA_Help">Получить домашний каталог сервера из NIS. Для систем UNIX, которые используют автомонтирование, домашний каталог пользователя часто монтируется на рабочую станцию ​​по запросу с удаленного сервера.
+
+Когда сервер авторизации (logon server) Samba оне является фактическим сервером домашнего каталога (home directory server), но монтирует домашние каталоги через NFS, тогда выяснение домашнего каталога пользователя будет проходить в два этапа, если logon server сказал клиенту использовать себя в качестве сервера SMB для домашних каталогов (один через SMB и один через NFS). Это может быть очень медленно.
+
+Эта опция позволяет Samba возвращать домашний общий ресурс как находящийся на другом сервере серверу входа в систему, и пока демон Samba работает на сервере домашнего каталога, он будет монтироваться на клиенте Samba непосредственно с сервера каталогов. Когда Samba возвращает клиенту домашний ресурс, он обращается к карте NIS, указанной в карте homedir, и возвращает указанный там сервер.
+
+Обратите внимание на то, что для работы этой опции требуется работающая система NIS и сервер Samba должен работать в режиме сервера авторизации.
+
+Значение по умолчанию:
+nis homedir = no</string>
+ <string id="POL_359CDEF8_9711_56A5_8621_C50718A5B8A1">nmbd bind explicit broadcast</string>
+ <string id="POL_359CDEF8_9711_56A5_8621_C50718A5B8A1_Help">Эта опция заставляет nmbd(8) явно связываться с широковещательным адресом локальных подсетей. Это необходимо для правильной работы nmbd в сочетании с опцией 'socket address'. Не нужно отключать эту опцию.
+
+Значение по умолчанию:
+nmbd bind explicit broadcast = yes</string>
+ <string id="POL_23418947_2DAF_54B3_812C_D9B43F49CFCB">panic action</string>
+ <string id="POL_23418947_2DAF_54B3_812C_D9B43F49CFCB_Help">Это опция разработчика Samba, которая позволяет вызвать системную команду при сбое smbd(8) или nmbd(8). Она используется, в основном, для того, чтобы привлечь внимание к тому факту, что проблема действительно есть.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/bin/sleep 90000</string>
+ <string id="POL_C5C3267E_6E80_5311_96A5_B492C8C3C0AF">perfcount module</string>
+ <string id="POL_C5C3267E_6E80_5311_96A5_B492C8C3C0AF_Help">Этот параметр указывает серверную часть perfcount, которая будет использоваться при мониторинге операций SMB. Можно использовать только один модуль perfcount, и он должен реализовывать все API, содержащиеся в структуре smb_perfcount_handler, определенной в smb.h.
+
+Значения по умолчанию нет
+</string>
+ <string id="POL_02EAE588_9ED7_589C_A454_5B168B65A48A">pid directory</string>
+ <string id="POL_02EAE588_9ED7_589C_A454_5B168B65A48A_Help">Этот параметр указывает каталог, в который будут помещены файлы pid.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/var/run/</string>
+ <string id="POL_77C5FC2D_BBFA_5B4E_906F_ED49B11BF069">registry shares</string>
+ <string id="POL_77C5FC2D_BBFA_5B4E_906F_ED49B11BF069_Help">Этот параметр включает или выключает поддержку определений общих ресурсов, считываемых из реестра. Общие ресурсы, определенные в smb.conf, имеют приоритет над общими ресурсами с тем же именем, определенным в реестре. Подробнее см. раздел о настройке на основе реестра.
+
+Обратите внимание, что по умолчанию этот параметр отключен (registry shares = no), но если для параметра 'config backend' установлено значение registry, то параметр 'registry shares' будет включен (registry shares = yes).
+
+Значение по умолчанию:
+registry shares = no
+
+Пример:
+registry shares = yes</string>
+ <string id="POL_0FB22970_94A4_5403_888E_3CF8242A955C">remote announce</string>
+ <string id="POL_0FB22970_94A4_5403_888E_3CF8242A955C_Help">Этот параметр позволяет настроить nmbd(8) на периодическое оповещение (о своем существовании) произвольных IP-адресов с произвольными именами рабочих групп. Такое поведение может пригодиться, если необходимо, чтобы сервер Samba отображался в удаленной рабочей группе, для которой обычная схема оповещения не работает. Удаленная рабочая группа может быть где угодно, с условием, что туда можно послать IP-пакет.
+
+Пример:
+remote announce = 192.168.2.255/SERVERS 192.168.4.255/STAFF
+
+данная строка говорит демону nmbd, что он должен объявить себя для двух IP-адресов в двух рабочих группах. Если опустить имя рабочей группы, то вместо него используется имя, указанное в параметре 'workgroup'.
+
+В качестве IP-адресов обычно используются широковещательные адреса удаленных сетей, но могут использоваться и адреса известных мастер-браузеров, если конфигурация сети предполагает то, что эти адреса остаются неизменными.
+
+См. раздел «Network Browsing» руководства Samba-HOWTO.
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_B570A06A_7945_5818_B81D_D27007986548">remote browse sync</string>
+ <string id="POL_B570A06A_7945_5818_B81D_D27007986548_Help">Этот параметр позволяет настроить демон nmbd(8) таким образом, что он будет периодически запрашивать список компьютеров у главного обозревателя (мастер-браузера) удаленного сегмента сети. Благодаря этому можно получать актуальные списки компьютеров сетевого окружения для разных рабочих групп, разбросанных по сети. Это работает только с серверами Samba.
+
+Такое поведение может пригодиться, если необходимо, чтобы сервер Samba и все локальные клиенты отображались в удаленной рабочей группе, для которой обычная схема оповещения не работает. Удаленная рабочая группа может быть где угодно, куда можно послать IP-пакет.
+
+remote browse sync = 192.168.2.255 192.168.4.255
+
+Данная строка заставит демон nmbd запрашивать списки компьютеров у мастер-браузеров указанных подсетей или адресов.
+
+В качестве IP-адресов обычно используются широковещательные адреса удаленных сетей, но могут использоваться и адреса известных мастер-браузеров, если конфигурация сети предполагает то, что эти адреса остаются неизменными. Если указан IP-адрес машины, Samba НЕ предпринимает НИКАКИХ попыток проверить, что удаленная машина доступна, слушает и что она фактически является мастер-браузером в своем сегменте.
+
+Этот параметр может быть использован в сетях без WINS-сервера, а также в сетях, которые разделены между собой и где каждая сеть имеет свой собственный WINS-сервер.
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_BA134175_B8C1_5781_9585_AF3A47C44354">reset on zero vc</string>
+ <string id="POL_BA134175_B8C1_5781_9585_AF3A47C44354_Help">Этот логический параметр определяет, следует ли очищать другие соединения, исходящие от одного IP-адреса во время входящей сессии SMB1. Это соответствует поведению Win2003. Установка этого параметра (eset on zero vc = yes) необходима, если у вас «нестабильная» (flaky) сеть и Windows решает переподключиться, в то время как предыдущее соединение имеет открытые файлы. Эти файлы будут недоступны для нового подключения. Клиент посылает сигнал zero VC, и Win2003 уничтожает все подключения, исходящие с этого IP-адреса кроме текущего. Таким образом, заблокированные файлы становятся снова доступными. Имейте в виду, что включение этой опции приведет к уничтожению соединений за маскарадным роутером и не сработает для клиентов, которые используют только SMB2 или SMB3.
+
+Значение по умолчанию:
+reset on zero vc = no</string>
+ <string id="POL_F0071286_C011_5F1C_A520_2DD14DF7682C">rpc_daemon:DAEMON</string>
+ <string id="POL_F0071286_C011_5F1C_A520_2DD14DF7682C_Help">Этот параметр определяет, использовать ли встроенный код или запускать отдельный процесс для определенных служб RPC. За префиксом rpc_daemon должны следовать имя сервера и значение.
+
+В настоящее время поддерживаются два возможных значения:
+
+ * disabled
+ * fork
+
+Классический метод — запускать службы RPC как внутренние службы, встроенные в smbd, поэтому внешние службы по умолчанию имеют значение disabled.
+
+Выбор значения fork приведет к тому, что Samba создаст отдельный процесс для каждого настроенного таким образом демона. Каждый демон может, в свою очередь, разветвлять несколько дочерних элементов, используемых для обработки запросов от нескольких smbd и прямых подключений TCP/IP (если включен сопоставитель конечных точек). Связь с smbd происходит через именованные каналы и требует, чтобы указанные каналы пересылались внешнему демону (см. параметр 'rpc_server').
+
+Fork RPC демоны поддерживают динамически fork дочерние процессы во время обработки соединений. Эвристика о том, сколько дочерних элементов оставить, и как быстро разрешить им разветвляться, а также, сколько клиентов может обрабатывать каждый дочерний элемент одновременно, определяется опциями, указанными по имени демона. В настоящее время поддерживаются пять вариантов:
+
+ * prefork_min_children
+ * prefork_max_children
+ * prefork_spawn_rate
+ * prefork_max_allowed_clients
+ * prefork_child_min_life
+
+Чтобы установить одну из этих опций, используйте следующий синтаксис:
+
+ daemonname: prefork_min_children = 5
+
+Samba включает отдельные демоны для spoolss, lsarpc/lsass, netlogon, samr, FSRVP и mdssvc (Spotlight). В настоящее время доступно пять демонов:
+ * epmd
+ * lsasd
+ * spoolssd
+ * fssd
+ * mdssd
+
+Значение по умолчанию:
+rpc_daemon:DAEMON = disabled
+
+Пример:
+rpc_daemon:spoolssd = fork</string>
+ <string id="POL_820BF686_A78C_5314_A371_3633A8448DC2">rpc_server:SERVER</string>
+ <string id="POL_820BF686_A78C_5314_A371_3633A8448DC2_Help">С помощью этой опции можно определить, должна ли работать внутренняя/встроенная в smbd служба RPC или должна быть перенаправлена на внешний демон, такой как Samba4, демон сопоставления конечных точек (endpoint mapper daemon), демон спула (spoolss daemon) или новый демон службы LSA (LSA service daemon). За префиксом rpc_server должны следовать имя канала и значение.
+
+Этот параметр можно установить для каждой доступной службы RPC в Samba. В следующем списке показаны все доступные службы имен каналов, которые можно изменить с помощью этой опции:
+
+ * epmapper — Endpoint Mapper
+ * winreg — Remote Registry Service
+ * srvsvc — Remote Server Services
+ * lsarpc — Local Security Authority
+ * samr — Security Account Management
+ * netlogon — Netlogon Remote Protocol
+ * netdfs — Settings for Distributed File System
+ * dssetup — Active Directory Setup
+ * wkssvc — Workstation Services
+ * spoolss — Network Printing Spooler
+ * svcctl — Service Control
+ * ntsvcs — Plug and Play Services
+ * eventlog — Event Logger
+ * initshutdown — Init Shutdown Service
+ * mdssvc — Spotlight
+
+В настоящее время поддерживаются три возможных значения:
+ * embedded
+ * external
+ * disabled
+
+Классический метод (значение embedded) — запускать каждый канал как внутреннюю функцию, встроенную в smbd. Значения по умолчанию зависят от службы.
+
+Выбор значения external, позволяет запускать отдельный демон или даже полностью независимый (сторонний) сервер, способный взаимодействовать с Samba через интерфейс MS-RPC по именованным каналам.
+
+В настоящее время в Samba3 поддерживается четыре демона: spoolssd, epmd, lsasd и mdssd. Эти демоны можно включить с помощью параметра 'rpc_daemon'. Для spoolssd необходимо включить демон и проксировать именованный канал (named pipe).
+
+Примеры:
+ rpc_daemon:lsasd = fork
+ rpc_server:lsarpc = external
+ rpc_server:samr = external
+ rpc_server:netlogon = external
+
+ rpc_server:spoolss = external
+ rpc_server:epmapper = disabled
+
+ rpc_daemon:mdssd = fork
+ rpc_server:mdssvc = external
+
+Есть одна специальная опция, которая позволяет включить службы RPC для прослушивания соединений ncacn_ip_tcp. В настоящее время она используется только для тестирования и не масштабируется!
+ rpc_server:tcpip = yes
+
+Значение по умолчанию:
+rpc_server:SERVER = embedded</string>
+ <string id="POL_70434A64_4979_53D2_80EE_09FBF1562741">smbd profiling level</string>
+ <string id="POL_70434A64_4979_53D2_80EE_09FBF1562741_Help">Этот параметр позволяет администратору включить поддержку профилирования.
+
+Возможные значения off, count и on.
+
+Значение по умолчанию:
+off
+
+Пример:
+on</string>
+ <string id="POL_9598A191_3D22_5B49_8188_8D6901A5B4CE">state directory</string>
+ <string id="POL_9598A191_3D22_5B49_8188_8D6901A5B4CE_Help">Обычно большая часть файлов TDB хранится в каталоге блокировки. Начиная с Samba 3.4.0, используя параметры каталога состояний и каталога кэша, можно различать файлы TDB с постоянными данными и файлы TDB с непостоянными данными.
+
+Этот параметр указывает каталог, в котором будут храниться файлы TDB, содержащие важные постоянные данные.
+
+Пример:
+/var/run/samba/locks/state</string>
+ <string id="POL_73FD8B56_579A_5BC6_A49A_4000BE94A02F">usershare allow guests</string>
+ <string id="POL_73FD8B56_579A_5BC6_A49A_4000BE94A02F_Help">Этот параметр позволяет не аутентифицированным пользователям получить доступ к общим ресурсам пользователей.
+
+Это эквивалентно значению параметра 'guest ok = yes' в настройках общего ресурса.
+
+По соображению безопасности этот параметр отключен.
+
+Значение по умолчанию:
+usershare allow guests = no</string>
+ <string id="POL_A0CE47E8_AE8A_5602_8265_1C8D3AEC6064">usershare max shares</string>
+ <string id="POL_A0CE47E8_AE8A_5602_8265_1C8D3AEC6064_Help">Этот параметр определяет число домашних каталогов пользователей, которые могут быть созданы пользователями, принадлежащими группе владельцев папки с домашними каталогами. Если установлено значение ноль (по умолчанию) общие ресурсы пользователей не создаются.
+
+Значение по умолчанию:
+usershare max shares = 0</string>
+ <string id="POL_411611B5_93F6_546F_B68B_05167A064628">usershare owner only</string>
+ <string id="POL_411611B5_93F6_546F_B68B_05167A064628_Help">Этот параметр контролирует, должен ли каталог, из которого создается общий ресурс пользователя принадлежать этому пользователю. Если параметр установлен (usershare owner only = yes), тогда smbd проверяет, что каталог принадлежит пользователю, который является хозяином общего ресурса, и отказывает в создании ресурса, если пользователь не владелец папки. Если параметр выключен (usershare owner only = no), тогда никакой проверки не выполняется, и путь каталога может быть экспортирован независимо от того, кому он принадлежит.
+
+Значение по умолчанию:
+usershare owner only = yes</string>
+ <string id="POL_DD97B40A_CB2A_5818_8D39_F94911EB3F13">usershare path</string>
+ <string id="POL_DD97B40A_CB2A_5818_8D39_F94911EB3F13_Help">Параметр определяет абсолютный путь к каталогу файловой системы, используемому для хранения домашних папок пользователей. Этот каталог должен принадлежать пользователю root, доступ на запись возможен только для владельца группы. Также должен быть установлен «sticky» бит, ограничение на переименование и удаление для владельцев файла (так обычно настраивают каталог /tmp). Члены группы владельцев каталога — это пользователи, которые могут создавать каталоги пользователей. Если параметр не определен, не получится создавать домашние каталоги пользователей.
+
+Например, домашний каталог пользователей определен в /usr/local/samba/lib/usershares, настройте его следующим образом:
+
+ls -ld /usr/local/samba/lib/usershares/
+drwxrwx—T 2 root power_users 4096 2006-05-05 12:27 /usr/local/samba/lib/usershares/
+
+В этом случае, только члены группы «power_users» могут создать пользовательские домашние каталоги.
+
+Значение по умолчанию:
+/usershares</string>
+ <string id="POL_4AAFAB11_EB55_5600_A574_08E074B5DC28">usershare prefix allow list</string>
+ <string id="POL_4AAFAB11_EB55_5600_A574_08E074B5DC28_Help">Этот параметр определяет список абсолютных путей, которые могут быть использованы в качестве домашних каталогов пользователей. Если путь к каталогу не совпадает с путем из этого списка, домашний каталог не подключится. Это позволяет администратору Samba ограничивать каталоги в системе, которые могут быть использованы в качестве домашних каталогов пользователей. Если существуют оба списка 'usershare prefix deny list' и 'usershare prefix allow list', то список запретов обрабатывается в первую очередь.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/home /data /space</string>
+ <string id="POL_1D783E13_3E5A_5FEB_B1C0_486FF385960E">usershare prefix deny list</string>
+ <string id="POL_1D783E13_3E5A_5FEB_B1C0_486FF385960E_Help">Этот параметр определяет список абсолютных путей, которые не могут быть использованы в качестве домашних каталогов пользователей. Если путь к каталогу совпадает с путем из этого списка, домашний каталог не подключится. Пути, не встречающиеся в этом списке, могут быть подключены как пользовательские домашние каталоги. Это позволяет администратору Samba ограничивать каталоги в системе, которые могут быть использованы в качестве домашних каталогов пользователей. Если существуют оба списка 'usershare prefix deny list' и 'usershare prefix allow list', то список запретов обрабатывается в первую очередь.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/etc /dev /private</string>
+ <string id="POL_2974E59A_2225_59CA_A4C8_C967FDB0E588">usershare template share</string>
+ <string id="POL_2974E59A_2225_59CA_A4C8_C967FDB0E588_Help">Пользователь может определять для общего ресурса только ограниченные параметры, такие как путь, 'guest ok' и т.д. Этот параметр «клонировать» общие ресурсы пользователя из существующего общего ресурса. Если значением параметра является существующий общий ресурс, тогда все пользовательские общие ресурсы создадутся с параметрами по умолчанию как у этого ресурса.
+
+Целевой общий ресурс может быть настроен как ошибочный общий ресурс с помощью параметра '-valid = False' и он может использоваться как шаблон. Он станет невидим как реальный общий ресурс, но может использоваться как шаблон для настройки пользовательских общих ресурсов.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+template_share</string>
+ <string id="POL_99ADA47F_F025_52B8_B8F5_DDFA0EEFEF31">utmp</string>
+ <string id="POL_99ADA47F_F025_52B8_B8F5_DDFA0EEFEF31_Help">Этот параметр доступен только в том случае, если Samba сконфигурирована и собрана с опцией –with-utmp. Если параметр установлен (utmp = yes), Samba попытается добавить utmp или utmpx записи (в зависимости от системы UNIX) при каждом подключении к серверу Samba. Сайты могут использовать это для записи пользователя, соединяющегося с общим ресурсом Samba.
+
+По требованиям к utmp записи, мы обязаны создавать уникальный идентификатор для вновь подключенного пользователя. Включение этого параметра создает n^2 алгоритм для нахождения этого числа. Это снизит быстродействие на больших серверах.
+
+Значение по умолчанию:
+utmp = no
+</string>
+ <string id="POL_21565354_4253_5482_97D2_9C2558461C47">utmp directory</string>
+ <string id="POL_21565354_4253_5482_97D2_9C2558461C47_Help">Этот параметр доступен только в том случае, если Samba сконфигурирована и собрана с опцией --with-utmp. Он определяет путь к каталогу, используемому для хранения utmp или utmpx файлов (в зависимости от системы UNIX), используемых для записи пользователей, подключающихся к серверу Samba. По умолчанию параметр не определен, это значит, что система будет использовать любой utmp файл, используемый в операционной системе (обычно в Linux это /var/run/utmp).
+
+Значение по умолчанию:
+пустая строка (определяется автоматически)
+
+Пример:
+/var/run/utmp
+ </string>
+ <string id="POL_4F8E9BC0_CFAB_52F8_9C49_B8BB7400E60A">wtmp directory</string>
+ <string id="POL_4F8E9BC0_CFAB_52F8_9C49_B8BB7400E60A_Help">Этот параметр доступен только в том случае, если Samba сконфигурирована и собрана с опцией --with-utmp. Он определяет путь к каталогу хранения wtmp или wtmpx файлов (в зависимости от системы UNIX), используемых для записи пользователей, подключающихся к серверу Samba. Отличается от параметра 'utmp directory' тем, что пользовательская информация сохраняется после того, как пользователь вышел из системы.
+
+По умолчанию параметр не определен, это значит, что система будет использовать любой utmp файл, используемый в операционной системе (обычно в Linux это /var/run/wtmp).
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/var/log/wtm</string>
+ <string id="POL_83F826D3_2069_552C_8376_C0512E99728D">addport command</string>
+ <string id="POL_83F826D3_2069_552C_8376_C0512E99728D_Help">В Samba 3.0.23 появилась поддержка добавления портов принтера, дистанционно использующих Windows «Add Standard TCP/IP Port Wizard» (мастер добавления стандартного TCP/IP порта). Эта опция определяет внешнюю программу, которая будет выполнена, когда smbd получает запрос добавить новый порт к системе. Сценарию передается два параметра:
+
+ * имя порта (port name)
+
+ * URI устройства (device URI)
+
+URI устройства имеет формат socket://&lt;hostname&gt;[:&lt;portnumber&gt;] или lpd://&lt;hostname&gt;/&lt;queuename&gt;.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/etc/samba/scripts/addport.sh
+</string>
+ <string id="POL_B4BE84FF_FB13_5496_AC34_B15BF764F654">addprinter command</string>
+ <string id="POL_B4BE84FF_FB13_5496_AC34_B15BF764F654_Help">С введением поддержки печати на основе MS-RPC клиентами Windows NT/2000 в Samba 2.2, значок MS Add Printer Wizard (APW) теперь также доступен в папке «Принтеры…» («Printers…»), отображающей список общих ресурсов. APW учитывает принтеры, чтобы добавлять их дистанционно к серверу печати Windows NT/2000 или Samba.
+
+Для хоста Samba это означает, что принтер нужно физически добавить к базовой системе печати. Параметр 'addprinter command' определяет сценарий, который будет выполнен, чтобы добавить принтер к системе печати, и добавит соответствующие опции в файл smb.conf.
+
+Команда добавления принтера автоматически вызывается со следующими параметрами:
+
+ * printer name
+ * share name
+ * port name
+ * driver name
+ * location (местоположение)
+ * Windows 9x driver location
+
+Все параметры заполняются из структуры PRINTER_INFO_2, отправленной клиентом Windows NT/2000, с одним исключением. Параметр «Windows 9x driver location» включен только для обратной совместимости. Остальные поля в структуре PRINTER_INFO_2 генерируются из ответов на APW вопросы.
+
+После выполнения команды добавления принтера, smbd повторно анализирует smb.conf, чтобы определить, существует ли общий ресурс, определенный APW. Если имя общего ресурса все еще недействителено, то smbd вернет клиенту ошибку ACCESS_DENIED.
+
+Скрипт 'addprinter command' может вывести одну строку текста, которую Samba установит как порт, к которому подключен новый принтер. Если эта строка не выводится, Samba не будет перезагружать общий ресурс принтеров.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/bin/addprinter</string>
+ <string id="POL_D9D048A2_779C_5D85_A26E_131535508B70">cups connection timeout</string>
+ <string id="POL_D9D048A2_779C_5D85_A26E_131535508B70_Help">Этот параметр применим, только если параметр 'printing' имеет значение cups.
+
+Этот параметр определяет количество секунд, в течение которых smbd будет ждать, пытаясь связаться с сервером CUPS. Соединение не будет установлено, если оно займет больше времени, чем указанное количество секунд.
+
+Значение по умолчанию:
+30
+
+Пример:
+60</string>
+ <string id="POL_AB9D00A2_AB72_5D21_94C6_8EC1238F2793">cups encrypt</string>
+ <string id="POL_AB9D00A2_AB72_5D21_94C6_8EC1238F2793_Help">Этот параметр применим только в том случае, только если параметр 'printing' имеет значение cups и если используется CUPS новее 1.0.x. Параметр используется для определения, следует ли Samba использовать шифрование при разговоре с сервером CUPS. Возможные значения: auto, yes и no.
+
+Если установлено значение auto, будут предприняты попытки выполнить шифрование TLS при каждой настройке подключения CUPS. Если это не удастся, Samba вернётся к незашифрованной работе.
+
+Значение по умолчанию:
+no</string>
+ <string id="POL_CDEAD263_A87A_550A_A067_3FF8C0C60986">cups server</string>
+ <string id="POL_CDEAD263_A87A_550A_A067_3FF8C0C60986_Help">Этот параметр применим, только если параметр 'printing' имеет значение cups.
+
+Если этот параметр установлен, он переопределяет параметр ServerName в CUPS client.conf. Это необходимо, если у вас есть виртуальные серверы Samba, которые подключаются к разным демонам CUPS.
+
+При желании можно указать порт, отделив имя сервера и номер порта двоеточием. Если порт не указан, будет использоваться порт по умолчанию для IPP (631).
+
+Значение по умолчанию:
+""
+
+Пример:
+mycupsserver
+
+Пример:
+mycupsserver:1631</string>
+ <string id="POL_7CC90037_633A_5C8D_99C5_380E6B2E1EF0">deleteprinter command</string>
+ <string id="POL_7CC90037_633A_5C8D_99C5_380E6B2E1EF0_Help">С введением поддержки принтеров на основе MS-RPC для клиентов Windows NT/2000 в Samba 2.2 стало возможно удалять принтер во время выполнения, выполнив RPC запрос DeletePrinter().
+
+Для хоста Samba это означает, что принтер должен быть физически удален из базовой системы печати. Параметр 'deleteprinter command' определяет сценарий, который выполнит необходимые операции для удаления принтера из системы печати и из smb.conf.
+
+Команда удаления принтера автоматически вызывается только с одним параметром: имя принтера.
+
+После выполнения команды удаления принтера, smbd повторно анализирует smb.conf на предмет существования принтера. Если общий ресурс все еще существует, то smbd вернет клиенту ошибку ACCESS_DENIED.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/bin/removeprinter</string>
+ <string id="POL_60B548F0_E8B3_576F_B520_D4954AF3ED8E">disable spoolss</string>
+ <string id="POL_60B548F0_E8B3_576F_B520_D4954AF3ED8E_Help">Включение этого параметра отключит поддержку в Samba SPOOLSS для MS-RPC и приведет к поведению идентичному Samba 2.0.x. Клиенты Windows NT/2000 перейдут к использованию команд печати в стиле Lanman. Этот параметр не повлияет на Windows 9x/ME. Однако он также отключит возможность загрузки драйверов принтера на сервер Samba с помощью мастера добавления принтера Windows NT или используя диалоговое окно свойств принтера NT. Также будет отключена возможность загрузки по требованию драйверов печати с главного компьютера Samba для клиентов Windows NT/2000. Будьте очень осторожны при использовании этого параметра.
+
+Значение по умолчанию:
+disable spoolss = no</string>
+ <string id="POL_EAFBD5E6_54EC_5776_A757_5401DE77BBCE">enable spoolss</string>
+ <string id="POL_EAFBD5E6_54EC_5776_A757_5401DE77BBCE_Help">Включение этого параметра включит поддержку в Samba SPOOLSS для MS-RPО.
+
+См. описание опции 'disable spoolss'.
+
+Значение по умолчанию:
+enable spoolss = yes</string>
+ <string id="POL_88C2E1AE_E15B_561A_83B3_A7A7610CB3A2">enumports command</string>
+ <string id="POL_88C2E1AE_E15B_561A_83B3_A7A7610CB3A2_Help">Понятие «порт» довольно чуждо компьютерам UNIX. У серверов печати Windows NT/2000, порт связан с локальным портом компьютера (например, LPT1:, COM1:, FILE:) или удаленным портом (например, LPD Port Monitor,, и т.д.). По умолчанию в Samba определен только один порт — «Samba Printer Port». В Windows NT/2000 все принтеры должны иметь допустимое имя порта. Если необходимо иметь список отображенных портов (smbd, не использует имя порта для чего-нибудь), отличное от заданного по умолчанию «Samba Printer Port», можно определить параметр 'enumports command', чтобы указать на программу, которая должна генерировать список портов, по одному на строку, в стандартный вывод. Этот список затем будет использоваться в ответ на запросы уровней 1 и 2 EnumPorts() RPC.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/bin/listports</string>
+ <string id="POL_5247D3AE_60E1_526B_B3A0_956818E2EA49">iprint server</string>
+ <string id="POL_5247D3AE_60E1_526B_B3A0_956818E2EA49_Help">Параметр применим только если параметр 'printing' имеет значение iprint. Если установлено, то параметр перекрывает опцию ServerName в файле CUPS client.conf. Это нужно, если у вас есть виртуальные сервера Samba, подключенные к разным CUPS демонам.
+
+Значение по умолчанию:
+""
+
+Пример:
+MYCUPSSERVER</string>
+ <string id="POL_A6ACC104_2480_55A0_A53C_D38DFF7A093B">load printers</string>
+ <string id="POL_A6ACC104_2480_55A0_A53C_D38DFF7A093B_Help">Булево значение, которое определяет все ли принтеры, будут загружены для просмотра по умолчанию. Смотрите секцию принтеры для получения более подробной информации.
+
+Значение по умолчанию:
+load printers = yes</string>
+ <string id="POL_5CC89C3B_45B2_5C52_ADE0_79FB968E5EDE">lpq cache time</string>
+ <string id="POL_5CC89C3B_45B2_5C52_ADE0_79FB968E5EDE_Help">Этот параметр контролирует то, как долго информация об lpq будет храниться в кэше для избежания слишком частых вызовов lpq. Для каждого пользователя хранится свой вариант кэша lpq, так что различные пользователи НЕ будут использовать одну и ту же информацию из кэша.
+
+Файлы кэша хранятся в /tmp/lpq.xxxx где xxxx — хэш команды lpq.
+
+Значение по умолчанию 30 секунд, означающее, что будут использоваться результаты выполнения команды из кэша, если она выполнена менее чем 30 секунд назад. Большое значение может быть полезным, если выполнение команд lpq в вашем случае очень медленное. Значение 0 вообще отменит кэширование.
+
+Значение по умолчанию:
+30
+
+Пример:
+10</string>
+ <string id="POL_45819251_B577_5069_AA0C_AD798BFDC903">os2 driver map</string>
+ <string id="POL_45819251_B577_5069_AA0C_AD798BFDC903_Help">Параметр используется для определения абсолютного пути к файлу, содержащему схему преобразования имен драйверов принтеров Windows NT к схеме OS/2. Формат следующий:
+
+ &lt;nt driver name&gt; = &lt;os2 driver name&gt;.&lt;device name&gt;
+
+Например, для имени драйвера принтера HP LaserJet 5 запись будет иметь вид HP LaserJet 5L = LASERJET.HP LaserJet 5L.
+
+Необходимость в этом файле связана с проблемой пространства имен драйвера принтера, описанной в разделе «Classical Printing» руководства Samba3-HOWTO. Для получения более подробной информации по клиентам OS/2, смотрите раздел «по другим клиентам» руководства Samba3-HOWTO.
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_40CAC79E_549A_5AAA_8FD3_DDF6FDC3EF35">printcap cache time</string>
+ <string id="POL_40CAC79E_549A_5AAA_8FD3_DDF6FDC3EF35_Help">Этот параметр указывает количество секунд, через которое подсистема печати будет опрошена о состоянии принтеров.
+
+Установка для этого параметра значения 0 отключает любое повторное сканирование новых или удаленных принтеров после первоначального запуска демона.
+
+Значение по умолчанию:
+750
+
+Пример:
+600</string>
+ <string id="POL_A0530959_BE77_53B1_82AC_B3E11CA6D2D8">printcap name</string>
+ <string id="POL_A0530959_BE77_53B1_82AC_B3E11CA6D2D8_Help">Этот параметр может быть использован для переопределения скомпилированного printcap name, используемого сервером (обычно /etc/printcap). В секции [printers] (smb.conf(5)) описано, почему это может потребоваться.
+
+Для использования интерфейса CUPS установите 'printcap name = cups'. Это должно быть подкреплено дополнительно установкой параметра 'printing = cups' в секции [global]. 'printcap name = cups' будет использовать «фиктивный» («dummy») printcap, созданный CUPS, как указано в конфигурационном файле CUPS.
+
+В системах System V, которые используют lpstat для получения списка доступных принтеров, для этих целей можно использовать 'printcap name = lpstat'. Это значение по умолчанию для систем, которые определяют SYSV во время настройки в Samba (это большинство ОС основанных на System V). Если в этих системах параметр 'printcap name' установлен в значение lpstat, тогда Samba запустит команду 'lpstat -v' и попытается проанализировать вывод, чтобы получить список принтеров.
+
+Минимальный файл printcap будет выглядеть примерно так:
+
+print1|My Printer 1
+print2|My Printer 2
+print3|My Printer 3
+print4|My Printer 4
+print5|My Printer 5
+
+где знак ‘|’ разделяет псевдонимы принтеров. Тот факт, что во втором псевдониме есть пробел подсказывает Samba, что это комментарий.
+
+Замечание: В ОС AIX значением параметра 'printcap name' по умолчанию является /etc/qconfig. Samba предполагает, что файл имеет формат AIX, если встретит подстроку qconfig в пути к файлу.
+
+Значение по умолчанию:
+/etc/printcap
+
+Пример:
+/etc/myprintcap</string>
+ <string id="POL_73B2297D_6138_544A_BAF8_A31CC8192C22">show add printer wizard</string>
+ <string id="POL_73B2297D_6138_544A_BAF8_A31CC8192C22_Help">С появлением в Samba 2.2 поддержки печати, основанной на MS-RPC клиентов Windows NT/2000, будет видна папка «Принтеры» на компьютере с Samba. Обычно эта папка содержит ярлык к «мастеру установки принтеров» («MS Add Printer Wizard»). Однако эту функцию можно отключить, причем, несмотря на привилегии пользователя.
+
+В нормальной ситуации клиент Windows NT/2000 обращается к серверу печати с помощью OpenPrinterEx(), запросив права администратора. Если у пользователя нет доступа к серверу печати (например, он НЕ root и не член группы printer admin), вызов OpenPrinterEx() завершится неудачей и клиент выполняет еще один вызов, который требует более низких привилегий. Этот запрос должен пройти успешно, но иконка «мастера установки принтера» не будет показана. Отключение параметра 'show add printer wizard' предопределит вызов OpenPrinterEx() — он всегда будет завершаться неудачей. Таким образом, иконка никогда не будет показана.
+
+Замечание:
+Это не запрещает пользователю иметь административные права на какой-либо принтер.
+
+Значение по умолчанию:
+show add printer wizard = yes</string>
+ <string id="POL_3CD8EF2C_23D9_58C5_A92C_3E1C2E4F3A4A">spoolss: architecture</string>
+ <string id="POL_3CD8EF2C_23D9_58C5_A92C_3E1C2E4F3A4A_Help">Клиенты печати Windows с буферизацией позволяют связывать серверные драйверы с принтерами только в том случае, если архитектура драйвера соответствует объявленной архитектуре сервера печати. С помощью этого параметра можно изменить архитектуру сервера печати с буфером печати Samba.
+
+Значение по умолчанию:
+Windows NT x86
+
+Пример:
+Windows x64</string>
+ <string id="POL_DE5BD97B_EB5B_571A_98EE_814B2C006262">spoolss: os_major</string>
+ <string id="POL_DE5BD97B_EB5B_571A_98EE_814B2C006262_Help">Windows может потребоваться новый номер версии ОС. Эта опция позволяет изменить номер сборки. Полный номер версии по умолчанию: 5.0.2195 (Windows 2000). Например, 6.1.7601 (Windows 2008 R2).
+
+Значение по умолчанию:
+5
+
+Пример:
+6</string>
+ <string id="POL_5EB4315D_6DDE_50E9_A228_2F5062CB23B9">spoolss: os_minor</string>
+ <string id="POL_5EB4315D_6DDE_50E9_A228_2F5062CB23B9_Help">Windows может потребоваться новый номер версии ОС. Эта опция позволяет изменить номер сборки. Полный номер версии по умолчанию: 5.0.2195 (Windows 2000). Например, 6.1.7601 (Windows 2008 R2).
+
+Значение по умолчанию:
+0
+
+Пример:
+1</string>
+ <string id="POL_FEE2B5DC_E367_5173_8A6A_43EB82F22680">spoolss: os_build</string>
+ <string id="POL_FEE2B5DC_E367_5173_8A6A_43EB82F22680_Help">Windows может потребоваться новый номер версии ОС. Эта опция позволяет изменить номер сборки. Полный номер версии по умолчанию: 5.0.2195 (Windows 2000). Например, 6.1.7601 (Windows 2008 R2).
+
+Значение по умолчанию:
+2195
+
+Пример:
+7601</string>
+ <string id="POL_6E7AC428_65F6_5006_97A7_B985AE445E43">spoolss_client: os_major</string>
+ <string id="POL_6E7AC428_65F6_5006_97A7_B985AE445E43_Help">Windows может потребоваться новый номер версии ОС. Эта опция позволяет изменить номер сборки. Полный номер версии по умолчанию: 6.1.7007 (Windows 7 и Windows Server 2008 R2).
+
+Значение по умолчанию:
+6</string>
+ <string id="POL_732E108C_5701_547E_903E_6112EDF3E999">spoolss_client: os_minor</string>
+ <string id="POL_732E108C_5701_547E_903E_6112EDF3E999_Help">Windows может потребоваться новый номер версии ОС. Эта опция позволяет изменить номер сборки. Полный номер версии по умолчанию: 6.1.7007 (Windows 7 и Windows Server 2008 R2).
+
+Значение по умолчанию:
+1</string>
+ <string id="POL_CBC8563A_7BEB_54F3_8554_74815EF130DF">spoolss_client: os_build</string>
+ <string id="POL_CBC8563A_7BEB_54F3_8554_74815EF130DF_Help">Windows может потребоваться новый номер версии ОС. Эта опция позволяет изменить номер сборки. Полный номер версии по умолчанию: 6.1.7007 (Windows 7 и Windows Server 2008 R2).
+
+Значение по умолчанию:
+7007</string>
+ <string id="POL_A51777A2_FA82_5D61_B7E1_9B223537A750">cldap port</string>
+ <string id="POL_A51777A2_FA82_5D61_B7E1_9B223537A750_Help">Эта опция контролирует порт, используемый протоколом CLDAP.
+
+Значение по умолчанию:
+389
+
+Пример:
+3389</string>
+ <string id="POL_E2162FCB_2AF4_5BED_8254_84C87787CAA8">client ipc max protocol</string>
+ <string id="POL_E2162FCB_2AF4_5BED_8254_84C87787CAA8_Help">Значение параметра (строка) — это самый высокий уровень протокола, который будет поддерживаться для соединений IPC$ в качестве транспорта DCERPC.
+
+Обычно этот параметр не следует устанавливать, так как фаза автоматического согласования в протоколе SMB сама заботится о выборе подходящего протокола.
+
+Значение default относится к последнему поддерживаемому протоколу, в настоящее время это SMB3_11.
+
+См. полный список доступных протоколов в описании параметра 'client max protocol'. Значения CORE, COREPLUS, LANMAN1, LANMAN2 автоматически обновляются до NT1.
+
+Значение по умолчанию:
+default
+
+Пример:
+SMB2_10</string>
+ <string id="POL_86DD41DB_D3AE_5445_8E2D_335E8182ECDF">client ipc min protocol</string>
+ <string id="POL_86DD41DB_D3AE_5445_8E2D_335E8182ECDF_Help">Значение параметра (строка) — это самый минимальный уровень протокола, который будет поддерживаться для соединений IPC$ в качестве транспорта DCERPC.
+
+Обычно этот параметр не следует устанавливать, так как фаза автоматического согласования в протоколе SMB сама заботится о выборе подходящего протокола.
+
+Значение default относится к последнему поддерживаемому протоколу, в настоящее время это SMB3_11.
+
+См. полный список доступных протоколов в описании параметра 'client max protocol'. Значения CORE, COREPLUS, LANMAN1, LANMAN2 автоматически обновляются до NT1.
+
+Значение по умолчанию:
+default
+
+Пример:
+SMB3_11</string>
+ <string id="POL_8E18914D_E4D5_5B9E_8641_02F84DEA8092">client max protocol</string>
+ <string id="POL_8E18914D_E4D5_5B9E_8641_02F84DEA8092_Help">Значение параметра (строка) — это самый высокий уровень протокола, который будет поддерживаться клиентом.
+
+Возможные значения:
+
+ * CORE: Самая ранняя версия. Концепция имен пользователей отсутствует.
+ * COREPLUS: Небольшие улучшения в CORE для повышения эффективности.
+ * LANMAN1: Первая современная версия протокола. Поддержка длинных файлов.
+ * LANMAN2: Обновление протокола Lanman1.
+ * NT1: Текущая последняя версия протокола. Используется Windows NT. Известна как CIFS.
+ * SMB2: Повторная реализация протокола SMB. Используется Windows Vista и более поздними версиями Windows. SMB2 имеет подпротоколы.
+ * SMB2_02: Самая ранняя версия SMB2.
+ * SMB2_10: Версия Windows 7 SMB2.
+ * SMB2_22: Ранняя версия Windows 8 SMB2.
+ * SMB2_24: Бета-версия SMB2 для Windows 8.
+ По умолчанию SMB2 выбирает вариант SMB2_10.
+ * SMB3: То же, что и SMB2. Используется Windows 8. SMB3 имеет подпротоколы.
+ * SMB3_00: Версия Windows 8 SMB3 (в основном то же, что и SMB2_24).
+ * SMB3_02: Версия Windows 8.1 SMB3.
+ * SMB3_10: Ранняя техническая предварительная версия Windows 10 SMB3.
+ * SMB3_11: Техническая предварительная версия Windows 10 SMB3 (возможно, окончательная).
+ По умолчанию SMB3 выбирает вариант SMB3_11.
+
+Обычно эту опцию не следует устанавливать, поскольку фаза автоматического согласования в протоколе SMB сама заботится о выборе подходящего протокола.
+
+Значение default относится к SMB3_11.
+
+IPC$ соединения для DCERPC, например в winbindd, обрабатываются опцией 'client ipc max protocol'.
+
+Значение по умолчанию:
+default
+
+Пример:
+LANMAN1</string>
+ <string id="POL_277C30D1_A2C2_5AB4_8748_A9ECC063AE91">client min protocol</string>
+ <string id="POL_277C30D1_A2C2_5AB4_8748_A9ECC063AE91_Help">Этот параметр определяет минимальную версию протокола, которую клиент попытается использовать.
+
+Обычно этот параметр не следует устанавливать, поскольку фаза автоматического согласования в протоколе SMB сама заботится о выборе подходящего протокола (если не происходит подключение к устаревшему серверу, поддерживающему только SMB1).
+
+См. полный список доступных протоколов в описании параметра 'client max protocol'.
+
+IPC$ соединения для DCERPC, например в winbindd обрабатываются опцией 'client ipc min protocol'.
+
+Обратите внимание, что большинство инструментов командной строки поддерживают --option = 'client min protocol = NT1', поэтому может не потребоваться глобальное включение протоколов SMB1 в smb.conf.
+
+Значение по умолчанию:
+SMB2_02
+
+Пример:
+NT1</string>
+ <string id="POL_89A40B64_721B_55DF_841D_C3481F32C2FF">client use spnego</string>
+ <string id="POL_89A40B64_721B_55DF_841D_C3481F32C2FF_Help">Этот параметр устарел, начиная с Samba 4.13, и поддержка аутентификации NTLMv2, NTLM и LanMan без NTLMSSP будет удалена в следующем выпуске Samba.
+
+То есть в будущем параметр 'client use spnego' будет установлен по умолчанию.
+
+Эта переменная определяет, будут ли клиенты Samba пытаться использовать простой и защищенный NEGOtiation (как указано в rfc2478) с поддерживающими серверами (включая WindowsXP, Windows2000 и Samba 3.0) для согласования механизма аутентификации. Это, в частности, включает проверку подлинности Kerberos.
+
+Когда этот параметр установлен, для использования NTLMv2 только в рамках NTLMSSP требуется расширенная безопасность (SPNEGO). Такое поведение было введено в исправлениях для CVE-2016-2111.
+
+Значение по умолчанию:
+client use spnego = yes</string>
+ <string id="POL_FCF4AF88_1B2D_5A6E_B630_7E88FA13F4EB">dcerpc endpoint servers</string>
+ <string id="POL_FCF4AF88_1B2D_5A6E_B630_7E88FA13F4EB_Help">Указывает, какие серверы конечных точек DCE/RPC должны быть запущены.
+
+Значение по умолчанию:
+epmapper, wkssvc, rpcecho, samr, netlogon, lsarpc, drsuapi, dssetup, unixinfo, browser, eventlog6, backupkey, dnsserver
+
+Пример:
+rpcecho</string>
+ <string id="POL_73CE9581_7CF3_5CD8_ABBD_3DD273E7ED10">defer sharing violations</string>
+ <string id="POL_73CE9581_7CF3_5CD8_ABBD_3DD273E7ED10_Help">При открытии файла Windows позволяет определять, как файл будет использоваться совместно несколькими процессами. Ошибки совместного доступа возникают, когда файл открывается другим процессом с параметрами, которые нарушают общие параметры, заданные другими процессами. Этот параметр заставляет smbd действовать как сервер Windows и задерживать сообщение об ошибке совместного доступа («sharing violation») на срок до одной секунды, позволяя клиенту вызвавшему нарушение закрыть файл.
+
+По умолчанию UNIX так себя не ведет.
+
+Не отключайте этот параметр, так как он предназначен для того, чтобы Samba могла более корректно эмулировать Windows.
+
+Значение по умолчанию:
+defer sharing violations = yes</string>
+ <string id="POL_951C9DAC_2C21_58B0_8B22_D9D2CCEB1755">dgram port</string>
+ <string id="POL_951C9DAC_2C21_58B0_8B22_D9D2CCEB1755_Help">Указывает, на каких портах сервер должен прослушивать пакеты NetBIOS.
+
+Значение по умолчанию:
+138</string>
+ <string id="POL_401F735E_7E1F_5EBC_A3E3_9642A9F023DA">disable netbios</string>
+ <string id="POL_401F735E_7E1F_5EBC_A3E3_9642A9F023DA_Help">Включение этого параметра отключит поддержку NetBIOS в Samba. NetBIOS — единственная доступная форма просмотра во всех версиях Windows, кроме 2000 и XP.
+
+Обратите внимание, что если поддержка NetBIOS отключена, клиенты, которые поддерживают только NetBIOS, не смогут видеть сервер Samba.
+
+Значение по умолчанию:
+disable netbios = no </string>
+ <string id="POL_6BB5884D_D948_5765_B165_FCB496E3A64A">enable asu support</string>
+ <string id="POL_6BB5884D_D948_5765_B165_FCB496E3A64A_Help">Компьютеры, использующие продукты «Advanced Server for Unix (ASU)» требуют создания общего ресурса [ADMIN$] для поддержания IPC соединений. Уже много лет это поведение по умолчанию в smbd. Однако, некоторые приложения Microsoft, такие как Print Migrator tool, требуют, чтобы удаленный сервер поддерживал общий ресурс [ADMIN$]. Отключение этого параметра разрешает создавать общий ресурс [ADMIN$] в файле smb.conf.
+
+Значение по умолчанию:
+enable asu support = no
+</string>
+ <string id="POL_D389B35D_C2C8_5971_A195_FBD8C0AAC94C">eventlog list</string>
+ <string id="POL_D389B35D_C2C8_5971_A195_FBD8C0AAC94C_Help">Эта опция определяет список лог файлов, которые Samba по запросу отправляет утилите Microsoft EventViewer. Перечисленные журналы будут связаны с tdb-файлом на диске в $(statedir)/eventlog.
+
+Администратор должен использовать внешний процесс, чтобы распарсить обычные файлы Unix-логов, такие как /var/log/messages и затем записывать информацию в tdb-файлы журнала событий. Обратитесь к eventlogadm(8) утилите для того, чтобы узнать, как записывать записи в журнал событий (eventlog).
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+Security Application Syslog Apache
+</string>
+ <string id="POL_04CE2D0D_386E_5CA3_B450_F1BC9FC9CC9B">large readwrite</string>
+ <string id="POL_04CE2D0D_386E_5CA3_B450_F1BC9FC9CC9B_Help">Этот параметр определяет, поддерживает ли smbd(8) новый 64-килобайтный поток чтения записи SMB запросов введенный в Windows 2000. Обратите внимание, что из-за ошибок редиректа клиентов Windows 2000 требуется, чтобы Samba работала в 64-разрядной операционной системе, такой как IRIX, Solaris или ядро Linux 2.4. При использовании возможно увеличение производительности на 10% с клиентами Windows 2000. Не протестирован с другими частями кода Samba.
+
+Значение по умолчанию:
+large readwrite = yes</string>
+ <string id="POL_63F5048E_6174_5012_8637_738DD79034E5">lsa over netlogon</string>
+ <string id="POL_63F5048E_6174_5012_8637_738DD79034E5_Help">Установка этого устаревшего параметра позволит серверу RPC в AD DC отвечать интерфейсу LSARPC на канале IPC \pipe\netlogon.
+
+Если параметр включен, это соответствует поведению Microsoft Windows из-за их внутреннего выбора реализации.
+
+Если параметр отключен (по умолчанию), AD DC может предложить улучшенную производительность, поскольку сервер входа в сеть отделен и может работать как несколько процессов.
+
+Значение по умолчанию:
+lsa over netlogon = no</string>
+ <string id="POL_87E8C778_F6AC_5666_8855_D40F11853504">max mux</string>
+ <string id="POL_87E8C778_F6AC_5666_8855_D40F11853504_Help">Этот параметр контролирует максимальное количество невыполненных одновременных операций SMB2, которое Samba разрешает клиенту. Никогда не нужно менять значение этого параметра.
+
+Значение по умолчанию:
+50</string>
+ <string id="POL_E754670E_4295_5CAC_8817_8C848E31BA0B">max ttl</string>
+ <string id="POL_E754670E_4295_5CAC_8817_8C848E31BA0B_Help">Этот параметр сообщает демону smbd(8), какое по умолчанию «время жизни» («time to live») NetBIOS-имён должно быть (в секундах), когда nmbd запрашивает имя с помощью широковещательного пакета или с WINS-сервера. Никогда не нужно изменять значение этого параметра. Значение по умолчанию 3 дня.
+
+Значение по умолчанию:
+259200</string>
+ <string id="POL_0AAACA11_DE41_5664_A306_F44D752598C5">max xmit</string>
+ <string id="POL_0AAACA11_DE41_5664_A306_F44D752598C5_Help">Эта опция задаёт максимальный размер пакета, который будет согласован между Samba и smbd(8) для установления соединения по протоколу SMB1. Значение по умолчанию 16644, что соответствует поведению Windows 2000. Значение ниже 2048 скорее всего вызывет проблемы. Никогда не нужно изменять значение этого параметра.
+
+Значение по умолчанию:
+16644
+
+Пример:
+8192
+</string>
+ <string id="POL_24E58521_FFD2_5ADE_A9C8_4050EE408BC2">min receivefile size</string>
+ <string id="POL_24E58521_FFD2_5ADE_A9C8_4050EE408BC2_Help">Этот параметр изменяет поведение smbd(8) при обработке вызовов SMBwriteX. Любой входящий вызов SMBwriteX в неподписанном соединении SMB/CIFS, превышающий это значение, не будет обрабатываться обычным способом, но будет передан любому базовому вызову recvfile ядра или системному вызову splice (если такого вызова нет, Samba будет эмулировать в пользовательском пространстве). Это позволяет записывать zero-copy непосредственно из буферов сетевых сокетов в буферный кэш файловой системы, если таковой имеется. Это может улучшить производительность, но рекомендуется пользовательское тестирование. Если установлено значение 0, Samba обрабатывает вызовы SMBwriteX как обычно. Чтобы включить поддержку большой записи POSIX (SMB/CIFS записывает до 16 МБ), этот параметр должен быть ненулевым. Максимальное значение 128к. Значения больше 128k будут автоматически установлены на 128k.
+
+Обратите внимание, что этот параметр не будет иметь ЭФФЕКТА, если он установлен для подключения с подписью SMB.
+
+По умолчанию — 0, что отключает эту опцию.
+
+Значение по умолчанию:
+0</string>
+ <string id="POL_1DDE423B_1CCB_5179_87D3_1FEE7D4CA621">name resolve order</string>
+ <string id="POL_1DDE423B_1CCB_5179_87D3_1FEE7D4CA621_Help">Этот параметр используется программами из набора Samba для определения того, какие сервисы имен использовать и в каком порядке разрешать имена хостов в IP-адреса. Его основная цель — управлять тем, как выполняется разрешение имен NetBIOS. В этом параметре указываются строковые значения разделенные пробелами.
+
+Возможные значения: lmhosts, host, wins и bcast&quot;. Они означают:
+
+ * lmhosts — искать IP-адрес в файле Samba lmhosts. Если в строке файла lmhosts не указан тип имени NetBIOS (см. man lmhosts), то для поиска подходит любой тип имени.
+
+ * host — произвести стандартную трансляцию имени хоста в IP-адрес, используя /etc/hosts, NIS или DNS запрос. Этот метод разрешения зависит от операционной системы, например в IRIX или Solaris, им можно управлять с помощью файла /etc/nsswitch.conf. Обратите внимание на то, что этот метод используется только тогда, когда тип запрашиваемого имени NetBIOS 0×20 (server) или 0×1c (domain controllers). Последний случай применим только для доменов AD и в результате будет DNS запрос для вхождения SRV RR соответсвующего _ldap._tcp.domain.
+
+ * wins — определить IP-адрес по имени, обозначенном в параметре 'wins server'. Если сервер WINS не указан, то метод будет проигнорирован.
+
+ * bcast — сделать широковещательный запрос по всем интерфейсам, перечисленным в параметре 'interfaces'. Это наименее надежный из методов разрешения имен, поскольку он зависит от того, находится ли целевой хост в локальной подсети.
+
+Пример ниже обозначает следующий порядок: сначала искать в локальном файле lmhosts, затем выполнить широковещательный запрос, затем использовать средства операционной системы.
+
+Рекомендуется использовать следующие настройки при работе Samba в режиме 'security = ads':
+
+name resolve order = wins bcast
+
+Запросы домен-контроллера все еще будут выполняться с помощью DNS, но в случае отката на имена NetBIOS, не затопит DNS-сервера запросами типа DOMAIN&lt;0x1c&gt; lookups.
+
+Значение по умолчанию:
+lmhosts host wins bcast
+
+Пример:
+lmhosts bcast host</string>
+ <string id="POL_B1C3F6FC_E4FB_58A7_9CE4_50090EF8FF17">nbt port</string>
+ <string id="POL_B1C3F6FC_E4FB_58A7_9CE4_50090EF8FF17_Help">Указывает, какой порт должен использовать сервер для трафика NetBIOS через службы IP-имен.
+
+Значение по умолчанию:
+137</string>
+ <string id="POL_E2A4C01A_1EFC_5826_9D3A_A4AD065518EF">nt pipe support</string>
+ <string id="POL_E2A4C01A_1EFC_5826_9D3A_A4AD065518EF_Help">Этот параметр определяет, будет ли демон smbd(8) позволять клиентам Windows NT подсоединяться к ресурсам IPC$ (характерным для NT SMB). Эта опция сделана в отладочных целях (для разработчиков), поэтому не нужно изменять её значение.
+
+Значение по умолчанию:
+nt pipe support = yes</string>
+ <string id="POL_C1F0941D_67B4_55EA_A915_6F5E9A945E57">nt status support</string>
+ <string id="POL_C1F0941D_67B4_55EA_A915_6F5E9A945E57_Help">Этот параметр определяет, будет ли демон smbd(8) объявлять поддержку специфического статуса NT при работе с клиентами Windows NT/2k/XP. Параметр создан разработчиками для отладки, поэтому не нужно изменять её значение. Если 'nt status support = no', то Samba будет генерировать ошибки DOS аналогично версии 2.2.3 и ниже.
+
+Никогда не нужно отключать этот параметр (устанавливать значение 'nt status support = no').
+
+Значение по умолчанию:
+nt status support = yes</string>
+ <string id="POL_CDB6A4B8_D076_5332_9EA2_CC994C8B45C7">read raw</string>
+ <string id="POL_CDB6A4B8_D076_5332_9EA2_CC994C8B45C7_Help">Этот параметр игнорируется, если установлен параметр 'async smb echo handler', потому что эта функция несовместима с необработанными запросами чтения SMB.
+
+Если параметр включен, «сырые запросы» (raw reads) будут передаваться по 65535 байт в одном пакете. Обычно это дает значительный прирост производительности для очень и очень старых клиентов.
+
+Однако некоторые клиенты либо неправильно согласовывают допустимый размер блока, либо не могут поддерживать большие размеры блока, и для этих клиентов может потребоваться отключить этот параметр.
+
+Этот параметр следует рассматривать как инструмент настройки системы и не изменять его значение.
+
+Значение по умолчанию:
+read raw = yes
+</string>
+ <string id="POL_F9AD06B5_1870_5BE4_87A9_08E3821667E4">rpc big endian</string>
+ <string id="POL_F9AD06B5_1870_5BE4_87A9_08E3821667E4_Help">Установка этого параметра заставит RPC-клиент и сервер передавать данные с обратным порядком следования байтов (big endian).
+
+Если этот параметр не установлен, данные будут передаваться с прямым порядком следования байтов (little endian).
+
+Поведение не зависит от порядка байтов хоста.
+
+Значение по умолчанию:
+rpc big endian = no</string>
+ <string id="POL_380E7843_58D7_505E_9092_392FE1FC4BA2">rpc server port</string>
+ <string id="POL_380E7843_58D7_505E_9092_392FE1FC4BA2_Help">Указывает, какой порт сервер должен прослушивать для трафика DCE/RPC через TCP/IP.
+
+Этот параметр управляет портом по умолчанию для всех протоколов, кроме NETLOGON.
+
+Если параметр не установлен, используется первый доступный порт из диапазона динамических портов сервера RPC, например 49152.
+
+Сервер NETLOGON будет использовать следующий доступный порт, например 49153. Можно изменить этот порт, например, 'rpc server port:netlogon = 4000'.
+
+Кроме того, все можно указать порт независимо для каждого сервера RPC, например, 'rpc server port:drsuapi = 5000'.
+
+Этот параметр в настоящее время применяется только тогда, когда samba(8) работает как контроллер домена Active Directory.
+
+Значение по умолчанию 0 заставляет Samba выбирать первый доступный порт из динамического диапазона портов сервера RPC (параметр 'rpc server dynamic port range').
+
+Значение по умолчанию:
+0</string>
+ <string id="POL_D910FC29_975B_5105_97C8_BD75D68FDC5F">server max protocol</string>
+ <string id="POL_D910FC29_975B_5105_97C8_BD75D68FDC5F_Help">Значение параметра (строка) — это самый высокий уровень протокола, который будет поддерживаться сервером.
+
+Возможные значения:
+ * LANMAN1: Первая современная версия протокола. Поддержка длинных файлов.
+ * LANMAN2: Обновление протокола Lanman1.
+ * NT1: Текущая последняя версия протокола. Используется Windows NT. Известная как CIFS.
+ * SMB2: повторная реализация протокола SMB. Используется Windows Vista и более поздними версиями Windows. SMB2 имеет подпротоколы:
+ * SMB2_02: самая ранняя версия SMB2.
+ * SMB2_10: версия Windows 7 SMB2.
+ * SMB2_22: Ранняя версия Windows 8 SMB2.
+ * SMB2_24: бета-версия SMB2 для Windows 8.
+ По умолчанию SMB2 выбирает вариант SMB2_10.
+ * SMB3: тоже, что и SMB2. Используется в Windows 8. SMB3 имеет подпротоколы:
+ * SMB3_00: версия SMB3 для Windows 8 (в основном то же, что и SMB2_24).
+ * SMB3_02: версия SMB3 Windows 8.1.
+ * SMB3_10: техническая предварительная версия SMB3 для ОС до Windows 10.
+ * SMB3_11: техническая предварительная версия SMB3 для Windows 10 (возможно окончательная).
+ По умолчанию SMB3 выбирает вариант SMB3_11.
+
+Эта опция не должна устанавливаться при нормальном режиме работы, т.к. протокол SMB сам позаботиться о выборе подходящего протокола на стадии автоматического согласования параметров.
+
+Значение по умолчанию:
+SMB3
+
+Пример:
+LANMAN1</string>
+ <string id="POL_98D56061_466A_5DDE_BFF3_8A194DE5FE2E">server min protocol</string>
+ <string id="POL_98D56061_466A_5DDE_BFF3_8A194DE5FE2E_Help">Этот параметр определяет минимальную версию протокола, которую сервер разрешает использовать клиенту.
+
+Эта опция не должна устанавливаться при нормальном режиме работы, т.к. протокол SMB сам позаботиться о выборе подходящего протокола на стадии автоматического согласования параметров, если только у вас нет устаревших клиентов, поддерживающих только SMB1.
+
+См. полный список доступных протоколов в описании параметра 'server max protocol'.
+
+Значение по умолчанию:
+SMB2_02
+
+Пример:
+NT1</string>
+ <string id="POL_2A034462_D418_5914_B24C_6535DD368A66">share:fake_fscaps</string>
+ <string id="POL_2A034462_D418_5914_B24C_6535DD368A66_Help">Этот параметр необходим для поддержки некоторого специального приложения, которое вызывает QFSINFO, чтобы проверить, установлен ли бит SPARSE_FILES (0x40). Если этот бит не установлен, то конкретное приложение отказывается работать с Samba. При 'share:fake_fscaps = 64' устанавливается флаг возможности файловой системы SPARSE_FILES. Используйте другие десятичные значения, чтобы указать битовую маску, которую нужно подделать.
+
+Значение по умолчанию:
+0</string>
+ <string id="POL_A3F9ABC7_494B_5007_B5A1_1DA0B9FC345D">smb2 max credits</string>
+ <string id="POL_A3F9ABC7_494B_5007_B5A1_1DA0B9FC345D_Help">Этот параметр контролирует максимальное количество невыполненных одновременных операций SMB2, которое Samba разрешает клиенту. Аналогичен параметру 'max mux' для SMB1. Никогда не нужно менять значение этого параметра.
+
+Значение по умолчанию — 8192 credits, что аналогично серверу SMB2 в Windows 2008R2.
+
+Значение по умолчанию:
+8192</string>
+ <string id="POL_209C2DE8_5843_50FC_9B61_A3F3EBFE95B5">smb2 max read</string>
+ <string id="POL_209C2DE8_5843_50FC_9B61_A3F3EBFE95B5_Help">Эта опция определяет значение протокола, которое smbd(8) будет возвращать клиенту, информируя клиента о самом большом размере, который может быть возвращен одним вызовом чтения SMB2.
+
+Максимальный размер составляет 8388608 байт (8 МБ), что соответствует уровню Windows Server 2012 r2.
+
+Обратите внимание, что значение по умолчанию — 8 МБ, но это ограничение основано на диалекте smb2 (64КБ для SMB == 2.0, 8МБ для SMB &gt;= 2.1 с LargeMTU). Large MTU не поддерживается через NBT (TCP-порт 139).
+
+Значение по умолчанию:
+8388608</string>
+ <string id="POL_0696582B_7928_558B_B4DA_9A0C647CFBB8">smb2 max trans</string>
+ <string id="POL_0696582B_7928_558B_B4DA_9A0C647CFBB8_Help">Эта опция указывает значение протокола, которое smbd(8) будет возвращать клиенту, информируя клиента о самом большом размере буфера, который может использоваться при запросе метаданных файла через QUERY_INFO и соответствующие вызовы SMB2.
+
+Максимальный размер составляет 8388608 байт (8 МБ), что соответствует уровню Windows Server 2012 r2.
+
+Обратите внимание, что значение по умолчанию — 8 МБ, но это ограничение основано на диалекте smb2 (64 КБ для SMB == 2.0, 1 МБ для SMB &amp; gt; = 2.1 с LargeMTU). Large MTU не поддерживается через NBT (TCP-порт 139).
+
+Значение по умолчанию:
+8388608</string>
+ <string id="POL_DA17FE47_6637_50D0_9AD1_A95AAA49F717">smb2 max write</string>
+ <string id="POL_DA17FE47_6637_50D0_9AD1_A95AAA49F717_Help">Эта опция указывает значение протокола, которое smbd(8) будет возвращать клиенту, информируя клиента о самом большом размере, который может быть отправлен на сервер одним вызовом записи SMB2.
+
+Максимальный размер составляет 8388608 байт (8 МБ), что соответствует уровню Windows Server 2012 r2.
+
+Обратите внимание, что значение по умолчанию — 8 МБ, но это ограничение основано на диалекте smb2 (64 КБ для SMB == 2.0, 1 МБ для SMB &amp; gt; = 2.1 с LargeMTU). Large MTU не поддерживается через NBT (TCP-порт 139).
+
+Значение по умолчанию:
+8388608</string>
+ <string id="POL_97C2005C_F45B_5675_B450_75842A4139F0">smb ports</string>
+ <string id="POL_97C2005C_F45B_5675_B450_75842A4139F0_Help">Указывает, на каких портах сервер должен прослушивать SMB-трафик.
+
+Значение по умолчанию:
+445 139</string>
+ <string id="POL_5B8B1A0B_AC6B_5E89_8FDE_4CBE538A9CB8">svcctl list</string>
+ <string id="POL_5B8B1A0B_AC6B_5E89_8FDE_4CBE538A9CB8_Help">Этот параметр определяет список сценариев init, которые smbd будет использовать для запуска и остановки служб Unix через Win32 ServiceControl API. Это позволяет администраторам Windows использовать плагины MS Management Console для управления сервером Unix, на котором работает Samba.
+
+Администратор должен создать каталог svcctl в каталоге Samba, указанном в переменной $(libdir), и создать символические ссылки на сценарии инициализации в /etc/init.d/. Имя ссылок должно совпадать с именами, указанными в списке svcctl.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+cups postfix portmap httpd</string>
+ <string id="POL_0E701672_524B_56CE_9C43_D9DE631558EA">time server</string>
+ <string id="POL_0E701672_524B_56CE_9C43_D9DE631558EA_Help">Этот параметр определяет, будет ли nmbd(8) выступать сервером времени для клиентов Windows.
+
+Значение по умолчанию:
+time server = no</string>
+ <string id="POL_B8322D3C_E4C4_5EAD_AE99_B912C35C56C8">unicode</string>
+ <string id="POL_B8322D3C_E4C4_5EAD_AE99_B912C35C56C8_Help">Указывает, должны ли сервер и клиент поддерживать Unicode.
+
+Если этот параметр выключен (unicode = no), использование ASCII будет принудительным.
+
+Значение по умолчанию:
+unicode = yes</string>
+ <string id="POL_4A31BF60_B9E4_5E35_B979_A1C15754CA9A">unix extensions</string>
+ <string id="POL_4A31BF60_B9E4_5E35_B979_A1C15754CA9A_Help">Параметр включает поддержку расширений CIFS UNIX от HP, что позволяет Samba лучше взаимодействовать с клиентами UNIX CIFS, включая поддержку символических ссылок, жестких ссылок и т.д. Эти расширения работают со специально настроенными клиентами и не применимы для клиентов Windows.
+
+Обратите внимание: если этот параметр включен, параметр 'wide links' автоматически отключается.
+
+См. параметр 'allow insecure wide links ', если нужно изменить связь между двумя параметрами.
+
+Значение по умолчанию:
+unix extensions = yes</string>
+ <string id="POL_911349A8_68E0_5370_B0C8_1E5D4DD47DA4">write raw</string>
+ <string id="POL_911349A8_68E0_5370_B0C8_1E5D4DD47DA4_Help">Этот параметр игнорируется, если установлен параметр 'async smb echo handler', потому что эта функция несовместима с необработанными запросами записи SMB.
+
+Если этот параметр включен, необработанные записи позволяют записывать 65535 байт в одном пакете. Обычно это дает значительное преимущество в производительности для очень и очень старых клиентов.
+
+Однако некоторые клиенты либо неправильно согласовывают допустимый размер блока, либо не могут поддерживать большие размеры блока, и для этих клиентов может потребоваться отключить необработанные записи.
+
+В общем, этот параметр следует рассматривать как инструмент настройки системы и не изменять его значение.
+
+Значение по умолчанию:
+write raw = yes</string>
+ <string id="POL_585034D0_C9E6_568C_AF40_354A01C24E02">server multi channel support</string>
+ <string id="POL_585034D0_C9E6_568C_AF40_354A01C24E02_Help">Этот логический параметр определяет, будет ли smbd(8) поддерживать многоканальность SMB3.
+
+Этот параметр был добавлен в версии 4.4.
+
+Предупреждение: обратите внимание, что эта функция все еще считается экспериментальной. Используйте её на свой страх и риск: даже если она может показаться хорошо работающей при тестировании, при определенных условиях она может привести к повреждению данных. Будущие выпуски могут улучшить эту ситуацию.
+
+Из-за зависимости от API ядра Linux или FreeBSD, на данный момент эту функцию можно использовать только в Linux и FreeBSD. Для тестирования это ограничение можно перезаписать, указав дополнительно 'force: server multi channel support = yes'.
+
+Значение по умолчанию:
+server multi channel support = no</string>
+ <string id="POL_4553EC0B_4966_52CE_83C6_948DAC67A281">smb2 disable lock sequence checking</string>
+ <string id="POL_4553EC0B_4966_52CE_83C6_948DAC67A281_Help">Этот логический параметр определяет, будет ли smbd(8) отключать проверку последовательности блокировок даже для многоканальных соединений, а также для надежных дескрипторов.
+
+В спецификации [MS-SMB2] (разделе 3.3.5.14 Receiving an SMB2 LOCK Request) указано, что сервер должен выполнить последовательность блокировок, если Open.IsResilient или Open.IsDurable или Open.IsPersistent имеет значение TRUE или если Connection.Dialect принадлежит семейству SMB 3.x диалектов и Connection.ServerCapabilities включают SMB2_GLOBAL_CAP_MULTI_CHANNEL.
+
+Но Windows Server (по крайней мере, до v2004) выполняет эти проверки только для Open.IsResilient и Open.IsPersistent. Это означает, что они не реализуют поведение указанное в [MS-SMB2].
+
+По умолчанию Samba ведет себя в соответствии со спецификацией и отправляет повторные попытки уведомления о прерывании блокировки smb2.
+
+Предупреждение. Включайте этот параметр, только если существующие клиенты не могут обрабатывать проверку последовательности блокировок для дескрипторов без Open.IsResilient и Open.IsPersistent, и оказывается, что требуется поведение Windows Server.
+
+Примечание. Вполне вероятно, что этот параметр будет снова удален, если будущие версии Windows изменят свое поведение.
+
+Примечание. Samba еще не поддерживает Open.IsResilient и Open.IsPersistent.
+
+Значение по умолчанию:
+smb2 disable lock sequence checking = no</string>
+ <string id="POL_690A701E_D101_57E5_A180_30E9E54B8B38">smb2 disable oplock break retry</string>
+ <string id="POL_690A701E_D101_57E5_A180_30E9E54B8B38_Help">Этот логический параметр определяет, будет ли smbd(8) инициировать повторные попытки уведомления о прерывании блокировки smb2, если включен параметр 'server multi channel support'.
+
+В спецификации [MS-SMB2] указано, что сервер должен посылать повторные попытки уведомления о прерывании блокировки smb2 по всем доступным каналам данному клиенту.
+
+Но версии Windows Server (по крайней мере, до 2019 года) не отправляют повторные попытки уведомления о нарушении блокировки smb2 при сбоях канала. Это означает, что они не реализуют поведение, указанное в [MS-SMB2].
+
+По умолчанию Samba ведет себя в соответствии со спецификацией и отправляет повторные попытки уведомления о прерывании блокировки smb2.
+
+Предупреждение. Включайте этот параметр только в том случае, если существующие клиенты не могут обрабатывать возможные повторные попытки и оказывается, что требуется поведение Windows Server.
+
+Примечание. Вполне вероятно, что этот параметр снова будет удален, если будущие версии Windows изменят свое поведение.
+
+Примечание. Это применимо только к oplocks, но не к аренде SMB2.
+
+Значение по умолчанию:
+smb2 disable oplock break retry = no</string>
+ <string id="POL_7564C5C4_88AA_576B_A9E8_091901A3D6E0">rpc server dynamic port range</string>
+ <string id="POL_7564C5C4_88AA_576B_A9E8_091901A3D6E0_Help">Этот параметр сообщает серверу RPC, какой диапазон портов можно использовать для создания прослушивающего сокета для LSA, SAM, Netlogon и других без того хорошо известных портов tcp. Первое значение — это наименьший номер диапазона портов, а второе — наибольший.
+
+Это относится к серверам RPC во всех ролях серверов.
+
+Значение по умолчанию:
+49152-65535</string>
+ <string id="POL_8D3A68BB_46F0_55A8_B53F_A4AA70C39B46">algorithmic rid base</string>
+ <string id="POL_8D3A68BB_46F0_55A8_B53F_A4AA70C39B46_Help">Этот параметр определяет, как Samba будет использовать алгоритмическое отображение из uids/gid в RID, необходимое для создания идентификаторов безопасности NT.
+
+Установка для этого параметра большего значения может быть полезна для сайтов, переходящих с WinNT и Win2k, поскольку в противном случае существующие пользователи и группы будут конфликтовать с пользователями системы и т.д.
+
+Для правильной работы ACL на сервере все UID и GID должны быть преобразованы в SID. Таким образом, алгоритмическое сопоставление нельзя «отключить» («turned off»), но его «отталкивание» («out of the way») должно решить проблемы. Затем пользователям и группам могут быть назначены «низкие» («low») идентификаторы RID в произвольно выбранном-rid диапазоне.
+
+Значение по умолчанию:
+1000
+
+Пример:
+100000</string>
+ <string id="POL_4A36DCFC_E9DB_5CD6_A67B_F94F3D95224F">allow dcerpc auth level connect</string>
+ <string id="POL_4A36DCFC_E9DB_5CD6_A67B_F94F3D95224F_Help">Этот параметр определяет, разрешено ли использование служб DCERPC с DCERPC_AUTH_LEVEL_CONNECT, которые обеспечивают аутентификацию, но не обеспечивают целостность сообщения или защиту конфиденциальности.
+
+Некоторые интерфейсы, такие как samr, lsarpc и netlogon, имеют жестко заданное значение по умолчанию no, а epmapper, mgmt и rpcecho имеют жестко заданное значение по умолчанию yes.
+
+Поведение может быть перезаписано для каждого имени интерфейса (например, lsarpc, netlogon, samr, srvsvc, winreg, wkssvc …) с помощью параметра 'allow dcerpc auth level connect: interface = yes'.
+
+Эта опция имеет приоритет над ограничениями, специфичными для реализации. Например, протоколы drsuapi и backupkey требуют DCERPC_AUTH_LEVEL_PRIVACY. Протокол dnsserver требует DCERPC_AUTH_LEVEL_INTEGRITY.
+
+Значение по умолчанию:
+allow dcerpc auth level connect = no</string>
+ <string id="POL_F3A8A539_E774_5498_B8B7_5D295841A159">allow trusted domains</string>
+ <string id="POL_F3A8A539_E774_5498_B8B7_5D295841A159_Help">Этот параметр действует только в том случае, если параметр 'security' установлен в значение server, domain или ads.
+ Если 'allow trusted domains = no', то попытки подключиться к ресурсу из домена или рабочей группы, отличной от той, в которой запущен smbd, завершатся ошибкой, даже если этому домену доверяет удаленный сервер, выполняющий аутентификацию.
+
+Это полезно, если необходимо, чтобы сервер Samba обслуживал запросы только пользователей домена, членом которого он является. В качестве примера предположим, что есть два домена DOMA и DOMB. DOMB доверяет DOMA, который содержит сервер Samba. При нормальных обстоятельствах пользователь с учетной записью в DOMB может затем получить доступ к ресурсам учетной записи UNIX с тем же именем учетной записи на сервере Samba, даже если у него нет учетной записи в DOMA. Это может затруднить реализацию границы безопасности.
+
+Значение по умолчанию:
+allow trusted domains = yes</string>
+ <string id="POL_DF7112E5_5322_5A42_A1AD_45085CB6EC86">binddns dir</string>
+ <string id="POL_DF7112E5_5322_5A42_A1AD_45085CB6EC86_Help">Этот параметр определяет каталог, который Samba будет использовать для хранения файлов конфигурации bind, таких как named.conf.
+
+ПРИМЕЧАНИЕ. Каталог bind dns должен находиться в той же точке монтирования, что и личный каталог!
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_41C0408D_BF8C_5BA3_992E_6D58CF58FF84">check password script</string>
+ <string id="POL_41C0408D_BF8C_5BA3_992E_6D58CF58FF84_Help">Имя программы, которая может использоваться, чтобы проверить сложность пароля. Пароль посылается на стандартный ввод программы.
+
+Программа должна возвратить 0 для сложного пароля и любое другое значение для слабого. Если пароль считается слабым (программа не возвращает 0), пользователь будет уведомлен и изменение пароля не произойдет.
+
+В Samba AD этот сценарий будет запускаться samba(8) от имени пользователя root без каких-либо замен.
+
+Обратите внимание, что начиная с Samba 4.11, в сценарий экспортируются следующие переменные среды:
+
+ * SAMBA_CPS_ACCOUNT_NAME всегда присутствует и содержит sAMAccountName пользователя, то же самое, что и подстановки %u в случае отсутствия AD DC.
+
+ * SAMBA_CPS_USER_PRINCIPAL_NAME является необязательным в случае AD DC, если присутствует userPrincipalName.
+
+ * SAMBA_CPS_FULL_NAME является необязательным, если присутствует displayName.
+
+Примечание. В каталоге с примерами есть типовая программа crackcheck, которая использует cracklib для проверки качества пароля.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/local/sbin/crackcheck</string>
+ <string id="POL_9869726F_8F58_512B_A708_C7360AC9146F">client ipc signing</string>
+ <string id="POL_9869726F_8F58_512B_A708_C7360AC9146F_Help">Этот параметр устарел, начиная с Samba 4.13, и поддерживается для аутентификации LanMan (в отличие от NTLM, NTLMv2 или Kerberos), поскольку клиент будет удален в следующем выпуске Samba.
+
+То есть в будущем параметр 'client NTLMv2 auth' будет принудительным включен.
+
+Этот параметр определяет, разрешено или необходимо клиенту использовать подписывание SMB для соединений IPC$ в качестве транспорта DCERPC. Возможные значения: auto, mandatory, disabled.
+
+Если установлено значение mandatory или default, требуется подпись SMB.
+
+Если установлено значение auto, подписывание SMB предлагается, но не принудительно, а если установлено значение disabled, полписывание SMB не предлагается.
+
+Подключения от winbindd к контроллерам домена Active Directory всегда требуют подписи.
+
+Значение по умолчанию:
+default</string>
+ <string id="POL_309DB173_58D7_5326_B21D_8DF044225CB9">client lanman auth</string>
+ <string id="POL_309DB173_58D7_5326_B21D_8DF044225CB9_Help">Этот параметр определяет, будут ли smbclient(8) и другие клиентские инструменты Samba пытаться аутентифицироваться на серверах, используя более слабый хэш пароля LANMAN. Если этот параметр отключен (client lanman auth = no), только сервера, поддерживающий механизмы паролей NT (например, Windows NT/2000, Samba и т.д., но не Windows 95/98), будут способны установить соединение.
+
+Ответ, зашифрованный LANMAN, легко взломать из-за его нечувствительности к регистру и выбора алгоритма. Клиентам без серверов Windows 95/98 рекомендуется отключить эту опцию.
+
+Отключение этой опции также отключит параметр 'client plaintext auth'.
+
+Аналогичным образом, если включен параметр 'client ntlmv2 auth', то попытки входа в систему будут выполняться только с использованием NTLMv2.
+
+Значение по умолчанию:
+client lanman auth = no</string>
+ <string id="POL_0F39ED01_BB64_5653_839C_CB26A70EC531">client NTLMv2 auth</string>
+ <string id="POL_0F39ED01_BB64_5653_839C_CB26A70EC531_Help">Этот параметр определяет, будет ли smbclient(8) пытаться аутентифицироваться на серверах, используя ответ с зашифрованным паролем NTLMv2.
+
+Если этот параметр включен (client NTLMv2 auth = yes), будут отправляться только ответы NTLMv2 и LMv2 (оба более безопасны, чем предыдущие версии). Старые серверы (включая NT4 &lt; SP4, Win9x и Samba 2.2) несовместимы с NTLMv2, если они не находятся в домене, поддерживающем NTLMv2.
+
+Аналогичным образом, если этот параметр включен, NTLMv1, параметр 'client lanman auth' и 'client plaintext auth' будут отключены. Это также отключает аутентификацию на уровне общего ресурса.
+
+Если этот параметр отключен, клиент отправит ответ NTLM (и, возможно, ответ LANMAN), в зависимости от значения параметра 'client lanman auth'.
+
+Обратите внимание, что Windows Vista и более поздние версии уже используют NTLMv2 по умолчанию, а некоторые сайты (особенно те, которые следуют 'best practice' политикам безопасности) разрешают только ответы NTLMv2, а не более слабые LM или NTLM.
+
+Когда также установлен параметр 'client use spnego', для использования NTLMv2 только в рамках NTLMSSP требуется расширенная безопасность (SPNEGO). Такое поведение было введено в исправлениях для CVE-2016-2111.
+
+Значение по умолчанию:
+client NTLMv2 auth = yes
+</string>
+ <string id="POL_94342D11_937E_5F14_BBEA_C9B370F6A523">client plaintext auth</string>
+ <string id="POL_94342D11_937E_5F14_BBEA_C9B370F6A523_Help">Этот параметр устарел, начиная с Samba 4.13, и поддержка открытого текста (в отличие от аутентификации NTLM, NTLMv2 или Kerberos) будет удалена в будущем выпуске Samba.
+
+То есть в будущем текущее значение по умолчанию 'client plaintext auth = no' будет принудительным поведением.
+
+Указывает, должен ли клиент отправлять пароль в виде открытого текста, если сервер не поддерживает зашифрованные пароли.
+
+Значение по умолчанию:
+client plaintext auth = no</string>
+ <string id="POL_DCB591D5_0F63_58EC_A0BB_F5F81064B714">client schannel</string>
+ <string id="POL_DCB591D5_0F63_58EC_A0BB_F5F81064B714_Help">Эта опция устарела в Samba 4.8 и будет удалена в будущем. В то же время значение по умолчанию изменено на yes, что будет жестко запрограммированным поведением в будущем.
+
+Этот параметр контролирует, будет ли предложено клиенту или даже потребует ли использования schannel netlogon:
+
+ * no — не требовать schannel,
+
+ * auto — предлагать schannel, но не предписывать это,
+
+ * yes — запрещает доступ, если сервер не способен производить вход в сеть schannel netlogon (Schannel означает безопасный метод передачи — secure channel).
+
+Обратите внимание, что для доменов Active Directory жестко задано значение 'client schannel = yes'.
+
+Опция 'require strong key' имеет приоритет над этой опцией.
+
+Значение по умолчанию:
+yes
+
+Пример:
+auto</string>
+ <string id="POL_F35419AB_2114_5382_8060_B1AAED24F2A1">client signing</string>
+ <string id="POL_F35419AB_2114_5382_8060_B1AAED24F2A1_Help">Это определяет, разрешено или необходимо клиенту использовать подпись SMB. Возможные значения: auto, mandatory и disabled.
+
+Если установлено значение auto или default, подпись SMB предлагается, но не принудительно.
+
+Если установлено значение mandatory, требуется подпись SMB, а при значении disabled подпись SMB также не предлагается.
+
+IPC$ соединения для DCERPC, например в winbindd обрабатываются опцией 'client ipc signing'.
+
+Значение по умолчанию:
+default</string>
+ <string id="POL_F761A7A7_2852_560C_B6D7_A50C613C5431">client use spnego principal</string>
+ <string id="POL_F761A7A7_2852_560C_B6D7_A50C613C5431_Help">Этот параметр определяет, будет ли smbclient(8) и другие компоненты Samba, действующие в качестве клиента, пытаться использовать предоставленный сервером принципал, который иногда указывается при обмене SPNEGO.
+
+Если параметр включен, Samba может пытаться использовать Kerberos для связи с серверами, известными только по IP-адресу. Kerberos полагается на имена, поэтому обычно не может работать в этой ситуации.
+
+Это ОЧЕНЬ ПЛОХАЯ ИДЕЯ по соображениям безопасности, поэтому этот параметр НЕ ДОЛЖЕН ИСПОЛЬЗОВАТЬСЯ. Он будет удален в будущей версии Samba.
+
+Если параметр отключен, Samba будет использовать имя, используемое для поиска сервера при запросе билета у KDC. Это позволяет избежать ситуаций, когда сервер может выдавать себя за другого, требуя аутентификации в качестве одного принципала, в то время как в сети он известен как другой.
+
+Обратите внимание, что Windows XP SP2 и поздние версии уже следуют этому поведению, а серверы Windows Vista и более поздних версий больше не предоставляют этот 'rfc4178 hint' принципал на стороне сервера.
+
+Этот параметр устарел в Samba 4.2.1 и будет удален (вместе с функциональностью) в более позднем выпуске Samba.
+
+Значение по умолчанию:
+client use spnego principal = no</string>
+ <string id="POL_158C42B4_685B_5FDE_BF9D_C42504E8C09C">debug encryption</string>
+ <string id="POL_158C42B4_685B_5FDE_BF9D_C42504E8C09C_Help">Эта опция заставит код сервера и клиента smbd, используя libsmb (smbclient, smbget, smbspool и т.д.), сбрасывать Session Id, decrypted Session Key, Signing Key, Application Key, Encryption Key и Decryption Key каждый раз, когда устанавливается сеанс SMB3+. Эта информация будет отражена в логах уровня 0.
+
+Предупреждение: доступ к этим значениям позволяет дешифровать любой зашифрованный трафик в сброшенных сеансах. Этот параметр следует включать только в целях отладки.
+
+Значение по умолчанию:
+debug encryption = no</string>
+ <string id="POL_8853D1A2_6482_58E1_9748_192D92523750">dedicated keytab file</string>
+ <string id="POL_8853D1A2_6482_58E1_9748_192D92523750_Help">Задает абсолютный путь к файлу keytab Kerberos, если для параметра 'kerberos method' установлено значение dedicated keytab.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/local/etc/krb5.keytab</string>
+ <string id="POL_3C1941B5_4894_501A_A7FD_F0C6BCE77DA9">encrypt passwords</string>
+ <string id="POL_3C1941B5_4894_501A_A7FD_F0C6BCE77DA9_Help">Этот параметр устарел, начиная с Samba 4.11, и поддержка открытого текста (в отличие от аутентификации NTLM, NTLMv2 или Kerberos) будет удалена в будущем выпуске Samba.
+
+То есть в будущем текущее значение по умолчанию 'encrypt passwords = yes' будет принудительным поведением.
+
+Это логическое значение определяет, будет ли использоваться шифрование паролей между сервером и клиентом. Обратите внимание, что Windows NT 4.0 SP3 и выше и также Windows 98 будут по умолчанию ожидать зашифрованные пароли, если системный реестр не изменен. Как использовать шифрование паролей в Samba, см. раздел «User Database» в руководстве Samba HOWTO.
+
+Клиенты MS Windows, которые ожидают зашифрованные пароли Microsoft и поэтому не допускают пароли открытым текстом, будут способны подключиться только к серверу Samba, на котором включена поддержка зашифрованных паролей и для которых учетные записи пользователей имеют действующий зашифрованный пароль. Обратитесь к странице руководства команды smbpasswd для получения информации относительно создания зашифрованных паролей учетных записей пользователей.
+
+Использование нешифрованых паролей (plain text passwords) не рекомендуется, поскольку более не поддерживается продуктами Microsoft Windows. Если необходимо использовать пароли в виде обычного текста, следует установить 'encrypt passwords = no'.
+
+Для поддержки зашифрованных паролей smbd(8) должен либо иметь доступ к локальному файлу smbpasswd(5) (см. smbpasswd(8) для получения информации о том, как настроить и поддерживать этот файл), либо установить параметр 'security' в значение [domain|ads], это заставит smbd подтверждать подлинность с другого сервера.
+
+Значение по умолчанию:
+encrypt passwords = yes</string>
+ <string id="POL_99472FC1_E6CE_5476_9EC3_EB2EF52862AE">guest account</string>
+ <string id="POL_99472FC1_E6CE_5476_9EC3_EB2EF52862AE_Help">Это имя пользователя, которое будет использоваться для доступа к службам, для которых задан параметр 'guest ok'. Независимо от привилегии пользователя гостевой общий ресурс будет доступен для любого клиента. Этот пользователь должен существовать в файле паролей, однако при подключении не требуется вводить пароль. Учетная запись «ftp» часто хороший выбор для этого параметра.
+
+В некоторых системах гостевая учетная запись по умолчанию — «nobody» возможно не получит доступ к печати. В этом случае используйте другую учетную запись. Необходимо проверить это, попытавшись войти в систему как гостевой пользователь (возможно, используя команду su-) и попытавшись выполнить печать с помощью системной команды печати, такой как lpr(1) или lp(1).
+
+В этом параметре нельзя использовать % макросы, необходимо чтобы значение параметра было постоянным для корректной работы сервиса.
+
+Значение по умолчанию:
+nobody
+
+Пример:
+ftp</string>
+ <string id="POL_75BBDBCB_46D1_55DE_9A7C_9EEA7DD026BF">kerberos encryption types</string>
+ <string id="POL_75BBDBCB_46D1_55DE_9A7C_9EEA7DD026BF_Help">Этот параметр определяет типы шифрования, которые будут использоваться при работе в качестве клиента Kerberos. Возможные значения: all, strong, и legacy.
+
+Samba использует библиотеку Kerberos (MIT или Heimdal) для получения билетов Kerberos. Эта библиотека обычно настраивается вне Samba с помощью файла krb5.conf. Этот файл может также включать директивы для настройки используемых типов шифрования. Однако Samba реализует протоколы и алгоритмы Active Directory для поиска контроллера домена. Чтобы заставить библиотеку Kerberos использовать правильный контроллер домена, некоторые процессы Samba, такие как winbindd(8) и net(8), создают частный файл krb5.conf для использования библиотекой Kerberos при вызове из Samba. Этот частный файл управляет всеми аспектами работы библиотеки Kerberos, и этот параметр управляет настройкой типов шифрования в этом сгенерированном файле и, следовательно, также контролирует типы шифрования, согласовываемые Samba.
+
+Если установлено значение all, разрешены все типы шифрования активного каталога.
+
+Если установлено значение strong, предлагаются только типы шифрования на основе AES. Это можно использовать в защищенных средах для предотвращения атак на более раннюю версию.
+
+Если задано значение legacy, разрешено использование только RC4-HMAC-MD5. Отказ от AES таким способом имеет очень конкретное применение. Обычно тип шифрования оговаривается между одноранговыми узлами. Однако есть один сценарий, в котором Windows read-only domain controller (RODC) объявляет о шифровании AES, но затем передает запрос на доступный для записи DC, который может не поддерживать шифрование AES, что приводит к сбою рукопожатия. Установка для этого параметра значения legacy приведет к тому, что Samba не будет согласовывать шифрование AES. Разумеется, предполагается, что для данной установки приемлемы более слабые устаревшие типы шифрования.
+
+Значение по умолчанию:
+all</string>
+ <string id="POL_4AE746EE_4A10_55CC_8934_7E4FEF028E4D">kerberos method</string>
+ <string id="POL_4AE746EE_4A10_55CC_8934_7E4FEF028E4D_Help">Параметр управляет проверкой билетов Kerberos.
+
+Допустимые значения:
+
+ * secrets only — используется только файл secrets.tdb для проверки билетов (default)
+ * system keytab — используется только system keytab для проверки билетов
+ * dedicated keytab — используется dedicated keytab для проверки билетов
+ * secrets and keytab — сначала используется secrets.tdb, затем system keytab
+
+Основное различие между «system keytab» и «dedicated keytab» заключается в том, что последний метод полагается на Kerberos для поиска правильной записи keytab вместо фильтрации на основе ожидаемых принципалов.
+
+Когда 'kerberos method' находится в режиме «dedicated keytab», то необходимо указать расположение файла keytab в параметре 'dedicated keytab file'.
+
+Значение по умолчанию:
+default</string>
+ <string id="POL_C0E75830_A92F_5E76_A2CF_8E864DF58497">kpasswd port</string>
+ <string id="POL_C0E75830_A92F_5E76_A2CF_8E864DF58497_Help">Указывает, какой порт сервер Kerberos должен прослушивать при смене пароля.
+
+Значение по умолчанию:
+464</string>
+ <string id="POL_37987863_7B25_5531_81BE_8EB427F3D0E1">krb5 port</string>
+ <string id="POL_37987863_7B25_5531_81BE_8EB427F3D0E1_Help">Указывает, какой порт KDC должен прослушивать трафик Kerberos.
+
+Значение по умолчанию:
+88</string>
+ <string id="POL_91CB69F0_B95B_565D_B50D_0BC441ED9E34">lanman auth</string>
+ <string id="POL_91CB69F0_B95B_565D_B50D_0BC441ED9E34_Help">Этот параметр устарел, начиная с Samba 4.11, и поддержка LanMan (в отличие от аутентификации NTLM, NTLMv2 или Kerberos) будет удалена в будущем выпуске Samba.
+
+То есть в будущем текущее значение по умолчанию 'lanman auth = no' будет принудительным поведением.
+
+Этот параметр определяет, будет ли smbd(8) пытаться аутентифицировать пользователей или разрешать изменение пароля с помощью хэша пароля LANMAN. Если этот параметр отключен (lanman auth = no), только клиенты, которые поддерживают хэши паролей NT (например, клиенты Windows NT/2000, smbclient, но не Windows 95/98 или сетевой клиент MS DOS) смогут подключаться к хосту Samba.
+
+Ответ, зашифрованный LANMAN, легко взломать из-за его нечувствительности к регистру и выбора алгоритма. Серверам без клиентов Windows 95/98/ME или MS DOS рекомендуется отключить эту опцию.
+
+Если этот параметр отключен (lanman auth = no), это также приведет к тому, что sambaLMPassword в базе данных Samba будет очищена после следующей смены пароля. В результате этого клиенты lanman не смогут пройти аутентификацию, даже если позже будет повторно включена проверка подлинности lanman.
+
+В отличие от параметра 'encrypt passwords', этот параметр не может изменить поведение клиента, и ответ LANMAN будет по-прежнему отправляться по сети. См. параметр 'client lanman auth', чтобы отключить это для клиентов Samba (таких как smbclient).
+
+Этот параметр переопределяется параметром 'ntlm auth', поэтому, если он также параметр 'ntlm auth' не установлен на ntlmv1-permitted или yes, тогда будут разрешены логины NTLMv2, а хэш LM не будет сохранен. Все современные клиенты поддерживают NTLMv2, но некоторые старые клиенты требуют специальной настройки для его использования.
+
+Значение по умолчанию:
+lanman auth = no</string>
+ <string id="POL_89CBBE4F_9104_594C_88D1_F9C11246B21F">log nt token command</string>
+ <string id="POL_89CBBE4F_9104_594C_88D1_F9C11246B21F_Help">Эта опция может быть установлена как команда, которая будет вызываться при создании новых токенов nt.
+
+Эта опция полезна только для целей разработки.
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_6BE3D165_D5BE_5252_A0A2_31CD0E777478">map to guest</string>
+ <string id="POL_6BE3D165_D5BE_5252_A0A2_31CD0E777478_Help">Этот параметр может принимать четыре разных значения, которые сообщают smbd(8), что делать с пользовательскими запросами на логин, которые каким-либо образом не соответствуют действующему пользователю UNIX.
+
+Возможные значения:
+
+ * Never — означает, что запросы пользователя на вход с недопустимым паролем отклоняются. Это значение по умолчанию.
+
+ * Bad User — означает, что вход в систему с недопустимым паролем отклоняется, если имя пользователя не существует, и в этом случае оно рассматривается как guest login и сопоставляется с файлом 'guest account'.
+
+ * Bad Password — означает, что вход в систему с недопустимым паролем рассматривается как гостевой логин и сопоставляется с файлом 'guest account'. Обратите внимание, что это может вызвать проблемы, поскольку это означает, что любой пользователь, неправильно вводящий свой пароль, будет автоматически входить в систему как «guest». Такой пользователь не будет знать причину, по которой он не может получить доступ к файлам, к которым, по его мнению, он должен иметь доступ — пользователю не будет отправлено сообщение о том, что он ошибся в пароле. Службы поддержки возненавидят вас, если вы настроите параметр 'map to guest' таким образом :-).
+
+ * Bad Uid — применимо только в том случае, если Samba настроен в режиме 'security = {domain|ads}' и означает, что логины пользователей, которые успешно аутентифицированы, но не имеют действующей учетной записи пользователя Unix (и smbd не может создать её) должны быть сопоставлены с указанной гостевой учетной записью. Это было поведением по умолчанию для выпусков Samba 2.x. Обратите внимание, что если на рядовом сервере работает winbindd, эта опция никогда не должна требоваться, потому что библиотека nss_winbind будет экспортировать пользователей и группы домена Windows в базовую ОС через интерфейс Name Service Switch.
+
+Обратите внимание, что этот параметр необходим для настройки «гостевых» общих служб. Это связано с тем, что в этих режимах имя запрашиваемого ресурса не отправляется на сервер до тех пор, пока сервер не аутентифицирует клиента, поэтому сервер не может принимать решения об аутентификации в правильное время (подключение к общему ресурсу) для «гостевых» общих ресурсов.
+
+Значение по умолчанию:
+Never
+
+Пример:
+Bad User</string>
+ <string id="POL_56EEE2C2_6458_524A_95A8_C59B86A453E0">mit kdc command</string>
+ <string id="POL_56EEE2C2_6458_524A_95A8_C59B86A453E0_Help">Эта опция указывает путь к двоичному файлу MIT kdc.
+
+Если KDC был установлен в каталог не по умолчанию и не был правильно обнаружен во время сборки, то следует изменить эту переменную и указать в ней правильный двоичный файл.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/opt/mit/sbin/krb5kdc</string>
+ <string id="POL_E82BE4E4_3F51_5B03_9809_03101186CE80">ntlm auth</string>
+ <string id="POL_E82BE4E4_3F51_5B03_9809_03101186CE80_Help">Этот параметр определяет, будет ли smbd(8) пытаться аутентифицировать пользователей, используя ответ с зашифрованным паролем NTLM для этой локальной passdb (SAM или БД учетных записей).
+
+Если этот параметр отключен, отключена проверка подлинности NTLM и LanMan по локальной базе данных passdb.
+
+Обратите внимание, что эти параметры применяются только к локальным пользователям, проверка подлинности будет по-прежнему перенаправлена, а проверка подлинности NTLM будет принята для любого домена, к которому мы присоединены, и любого доверенного домена, даже если он отключен или здесь применяется только NTLMv2. Чтобы управлять аутентификацией NTLM для пользователей домена, этот параметр должен быть настроен на каждом контроллере домена.
+
+По умолчанию, если для 'ntlm auth' установлено значение ntlmv2, разрешены только NTLMv2-логины. Все современные клиенты поддерживают NTLMv2 по умолчанию, но для некоторых старых клиентов потребуется специальная конфигурация для его использования.
+
+Основным пользователем NTLMv1 является MSCHAPv2 для сетей VPN и 802.1x.
+
+Доступные значения:
+
+ * ntlmv1-permitted (алиас yes) — разрешить NTLMv1 и выше для всех клиентов. Это необходимая настройка для включения параметра аутентификации lanman.
+
+ * ntlmv2-only (алиас no) — не разрешать использование NTLMv1, но разрешать NTLMv2.
+
+ * mschapv2-and-ntlmv2-only — разрешать NTLMv1 только тогда, когда клиент обещает, что он предоставляет аутентификацию MSCHAPv2 (например, как ntlm_auth).
+
+ * disabled — не принимать NTLM (или LanMan) аутентификацию любого уровня и не разрешать изменение пароля NTLM.
+
+Значение по умолчанию изменилось с yes на no в Samba 4.5. Значение по умолчанию снова изменилось на ntlmv2-only с Samba 4.7, однако поведение не изменилось.
+
+Значение по умолчанию:
+ntlmv2-only</string>
+ <string id="POL_BEB01EAD_B60E_5832_BDD5_5C8ACE276FD4">ntp signd socket directory</string>
+ <string id="POL_BEB01EAD_B60E_5832_BDD5_5C8ACE276FD4_Help">Этот параметр управляет расположением сокета, который использует демон NTP для коммуникации с Samba для подписи пакетов.
+
+Если здесь указан путь, отличный от пути по умолчанию, то также необходимо уведомить NTP о новом пути с помощью директивы ntpsigndsocket в ntp.conf.
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_C04AB7ED_DBC2_50A6_8082_AD0D6CCB758A">null passwords</string>
+ <string id="POL_C04AB7ED_DBC2_50A6_8082_AD0D6CCB758A_Help">Разрешить или запретить доступ клиентов к учетным записям с пустыми паролями.
+
+См. также smbpasswd(5).
+
+Значение по умолчанию:
+null passwords = no</string>
+ <string id="POL_E305251F_7C82_54A6_8F9D_CFBB7934B1DF">obey pam restrictions</string>
+ <string id="POL_E305251F_7C82_54A6_8F9D_CFBB7934B1DF_Help">Когда Samba 3.0 сконфигурирована с поддержкой PAM (т.е. собрана с опцией --with-pam), этот параметр будет определять, должна ли Samba подчиняться правилам управления учетной записью PAM и правилам управления сессиями. По умолчанию PAM используется только для аутентификации в виде открытого текста и игнорирует управление учетной записью или сессиями. Обратите внимание, что Samba не использует PAM для аутентификации, если установлен параметр 'encrypt passwords = yes'. Причина в том, что модули PAM не могут поддерживать механизмы аутентификации, основанные на challenge/response, которые требуются для шифрования паролей SMB.
+
+Значение по умолчанию:
+obey pam restrictions = no</string>
+ <string id="POL_DD8E3C33_F1AE_59CB_B2B6_3358FFBF41AF">old password allowed period</string>
+ <string id="POL_DD8E3C33_F1AE_59CB_B2B6_3358FFBF41AF_Help">Количество минут, в течение которых разрешается вход NTLM после изменения или сброса пароля с использованием старого пароля. Это позволяет пользователю повторно кэшировать новый пароль на нескольких клиентах, не прерывая при этом переподключение к сети.
+
+Этот параметр применяется, только если параметр 'server role' имеет значение Контроллер домена Active Directory.
+
+Значение по умолчанию:
+60</string>
+ <string id="POL_B65F086B_4235_5646_8C8B_AF4C16B6E4AD">pam password change</string>
+ <string id="POL_B65F086B_4235_5646_8C8B_AF4C16B6E4AD_Help">С добавлением улучшенной поддержки PAM в Samba 2.2, этот параметр, можно использовать как флаг управления сменой пароля PAM для Samba. Если параметр включен (pam password change = yes), тогда PAM будет использоваться для смены пароля по запросу клиента SMB вместо программы, указанной в паарметре 'passwd program'. Для большинства конфигураций, должно быть возможно использование этого параметра без изменения параметра 'passwd chat'.
+
+Значение по умолчанию:
+pam password change = no</string>
+ <string id="POL_755D3500_5D11_5DF0_82AC_E5E964C7707B">passdb backend</string>
+ <string id="POL_755D3500_5D11_5DF0_82AC_E5E964C7707B_Help">Этот параметр позволяет администратору выбрать механизм для хранения информации о пользователях и, возможно, о группах. Это позволяет переключаться между различными механизмами хранения без перекомпиляции Samba.
+
+Значение параметра делится на две части, имя механизма и местонахождение, строка, которая означает, что механизм имеет отношение только к указанной зоне. Они разделяются знаком «:».
+
+Доступные механизмы:
+
+ * smbpasswd — старый механизм passdb с открытым текстом. Некоторые функции Samba не будут работать, если используется этот механизм. Принимает путь к файлу smbpasswd в качестве необязательного аргумента.
+
+ * tdbsam — механизм для хранения паролей на основе TDB. Принимает путь к TDB в качестве необязательного аргумента (по умолчанию passdb.tdb в каталоге 'private dir').
+
+ * ldapsam — механизм passdb на основе LDAP. Принимает URL-адрес LDAP в качестве необязательного аргумента (по умолчанию ldap://localhost). Соединения LDAP должны быть зашифрованы, там, где это возможно. Это можно сделать либо с помощью Start-TLS (см. параметр 'ldap ssl'), либо указав ldaps:// в аргументе URL. В двойных кавычках могут быть указаны несколько серверов. Возможность поддержки нескольких серверов и точный синтаксис зависит от используемой библиотеки LDAP.
+
+Значение по умолчанию:
+tdbsam
+
+Пример:
+tdbsam:/etc/samba/private/passdb.tdb
+
+Мультисерверный URL LDAP с библиотекой OpenLDAP:
+ldapsam:&quot;ldap://ldap-1.example.com ldap://ldap-2.example.com&quot;
+
+Мультисерверный LDAP URL с библиотекой LDAP на основе Netscape:
+ldapsam:&quot;ldap://ldap-1.example.com ldap-2.example.com&quot;</string>
+ <string id="POL_2F42A35D_FAD2_545A_9ACE_84CD88BEBDB4">passdb expand explicit</string>
+ <string id="POL_2F42A35D_FAD2_545A_9ACE_84CD88BEBDB4_Help">Этот параметр определяет, заменяет ли Samba %-макросы в полях passdb, если они заданы явно. Раньше мы расширяли макросы здесь, но оказалось, что это ошибка, потому что клиент Windows может расширить переменную %G_osver%, в которой %G будет заменен основной группой пользователя.
+
+Значение по умолчанию:
+passdb expand explicit = no</string>
+ <string id="POL_87D22064_A317_506A_8057_62D7EB06E246">passwd chat</string>
+ <string id="POL_87D22064_A317_506A_8057_62D7EB06E246_Help">Эта строка контролирует диалог («чат»), который происходит между smbd(8) и локальной программой изменения пароля при изменении пароля пользователя. Строка описывает последовательность пар запрос-ответ, которую smbd(8) использует для определения того, что отправлять программе определенной в параметре 'v' и что ожидать в ответ. Если ожидаемый результат не получен, пароль не изменяется.
+
+Этот диалог весьма специфичен для конкретного места, и зависит от того, какие локальные методы используются для управления паролями (например, NIS и т.д.).
+
+Обратите внимание, что этот параметр используется только в том случае, если установлен параметр 'unix password sync'. Если пароль SMB в файле smbpasswd изменяется без доступа к старому паролю, то этот диалог вызывается с правами пользователя ROOT. Это значит, что пользователь root должен иметь возможность сбросить пароль пользователя, не зная предыдущего пароля. При наличии NIS/YP это означает, что скрипт 'passwd program' должен выполняться на главном сервере NIS.
+
+Строка может содержать макрос %n, который заменяет новый пароль. Старый пароль (%o) доступен, только если шифрование паролей отключено (encrypt passwords = no). Диалог также может содержать стандартные макросы \n, \r, \t и \s для перевода строки, возврата каретки, табуляции и пробела. Диалог также может содержать символ '*', который соответствует любой последовательности символов. Двойные кавычки можно использовать для объединения строк с пробелами в одну строку.
+
+Если в отправляемой строке диалога строка есть точка («.»), то такая строка не отправляется. Точно так же, если на месте ожидаемой строки стоит точка, никакой строки не ожидается.
+
+Если установлен параметр 'pam password change', пары чата могут быть сопоставлены в любом порядке, и успех определяется результатом PAM, а не каким-либо конкретным выходом. Макрос \n игнорируется для преобразований PAM.
+
+Значение по умолчанию:
+*new*password* %n\n *new*password* %n\n *changed*
+
+Пример:
+&quot;*Enter NEW password*&quot; %n\n &quot;*Reenter NEW password*&quot; %n\n &quot;*Password changed*&quot;</string>
+ <string id="POL_FB5B5BAF_88EA_547F_B6C1_C26EF698C89B">passwd chat debug</string>
+ <string id="POL_FB5B5BAF_88EA_547F_B6C1_C26EF698C89B_Help">Это логическое значение указывает, запускается ли сценарий 'passwd chat' в режиме отладки. В этом режиме, строки, передаваемые и получаемые в диалоге 'passwd chat', записываются в файл журнала smbd(8) с уровнем отладки 100 ('debug level = 100'). Включение этой опции небезопасно, поскольку пароли можно будет увидеть в открытом виде в журнале smbd. Данная опция доступна для отладки администраторами Samba диалога 'passwd chat' при вызове 'passwd program', и должна быть отключена после завершения отладки. Эта опция игнорируется, если установлен параметр 'pam password change'. По умолчанию эта опция отключена.
+
+Значение по умолчанию:
+passwd chat debug = no</string>
+ <string id="POL_885CA09B_77E8_5E63_85E8_108397557B0B">passwd chat timeout</string>
+ <string id="POL_885CA09B_77E8_5E63_85E8_108397557B0B_Help">Этот параметр (целое число) определяет количество секунд, в течение которых smbd будет ожидать первый ответ от запущенного сценария 'passwd chat'. После получения первого ответа последующие ответы должны быть получены в течение одной десятой этого времени. По умолчанию это две секунды.
+
+Значение по умолчанию:
+2</string>
+ <string id="POL_E710453F_700A_5430_BE8D_5364117F7E85">passwd program</string>
+ <string id="POL_E710453F_700A_5430_BE8D_5364117F7E85_Help">Этот параметр определяет программу, которая может использоваться для установки паролей пользователей UNIX. Макрос %u будет заменен именем пользователя. Перед вызовом программы изменения пароля, будет проверено существование данного имени пользователя.
+
+Обратите внимание, что большинство команд смены пароля требуют для паролей обоснованной сложности (минимальная длина или включение цифр и символов в разных регистрах). Это может создать проблему, так как некоторые клиенты (например, Windows for Workgroups) переводят пароль в верхний регистр перед его отправкой.
+
+Обратите внимание, что если установлен параметр 'unix password sync', программа, определенная в данном параметре, вызывается с правами пользователя ROOT перед изменением пароля SMB в файле smbpasswd. Если изменение пароля UNIX потерпело неудачу, то smbd также не сможет изменить пароль SMB (это сделано намеренно).
+
+Если установлен параметр 'unix password sync', параметр 'passwd program' ДОЛЖЕН ИСПОЛЬЗОВАТЬ АБСОЛЮТНЫЕ ПУТИ для ВСЕХ вызываемых программ и вызываемые программы должны быть исследованы на предмет последствий для безопасности. Обратите внимание, что по умолчанию параметр 'unix password sync' не установлен.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/bin/passwd %u</string>
+ <string id="POL_77F6400F_03D4_53F9_AB7B_E0464F72E61F">password hash gpg key ids</string>
+ <string id="POL_77F6400F_03D4_53F9_AB7B_E0464F72E61F_Help">Если Samba работает как контроллер домена Active Directory, можно сохранить пароли учетных записей в открытом виде в зашифрованной форме PGP/OpenGPG.
+
+Можно указать одного или нескольких получателей по идентификатору ключа или идентификатору пользователя. Обратите внимание, что 32-битные идентификаторы ключей не допускаются, необходимо указать как минимум 64-битный.
+
+Значения хранятся как «Primary:SambaGPG» в атрибуте supplementalCredentials.
+
+Поскольку изменение пароля может произойти на любом контроллере домена, необходимо настроить данный параметр на каждом из них. Обратите внимание, что эта функция в настоящее время доступна только на контроллерах домена Samba.
+
+Эта опция доступна, только если Samba была скомпилирована с поддержкой gpgme.
+
+Возможно, потребуется экспортировать переменную среды GNUPGHOME перед запуском Samba. Настоятельно рекомендуется хранить только открытый ключ в этом месте. Закрытый ключ не используется для шифрования и должен храниться только там, где требуется дешифрование.
+
+Возможность восстановления паролей в открытом виде помогает, когда позже потребуется импортировать их в другие системы аутентификации (см. команду 'samba-tool user getpassword') или если требуется, чтобы пароли синхронизировались с другой системой, например с сервером OpenLDAP (см. команду 'samba-tool user syncpasswords').
+
+Хотя этот параметр необходимо настроить на всех контроллерах домена, команда 'samba-tool user syncpasswords' должна выполняться только на одном контроллере домена (обычно это эмулятор PDC).
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+4952E40301FAB41A
+
+Пример:
+selftest@samba.example.com
+
+Пример:
+selftest@samba.example.com, 4952E40301FAB41A</string>
+ <string id="POL_5EA8345D_5B61_554F_AAF5_2C069A37DFCA">password hash userPassword schemes</string>
+ <string id="POL_5EA8345D_5B61_554F_AAF5_2C069A37DFCA_Help">Этот параметр определяет, будет ли samba(8), которая работает как контроллер домена Active Directory, сохранять дополнительные типы хэшей паролей для пользователя.
+
+Значения хранятся как «Primary:userPassword» в атрибуте additionalCredentials. Значение этой опции — тип хэша.
+
+В настоящее время поддерживаются следующие типы хэшей:
+
+ * CryptSHA256
+
+ * CryptSHA512
+
+Могут быть вычислены и сохранены несколько экземпляров типов хэшей. Хэши паролей вычисляются с помощью вызова crypt(3). Количество раундов, используемых для вычисления хэша, можно указать, добавив ':rounds = xxxx' к типу хэша, то есть если 'CryptSHA512:rounds = 4500', хэш SHA512 будет вычисляться с использованием 4500 раундов. Если не указано иное, для crypt(3) используются значения операционной системы по умолчанию.
+
+Поскольку изменение пароля может произойти на любом контроллере домена, необходимо настроить данный параметр на каждом из них. Обратите внимание, что эта функция в настоящее время доступна только на контроллерах домена Samba.
+
+В настоящее время при вычислении и хранении этих хэшей регистрируется NT-хэш пароля. При получении хэша текущее значение NT Hash сравнивается с сохраненным NT Hash. Это позволяет обнаружить изменения пароля, которые не обновили хэши паролей. В этом случае команда 'samba-tool user' проигнорирует сохраненные хэш-значения.
+
+Возможность получить хэшированный пароль помогает, когда позже потребуется импортировать их в другие системы аутентификации (см. команду 'samba-tool user getpassword') или если требуется, чтобы пароли синхронизировались с другой системой, например с сервером OpenLDAP (см. команду 'samba-tool user syncpasswords').
+
+Связанный параметр: 'unix password sync'
+
+Значение по умолчанию:
+password hash userPassword schemes
+
+Пример:
+CryptSHA256
+
+Пример:
+CryptSHA256 CryptSHA512
+
+Пример:
+CryptSHA256:rounds=5000 CryptSHA512:rounds=7000</string>
+ <string id="POL_1D36B51B_8AB7_593A_95D8_93B12C9F9EFA">password server</string>
+ <string id="POL_1D36B51B_8AB7_593A_95D8_93B12C9F9EFA_Help">Указав, с помощью этой опции, имя контроллера домена и используя параметр security = [ads|domain], можно заставить Samba выполнять все проверки пользователь/пароль с помощью определенного удаленного сервера.
+
+В идеале этот параметр не следует использовать, поскольку значение по умолчанию «*», указывает Samba на определение наилучшего DC для динамических связей, также как это делают все остальные хосты в домене AD. Это позволяет поддерживать домен (добавление и удаление контроллеров домена) без изменения файла smb.conf. Криптографическая защита аутентифицированных вызовов RPC, используемых для проверки паролей, гарантирует безопасность этого значения по умолчанию.
+
+Настоятельно рекомендуется использовать значение по умолчанию «*», однако, если в вашей конкретной среде у вас есть причина указать конкретный список контроллеров домена, то список машин в этой опции должен быть списком имен или IP-адресов контроллеров домена. Если используется значение по умолчанию «*» или указано несколько хостов в параметре сервера паролей, то smbd будет пробовать каждый по очереди, пока не найдет тот, который отвечает. Это полезно в случае, если основной сервер выйдет из строя.
+
+Если список серверов содержит и имена/IP-адреса, и символ «*», список рассматривается как список предпочтительных контроллеров домена, но в список также будет добавлен автоматический поиск всех оставшихся контроллеров домена. Samba не будет пытаться оптимизировать этот список, определяя местонахождение ближайшего DC.
+
+Если значением параметра является имя, оно может быть разрешено любым методом и в любом порядке, описанном в параметре 'name resolve order'.
+
+Значение по умолчанию:
+*
+Пример:
+NT-PDC, NT-BDC1, NT-BDC2, *
+
+Пример:
+windc.mydomain.com:389 192.168.1.101 *</string>
+ <string id="POL_4605CA34_85F3_51DB_8BCE_C56B51AA39BF">preload modules</string>
+ <string id="POL_4605CA34_85F3_51DB_8BCE_C56B51AA39BF_Help">Это список путей к модулям, которые должны быть загружены в smbd перед подключением клиента. Это несколько увеличивает скорость smbd при реагировании на новые соединения.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/lib/samba/passdb/mysql.so</string>
+ <string id="POL_5103CDE2_436D_5FB9_8633_6BB5EBB59406">private dir</string>
+ <string id="POL_5103CDE2_436D_5FB9_8633_6BB5EBB59406_Help">Параметр определяет каталог, который smbd будет использовать для хранения таких файлов, как smbpasswd и secrets.tdb.
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_7DB136EF_7DAD_5A4F_8C40_F3079FCB925F">raw NTLMv2 auth</string>
+ <string id="POL_7DB136EF_7DAD_5A4F_8C40_F3079FCB925F_Help">Этот параметр устарел, начиная с Samba 4.13, и поддержка аутентификации NTLMv2 без NTLMSSP будет удалена в следующем выпуске Samba.
+
+То есть в будущем параметр 'raw NTLMv2 auth' будет принудительно выключен.
+
+Этот параметр определяет, разрешит ли smbd(8) клиентам SMB1 без расширенной безопасности (без SPNEGO) использовать аутентификацию NTLMv2.
+
+Если этот параметр, а также параметры 'lanman auth' и 'ntlm auth' отключены, будут разрешены только клиенты с поддержкой SPNEGO. Это означает, что NTLMv2 поддерживается только в NTLMSSP.
+
+Значение по умолчанию:
+raw NTLMv2 auth = no</string>
+ <string id="POL_E4D542FC_3D67_5397_9AC3_3868BB017F03">rename user script</string>
+ <string id="POL_E4D542FC_3D67_5397_9AC3_3868BB017F03_Help">В этом параметре указывается полный путь к сценарию, который будет запущен smbd(8) от имени пользователя root, при обстоятельствах, описанных ниже.
+
+Когда пользователь с правами администратора или с правами SeAddUserPrivilege переименовывает пользователя (например, через панель управления доменами NT4), этот сценарий будет запущен для того, чтобы переименовать пользователя POSIX. Две переменные, %uold и %unew, будут использоваться для определения старого и нового имени соответственно. Скрипт должен возвращать 0 при успешном завершении и ненулевое значение в противном случае.
+
+Примечание:
+ Сценарий несет полную ответственность за переименование всех необходимых данных, доступных в этом методе posix. Это может означать разное для разных платформ. Серверные программы tdbsam и smbpasswd позаботятся о содержимом своих файлов, поэтому сценарий отвечает только за изменение имени пользователя POSIX и других данных, которые характерны для конкретной ситуации (например, домашние каталоги). Также подумайте, нужно ли переименовывать сами домашние каталоги. ldapsam не будет вносить никаких изменений из-за потенциальных проблем с переименованием атрибута именования LDAP (LDAP naming attribute). В этом случае сценарий отвечает за изменение атрибута (uid), который Samba использует для поиска пользователей, а также за любые данные, которые необходимо изменить для других приложений, использующих тот же каталог.
+
+Значение по умолчанию:
+пустая строка</string>
+ <string id="POL_7D42E3F0_DE0E_57E0_8EAF_F56111560EA3">restrict anonymous</string>
+ <string id="POL_7D42E3F0_DE0E_57E0_8EAF_F56111560EA3_Help">Установка этого параметра определяет, можно ли получить доступ к службам SAMR и LSA DCERPC анонимно. Этот параметр соответствует следующим параметрам реестра Windows Server:
+
+ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\RestrictAnonymous
+
+Этот параметр также влияет на параметр просмотра, который требуется для устаревших клиентов, которые полагаются на просмотр NetBIOS. Хотя современные версии Windows должны работать с ограничением доступа, все же могут быть приложения, полагающиеся на анонимный доступ.
+
+Установка значения 'restrict anonymous = 1' отключит анонимный доступ к SAMR.
+
+Установка 'restrict anonymous = 2' помимо ограничения доступа SAMR запрещает анонимные подключения к общему ресурсу IPC$. Установка параметра 'guest ok = yes' для любого общего ресурса переопределяет это значение.
+
+Значение по умолчанию:
+0</string>
+ <string id="POL_6745DAC3_A866_5519_83C8_8086C063AAB7">root directory</string>
+ <string id="POL_6745DAC3_A866_5519_83C8_8086C063AAB7_Help">При запуске сервер поменяет корневой каталог (chroot()) на каталог, указанный в этом параметре. Нет необходимости делать это в целях безопасности. Даже без этого параметра сервер запретит доступ к файлам, которые находятся за пределами доступности сервисов. Сервер также может проверить и запретить следовать по симлинкам, которые ведут в другие части файловой системы или попытки использовать «..» в именах файлов для доступа к другим каталогам (в зависимости от настройки параметра 'wide smbconfoptions').
+
+Добавление записи корневого каталога отличного от «/», добавляет дополнительный уровень безопасности, но за все приходится платить. При этом гарантируется, что не будет предоставлен доступ к файлам, не входящим в поддерево, указанное в параметре 'root directory', включая некоторые файлы, необходимые для полной работы сервера. Для обеспечения полной работоспособности сервера, вам придется скопировать некоторые файлы относительно нового корневого каталога. В частности, нужен будет файл /etc/passwd (или его часть) и все бинарные файлы и файлы конфигурации, необходимые для печати (при необходимости). Набор этих файлов зависит от операционной системы.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/homes/smb</string>
+ <string id="POL_9218F54E_BE22_57C0_BEF2_489F89B7D3BA">samba kcc command</string>
+ <string id="POL_9218F54E_BE22_57C0_BEF2_489F89B7D3BA_Help">Эта опция указывает путь к сценарию Samba KCC. Этот сценарий используется для репликации топологии.
+
+Нет необходимости изменять эту опцию, кроме как в целях тестирования или если samba_kcc был установлен не в папку по умолчанию.
+
+Значение по умолчанию:
+/samba_kcc
+
+Пример:
+/usr/local/bin/kcc</string>
+ <string id="POL_86AEEBA8_5181_54A2_A436_FD35443F7C03">security</string>
+ <string id="POL_86AEEBA8_5181_54A2_A436_FD35443F7C03_Help">Этот параметр влияет на то, как будут себя вести клиенты Samba и это один из наиболее важных параметров файла smb.conf.
+
+По умолчанию 'security = user', так как это наиболее распространенный параметр, используемый для автономного файлового сервера или контроллера домена.
+
+Альтернативные значения: 'security = ads' или 'security = domain', поддерживают присоединение Samba к домену Windows.
+
+Необходимо использовать 'security = user' и параметр 'map to guest', если необходимо в основном настроить общие ресурсы без пароля (гостевые ресурсы). Обычно такие настройки используются для общего сервера печати.
+
+
+ security = AUTO
+
+Это значение по умолчанию в Samba, которое заставляет Samba обращаться к параметру 'server role' (если он установлен) для определения режима безопасности.
+
+ security = USER
+
+Это значение по умолчанию в Samba, если параметр 'server role' не установлен. С безопасностью на уровне пользователя клиент должен сначала «войти в систему» (logon) ​​с существующим именем пользователя и паролем (которые могут быть сопоставлены с помощью параметра 'username map'). В этом режиме безопасности также можно использовать зашифрованные пароли (см. параметр 'encrypt passwords'). Параметры 'user' и 'guest only', если они установлены, могут изменить пользователя UNIX для использования в этом соединении, НО только после того как пользователь успешно пройдет аутентификацию.
+
+Обратите внимание, что имя запрашиваемого ресурса не отправляется на сервер до тех пор, пока сервер не аутентифицирует клиента. Именно поэтому гостевые учетные записи не работают в режиме безопасности USER, не позволяя серверу автоматически сопоставлять неизвестных пользователей с 'guest account'. Подробнее об этом см. параметр 'map_to_guest'.
+
+ security = DOMAIN
+
+Этот режим будет работать правильно только в том случае, если для добавления компьютера в домен Windows NT использовалась команда net(8). При этом должен быть установлен параметр 'encrypt passwords = yes'. В этом режиме Samba будет пытаться проверить имя пользователя/пароль, передав его основному или резервному домен контроллерам Windows NT т.е. сделает тоже самое, что сделал бы сервер Windows NT.
+
+Обратите внимание, что действующий пользователь UNIX должен существовать, а также учетная запись на контроллере домена, чтобы у Samba была действующая учетная запись UNIX для сопоставления доступа к файлам.
+
+Заметьте, что с точки зрения клиента, нет разницы между режимами security = domain и security = user. Это влияет только на то, как сервер работает с аутентификацией, и никоим образом не влияет на то, что видит клиент.
+
+Заметьте, что имя запрошенного ресурса не будет послано серверу до тех пор, пока сервер не аутентифицирует клиента. Вот почему гостевые общие ресурсы не работают в режиме security = USER, не позволяя серверу автоматически сопоставлять неизвестных пользователей с 'guest account'. Подробнее об этом см. параметр 'map to guest'.
+
+См. также параметры 'password server' и 'encrypt passwords'.
+
+ security = ADS
+
+В этом режиме Samba работает как член домена AD. Для работы в этом режиме на машине, на которой работает Samba, должен быть установлен и настроен Kerberos, а Samba должна быть присоединена к области AD с использованием утилиты net.
+
+
+Обратите внимание, что этот режим НЕ заставляет Samba работать в качестве контроллера домена Active Directory.
+
+Обратите внимание, что для этого для основного домена должны быть установлены параметры 'require strong key = yes' и 'client schannel = yes'.
+
+См. раздел «Domain Membership» в руководстве Samba-HOWTO для получения более подробной информации.
+
+Значение по умолчанию:
+AUTO
+
+Пример:
+DOMAIN</string>
+ <string id="POL_925F9081_BDD3_5BE8_BB73_89EBE3A0A8F0">server role</string>
+ <string id="POL_925F9081_BDD3_5BE8_BB73_89EBE3A0A8F0_Help">Этот параметр определяет основной режим работы сервера Samba и является одним из наиболее важных параметров в файле smb.conf.
+
+Значение по умолчанию — 'server role = auto', так как Samba работает в соответствии с настройками параметра 'security' или, если они не указаны, как простой файловый сервер, не подключенный ни к какому домену.
+
+Альтернативные варианты: 'server role = standalone' и 'server role = member server', которые поддерживают присоединение Samba к домену Windows, а также 'server role = domain controller', который запускает Samba в качестве контроллера домена Windows.
+
+Необходимо использовать 'server role = standalone' и параметр 'map to guest', если необходимо в основном настроить общие ресурсы без пароля (гостевые ресурсы). Обычно такие настройки используются для общего сервера печати.
+
+SERVER ROLE = AUTO
+
+Это значение 'server role' по умолчанию в Samba, при этом Samba будет обращаться к параметру 'security' (если он установлен) для определения роли сервера, обеспечивая совместимость поведения с предыдущими версиями Samba.
+
+SERVER ROLE = STANDALONE
+
+Это значение по умолчанию в Samba, если параметр 'security' не указан. В автономном режиме клиент должен сначала «войти в систему» ​​(logon) ​​с существующим именем пользователя и паролем (которые могут быть сопоставлены с помощью параметра 'username map'), хранящимся на этом компьютере. В этом режиме по умолчанию используются зашифрованные пароли (см. параметр 'encrypt passwords'). Параметры 'user' и 'guest only', если они установлены, могут изменить пользователя UNIX для использования в этом соединении, НО только после того как пользователь успешно пройдет аутентификацию.
+
+SERVER ROLE = MEMBER SERVER
+
+Этот режим будет работать правильно только в том случае, если для добавления компьютера в домен Windows использовалась команда net(8). При этом должен быть установлен параметр 'encrypt passwords = yes'. В этом режиме Samba будет пытаться проверить имя пользователя/пароль, передав его контроллеру домена Windows или Samba точно так же, как это сделал бы Windows Server.
+
+Обратите внимание, что действующий пользователь UNIX должен существовать, а также должна существовать учетная запись на контроллере домена, чтобы у Samba была действующая учетная запись UNIX для сопоставления доступа к файлам. Это может обеспечить Winbind.
+
+SERVER ROLE = CLASSIC PRIMARY DOMAIN CONTROLLER
+
+В этом режиме работы выполняется классический основной контроллер домена Samba, предоставляющий услуги входа в систему для клиентов Windows и Samba NT4-подобного домена. Клиенты должны быть присоединены к домену, чтобы создать безопасный, надежный путь в сети. В каждой области NetBIOS должен быть только один PDC (обычно это широковещательная сеть или клиенты, обслуживаемые одним WINS-сервером).
+
+SERVER ROLE = CLASSIC BACKUP DOMAIN CONTROLLER
+
+В этом режиме работы выполняется классический резервный контроллер домена Samba, предоставляющий услуги входа в систему для клиентов Windows и Samba NT4-подобного домена. В качестве BDC это позволяет нескольким серверам Samba предоставлять избыточные службы входа в единую область NetBIOS.
+
+SERVER ROLE = ACTIVE DIRECTORY DOMAIN CONTROLLER
+
+Этот режим работы запускает Samba как контроллер домена Active Directory, предоставляя услуги входа в домен для клиентов Windows и Samba домена. Эта роль требует особой настройки, см. руководство Samba4-HOWTO.
+
+Значение по умолчанию:
+AUTO
+
+Пример:
+ACTIVE DIRECTORY DOMAIN CONTROLLER</string>
+ <string id="POL_6B0930DB_3CC7_57DB_8798_A6B6D3AF05B9">server schannel</string>
+ <string id="POL_6B0930DB_3CC7_57DB_8798_A6B6D3AF05B9_Help">Эта опция устарела, начиная с Samba 4.8 и будет удалена в будущем, так как если не установлено значение yes (что будет жестко запрограммировано в будущем) существует проблема безопасности.
+
+Samba будет записывать в файлы журнала (на уровне 0) сообщения о проблеме безопасности, если значение этого праметра не равно yes.
+
+См. CVE-2020-1472 (ZeroLogon) https://bugzilla.samba.org/show_bug.cgi?id=14497
+
+Если у вас все еще есть старые члены домена, используйте параметр 'server require schannel:COMPUTERACCOUNT'.
+
+Параметр 'server require schannel:COMPUTERACCOUNT' имеет приоритет над данным параметром.
+
+Значение по умолчанию:
+yes
+</string>
+ <string id="POL_6DC4F5E8_3493_5D3C_8E35_D928C38C2604">server signing</string>
+ <string id="POL_6DC4F5E8_3493_5D3C_8E35_D928C38C2604_Help">Этот параметр определяет, следует ли серверу предлагать или требовать от клиента подписывания SMB1 и SMB2. Возможные значения: default, auto, mandatory и disabled.
+
+Если установлено значение default и если параметр 'server role' имеет значение active directory domain controller, подпись smb обязательна, и не требуется в противном случае.
+
+Если установлено значение auto, подписывание SMB1 предлагается, но не обязательно. Если установлено значение mandatory, подписывание SMB1 обязательно. Если установлено значение disabled подписывание SMB даже не предлагается.
+
+Для протокола SMB2 значение этого параметра не может иметь значение disabled. При согласовании SMB2, если этот параметр имеет значение disabled, он будет рассматриваться как значение auto. Если установить значение mandatory, подписывание SMB2 обязательно.
+
+Значение по умолчанию:
+default</string>
+ <string id="POL_7C0D1957_E0F4_5B60_805D_FBA7399D8737">smb passwd file</string>
+ <string id="POL_7C0D1957_E0F4_5B60_805D_FBA7399D8737_Help">В этом параметре указывается путь к шифрованному файлу smbpasswd. По умолчанию путь к файлу smbpasswd вкомпилирован в Samba.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/etc/samba/smbpasswd</string>
+ <string id="POL_94D60BE2_185E_5EC1_8E58_146C4B17C1E7">tls cafile</string>
+ <string id="POL_94D60BE2_185E_5EC1_8E58_146C4B17C1E7_Help">Этот параметр определяет файл (в формате PEM) содержащий сертификаты CA корневых удостоверяющих центров (root CA), которым можно доверять для подписи сертификатов или промежуточных сертификатов CA.
+
+Это путь относительно каталога определённого в параметре 'private dir', если путь не начинается с /.
+
+Значение по умолчанию:
+tls/ca.pem</string>
+ <string id="POL_A9FA5D2E_2052_5A81_812D_83A2952DF38B">tls certfile</string>
+ <string id="POL_A9FA5D2E_2052_5A81_812D_83A2952DF38B_Help">Этот параметр определяет файл (в формате PEM) содержащий RSA сертификат.
+
+Это путь относительно каталога определённого в параметре 'private dir', если путь не начинается с /.
+
+Значение по умолчанию:
+tls/cert.pem</string>
+ <string id="POL_C3E30BBB_123E_55E6_9693_7FF6CCF7488D">tls crlfile</string>
+ <string id="POL_C3E30BBB_123E_55E6_9693_7FF6CCF7488D_Help">Этот параметр определяет файл содержащий список отозванных сертификатов (CRL).
+
+Это путь относительно каталога определённого в параметре 'private dir', если путь не начинается с /.
+
+Значение по умолчанию:
+tls crlfile =</string>
+ <string id="POL_ABFC90A0_6AA2_5372_85E6_FCD989E458EE">tls dh params file</string>
+ <string id="POL_ABFC90A0_6AA2_5372_85E6_FCD989E458EE_Help">Этот параметр определяет файл содержащий параметры Диффи-Хеллмана, который будет использоваться с шифрами DH.
+
+Это путь относительно каталога определённого в параметре 'private dir', если путь не начинается с /.
+
+Значение по умолчанию:
+tls dh params file =</string>
+ <string id="POL_0F91E806_ADD5_59A1_B4FA_E99A51FED659">tls enabled</string>
+ <string id="POL_0F91E806_ADD5_59A1_B4FA_E99A51FED659_Help">Если это параметр установлен (tls enabled = yes), то Samba будет по возможности использовать TLS для связи.
+
+Значение по умолчанию:
+tls enabled = yes</string>
+ <string id="POL_D245CE57_C525_5967_A452_F28BFDB9509B">tls keyfile</string>
+ <string id="POL_D245CE57_C525_5967_A452_F28BFDB9509B_Help">Этот параметр определяет файл (в формате PEM) содержащий закрытый ключ RSA. Этот файл должен быть доступен без пароля, т.е. он не должен быть зашифрован.
+
+Это путь относительно каталога определённого в параметре 'private dir', если путь не начинается с /.
+
+Значение по умолчанию:
+tls/key.pem</string>
+ <string id="POL_6DB833DB_F8B8_5A20_8E2A_6B7D8E298B9D">tls verify peer</string>
+ <string id="POL_6DB833DB_F8B8_5A20_8E2A_6B7D8E298B9D_Help">Этот параметр контролирует, будет ли клиент проверять сертификат и имя однорангового узла и насколько строго. Возможные значения (в порядке возрастания): no_check, ca_only, ca_and_name_if_available, ca_and_name и as_strict_as_possible.
+
+Если установлено значение no_check, сертификат не проверяется вообще, что допускает тривиальные атаки «человек посередине».
+
+Если установлено значение ca_only, сертификат проверяется на подпись от CA, указанного в параметре 'tls cafile'. Требуется установить для параметра 'tls cafile' допустимый файл. Срок действия сертификата также проверяется. Если настроена опция 'tls crlfile', сертификат также проверяется на соответствие c списка отозванных сертификатов.
+
+Если установлено значение ca_and_name_if_available, выполняются все проверки из ca_only. Кроме того, одноранговое имя хоста (peer hostname) сверяется с именем сертификата, если оно предоставлено прикладным уровнем и не задано как строка IP-адреса.
+
+Если установлено значение ca_and_name, выполняются все проверки из ca_and_name_if_available. Кроме того, необходимо указать имя хоста однорангового узла, и даже IP-адрес сверяется с именем сертификата.
+
+Если установлено значение as_strict_as_possible, выполняются все проверки из ca_and_name. Кроме того, необходимо настроить опцию 'tls crlfile'. В будущих версиях Samba могут быть реализованы дополнительные проверки.
+
+Значение по умолчанию:
+as_strict_as_possible</string>
+ <string id="POL_82913C09_64C3_59C3_8303_3A815661F70E">unix password sync</string>
+ <string id="POL_82913C09_64C3_59C3_8303_3A815661F70E_Help">Параметр заставляет синхронизировать пароль UNIX с паролем SMB при изменении зашифрованного пароля SMB в файле smbpasswd. При включении этого параметра (unix password sync = yes), от имени пользователя ROOT вызывается программа, определенная в параметре 'passwd program', что позволяет установить новый пароль UNIX без доступа к старому паролю UNIX (т.к. у программы смены пароля SMB нет никакого доступа к открытому тексту старого пароля, есть только новый пароль).
+
+Этот параметр не действует, если Samba работает как контроллер домена Active Directory. В этом случае обратите внимание на параметр 'password hash gpg key ids' и команду 'samba-tool user syncpasswords'.
+
+Значение по умолчанию:
+unix password sync = no</string>
+ <string id="POL_37EE4890_B571_50D5_B6D7_3462FF89BCE1">username level</string>
+ <string id="POL_37EE4890_B571_50D5_B6D7_3462FF89BCE1_Help">Этот параметр помогает Samba попытаться «угадать» реальное имя пользователя UNIX, поскольку многие клиенты DOS отправляют имя пользователя в верхнем регистре. По умолчанию Samba пробует использовать все строчные буквы, а затем имя пользователя с заглавной первой буквой и терпит неудачу, если имя пользователя не найдено на машине UNIX.
+
+Если для этого параметра установлено ненулевое значение, поведение меняется. Этот параметр представляет собой число, указывающее количество комбинаций верхнего регистра, которые следует попробовать при попытке определить имя пользователя UNIX. Чем выше число, тем больше комбинаций будет пробовано, но тем медленнее будет обнаружение имен пользователей. Используйте этот параметр при наличии «странных» имен пользователей на машине UNIX, таких как AstrangeUser.
+
+Этот параметр необходим только на системах UNIX, у которых имена пользователей чувствительны к регистру.
+
+Значение по умолчанию:
+0
+
+Пример:
+5</string>
+ <string id="POL_086EBC7E_1D72_5C67_9447_F5F6E36EFA8F">username map</string>
+ <string id="POL_086EBC7E_1D72_5C67_9447_F5F6E36EFA8F_Help">Параметр разрешает задать файл определяющий соответствие имен пользователей для клиентов на сервере. Может использоваться в нескольких целях. Самое стандартное применение это сопоставление имен пользователей DOS или Windows именам, используемым на UNIX системе. Другой вариант — привязать нескольких пользователей к одному имени пользователя, чтобы им было легче обмениваться файлами.
+
+Заметьте, что для пользователя или режима безопасности share, сопоставление пользователя применимо до утверждения пользовательских вверительных грамот (credentials). Серверы члены домена (домена или ads) применяют сопоставление имени пользователя после того, как пользователь был успешно зарегистрирован контроллером домена и требуют полного имени в таблице соответствия (например, biddle = DOMAINfoo).
+
+Файл соответствия анализируется построчно. Каждая строка должна содержать имя пользователя UNIX, потом знак равенства («=»), за которым следует список имен пользователей. Список имен пользователя может содержать имена в формате @group, и в этом случае они будут соответствовать любому имени пользователя UNIX в этой группе. Специальное имя клиента «*» является групповым символом и соответствует любому имени. Каждая строка файла соответствий может достигать 1023 символов.
+
+Файл обрабатывается построчно, берется имя пользователя и сравнивается его с каждым именем пользователя справа от знака «=». Если предоставленное имя совпадает с каким-либо из имен справа, оно заменяется именем слева. Затем обработка продолжается со следующей строки.
+
+Если строка начинается с «#» или «;» она игнорируется.
+
+Если строка начинается с «!» тогда обработка файла остановится после этой строки, если соответствие найдено. Иначе поиск соответствия продолжится дальше. Использование «!» является полезным, если в следующих строках у вас есть групповые соответствия. Например, для создания сопоставления имени admin или administrator к UNIX имени root, создайте такую строку:
+
+root = admin administrator
+
+Или создайте соответствие любой пользователь группы system UNIX к UNIX имени sys:
+
+sys = @system
+
+Можно создать множество соответствий имен в файле соответствий.
+
+Если система поддерживает опцию NIS NETGROUP, тогда база данных netgroup проверяется перед базой данных /etc/group для поиска соответствий в группах.
+
+Можно создать соответствия для имен пользователей Windows, используя двойные кавычки вокруг имени, в котором есть пробелы. Например:
+
+tridge = &quot;Andrew Tridgell&quot;
+
+создаст соответствие «Andrew Tridgell» с именем пользователя UNIX «tridge».
+
+Следующий пример создаст соответствие для mary и fred к Unix пользователю sys, и для остальных создаст соответствие к пользователю guest. Заметьте, что использование «!» укажет Samba прекращать обработку файла, если соответствие найдено в текущей строке:
+
+!sys = mary fred
+guest = *
+
+
+Заметьте, что переназначение имен применяется ко всем найденным именам пользователей. Таким образом, если вы соединитесь с \\server\fred, и fred повторно переназначен в mary, то фактически вы будете соединяться с \\server\mary и должны будете предоставить пароль, подходящий для mary, а не fred. Единственное исключение — это имя пользователя, которое передается серверу пароля (если он у вас один). Сервер пароля получит любое имя пользователя клиента без модификации.
+
+Также заметьте, что обратное переназначение имени не делается. Основная проблема в данном случае с печатью. У пользователей, которые были сопоставлены, может возникнуть проблема при удалении заданий печати, поскольку PrintManager под WfWg будет думать, что очередь печати им не принадлежит.
+
+Версии Samba до 3.0.8 поддерживали чтение только полного имени пользователя (например, DOMAIN\user) из таблицы соответствий при выполнении kerberos логина от клиента. Однако, при поиске соответствия для пользователя использующего NTLM [SSP], использовалось только имя пользователя. Иногда это приводило к противоречивому поведению даже на том же самом сервере.
+
+Следующие функциональные возможности появились в версии 3.0.8 и более поздни:
+
+ * При локальной аутентификации, таблица соответствия применяется к имени пользователя прежде подтверждения подлинности соединения.
+
+ * Полагаясь на внешний контроллер домена для подтверждения запроса аутентификации, smbd применит таблицу соответствия пользователя к полному имени пользователя (т.е. DOMAIN\user), только после того, как пользователь был успешно аутентифицирован.
+
+Значение по умолчанию:
+пустая строка (no username map)
+
+Пример:
+/usr/local/samba/lib/users.map</string>
+ <string id="POL_0FE7956E_5744_5658_A2ED_8433C45918D7">username map cache time</string>
+ <string id="POL_0FE7956E_5744_5658_A2ED_8433C45918D7_Help">Сопоставление имен пользователей с 'username map' или 'username map script' с функциями Samba может быть относительно дорогостоящим. При входе пользователя в систему сопоставление выполняется несколько раз. В частности, вызов сценария 'username map script' может замедлить вход в систему, если необходимо запрашивать внешние базы данных из вызываемого сценария.
+
+Параметр 'username map cache time' управляет кэшем отображения. Он определяет количество секунд, в течение которых отображение из файла сопоставления имен пользователей или сценария должно быть эффективно кэшировано. Значение по умолчанию 0 означает, что кэширование не выполняется.
+
+Значение по умолчанию:
+0
+
+Пример:
+60</string>
+ <string id="POL_7C2B49D9_45DE_5D97_B844_9F509F86D211">username map script</string>
+ <string id="POL_7C2B49D9_45DE_5D97_B844_9F509F86D211_Help">Этот сценарий является взаимоисключающей альтернативой параметру 'username map'. Этот параметр указывает внешнюю программу или сценарий, которые должны принимать один параметр командной строки (имя пользователя, переданное в запросе аутентификации) и возвращать строку в стандартном выводе (имя, с которым должна быть сопоставлена учетная запись). Таким образом, можно хранить таблицы сопоставления имен пользователей в службах каталогов LDAP или NIS.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/etc/samba/scripts/mapusers.sh</string>
+ <string id="POL_22AAB8AC_4E62_5B51_BC38_C9340E8AC56E">tls priority</string>
+ <string id="POL_22AAB8AC_4E62_5B51_BC38_C9340E8AC56E_Help">Этот параметр опредеяет строку, описывающую протоколы TLS, которые будут поддерживаться в частях Samba, которые используют GnuTLS, в частности AD DC.
+
+Строка добавляется к списку приоритетов по умолчанию GnuTLS.
+
+Допустимые параметры описаны в документации GNUTLS Priority-Strings по адресу http://gnutls.org/manual/html_node/Priority-Strings.html.
+
+Протокол SSL3.0 будет отключен.
+
+Значение по умолчанию:
+NORMAL:-VERS-SSL3.0</string>
+ <string id="POL_08DDB9FE_1D88_5264_BEB0_6D60420CE12B">aio max threads</string>
+ <string id="POL_08DDB9FE_1D88_5264_BEB0_6D60420CE12B_Help">Целочисленный параметр, указывающий максимальное количество потоков, которые каждый процесс smbd будет создавать при выполнении параллельных асинхронных вызовов ввода-вывода. Если количество невыполненных вызовов превышает это число, запросы не будут отклонены, а будут помещены в очередь и будут запланированы, в свою очередь, как завершенные невыполненные запросы.
+
+Связанный параметр: 'aio read size'
+
+Связанный параметр: 'aio write size'
+
+Значение по умолчанию:
+100</string>
+ <string id="POL_0F98F240_9B2D_5788_AC7C_7B2ECDAE60A2">deadtime</string>
+ <string id="POL_0F98F240_9B2D_5788_AC7C_7B2ECDAE60A2_Help">Значением данного параметра (десятичное целое число) является время бездействия в минутах, по истечении которого соединение считается утраченным и происходит разъединение. 'deadtime' срабатывает только в том случае, если нет открытых файлов.
+
+Он используется для освобождения ресурсов сервера, нагруженного большим количеством неактивных соединений.
+
+У большинства клиентов есть функция автоматического переподключения при разрыве соединения, поэтому в большинстве случаев этот параметр прозрачен для пользователей.
+
+Для большинства систем рекомендуется использовать этот параметр с таймаутом в несколько минут.
+
+Нулевое время 'deadtime' указывает на то, что соединение разрываться не будет.
+
+Значение по умолчанию:
+10080
+
+Пример:
+15</string>
+ <string id="POL_BAC6D3CB_A32D_5702_93FD_289B714016C3">getwd cache</string>
+ <string id="POL_BAC6D3CB_A32D_5702_93FD_289B714016C3_Help">Это тюнинговый параметр. Если он установлен (getwd cache = yes), будет использоваться алгоритм кэширования для сокращения времени, необходимого для getwd() вызовов. Существенно повышает производительность, особенно, когда параметр 'wide links' не установлен.
+
+Значение по умолчанию:
+getwd cache = yes</string>
+ <string id="POL_0FB07FB9_33B4_5ECF_9725_9B7A38F863AF">hostname lookups</string>
+ <string id="POL_0FB07FB9_33B4_5ECF_9725_9B7A38F863AF_Help">Указывает, следует ли Samba преобразовывать IP-адреса в имена компьютеров или использовать вместо этого IP-адреса. Например, преобразование имени компьютера используется при проверке запрета (hosts deny) или разрешения доступа (hosts allow) компьютера к Samba.
+
+Значение по умолчанию:
+hostname lookups = no</string>
+ <string id="POL_C2D014CF_45D1_5A08_9727_3F2B500A4D58">keepalive</string>
+ <string id="POL_C2D014CF_45D1_5A08_9727_3F2B500A4D58_Help">Значение параметра (целое число) представляет количество секунд между пакетами поддерживающими соединение (keepalive). Если этот параметр равен нулю, пакеты отправляться не будут. Пакеты поддерживающие соединение позволяют серверу проверять активность клиента.
+
+Если сокет имеет набор атрибутов SO_KEEPALIVE по умолчанию, то пакеты поддерживающие соединение не требуются (см. параметр 'socket options'). Обычно следует использовать эту опцию, только если вы столкнулись с трудностями.
+
+Обратите внимание, что этот параметр применяется только к клиентским соединениям SMB1 и не влияет на клиентов SMB2.
+
+Значение по умолчанию:
+300
+
+Пример:
+600</string>
+ <string id="POL_AF4738EE_230C_5D39_A4CE_F270B28FE9AB">max disk size</string>
+ <string id="POL_AF4738EE_230C_5D39_A4CE_F270B28FE9AB_Help">Этот параметр позволяет ограничить верхний предел видимого размера диска. Если для этого параметра установлено значение 100, тогда размер всех общих ресурсов будет не больше 100МБ.
+
+Обратите внимание, что этот параметр не ограничивает размер объем данных, которые можно поместить на диск. В приведенном выше случае всё равно можно хранить на диске гораздо больше, чем 100МБ, но если клиент запросит информацию о свободном пространстве на диске или о размере диска, то результат будет ограничен объемом, указанным в 'max disk size'.
+
+Этот параметр в первую очередь полезен для работы с ошибками в ПО, которое не может работать со слишком большими дисками, особенно с дисками, размером более 1ГБ.
+
+Значение 0 означает отсутствие ограничений.
+
+Значение по умолчанию:
+0
+
+Пример:
+1000</string>
+ <string id="POL_21C3BE22_42E5_544F_97AB_732B2163839B">max open files</string>
+ <string id="POL_21C3BE22_42E5_544F_97AB_732B2163839B_Help">Этот параметр ограничивает количество открытых файлов, которые будет обслуживать демон smbd(8) для одного клиента. Значение по умолчанию очень большое (16384), т.к. Samba использует всего один бит в памяти на один открытый файл. Установка этого параметра ниже 16384 приведет к тому, что Samba пожалуется и вернет это значение к минимуму 16384, поскольку Windows 7 зависит от этого количества доступных дескрипторов открытых файлов.
+
+Реальное ограничение количества открытых файлов обычно срабатывает раньше и устанавливается другим параметром — это количество открытых файлов, которое может открыть процесс (UNIX per-process file descriptor limit), а не этим параметром, поэтому не нужно изменять значение этого параметра.
+
+Значение по умолчанию:
+16384</string>
+ <string id="POL_67BA8388_A439_54EA_8A1B_B6D2CCD8BB9B">max smbd processes</string>
+ <string id="POL_67BA8388_A439_54EA_8A1B_B6D2CCD8BB9B_Help">Этот параметр ограничивает максимальное количество одновременно запущенных процессов smbd(8). Он предотвращает истощение ресурсов сервера, если сервер испытывает проблемы с обслуживанием большего, чем определенное количество подключений. Помните, что в номальных условиях, на каждого пользователя запускается по одному процессу smbd(8).
+
+Для Samba ADDC, использующего стандартную модель процесса, эта опция ограничивает количество процессов, разветвленных для обработки запросов. В настоящее время новые процессы форкуются только для запросов ldap и netlogon.
+
+Значение по умолчанию:
+0
+
+Пример:
+1000</string>
+ <string id="POL_7CB978B4_3314_5AE7_9821_574DC024294B">name cache timeout</string>
+ <string id="POL_7CB978B4_3314_5AE7_9821_574DC024294B_Help">Определяет количество секунд до истечения времени ожидания записи в кэше разрешения имени хоста Samba. Если установлено значение 0 — кэширование отключено.
+
+Значение по умолчанию:
+660
+
+Пример:
+0</string>
+ <string id="POL_93A78BFD_8C1E_5643_8329_A90FF5CE5A6B">socket options</string>
+ <string id="POL_93A78BFD_8C1E_5643_8329_A90FF5CE5A6B_Help">Современные серверные операционные системы в большинстве ситуаций настроены на высокую производительность сети. При установке параметров сокета, эти настройки переопределяются. В частности, в Linux есть механизм автонастройки размера буфера, который будет отключен, при указании размера буфера сокета. Это потенциально может вывести из строя стек TCP/IP.
+
+Правильная настройка параметров сокета может иметь большое значение для производительности, но неправильное их использование может ухудшить её на столько же. Как и в случае любой другой настройки низкого уровня, если необходимо внести изменения, внесите небольшие изменения и проверьте эффект, прежде чем вносить какие-либо большие изменения.
+
+Этот параметр позволяет задать параметры сокета, который будет использоваться для обслуживания клиентов.
+
+Параметры сокета — это элементы управления на сетевом уровне операционных систем, которые позволяют настраивать соединение.
+
+Обычно с помощью этого параметра проводится тонкая настройка сервера Samba для достижения оптимальной производительности в локальной сети. Нет способа узнать, какие параметры лучше подходят для сети, так что экспериментируйте. Настоятельно рекомендуется сначала прочитать соответствующую документацию для ОС (можеть быть поможет 'man setsockopt').
+
+Может обнаружиться, что на некоторых системах Samba сообщит «Unknown socket option», если включить тот или иной параметр. Это означает, что имя параметра было указано некорректно или нужно включить файл includes.h для системы. В последнем случае, пожалуйста, вышлите нам patch по адресу samba-technical@samba.org.
+
+Любые из поддерживаемых опций сокетов можно комбинировать любым способом, если это позволяет ОС.
+
+Список опций сокета, которые доступны на сегодняшний день:
+
+ SO_KEEPALIVE
+ SO_REUSEADDR
+ SO_BROADCAST
+ TCP_NODELAY
+ TCP_KEEPCNT *
+ TCP_KEEPIDLE *
+ TCP_KEEPINTVL *
+ IPTOS_LOWDELAY
+ IPTOS_THROUGHPUT
+ SO_REUSEPORT
+ SO_SNDBUF *
+ SO_RCVBUF *
+ SO_SNDLOWAT *
+ SO_RCVLOWAT *
+ SO_SNDTIMEO *
+ SO_RCVTIMEO *
+ TCP_FASTACK *
+ TCP_QUICKACK
+ TCP_NODELAYACK
+ TCP_KEEPALIVE_THRESHOLD *
+ TCP_KEEPALIVE_ABORT_THRESHOLD *
+ TCP_DEFER_ACCEPT *
+ TCP_USER_TIMEOUT *
+
+Опции, помеченные * принимают целые значения. Остальные принимают только 1 или 0, соответственно разрешая или запрещая опцию, по умолчанию все они разрешены, если не указать явно 1 или 0.
+
+Чтобы указать аргумент, используйте синтаксис SOME_OPTION=VALUE, например SO_SNDBUF=8192. Обратите внимание, что до и после знака равенства не должно быть пробелов.
+
+В локальной сети разумным будет использование опции 'socket options = IPTOS_LOWDELAY' и можно попытаться использовать 'socket options = IPTOS_LOWDELAY TCP_NODELAY'. В сети WAN попробуйте установить значение IPTOS_THROUGHPUT.
+
+Заметьте, что некоторые из этих параметров могут привести к тому, что Samba вообще не будет работать. Используйте эти параметры с осторожностью!
+
+Значение по умолчанию:
+TCP_NODELAY
+
+Пример:
+IPTOS_LOWDELAY</string>
+ <string id="POL_3FD02174_8A27_5426_848C_B3123EA8C4C3">use mmap</string>
+ <string id="POL_3FD02174_8A27_5426_848C_B3123EA8C4C3_Help">Этот глобальный параметр определяет, зависит ли содержимое tdb файлов Samba от mmap в работающей операционной системе. Samba требует согласованный mmap/read-write кэш памяти. В настоящее время только OpenBSD и HPUX не имеют такой согласованный кэша, и на этих платформах этот параметр внутренне переопределен и фактически не имеет значения. Во всех системах этот параметр следует оставить в покое. Этот параметр предоставлен, чтобы помочь разработчикам Samba отследить проблемы с внутренним кодом tdb.
+
+Значение по умолчанию:
+use mmap = yes</string>
+ <string id="POL_77FC1090_5D4B_587E_BD3B_DAE9F7A9682F">get quota command</string>
+ <string id="POL_77FC1090_5D4B_587E_BD3B_DAE9F7A9682F_Help">Параметр 'get quota command' можно использовать, если ОС, на которой установлен сервер Samba, имеет API для работы с квотами.
+
+Эта опция доступна только Samba была скомпилирована с поддержкой квот.
+
+Этот параметр должен указывать путь к сценарию, который запрашивает информацию о квоте для указанного пользователя/группы для раздела, в котором находится указанный каталог.
+
+Этот скрипт получает 3 аргумента:
+
+ * каталог
+ * тип запроса
+ * uid пользователя или gid группы
+
+Каталог на самом деле это просто «.» — его нужно обрабатывать относительно текущего рабочего каталога, который также может запрашивать скрипт.
+
+Тип запроса:
+
+ 1 — квота пользователя
+ 2 — квота пользователя по умолчанию (uid = -1)
+ 3 — квота группы
+ 4 — квота группы по умолчанию (gid = -1)
+
+Этот сценарий должен выводить одну строку с пробелами между столбцами. В столбцах выводится:
+
+ 1 — флаги квоты (0 = нет квот, 1 = квоты включены, 2 = квоты включены и обязательны)
+ 2 — текущее количество использованных блоков
+ 3 — мягкое (softlimit) количество блоков
+ 4 — жесткое (hardlimit) количество блоков
+ 5 — текущее количество inodes
+ 6 — мягкое (softlimit) количество индексных дескрипторов (inodes)
+ 7 — жесткое (hardlimit) количество индексных дескрипторов (inodes)
+ 8 (опционально) — количество байт в блоке (по умолчанию 1024)
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/local/sbin/query_quota</string>
+ <string id="POL_B093DF52_6C77_5327_AC90_AAC6AF6CB126">host msdfs</string>
+ <string id="POL_B093DF52_6C77_5327_AC90_AAC6AF6CB126_Help">Если этот параметр установлен, то Samba будет выступать в качестве сервера Dfs, и позволит Dfs клиентам просматривать Dfs деревья, размещенные на сервере.
+
+См. также уровень параметра 'msdfs root'. Дополнительную информацию о создании Dfs дерева на Samba, см. в разделе «MSFDS» руководства Samba3-HOWTO.
+
+Значение по умолчанию:
+host msdfs = yes</string>
+ <string id="POL_6B9A8C91_49AF_58C8_931C_0304B60491D2">set quota command</string>
+ <string id="POL_6B9A8C91_49AF_58C8_931C_0304B60491D2_Help">Этот параметр следует использовать только тогда, когда для Samba недоступны средства API операционной системы.
+
+Этот параметр доступен лишь в том случае если Samba была скомпилирована с поддержкой квот.
+
+Этот параметр должен указывать путь к сценарию, который устанавливает квоты для заданных аргументов.
+
+Указанный сценарий должен принимать следующие параметры:
+
+ * 1 — путь к месту установки квоты. Это значение необходимо интерпретировать относительно текущего рабочего каталога, который также может проверять сценарий.
+ * 2 — тип квоты:
+ * 1 — пользовательская квота
+ * 2 — пользовательские квоты по умолчанию (uid = -1)
+ * 3 — квоты групп
+ * 4 — квоты групп по умолчанию (gid = -1)
+ * 4 — состояние квоты (0 — запрещена (disable), 1 — разрешена (enable), 2 — включена и навязывается (enable and enforce))
+ * 5 — граница мягкой блокировки
+ * 6 — граница жесткой блокировки
+ * 7 — граница мягкой блокировки inode
+ * 8 — граница жесткой блокировки inode
+ * 9 — (необязателен) размер блока, по умолчанию 1024
+
+Скрипт должен вывести хотя бы одну строку данных, если все прошло успешно и не выводить ничего, если случилась ошибка.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+/usr/local/sbin/set_quota</string>
+ <string id="POL_6A683A86_8075_55FF_B1E6_D7874A3539AA">apply group policies</string>
+ <string id="POL_6A683A86_8075_55FF_B1E6_D7874A3539AA_Help">Этот параметр определяет, будет ли winbind выполнять команду gpupdate, определенную в параметре 'gpo update command', в интервале обновления групповой политики. Интервал обновления групповой политики определяется как каждые 90 минут плюс случайное смещение от 0 до 30 минут. При этом политики компьютера групповой политики применяются к клиенту или KDC, а политики компьютера — к серверу.
+
+Значение по умолчанию:
+apply group policies = no</string>
+ <string id="POL_0471CC71_51D5_58F6_A00A_6E8B283C3AF5">create krb5 conf</string>
+ <string id="POL_0471CC71_51D5_58F6_A00A_6E8B283C3AF5_Help">Снятие отметки с этого параметра (значение 'create krb5 conf = no') запрещает winbind создавать собственные файлы krb5.conf. Winbind обычно делает это, потому что библиотеки krb5 не поддерживают сайты AD и поэтому могут выбрать любой контроллер домена из потенциально очень многих. Winbind ориентирован на сайт и заставляет библиотеки krb5 использовать локальный контроллер домена, создавая свои собственные файлы krb5.conf.
+
+Предотвратить такое поведение может потребоваться, если нужно добавить в system-krb5.conf специальные параметры, которые winbind не видит.
+
+Значение по умолчанию:
+create krb5 conf = yes</string>
+ <string id="POL_46FF92BD_F484_5B2C_A639_ACBE73F15F3A">idmap backend</string>
+ <string id="POL_46FF92BD_F484_5B2C_A639_ACBE73F15F3A_Help">Параметр является интерфейсом к Winbind для хранения переменных подсистем к таблицам соответствия SID/uid/gid.
+
+Эта опция указывает бэкэнд по умолчанию, который используется, когда не задана специальная конфигурация, но теперь он устарел и заменен новым параметром 'idmap config * : backend'.
+
+Значение по умолчанию:
+tdb</string>
+ <string id="POL_309434B4_68BA_53E0_BDF9_CA589711EA29">idmap cache time</string>
+ <string id="POL_309434B4_68BA_53E0_BDF9_CA589711EA29_Help">Этот параметр определяет время в секундах, в течение которого кэшируются положительные результаты ID/uid/gid запросов к интерфейсу Winbind idmap. По умолчанию Samba кэширует эти результаты в течение одной недели.
+
+Значение по умолчанию:
+604800</string>
+ <string id="POL_066B06D4_3BC0_5CFA_80A9_D2B1C046B5B0">idmap gid</string>
+ <string id="POL_066B06D4_3BC0_5CFA_80A9_D2B1C046B5B0_Help">Параметр определяет диапазон групповых идентификаторов, для конфигурации idmap по умолчанию. Теперь он устарел и заменен на 'idmap config * : range'.
+
+См. также параметр 'idmap config'.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+10000-20000</string>
+ <string id="POL_9B5D009F_1EBE_5E94_A46B_8644157A6061">idmap negative cache time</string>
+ <string id="POL_9B5D009F_1EBE_5E94_A46B_8644157A6061_Help">Этот параметр указывает количество секунд, в течение которых интерфейс Winbind idmap будет кэшировать отрицательные результаты запроса SID/uid/gid.
+
+Значение по умолчанию:
+120</string>
+ <string id="POL_37D1856A_CAF9_5395_AC8E_8E0F3E9C03E4">idmap uid</string>
+ <string id="POL_37D1856A_CAF9_5395_AC8E_8E0F3E9C03E4_Help">Параметр 'idmap uid' указывает диапазон идентификаторов пользователей для конфигурации idmap по умолчанию. Этот параметр устарел и заменен на 'idmap config * : range'.
+
+См. параметр 'idmap config'.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+10000-20000</string>
+ <string id="POL_283F0A5F_5841_5D1D_8EE3_D2715805A463">include system krb5 conf</string>
+ <string id="POL_283F0A5F_5841_5D1D_8EE3_D2715805A463_Help">Установка для этого параметра значения no не позволит Winbind включить системный файл /etc/krb5.conf в создаваемый файл krb5.conf. См. также параметр 'create krb5 conf'. Эта опция применима только к Samba, построенной с использованием MIT Kerberos.
+
+Значение по умолчанию:
+include system krb5 conf = yes</string>
+ <string id="POL_61C9E6AE_96EF_5E8D_9AB8_7598584D391E">neutralize nt4 emulation</string>
+ <string id="POL_61C9E6AE_96EF_5E8D_9AB8_7598584D391E_Help">Этот параметр определяет, отправляет ли winbindd флаг NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION, чтобы обойти эмуляцию NT4 контроллера домена.
+
+Обычно не нужно устанавливать этот параметр. Это может быть полезно при обновлении доменов NT4 до AD.
+
+Поведение можно контролировать для каждого домена NetBIOS с помощью опции 'neutralize nt4 emulation:NETBIOSDOMAIN = yes'.
+
+Значение по умолчанию:
+neutralize nt4 emulation = no</string>
+ <string id="POL_D8459DE9_6E91_58A6_8E4E_83BFBB41AE4E">reject md5 servers</string>
+ <string id="POL_D8459DE9_6E91_58A6_8E4E_83BFBB41AE4E_Help">Этот параметр определяет, требуется ли winbindd поддержка aes для безопасного канала netlogon.
+
+Должны быть установлены флаги: NETLOGON_NEG_ARCFOUR, NETLOGON_NEG_SUPPORTS_AES, NETLOGON_NEG_PASSWORD_SET2 и NETLOGON_NEG_AUTHENTICATED_RPC.
+
+Можно установить этот параметр (reject md5 servers = yes), если все контроллеры домена поддерживают AES. Это предотвратит атаки перехода на более раннюю версию.
+
+Такое поведение можно контролировать для каждого домена NetBIOS с помощью опции 'reject md5 servers:NETBIOSDOMAIN = yes'.
+
+Эта опция имеет приоритет перед опцией 'require strong key'.
+
+Значение по умолчанию:
+reject md5 servers = no</string>
+ <string id="POL_E3A88031_AF89_5D12_9F48_5BD36B25F58C">require strong key</string>
+ <string id="POL_E3A88031_AF89_5D12_9F48_5BD36B25F58C_Help">Этот параметр определяет, требуется ли winbindd поддержка сильного ключа md5 для безопасного канала netlogon.
+
+Должны быть установлены флаги: NETLOGON_NEG_STRONG_KEYS, NETLOGON_NEG_ARCFOUR и NETLOGON_NEG_AUTHENTICATED_RPC.
+
+Можно отключить этот параметр (require strong key = no), если некоторые контроллеры домена поддерживают только DES. Это может позволить согласовать слабую криптографию, возможно, с помощью атак на более раннюю версию.
+
+Такое поведение можно контролировать для каждого домена NetBIOS с помощью опции 'require strong key:NETBIOSDOMAIN = no'.
+
+Обратите внимание, что для домена Active Directory эта опция принудительно включена.
+
+Опция 'reject md5 servers' имеет приоритет над этой опцией.
+
+Эта опция имеет приоритет перед опцией 'client schannel'.
+
+Значение по умолчанию:
+require strong key = yes</string>
+ <string id="POL_D55FF104_CF84_512D_9962_D01784923C49">template homedir</string>
+ <string id="POL_D55FF104_CF84_512D_9962_D01784923C49_Help">При передаче информации о пользователе Windows NT, значение этого параметра будет использоваться демоном winbindd(8) в качестве домашнего каталога пользователя. Если присутствует последовательность %D, она заменяется доменным именем пользователя Windows NT. Если присутствует последовательность %U, она заменяется именем пользователя Windows NT.
+
+Значение по умолчанию:
+/home/%D/%U</string>
+ <string id="POL_A317595E_2C79_5B73_9043_CEB7525F6692">template shell</string>
+ <string id="POL_A317595E_2C79_5B73_9043_CEB7525F6692_Help">При передаче информации о пользователе Windows NT, значение этого параметра будет использоваться демоном winbindd(8) для определения командного интерпретатора (shell).
+
+Значение по умолчанию:
+/bin/false</string>
+ <string id="POL_F8F9B8BF_2D26_5079_928E_7168BBCA91BE">winbind cache time</string>
+ <string id="POL_F8F9B8BF_2D26_5079_928E_7168BBCA91BE_Help">Этот параметр указывает количество секунд, в течение которых демон winbindd(8) будет кэшировать информацию о пользователях и группах перед повторным запросом к серверу Windows NT.
+
+Это не относится к запросам аутентификации, они всегда оцениваются в реальном времени, если не включена опция 'winbind offline logon'.
+
+Значение по умолчанию:
+300</string>
+ <string id="POL_07E24EA1_B340_5215_BDBB_5248537F9540">winbindd socket directory</string>
+ <string id="POL_07E24EA1_B340_5215_BDBB_5248537F9540_Help">Этот параметр управляет расположением сокета демона winbind.
+
+За исключением сценариев автоматического тестирования, этот параметр не должен изменяться, поскольку клиентские инструменты (nss_winbind и т.д.) не поддерживают этот параметр. Клиентские инструменты должны быть уведомлены об измененном пути с помощью переменной среды WINBINDD_SOCKET_DIR.
+
+Значение по умолчанию:
+winbindd socket directory =</string>
+ <string id="POL_8FEAD8B9_8097_5BA2_BD78_7BB0AA8691C1">winbind enum groups</string>
+ <string id="POL_8FEAD8B9_8097_5BA2_BD78_7BB0AA8691C1_Help">При больших установках с использованием winbindd(8) бывает необходимо подавить перечисление групп через системные вызовы setgrent(), getgrent() и endgrent(). Если параметр не установлен (winbind enum groups = no), системный вызов getgrent() не будет возвращать данных.
+
+Внимание. Отключение перечисления групп может привести к странному поведению некоторых программ.
+
+Значение по умолчанию:
+winbind enum groups = no</string>
+ <string id="POL_FAB1BAAD_85CD_5FE6_B0AA_AC48B77ACCCC">winbind enum users</string>
+ <string id="POL_FAB1BAAD_85CD_5FE6_B0AA_AC48B77ACCCC_Help">При больших установках с использованием winbindd(8) бывает необходимо подавить перечисление пользователей через системные вызовы setpwent(), getpwent() и endpwent(). Если параметр не установлен (winbind enum users = no), системный вызов getpwent() не будет возвращать данных.
+
+Внимание. Отключение перечисления пользователей может привести к странному поведению некоторых программ. Например, программа finger полагается на доступ к полному списку пользователей при поиске совпадающих имен пользователей.
+
+Значение по умолчанию:
+winbind enum users = no</string>
+ <string id="POL_2B331ECE_5A4A_5DE9_8DBF_EFBCE108F070">winbind expand groups</string>
+ <string id="POL_2B331ECE_5A4A_5DE9_8DBF_EFBCE108F070_Help">Этот параметр управляет максимальной глубиной, которую будет проходить winbindd при выравнивании членства во вложенных группах доменных групп Windows. Эта опция отличается от опции 'winbind nested groups', которая реализует модель локального вложения групп Windows NT4. Параметр 'winbind expand groups' специально применяется к членству в группах домена.
+
+Этот параметр также влияет на возврат членства в невложенных группах пользователей домена Windows. С новым значением по умолчанию 'winbind expand groups = 0' winbind вообще не запрашивает членство в группах.
+
+Имейте в виду, что высокое значение этого параметра может привести к замедлению работы системы, поскольку основной родительский демон winbindd должен выполнить развертывание группы и не сможет отвечать на входящие запросы NSS или аутентификации в это время.
+
+Значение по умолчанию было изменено с 1 на 0 в Samba 4.2. Некоторые неработающие приложения (включая некоторые реализации newgrp и sg) вычисляют членство пользователей в группах путем обхода групп, для таких приложений потребуется 'winbind expand groups = 1'. Но новое значение по умолчанию делает winbindd более надежным, поскольку он не требует доступа SAMR к контроллерам домена доверенных доменов.
+
+Значение по умолчанию:
+0</string>
+ <string id="POL_7F3A4DCD_923C_5586_AFFB_1BA559F399CB">winbind:ignore domains</string>
+ <string id="POL_7F3A4DCD_923C_5586_AFFB_1BA559F399CB_Help">Этот параметр позволяет ввести список доверенных доменов, которые winbind должен игнорировать (не доверять). Это поможет избежать дополнительных затрат ресурсов на попытки входа в DC, с которыми не следует связываться.
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+DOMAIN1, DOMAIN2</string>
+ <string id="POL_FE5A1763_2311_55A2_AB2E_10D92C3A7FC4">winbind max clients</string>
+ <string id="POL_FE5A1763_2311_55A2_AB2E_10D92C3A7FC4_Help">Этот параметр указывает максимальное количество клиентов, с которыми демон winbindd(8) может соединиться. Параметр не является жестким пределом. Демон winbindd(8) настраивается так, чтобы принимать, по крайней мере, такое количество подключений, и если предел достигнут, делается попытка отключить неактивных клиентов.
+
+Значение по умолчанию:
+200</string>
+ <string id="POL_57855ED8_E596_52E6_A8F8_B710E76BD0F6">winbind max domain connections</string>
+ <string id="POL_57855ED8_E596_52E6_A8F8_B710E76BD0F6_Help">Этот параметр указывает максимальное количество одновременных подключений, которые демон winbindd(8) должен открыть к контроллеру домена одного домена. Установка для этого параметра значения больше 1 может улучшить масштабируемость с множеством одновременных запросов winbind, некоторые из которых могут быть медленными.
+
+Обратите внимание: если установлен параметр 'winbind offline logon', то для каждого домена разрешено только одно подключение к DC, независимо от значения параметра 'winbind max domain connections'.
+
+Значение по умолчанию:
+1
+
+Пример:
+10</string>
+ <string id="POL_6C096F2D_4DB1_5E05_84BB_9E9E3E0708BB">winbind nested groups</string>
+ <string id="POL_6C096F2D_4DB1_5E05_84BB_9E9E3E0708BB_Help">Если этот параметр установлен, активируется поддержка вложенных групп. Вложенные группы также называются локальными группами или псевдонимами. Они работают так же, как и их аналоги в Windows: вложенные группы определяются локально на любом компьютере (они совместно используются контроллерами домена через их SAM) и могут содержать пользователей и глобальные группы из любого доверенного SAM. Чтобы иметь возможность использовать вложенные группы, необходимо запустить nss_winbind.
+
+Значение по умолчанию:
+winbind nested groups = yes</string>
+ <string id="POL_7C9859FE_6BA0_526D_A308_9454D3063550">winbind normalize names</string>
+ <string id="POL_7C9859FE_6BA0_526D_A308_9454D3063550_Help">Этот параметр контролирует, заменять или нет пробелы в имени пользователя, группы на символ подчеркивания «_». Например, следует ли заменить имя «Space Kadet» на строку «space_kadet». У сценариев командного процессора Unix возникают ошибки с именами пользователей, содержащих пробелы, т.к. пробел является разделителем по умолчанию для shell. Если в домене есть имена учётных записей пользователей, содержащие символ подчеркивания, этот параметр может вызвать проблемы, если функция псевдонима не поддерживается плагином nss_info.
+
+Эта функция также включает API псевдонимов имен, который можно использовать для преобразования имен пользователей и групп домена в неквалифицированную версию. Пожалуйста, обратитесь к странице руководства по настройке плагинов idmap и nss_info, чтобы узнать, как настроить псевдонимы для конкретной конфигурации. Использование псевдонимов имеет приоритет (и является взаимоисключающим) над механизмом замены пробелов.
+
+Значение по умолчанию:
+winbind normalize names = no</string>
+ <string id="POL_3D3D280A_1D60_58AA_A7BD_54D13DDBE1A6">winbind nss info</string>
+ <string id="POL_3D3D280A_1D60_58AA_A7BD_54D13DDBE1A6_Help">Параметр предназначен для контроля над тем, как Winbind получает информацию от Name Service Information для создания пользовательских домашних каталогов и login shell. В настоящее время доступны следующие значения параметра:
+
+ * template — по умолчанию, используются шаблоны для login shell и home directory.
+
+ * &lt;sfu | sfu20 | rfc2307 &gt; — если Samba запущена с 'security = ads' и контроллер домена Active Directory поддерживает Microsoft «Services for Unix» (SFU) LDAP schema, может получить атрибуты login shell и home directory непосредственно от Directory Server. Для SFU 3.0 или 3.5 просто выберите «sfu», если вы используете SFU 2.0, выберите «sfu20».
+
+Обратите внимание, что для бэкэнда idmap idmap_ad необходимо настроить эти параметры в разделе конфигурации idmap. Обязательно ознакомьтесь с документацией используемого вами бэкенда idmap.
+
+Значение по умолчанию:
+template
+
+Пример:
+sfu</string>
+ <string id="POL_34B48F10_7723_5E77_A57B_AE606BBB43B7">winbind offline logon</string>
+ <string id="POL_34B48F10_7723_5E77_A57B_AE606BBB43B7_Help">Этот параметр определяет, можно ли осуществлять подключение с модулем pam_winbind, используя Cached Credentials (буферизированные личные данные). Если параметр включен, winbindd сохранит пользовательские Credentials от успешных логинов, в локальном кэше в зашифрованном виде.
+
+Значение по умолчанию:
+winbind offline logon = no</string>
+ <string id="POL_05A14875_99EE_5000_A1E2_100D2F7B079F">winbind reconnect delay</string>
+ <string id="POL_05A14875_99EE_5000_A1E2_100D2F7B079F_Help">Этот параметр указывает количество секунд, в течение которых демон winbindd(8) будет ждать между попытками связи с контроллером домена, для домена, который определен как неработающий или недоступный.
+
+Значение по умолчанию:
+30</string>
+ <string id="POL_98A94538_AA09_51C8_A96D_ACB0B314F5F4">winbind refresh tickets</string>
+ <string id="POL_98A94538_AA09_51C8_A96D_ACB0B314F5F4_Help">Этот параметр определяет, должен ли Winbind обновлять билеты Kerberos при использовании модуля pam_winbind.
+
+Значение по умолчанию:
+winbind refresh tickets = yes</string>
+ <string id="POL_96B1E9F8_5418_5EA0_8B87_614B45822D92">winbind request timeout</string>
+ <string id="POL_96B1E9F8_5418_5EA0_8B87_614B45822D92_Help">Этот параметр указывает количество секунд, в течение которых демон winbindd (8) будет ждать перед отключением клиентского соединения без ожидающих запросов (простаивающее соединение), либо клиентского соединения с запросом, который оставался невыполненным (зависшим) дольше указанного количества секунд.
+
+Значение по умолчанию:
+60</string>
+ <string id="POL_FEC015B1_6B0B_5D76_B23D_71363578FAF7">winbind rpc only</string>
+ <string id="POL_FEC015B1_6B0B_5D76_B23D_71363578FAF7_Help">Установка этого параметра (winbind rpc only = yes) заставляет winbindd использовать RPC вместо LDAP для получения информации с контроллеров домена.
+
+Значение по умолчанию:
+winbind rpc only = no</string>
+ <string id="POL_412B470E_EC88_556F_B9DE_1952C70E45B1">winbind scan trusted domains</string>
+ <string id="POL_412B470E_EC88_556F_B9DE_1952C70E45B1_Help">Этот параметр работает только в том случае, если параметр 'security' имеет значение domain или ads. Если параметр установлен (winbind scan trusted domains = yes) (по умолчанию), winbindd периодически пытается сканировать новые доверенные домены, и добавляет их в глобальный список внутри winbindd. Список можно извлечь с помощью 'wbinfo --trusted-domains --verbose'. Это соответствует поведению Samba 4.7 и старше.
+
+Создание этого глобального списка ненадежно и часто бывает неполным в сложных установках доверия. В большинстве случаев для правильной работы winbindd список больше не нужен. Например, для обслуживания простых файлов через SMB с использованием простой настройки idmap с autorid, tdb или ad. Однако для некоторых более сложных настроек требуется список, например, при указании бэкендов idmap для определенных доменов. Для некоторых настроек pam_winbind также может потребоваться глобальный список.
+
+Если у вас есть установка, которая не требует глобального списка, необходимо установить 'winbind scan trusted domains = no'.
+
+Значение по умолчанию:
+winbind scan trusted domains = yes</string>
+ <string id="POL_6247DEB4_05CC_51B8_A8CB_1FF7DEDA741C">winbind sealed pipes</string>
+ <string id="POL_6247DEB4_05CC_51B8_A8CB_1FF7DEDA741C_Help">Этот параметр определяет, будут ли запечатываться какие-либо запросы от winbindd к конвейеру контроллеров домена. Отключение запечатывания может быть полезно для отладки.
+
+Поведение можно контролировать для каждого домена NetBIOS с помощью опции 'winbind sealed pipes:NETBIOSDOMAIN = no'.
+
+Значение по умолчанию:
+winbind sealed pipes = yes</string>
+ <string id="POL_7E1E179F_7E0D_5CB4_BDAA_B8EDF41428CC">winbind separator</string>
+ <string id="POL_7E1E179F_7E0D_5CB4_BDAA_B8EDF41428CC_Help">Этот параметр разрешает администратору выбрать разделитель, используемый в имени пользователя в формате DOMAIN\user. Этот параметр применим для Unix служб с модулями pam_winbind.so и nss_winbind.so.
+
+Обратите внимание, что установка этого параметра в «+» вызывает проблемы с членством в группах, по крайней мере, в системах glibc, поскольку символ «+» используется в качестве специального символа для NIS в /etc/group.
+
+Значение по умолчанию:
+\
+
+Пример:
++</string>
+ <string id="POL_1780A1A5_0535_5D0B_8105_2129879E3C40">winbind use default domain</string>
+ <string id="POL_1780A1A5_0535_5D0B_8105_2129879E3C40_Help">Этот параметр разрешает winbindd(8) работать с пользователями без доменной части в имени пользователя. Пользователи без доменной части в имени рассматриваются winbindd как часть собственного домена сервера winbindd. Хотя это не приносит пользы пользователям Windows, это делает работу служб SSH, FTP и электронной почты вести себя также как они ведут себя в системе UNIX.
+
+По возможности следует избегать этого варианта. Это может вызвать путаницу в отношении обязанностей пользователя или группы. Во многих ситуациях неясно, следует ли считать winbind или /etc/passwd полномочными для пользователя, равно как и для групп.
+
+Значение по умолчанию:
+winbind use default domain = no</string>
+ <string id="POL_71A1842A_9526_5BF9_A0FC_07322D2C6C81">winbind use krb5 enterprise principals</string>
+ <string id="POL_71A1842A_9526_5BF9_A0FC_07322D2C6C81_Help">winbindd может получить билеты Kerberos для pam_winbind с помощью krb5_auth или wbinfo -K/--krb5auth=.
+
+winbindd (по крайней мере, как член домена) никогда не сможет получить полную картину топологии доверия (которая управляется контроллерами домена). Могут быть значения uPNSuffixes и msDS-SPNSuffixes, которые вообще не принадлежат ни одному домену AD.
+
+Если параметр 'winbind scan trusted domains = no' winbindd не сможет получить даже неполное представление о топологии.
+
+На самом деле знать о топологии доверия не обязательно. Можно просто полагаться на [K]-ый контроллер домена основного домена (например, PRIMARY.A.EXAMPLE.COM), использовать принципалы предприятия, например, upnfromB@B.EXAMPLE.COM@PRIMARY.A.EXAMPLE.COM и следовать рекомендациям WRONG_REALM, чтобы найти правильный DC. Последний принципал может быть userfromB@INTERNALB.EXAMPLE.PRIVATE.
+
+Если параметр 'winbind use krb5 enterprise principals = yes' будут использованы принципал winbindd.
+
+Значение по умолчанию:
+winbind use krb5 enterprise principals = no</string>
+ <string id="POL_B05D0593_B0CE_52A9_977C_E7A897EEA307">dns proxy</string>
+ <string id="POL_B05D0593_B0CE_52A9_977C_E7A897EEA307_Help">Указывает, что nmbd(8) при работе в качестве WINS-сервера и обнаружении того, что имя NetBIOS не было зарегистрировано, должен обрабатывать имя NetBIOS дословно как имя DNS и выполнять поиск на DNS-сервере для этого имени от имени клиента, запрашивающего имя.
+
+Обратите внимание, что максимальная длина имени NetBIOS составляет 15 символов, поэтому имя DNS (или псевдоним DNS) также может состоять максимум из 15 символов.
+
+nmbd порождает свою вторую копию для выполнения запросов поиска имени DNS, поскольку поиск имени является действием блокировки.
+
+Значение по умолчанию:
+dns proxy = yes</string>
+ <string id="POL_C1A54865_BE76_5627_B737_BBB708AEC44C">max wins ttl</string>
+ <string id="POL_C1A54865_BE76_5627_B737_BBB708AEC44C_Help">Этот параметр сообщает демону smbd(8), когда он действует как WINS-сервер (параметр 'wins support = yes'), какое максимально «время жизни» («time to live») NetBIOS-имён будет предоставлять nmbd (в секундах). Никогда не нужно изменять значение этого параметра. По умолчанию 6 дней (518400 секунд).
+
+Значение по умолчанию:
+518400</string>
+ <string id="POL_BEE0A696_13BD_578B_B448_1E0A01AB915A">min wins ttl</string>
+ <string id="POL_BEE0A696_13BD_578B_B448_1E0A01AB915A_Help">Этот параметр сообщает демону smbd(8), когда он действует как WINS-сервер (параметр 'wins support = yes'), какое минимальное «время жизни» («time to live») NetBIOS-имён будет предоставлять nmbd (в секундах). Никогда не нужно изменять значение этого параметра. По умолчанию 6 часов (21600 секунд).
+
+Значение по умолчанию:
+21600</string>
+ <string id="POL_890DE0DC_C0FC_565A_A1D3_AD06EFAC41ED">nbtd:wins_prepend1Bto1Cqueries</string>
+ <string id="POL_890DE0DC_C0FC_565A_A1D3_AD06EFAC41ED_Help">Обычно запросы для имен 0x1C (все logon server-а для домена) возвращают первый адрес из имен 0x1B (масте-браузер домена и PDC) в качестве первого адреса в списке результатов. Поскольку многие клиенты по умолчанию используют только первый адрес в списке, все клиенты будут использовать один и тот же сервер (PDC). Серверы Windows имеют возможность отключить это поведение (начиная с Windows 2000 Service Pack 2).
+
+Значение по умолчанию:
+yes</string>
+ <string id="POL_06F0FFB1_F595_57BB_B964_6D419A02F468">nbtd:wins_wins_randomize1Clist</string>
+ <string id="POL_06F0FFB1_F595_57BB_B964_6D419A02F468_Help">Обычно запросы для имен 0x1C возвращают адреса в том же порядке, в каком они хранятся в базе данных, то есть сначала все адреса, которые были непосредственно зарегистрированы на локальном сервере WINS, а затем все адреса, зарегистрированные на других серверах. Серверы Windows имеют возможность изменить это поведение и рандомизировать возвращаемые адреса. При установке этого параметра (nbtd:wins_wins_randomize1Clist = yes) Samba будет сортировать список адресов в зависимости от адреса клиента и совпадающих битов адресов, первый адрес рандомизируется в зависимости от параметра 'nbtd:wins_randomize1Clist_mask'.
+
+Значение по умолчанию:
+nbtd:wins_wins_randomize1Clist = no</string>
+ <string id="POL_F63D2A1E_D6BA_516E_995D_F9FEE05D49DB">nbtd:wins_randomize1Clist_mask</string>
+ <string id="POL_F63D2A1E_D6BA_516E_995D_F9FEE05D49DB_Help">Если параметр 'nbtd:wins_randomize1Clist' имеет значение yes, то рандомизация первого возвращенного адреса производится на основе указанной сетевой маски. Если есть адреса, которые находятся в той же подсети, что и адрес клиента, из них случайным образом выбирается первый возвращенный адрес. В противном случае из всех адресов случайным образом выбирается первый возвращенный адрес.
+
+Значение по умолчанию:
+255.255.255.0</string>
+ <string id="POL_D0A83CCC_07AF_553B_84AE_4824377AE692">winsdb:local_owner</string>
+ <string id="POL_D0A83CCC_07AF_553B_84AE_4824377AE692_Help">Этот параметр определяет адрес, который хранится в атрибуте winsOwner локально зарегистрированных объектов winsRecord. По умолчанию используется IP-адрес первого сетевого интерфейса.
+
+Значения по умолчанию нет</string>
+ <string id="POL_06442D20_4739_5DE0_820F_516416AD0ECF">winsdb:dbnosync</string>
+ <string id="POL_06442D20_4739_5DE0_820F_516416AD0ECF_Help">Этот параметр отключает fsync() после изменений в базе данных WINS.
+
+Значение по умолчанию:
+winsdb:dbnosync = no</string>
+ <string id="POL_F7271C08_2949_53E0_809D_9B976AB9DE2E">wins hook</string>
+ <string id="POL_F7271C08_2949_53E0_809D_9B976AB9DE2E_Help">Если Samba запущена как сервер WINS, существует возможность для осуществления вызовов внешних программ для изменения базы данных WINS. Основное назначение этого параметра — разрешить динамическое обновление внешних баз данных, таких как динамический DNS.
+
+Параметр определяет имя сценария или программы вызываемой в формате:
+
+ wins_hook operation name nametype ttl IP_list
+
+ * Первый аргумент — это операция («add», «delete» или «refresh»). В большинстве случаев операцию можно игнорировать, поскольку остальные параметры предоставляют достаточную информацию. Обратите внимание, что операцию «refresh» можно использовать, когда имя ранее не было добавлено, этот случай нужно рассматривать как добавление.
+
+ * Второй аргумент — NetBIOS имя. Если введенное имя не существует, 'wins hook' вызов не выполнится. Имя может содержать только буквы, цифры, дефисы, символы подчеркивания и периоды.
+
+ * Третий аргумент — NetBIOS имя в формате 2 шестнадцатеричных чисел.
+
+ * Четвертый аргумент — TTL (время жизни) имени в секундах.
+
+ * Пятый и последующие аргументы — IP-адреса, в настоящее время зарегистрированные для этого имени. Если этот список пуст, имя следует удалить.
+
+Пример сценария, который вызывает программу обновления динамического DNS BIND nsupdate, находится в каталоге примеров исходного кода Samba.
+
+Значения по умолчанию нет</string>
+ <string id="POL_A1E6C0E7_38BA_5583_816D_73C91FCAADB4">wins proxy</string>
+ <string id="POL_A1E6C0E7_38BA_5583_816D_73C91FCAADB4_Help">Этот параметр управляет поведением nmbd(8), будет ли тот отвечат на широковещательные запросы по разрешению имен от других компьютеров. Возможно, потребуется установить этот параметр (wins proxy = yes) для некоторых старых клиентов.
+
+Значение по умолчанию:
+wins proxy = no</string>
+ <string id="POL_31C40FB1_1B0A_5AA3_80F9_7914AC38FD99">wins server</string>
+ <string id="POL_31C40FB1_1B0A_5AA3_80F9_7914AC38FD99_Help">Параметр определяет IP-адрес (или DNS-имя, IP-адрес предпочтительнее) для WINS-сервера. Если в сети уже есть WINS-сервер, пропишите в этом параметре его IP-адрес.
+
+Также если локальная сеть состоит из множества подсетей, необходимо указать в этом параметре WINS-сервер.
+
+При работе в множественном пространстве имен необходимо назначить каждому серверу имен свой «tag» (признак). Для каждого «tag» может быть назначен только один сервер имен. «tag» отделяется от IP-адреса двоеточием.
+
+Необходимо настроить Samba так, чтобы она указывала на WINS-сервер, если есть несколько подсетей и необходимо, чтобы просмотр между подсетями работал правильно (см. раздел «Network Browsing» руководства Samba3-HOWTO).
+
+Значение по умолчанию:
+пустая строка
+
+Пример:
+mary:192.9.200.1 fred:192.168.3.199 mary:192.168.2.61
+В этом примере сначала будет опрошен сервер 192.9.200.1 и если он не отвечает 192.168.2.61. Если имя не будет разрешено, запрос пойдет на 192.168.3.199
+
+Пример:
+192.9.200.1 192.168.2.61</string>
+ <string id="POL_44517D2D_845B_5F7B_90F2_F7BD0DA063A9">wins support</string>
+ <string id="POL_44517D2D_845B_5F7B_90F2_F7BD0DA063A9_Help">Параметр определяет, будет ли процесс nmbd(8) в Samba работать как WINS-сервер. Не устанавливайте этот параметр (wins support = yes), если у вас нет нескольких подсетей, и вы не хотите чтобы nmbd работал как WINS-сервер. Никогда не устанавливайте этот параметр более чем на одной машине в пределах одной подсети.
+
+Значение по умолчанию:
+wins support = no</string>
+ <string id="POL_8A035569_9C85_59DC_9BF8_241994D4E947">wreplsrv:periodic_interval</string>
+ <string id="POL_8A035569_9C85_59DC_9BF8_241994D4E947_Help">Максимальный интервал в секундах между двумя периодически запланированными запусками, когда мы проверяем наличие изменений wins.ldb и отправляем push-уведомления нашим push-партнерам. Также в этом интервале проверяются изменения wins_config.ldb и выполняются перезагрузки конфигурации партнера.
+
+Значение по умолчанию:
+15</string>
+ <string id="POL_186864AE_CE31_5628_BA4E_6B9F06F087E5">wreplsrv:propagate name releases</string>
+ <string id="POL_186864AE_CE31_5628_BA4E_6B9F06F087E5_Help">Если этот параметр включен, то явное (от клиента) и неявное (через очистку) выпуски имени распространяются на другие серверы напрямую, даже если есть другие активные адреса, это относится к записям SPECIAL GROUP (2) и MULTIHOMED (3). Также алгоритм слияния конфликтов репликации для записей SPECIAL GROUP (2) отбрасывает адреса реплик, где владельцем адреса является локальный сервер, если адрес ранее не хранился локально. Результат слияния распространяется напрямую, если адрес был отброшен. Серверы Windows не распространяют версии имен записей SPECIAL GROUP (2) и MULTIHOMED (3) напрямую, что означает, что серверы Windows могут возвращать разные результаты для запросов имен для имен SPECIAL GROUP (2) и MULTIHOMED (3). Эта опция не имеет большого негативного влияния, если рядом есть серверы Windows, но имейте в виду, что они могут возвращать неожиданные результаты.
+
+Значение по умолчанию:
+wreplsrv:propagate name releases = no
+</string>
+ <string id="POL_8DC9CC59_A490_5F52_8C69_A9EEC802C48C">wreplsrv:scavenging_interval</string>
+ <string id="POL_8DC9CC59_A490_5F52_8C69_A9EEC802C48C_Help">Интервал в секундах между двумя запусками очистки, которые очищают базу данных WINS и изменяют состояния просроченных записей имен. По умолчанию это половина значения 'wreplsrv:renew_interval'.
+
+Значения по умолчанию нет
+</string>
+ <string id="POL_DB737BF2_9B47_5895_A3F8_D51BBD764222">wreplsrv:tombstone_extra_timeout</string>
+ <string id="POL_DB737BF2_9B47_5895_A3F8_D51BBD764222_Help">Время в секундах, в течение которого сервер должен работать, пока мы не удалим tombstone-записи из базы данных. По умолчанию 3 дня.
+
+Значение по умолчанию:
+259200</string>
+ <string id="POL_30D1C3B2_BDCD_5A5C_A131_11E1E6DA2A76">wreplsrv:tombstone_interval</string>
+ <string id="POL_30D1C3B2_BDCD_5A5C_A131_11E1E6DA2A76_Help">Интервал, в течение которого все выпущенные записи WINS-сервера становятся tombstone-записями. По умолчанию 6 дней.
+
+Значение по умолчанию:
+518400</string>
+ <string id="POL_F19C445A_AFD5_51B6_B87A_E42499C3C5D8">wreplsrv:tombstone_timeout</string>
+ <string id="POL_F19C445A_AFD5_51B6_B87A_E42499C3C5D8_Help">Интервал в секундах до удаления tombstone-записей из базы данных WINS. По умолчанию 1 день.
+
+Значение по умолчанию:
+86400</string>
+ <string id="POL_8CF1FEA3_BD3E_53C0_9F73_34050187A91E">wreplsrv:verify_interval</string>
+ <string id="POL_8CF1FEA3_BD3E_53C0_9F73_34050187A91E_Help">Интервал в секундах, в течение которого проверяются активные записи реплик с WINS-сервером. К сожалению, еще не реализовано. По умолчанию 24 дня.
+
+Значение по умолчанию:
+2073600</string>
+ <string id="CAT_9DEF582D_447A_47E9_A1F5_363558D03FA9">Сообщения</string>
+ <string id="POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07">Message of the day</string>
+ <string id="POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07_Help">Содержимое текстового файла /etc/motd, отображается после успешного входа в систему, но непосредственно перед запуском пользовательской оболочки.</string>
+ <string id="POL_68E9155C_CB49_428E_AFE0_B89316FFD948">Login Prompt Message</string>
+ <string id="POL_68E9155C_CB49_428E_AFE0_B89316FFD948_Help">Данная строка может содержать определенные escape-коды для отображения имени системы, даты, времени и т.д. Все escape-коды состоят из символа обратной косой черты (\), за которой сразу следует один из символов, перечисленных ниже.
+
+ 4 или 4{интерфейс}
+ Вставить IPv4-адрес указанного сетевого интерфейса (например, \4{eth0}). Если аргумент интерфейса не указан, выбрать первый полностью настроенный интерфейс (UP, non-LOCALBACK, RUNNING). Если ни один настроенный интерфейс не найден, вернуться к IP-адресу хоста машины.
+
+ 6 или 6{интерфейс}
+ Тоже, что и \4 но для IPv6.
+
+ b Вставить несущую часть текущей строки.
+
+ d Вставить текущую дату.
+
+ e или e{имя}
+ Преобразовать имя в escape-последовательность и вставьте ее (например, \e{red}Alert text.\e{reset}). Если аргумент имя не указан, тогда вставить \033. В настоящее время поддерживаются следующие имена: black, blink, blue, bold, brown, cyan, darkgray, gray, green, halfbright, lightblue, lightcyan, lightgray, lightgreen, lightmagenta, lightred, magenta, red, reset, reverse, и yellow. Все неизвестные имена игнорируются.
+
+ s Вставить имя системы (имя операционной системы). То же, что и 'uname -s'. См. также escape-код \S.
+
+ S или S{ПЕРЕМЕННАЯ}
+ Вставить значение ПЕРЕМЕННОЙ из /etc/os-release. Если этот файл не существует, обратиться к /usr/lib/os-release. Если аргумент ПЕРЕМЕННАЯ не указан, тогда использовать PRETTY_NAME из файла или имени системы (см. \s). Этот escape-код позволяет сохранить распределение /etc/issue и независимый релиз. Обратите внимание, что \S{ANSI_COLOR} преобразуется в настоящую escape-последовательность терминала.
+
+ l Вставить имя текущей линии tty.
+
+ m Вставить идентификатор архитектуры машины. То же, что и 'uname -m'.
+
+ n Вставить имя узла машины, также известное как имя хоста. То же, что и 'uname -n'.
+
+ o Вставить NIS-имя машины. То же, что и 'hostname -d'.
+
+ O Вставить DNS-имя машины.
+
+ r Вставить номер версии ОС. То же, что и 'uname -r'.
+
+ t Вставить текущее время.
+
+ u Вставить количество текущих пользователей, вошедших в систему..
+
+ U Вставить строку «1 user» или «&lt;n&gt; users», где &lt;n&gt; — количество текущих пользователей, вошедших в систему.
+
+ v Вставить версию ОС, то есть дату сборки и т.д.
+
+Значение по умолчанию:
+Welcome to \s \r \l</string>
+ </stringTable>
+ <presentationTable>
+ <presentation id="POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061">
+ <listBox refId="LST_2E9A4684_3C0E_415B_8FD6_D4AF68BC8AC6">Script and arguments</listBox>
+ </presentation>
+ <presentation id="POL_825D441F_905E_4C7E_9E4B_03013697C6C1">
+ <listBox refId="LST_1AA93D59_6372_4F1E_90BB_D4CBBBB77238">Script and arguments</listBox>
+ </presentation>
+ <presentation id="POL_D298F3BD_44D9_426D_AF11_3163D31582F6">
+ <listBox refId="LST_8BC6757D_B1FB_4780_83B4_F85F27BF6E60">Script and arguments</listBox>
+ </presentation>
+ <presentation id="POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674">
+ <listBox refId="LST_1E7198A6_7850_4CAB_B656_BC18752564FC">Script and arguments</listBox>
+ </presentation>
+ <presentation id="POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3">
+ <listBox refId="LST_4F4BA073_4F7B_4B64_A61D_8E75257A4B9F">Sudoers commands</listBox>
+ </presentation>
+ <presentation id="POL_A3D6C2F2_2798_527E_861E_FA8BADBBE6E6">
+ <textBox refId="TXT_F940E18B_16AE_594B_9669_96417E695AC9">
+ <label>additional dns hostnames</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_AC8777B4_88D7_5A1A_BB7E_E47AB5DBD6AA">
+ <checkBox refId="CHK_5C837672_BFBB_592A_907C_E378BEEDA2E4">bind interfaces only</checkBox>
+ </presentation>
+ <presentation id="POL_D03F1811_D0CA_56CF_9D18_B480E9B5AFAD">
+ <textBox refId="TXT_03C82812_CCD0_5E35_8FA1_2704BAF796E9">
+ <label>config backend</label>
+ <defaultValue>file</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DE840DAF_58CD_5B21_A76B_70740BD125A1">
+ <textBox refId="TXT_CF5594A6_FA4A_5AB4_881B_AD9270CE3523">
+ <label>dos charset</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3783DBBE_7F1F_52B4_BECB_6176E8D43AE1">
+ <checkBox defaultChecked="true" refId="CHK_A51834ED_BBB9_52C3_A7C5_A566ABE7AB3D">enable core files</checkBox>
+ </presentation>
+ <presentation id="POL_5EE2E645_A509_5C51_94FE_4F84668AC869">
+ <textBox refId="TXT_3E2FB206_740F_580E_889D_B53C2540732C">
+ <label>mdns name</label>
+ <defaultValue>netbios</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_32EB220A_5721_51EC_810C_0BEF4B9EA706">
+ <checkBox defaultChecked="true" refId="CHK_03FFDBD4_C185_5951_954F_189B0D4C40DA">multicast dns register</checkBox>
+ </presentation>
+ <presentation id="POL_51EEB44F_42B8_5CEA_8DA6_CB78139F4804">
+ <textBox refId="TXT_6A12C17F_F8CF_56F3_8D82_43CAB3C57F55">
+ <label>netbios aliases</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_4AEFFAC4_3FBE_5DFA_9D3F_D78B50416B7C">
+ <textBox refId="TXT_34827D8A_E97C_590B_BD8A_6DEA6A354BE8">
+ <label>netbios name</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_24E6BE64_5FEA_56A1_83AF_844C8A96E96D">
+ <textBox refId="TXT_0ED12914_E653_5CDA_9F46_E1C3AB2FC32E">
+ <label>netbios scope</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0901DFB6_7C73_5D10_82CC_5D77CD14685D">
+ <decimalTextBox defaultValue="10" refId="DXT_F0896598_D8F1_579A_B01D_09A48282AC76"/>
+ </presentation>
+ <presentation id="POL_26F4B846_C66B_5649_AA7E_B06E899017CA">
+ <decimalTextBox defaultValue="4" refId="DXT_BD459D8F_47F9_558D_A641_97892C9E577E"/>
+ </presentation>
+ <presentation id="POL_9C3E188A_07B9_5354_A206_DD0FA0B4A235">
+ <decimalTextBox defaultValue="120" refId="DXT_16991D04_74C7_54C3_9E4F_52EF9C9AEDB4"/>
+ </presentation>
+ <presentation id="POL_609F7E6F_9AAC_56B4_B098_4E63BBBB98B4">
+ <textBox refId="TXT_5B075596_6622_5C89_A426_B9DA3F43AC3A">
+ <label>realm</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_68ED4DED_E13E_5C54_BD04_23E499D77D51">
+ <textBox refId="TXT_E2BF4D58_613E_5C2D_850A_C3585BC311C2">
+ <label>server services</label>
+ <defaultValue>s3fs, rpc, nbt, wrepl, ldap, cldap, kdc, drepl, winbindd, ntp_signd, kcc, dnsupdate, dns</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_584FF155_77A9_5209_AC2F_071DEAB5FA42">
+ <textBox refId="TXT_EC20B2FC_7658_536F_A876_F0B61196042C">
+ <label>server string</label>
+ <defaultValue>Samba %v</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3D10A56C_5C5B_516D_8718_0112384056DB">
+ <textBox refId="TXT_682410E7_F583_5A97_BB60_6BBAA190DA1C">
+ <label>share backend</label>
+ <defaultValue>classic</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A64B2059_EC1C_5759_94E8_CD95EEB42F35">
+ <textBox refId="TXT_3F03354B_7221_5D54_8D25_FA3229D9A026">
+ <label>unix charset</label>
+ <defaultValue>UTF-8</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_38764DE0_53DC_587E_A94B_7C03323B0C69">
+ <textBox refId="TXT_A1CD4626_197B_582B_9C09_E35945F84ECF">
+ <label>workgroup</label>
+ <defaultValue>WORKGROUP</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DD5ADDCF_E8DF_50F9_9847_E821787C2C3C">
+ <textBox refId="TXT_18F101C1_8754_5052_8D12_3D4B3755A739">
+ <label>interfaces</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EECBA792_3D9C_5624_A01E_F5876EF8224D">
+ <checkBox defaultChecked="true" refId="CHK_1D40EF50_9DF5_5D95_B5EF_406C4F3774B8">browse list</checkBox>
+ </presentation>
+ <presentation id="POL_414481A1_7B9D_551A_96F0_B235A226F141">
+ <textBox refId="TXT_69092348_8194_5EA4_9EB2_AFFFF4A2A6C8">
+ <label>domain master</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_25D5E28F_5847_5A16_8CF5_01E528D1807D">
+ <checkBox defaultChecked="true" refId="CHK_7A02FE2C_82BF_50CE_91F0_14B1191E7258">enhanced browsing</checkBox>
+ </presentation>
+ <presentation id="POL_7356F015_5915_5A1E_9154_AEE48849DC85">
+ <textBox refId="TXT_9C07BE5E_EF60_51EC_B26C_CEA97CD41C69">
+ <label>lm announce</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_37CB9A35_D06B_581B_8BBC_96F636F2DF0D">
+ <decimalTextBox defaultValue="60" refId="DXT_6B8EAB54_6B9E_5EE3_BBB3_286F512AC0F9"/>
+ </presentation>
+ <presentation id="POL_00BB67E5_7846_53BF_990A_8B7D03F9D88E">
+ <checkBox defaultChecked="true" refId="CHK_CFD7EF58_DD73_5465_B0CE_4C6B4E35F416">local master</checkBox>
+ </presentation>
+ <presentation id="POL_99809647_A4DC_5363_8E8B_A27B51B90E87">
+ <decimalTextBox defaultValue="20" refId="DXT_3DF3E95D_2453_53C1_A98D_DB040E45E676"/>
+ </presentation>
+ <presentation id="POL_69BB8325_FE45_56C0_8D34_F23EC38D2107">
+ <textBox refId="TXT_82D47B73_2C75_5779_A283_E9A39FD54705">
+ <label>preferred master</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F664E709_2422_5047_BD55_E95C422B6B33">
+ <textBox refId="TXT_BEC7C085_5840_5531_9E64_A727E258569A">
+ <label>allow dns updates</label>
+ <defaultValue>secure only</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C69048CD_ABF0_5333_B5CB_7455D5F226FF">
+ <textBox refId="TXT_64C9BBC7_F73A_5844_A613_08685212F33C">
+ <label>dns forwarder</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F9D5C585_21FD_5990_BE36_3A58B7AF326B">
+ <textBox refId="TXT_05BC3827_6AE7_54BF_8E0C_008D698CC732">
+ <label>dns update command</label>
+ <defaultValue>/samba_dnsupdate</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2363A474_4143_52A2_A69B_05285C98E4CF">
+ <checkBox refId="CHK_3104780C_9730_550D_8DF9_5C5A226B2AAE">dns zone scavenging</checkBox>
+ </presentation>
+ <presentation id="POL_F2F11B02_D190_5766_95DC_FDB846EEEB13">
+ <textBox refId="TXT_A8FD53BD_1ED7_54DB_9A7C_159348F47A6D">
+ <label>gpo update command</label>
+ <defaultValue>/samba-gpupdate</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A83B176D_D2FE_5F41_9977_9A16F5B8C5ED">
+ <decimalTextBox defaultValue="604800" refId="DXT_E5687DEB_DB51_5266_ACDB_2E619982BAD7"/>
+ </presentation>
+ <presentation id="POL_5BD73E55_C69F_5CCF_8D91_2513716FB1C6">
+ <textBox refId="TXT_3BA3F934_5C9D_5EAB_BAEB_7FBDAE0268F5">
+ <label>nsupdate command</label>
+ <defaultValue>/usr/bin/nsupdate -g</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E38856B0_C9B1_5577_9055_C48A4CCE499C">
+ <textBox refId="TXT_041114D6_313A_501F_BFC9_FD004546248B">
+ <label>spn update command</label>
+ <defaultValue>/samba_spnupdate</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C2FCADD1_1EF0_5726_9CDE_0E155B0B6575">
+ <decimalTextBox defaultValue="1" refId="DXT_0BA0C537_293A_525C_AC5C_9BB5C0524277"/>
+ </presentation>
+ <presentation id="POL_620B56BA_84B7_5E72_AC2D_4F0574FBB199">
+ <textBox refId="TXT_241061E9_3BDA_5AFE_87CB_13C53A164649">
+ <label>mangling method</label>
+ <defaultValue>hash2</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E59D859C_7C78_5AB6_8DE3_27F672637189">
+ <decimalTextBox defaultValue="512" refId="DXT_EA859956_0483_500A_9962_8A26A8B81BB4"/>
+ </presentation>
+ <presentation id="POL_6BB5939F_7CE6_588E_A6E2_B114EF17F60F">
+ <checkBox defaultChecked="true" refId="CHK_45471F8A_D0BD_53A3_B51F_393DE6CC03D2">stat cache</checkBox>
+ </presentation>
+ <presentation id="POL_BE2B9E4A_5ABE_543F_8564_4CBDD1AF9179">
+ <textBox refId="TXT_4A85EF32_894F_50AF_9917_B7F431720A82">
+ <label>client ldap sasl wrapping</label>
+ <defaultValue>sign</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F4937393_B88E_5B26_89F5_F9933BEBEF8B">
+ <textBox refId="TXT_4B00C10F_7EBB_52D5_9AD1_C893F9C094C5">
+ <label>ldap admin dn</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_5187BD6B_3008_59FC_887D_1C89E807B11E">
+ <decimalTextBox defaultValue="2" refId="DXT_87AD8E93_91B6_5439_B928_9776BF986ED0"/>
+ </presentation>
+ <presentation id="POL_96311867_A4DE_5B57_BD8C_3D25B5084F68">
+ <checkBox refId="CHK_2BC96AC0_ECEF_55D4_AEA4_039FDD24C999">ldap delete dn</checkBox>
+ </presentation>
+ <presentation id="POL_193E7C6B_E70E_55EB_AB50_3788B93F4607">
+ <textBox refId="TXT_FCC83065_2F1A_585B_A998_85AA52D99537">
+ <label>ldap deref</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E6D23CDA_DABC_5749_BEF1_D15FF80E02BF">
+ <textBox refId="TXT_DEC758B4_6B3C_5882_B0B8_386473EECFD3">
+ <label>ldap follow referral</label>
+ <defaultValue>auto</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_6C44A469_31FA_512A_AB08_ACDADD5B7238">
+ <textBox refId="TXT_B51FB55F_3A49_539E_A77A_7F7F2AF2CC39">
+ <label>ldap group suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_83D7A344_AE69_5DCA_A3D9_A79DF817A7D4">
+ <textBox refId="TXT_E49CAB56_E62A_5930_99DE_EEC0B04DBCF4">
+ <label>ldap idmap suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_07D748C7_B6EA_558D_B652_62F9BC2E9A1B">
+ <textBox refId="TXT_2B9911E2_33DC_5CB0_A9CC_E7DD7B2A5799">
+ <label>ldap machine suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F831F898_66A7_53D3_B6EA_B90065F7EF41">
+ <decimalTextBox defaultValue="1000" refId="DXT_1C52332B_FC98_54CA_8C3D_64E63D450DD7"/>
+ </presentation>
+ <presentation id="POL_068B0430_6CF2_5CAC_BDC8_F7074411AA6C">
+ <textBox refId="TXT_03529C2D_378A_5BE4_A342_9FF088AC8396">
+ <label>ldap passwd sync</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DC0C1ABD_D8CE_5175_A9AB_D58661AACFB1">
+ <decimalTextBox defaultValue="1000" refId="DXT_B21A5F63_507D_5407_B582_DA64138C6B97"/>
+ </presentation>
+ <presentation id="POL_F12B9752_4939_52A6_9A5E_52FFF53FC34F">
+ <textBox refId="TXT_3ADB0A83_AA24_5C68_BD2E_3723FC2F2268">
+ <label>ldapsam:editposix</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_90ECE51D_8CF8_50F9_809F_87A024DDCAAE">
+ <textBox refId="TXT_B10770E9_1959_5A4A_8D44_F070923C2A12">
+ <label>ldapsam:trusted</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B58FAA75_79BA_53E3_A895_69D6DE3E547E">
+ <textBox refId="TXT_9F11612E_1A6E_5CF7_BC96_4ADBD123A76D">
+ <label>ldap server require strong auth</label>
+ <defaultValue>yes</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D6465FAC_2205_59C0_A3E6_1F1DE4C50A58">
+ <textBox refId="TXT_950B2F92_3A19_5FC4_839A_3226C858811C">
+ <label>ldap ssl</label>
+ <defaultValue>start tls</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EAF3D0F1_C7E5_5864_AE5D_FBF9F6102FF4">
+ <checkBox refId="CHK_0D06C9D8_3A6A_509E_9B4A_DE497AFA6B58">ldap ssl ads</checkBox>
+ </presentation>
+ <presentation id="POL_208E2789_E8A9_53CA_B756_2694096B8DAF">
+ <textBox refId="TXT_ABB81954_F41C_5FAD_BD35_873007549C27">
+ <label>ldap suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D76D653B_C2A3_5939_BF95_9BAE0CF6C88C">
+ <decimalTextBox defaultValue="15" refId="DXT_8B73DF13_A7A3_57B4_A4BE_AC816E59EBAB"/>
+ </presentation>
+ <presentation id="POL_B3FBC8E2_DD5D_5CEA_9FC5_44687CF36BB5">
+ <textBox refId="TXT_B9F4F586_8F61_53D2_AFEE_B2011D0DFF43">
+ <label>ldap user suffix</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_94ABA1F3_F411_52AE_ADAA_72B53F9198CA">
+ <decimalTextBox defaultValue="256000" refId="DXT_B7AEDDC2_0B5A_5C1C_AFA0_7518773C5F5F"/>
+ </presentation>
+ <presentation id="POL_A2C8FD60_A284_5409_B130_B135DEE4B615">
+ <decimalTextBox defaultValue="16777216" refId="DXT_1B597D08_FFDB_5BA4_ABD9_31A8446A3625"/>
+ </presentation>
+ <presentation id="POL_695C7E25_8C69_519C_907E_9A71D1FE2EC3">
+ <decimalTextBox defaultValue="256000" refId="DXT_6FA557BE_E2D9_54CC_9A8D_FAA4BFCD552A"/>
+ </presentation>
+ <presentation id="POL_60E126C5_9E79_54DC_B201_A3E643352D00">
+ <decimalTextBox defaultValue="200" refId="DXT_8D517C10_BE65_5D58_AC86_8A21017F479A"/>
+ </presentation>
+ <presentation id="POL_6B50B6B6_D038_54C5_BD82_9D377C2E8C0C">
+ <decimalTextBox defaultValue="0" refId="DXT_14C326D8_5326_5883_95FA_D903E07A457A"/>
+ </presentation>
+ <presentation id="POL_D9E75BB0_F19B_5F72_A58E_22718E614EB3">
+ <checkBox defaultChecked="true" refId="CHK_8649286E_DE5D_5DE7_A836_AA15E736A911">smb2 leases</checkBox>
+ </presentation>
+ <presentation id="POL_D7003A7B_D00A_51AE_8D40_7446533B2974">
+ <checkBox refId="CHK_4915975F_60D1_5187_9E6A_F835D1086622">debug class</checkBox>
+ </presentation>
+ <presentation id="POL_CF714212_43A8_52ED_BDAD_B1D6F82A6EF9">
+ <checkBox defaultChecked="true" refId="CHK_ADDEF100_7619_5056_B632_ECEF204DBEC8">debug hires timestamp</checkBox>
+ </presentation>
+ <presentation id="POL_CF524D7E_11CA_5027_9777_5398DD2804B4">
+ <checkBox refId="CHK_6D39A340_480D_596C_A9F5_3412FC28765D">debug pid</checkBox>
+ </presentation>
+ <presentation id="POL_BDF671C9_3811_5B19_AB78_5F12B25CEC84">
+ <checkBox refId="CHK_2367747B_4E47_503A_A92C_1EA98AC3D5CC">debug prefix timestamp</checkBox>
+ </presentation>
+ <presentation id="POL_B76DE893_21E7_5B6A_81AB_23B8F00D782D">
+ <checkBox refId="CHK_5BD4217F_5C51_59D6_9582_3037FB4B6E4F">debug uid</checkBox>
+ </presentation>
+ <presentation id="POL_BACB061C_C7A0_5830_80FE_15FA009DEAA2">
+ <decimalTextBox defaultValue="0" refId="DXT_DBF1992F_D735_55E7_9029_AE5D9EBA66FB"/>
+ </presentation>
+ <presentation id="POL_B51CE2D4_7EFD_577E_97EC_8EEA650C0F0F">
+ <decimalTextBox defaultValue="10" refId="DXT_2D488F55_5DE8_5AC6_85AE_F77BE4429364"/>
+ </presentation>
+ <presentation id="POL_1C03B9BE_5E74_58CF_A649_CDFD9E91F6CC">
+ <textBox refId="TXT_2C83A41B_5CDA_5130_8343_1278307321CD">
+ <label>log file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_FA6B22DA_628C_5C5E_8BAD_97BBCE0E4F1F">
+ <textBox refId="TXT_2533346E_4C1C_5ACB_9355_B40495EB63CD">
+ <label>logging</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C4E11396_B289_5D98_9F39_6BD19BBB4330">
+ <textBox refId="TXT_60E8D3F6_8EC7_5FDC_8645_3E4E3EF85512">
+ <label>log level</label>
+ <defaultValue>0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EA5127A5_4C6A_5B8A_9D52_D5D17D9E8AFE">
+ <decimalTextBox defaultValue="5000" refId="DXT_60E6F44F_5185_576D_91C2_9B10FB853416"/>
+ </presentation>
+ <presentation id="POL_69FD7A6B_0BA2_570F_9BB1_B869C7404630">
+ <decimalTextBox defaultValue="1" refId="DXT_FCD3912D_FD93_54A5_91E4_A834457B8F2E"/>
+ </presentation>
+ <presentation id="POL_FD3A0B38_1664_58B4_983A_3A21EC4A76EA">
+ <checkBox refId="CHK_88778A4E_D102_588A_A01C_E930BEE81D6C">syslog only</checkBox>
+ </presentation>
+ <presentation id="POL_AB153BC2_9291_51D0_81AC_1A78B1A0DE6F">
+ <checkBox defaultChecked="true" refId="CHK_16FD7E9E_1FCF_58D9_940E_42D45860825B">timestamp logs</checkBox>
+ </presentation>
+ <presentation id="POL_7C7A3857_7762_5F1F_BDB5_A621FEBD0E99">
+ <textBox refId="TXT_6716C37B_3C84_5AB4_8A8D_B6D070787CEB">
+ <label>abort shutdown script</label>
+ <defaultValue>&quot;&quot;</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A6105481_F59A_5B08_8B4C_B100EF112BD9">
+ <textBox refId="TXT_BB6CFFBF_3E2F_5FDF_A2CC_E255231A3370">
+ <label>add group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_01C79ED8_2727_54DF_AF75_96E5A25722DD">
+ <textBox refId="TXT_C3FD37B5_A643_57DF_AE57_048E75B21BDF">
+ <label>add machine script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_BA7787E8_0D26_5963_8F44_498B278A4703">
+ <textBox refId="TXT_56C28546_216A_5AFF_B212_FFEC207F3FFD">
+ <label>add user script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_077466DB_CB4D_5489_8934_C2F22592D94A">
+ <textBox refId="TXT_218549FC_FD8A_5036_8199_9B2AB628624F">
+ <label>add user to group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8F632169_4F0C_500B_BE8B_88960312C345">
+ <checkBox refId="CHK_61299541_E6C3_50AD_9CCD_409DBABC3DA2">allow nt4 crypto</checkBox>
+ </presentation>
+ <presentation id="POL_5A6DC206_1A48_5FFE_8B2D_897EF95CCBAD">
+ <checkBox refId="CHK_F34DA878_4D45_5E26_8454_77BAE0D9FCAA">auth event notification</checkBox>
+ </presentation>
+ <presentation id="POL_3152501B_87A8_5907_AAD5_00B3F7752516">
+ <textBox refId="TXT_F75A550B_6B11_57A4_9EAD_27361359E4CB">
+ <label>delete group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_676F211D_0B27_54F6_9FF0_1B6F6CC88CA6">
+ <textBox refId="TXT_E6287F6E_CDD6_57CC_A6CF_59E26391473A">
+ <label>delete user from group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3033EDC8_8938_5A64_A8B9_1F7349DC1149">
+ <textBox refId="TXT_1FC62BD1_6541_5C03_B233_B5DE1B987775">
+ <label>delete user script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_27365CD7_D0DF_5A41_9140_A1C6970CB3D0">
+ <checkBox refId="CHK_B67618DB_ED7B_5A2E_AC14_C2E808E1A927">domain logons</checkBox>
+ </presentation>
+ <presentation id="POL_49526C11_2F64_5D85_A25D_A90D2152195E">
+ <checkBox defaultChecked="true" refId="CHK_A6532133_05F0_5D5F_983E_8924AB2334D5">enable privileges</checkBox>
+ </presentation>
+ <presentation id="POL_026CF0E2_B95C_5B67_BBAA_E95C5F809B28">
+ <decimalTextBox defaultValue="100" refId="DXT_1FD373A1_8A61_5884_9208_07A886F6334F"/>
+ </presentation>
+ <presentation id="POL_B9587C82_562E_5CA5_8BBD_835B3940D00D">
+ <textBox refId="TXT_633A0D2D_C7E6_54EF_BCE0_46ECFB6B2C1E">
+ <label>init logon delayed hosts</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_84F161E0_6C65_55C2_9DB5_CC61E66CEA9F">
+ <textBox refId="TXT_8F910181_D80D_58A5_937D_186E347E6433">
+ <label>logon drive</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_508CD547_53D7_59ED_BB1F_E6EE939C1AF2">
+ <textBox refId="TXT_3C94DDFB_94DD_598E_BC0D_B70465DA9C0C">
+ <label>logon home</label>
+ <defaultValue>\\%N\%U</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_204A522A_CF55_5E96_A2AD_B58E105AA80C">
+ <textBox refId="TXT_05B40781_B875_53DD_B1DD_4CA590B56E4A">
+ <label>logon path</label>
+ <defaultValue>\\%N\%U\profile</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A1B5FFEC_19C2_5415_ACE0_38E5D118E369">
+ <textBox refId="TXT_C1B894A7_BDF5_52B8_AC59_900953D453AC">
+ <label>logon script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DD7A32CE_6F63_596B_8E15_43B11C82E2AF">
+ <checkBox refId="CHK_805FD143_5242_56DE_BD51_0B514A588E9F">reject md5 clients</checkBox>
+ </presentation>
+ <presentation id="POL_2AD85924_5D09_571B_B048_E996EC819C57">
+ <textBox refId="TXT_B00F123E_2430_5EA0_A543_92D22A0F5FD4">
+ <label>set primary group script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A8F30942_8D30_583F_8C0F_877BD20D9B26">
+ <textBox refId="TXT_74A021FE_F97F_5D54_9C4E_023D1964D37E">
+ <label>shutdown script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F0D581AB_54B4_58AA_9B84_6794FB8D3D55">
+ <textBox refId="TXT_C77D6CE7_BED5_52A8_BD8C_0259439992FA">
+ <label>add share command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_91CEEB79_E73B_563E_84CC_0C1483141142">
+ <decimalTextBox defaultValue="604800" refId="DXT_FBB1DAD6_26B9_5FB1_9678_EB499E48CC26"/>
+ </presentation>
+ <presentation id="POL_77D04206_AF73_51DE_9BE8_63524E440826">
+ <textBox refId="TXT_22E4592F_8119_5A26_AF4F_0624F1AC5E0E">
+ <label>afs username map</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_5FA91D1E_B675_5681_9FE8_E14B3E1BA737">
+ <checkBox refId="CHK_AC4E2E8E_74FE_5FD1_B6F4_3637B4582348">allow insecure wide links</checkBox>
+ </presentation>
+ <presentation id="POL_153D9711_80CD_56CD_8A51_DDA71A3800C0">
+ <checkBox refId="CHK_D36441A8_7E2F_5174_8483_4DFE0503C16D">allow unsafe cluster upgrade</checkBox>
+ </presentation>
+ <presentation id="POL_DFD4B19F_8874_5AE7_83CE_F8F507F26D51">
+ <checkBox refId="CHK_E37B6C82_F04E_5025_B457_01D9296753BE">async smb echo handler</checkBox>
+ </presentation>
+ <presentation id="POL_AA42E677_62D1_5408_A8B7_98222854E79B">
+ <textBox refId="TXT_34B124B0_A219_5575_BFDC_EAC426D7A3A5">
+ <label>auto services</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2099F7FC_F033_5E2F_B2D0_17E1CCB2969A">
+ <textBox refId="TXT_07FAF490_385F_5A63_8A03_BF34531D019D">
+ <label>cache directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2CD315A0_5DDA_5123_A973_79C1DE40BC82">
+ <checkBox defaultChecked="true" refId="CHK_1A966B04_20C5_5E97_8C75_71519DB4783C">change notify</checkBox>
+ </presentation>
+ <presentation id="POL_2D514759_876D_5B59_B854_8DC51888BB02">
+ <textBox refId="TXT_B8991748_9729_56D2_8DAD_5BAFEC5A7A8A">
+ <label>change share command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_239BABBB_C9C7_538A_B6CF_0FA2FC980562">
+ <textBox refId="TXT_E05A6480_11BB_5FF4_8E6E_37E281DA95F6">
+ <label>cluster addresses</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_92925554_781D_56B7_958E_DD33A753ED22">
+ <checkBox refId="CHK_D800E6F3_FB17_5561_9C47_88EB4384129D">clustering</checkBox>
+ </presentation>
+ <presentation id="POL_F2210D02_1B94_561B_9B05_1C5B896AF6D4">
+ <textBox refId="TXT_EB6161C1_BF92_5E6F_A106_AAE90FBD9EBD">
+ <label>config file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2EED8B7C_AF41_514A_A33D_8100A5F831AC">
+ <textBox refId="TXT_E56A7A49_B6A1_502F_AF0E_A3944A5DBFFA">
+ <label>ctdbd socket</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0DE178AC_0A5A_5CDD_8BE6_0E24150CF2BA">
+ <decimalTextBox defaultValue="0" refId="DXT_BB942009_69C3_5BAD_8507_AF692DF05CA1"/>
+ </presentation>
+ <presentation id="POL_026C959C_5371_5698_903A_03F46EEDEBE9">
+ <decimalTextBox defaultValue="0" refId="DXT_8A4C2887_09B3_542A_A22B_EEC3404DBEF8"/>
+ </presentation>
+ <presentation id="POL_C16447B8_9E34_57E6_A1F7_A6F87E66CF73">
+ <textBox refId="TXT_70112D53_C921_5D1F_9AFC_15D4890131CE">
+ <label>default service</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_41887133_D321_5526_B73E_2D5BEDA6B644">
+ <textBox refId="TXT_7B81ED14_1277_5697_B4DE_2CCFB8F79BC3">
+ <label>delete share command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B93F17F1_6F2A_5D04_AC96_EA043AC87144">
+ <checkBox refId="CHK_3D317248_E078_5FDD_B3C7_B7051C10506D">dsdb event notification</checkBox>
+ </presentation>
+ <presentation id="POL_ED5A8D54_C086_5C46_985E_746D4ED62FEA">
+ <checkBox refId="CHK_F76A8EFA_4388_54E3_B283_976BA2DD2A2E">dsdb group change notification</checkBox>
+ </presentation>
+ <presentation id="POL_5B2313F4_5239_57E8_88E9_822DBB4C0E77">
+ <checkBox refId="CHK_4B61A9A1_8E18_56CF_9B9E_6904A78328A0">dsdb password event notification</checkBox>
+ </presentation>
+ <presentation id="POL_B86BF972_B64C_57B2_9E82_96C5EECFAFA7">
+ <textBox refId="TXT_7AB84D08_FB4A_5676_B106_B4DB68C5F577">
+ <label>elasticsearch:mappings</label>
+ <defaultValue>/elasticsearch_mappings.json</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_444019F3_369A_5807_805C_AB00E59CDD4B">
+ <checkBox refId="CHK_9EA28A80_4AA6_5D4A_8A14_E22205D488CD">fss: prune stale</checkBox>
+ </presentation>
+ <presentation id="POL_472F0591_240C_5E5D_827C_49E760A75B8E">
+ <decimalTextBox refId="DXT_D5D56481_74EE_5D10_8476_B3FDB82AE518"/>
+ </presentation>
+ <presentation id="POL_DADF0887_C19B_5B14_9CEF_6721596557EB">
+ <textBox refId="TXT_B001AD6C_7FA0_5EE0_8C4D_D506EECFF497">
+ <label>homedir map</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_AFF4FEEA_8C88_5AED_9414_F4A320074A99">
+ <checkBox defaultChecked="true" refId="CHK_F273132D_C805_596F_A0E1_B6ECB4752ADB">kernel change notify</checkBox>
+ </presentation>
+ <presentation id="POL_4F279322_30AA_564B_844F_7827454574D2">
+ <textBox refId="TXT_A384C210_BD62_5E63_B7EB_BC26844F51C8">
+ <label>lock directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1120E96A_0F8E_5827_A6D2_3CA7AD66D689">
+ <checkBox refId="CHK_EB18668D_E754_524B_B2D7_CC74BA90421D">log writeable files on exit</checkBox>
+ </presentation>
+ <presentation id="POL_63067D3C_4F00_5193_92FE_A58651D4BACC">
+ <textBox refId="TXT_18DDFF0D_D5DB_5617_AE32_D93BE7E38C4B">
+ <label>message command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8765A188_6EFA_515B_B602_8F67140CFE7F">
+ <textBox refId="TXT_C551A0C4_E3B9_5985_9492_C7F42D10E75C">
+ <label>nbt client socket address</label>
+ <defaultValue>0.0.0.0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D7C62F7B_B1B6_57B3_AE48_34D09A88ECFE">
+ <textBox refId="TXT_1A090CE6_58F5_56F0_A29C_175CADD196D7">
+ <label>ncalrpc dir</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_CCC72421_6131_58BC_BFE1_D9EC7399CD57">
+ <checkBox refId="CHK_8E5A65B4_42A2_5F00_8558_E69C28758E1B">NIS homedir</checkBox>
+ </presentation>
+ <presentation id="POL_3E9DEECC_9015_5720_9251_CF804FAB2602">
+ <checkBox defaultChecked="true" refId="CHK_49457A99_B4CF_594B_B796_916B9AB74838">nmbd bind explicit broadcast</checkBox>
+ </presentation>
+ <presentation id="POL_5A63DA17_F433_5414_A47F_26C5B9BE57C2">
+ <textBox refId="TXT_A21115E3_D3E1_505B_9D2C_84A3DC428246">
+ <label>panic action</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_50CDC71F_7927_5631_A40A_C0BD12899CA1">
+ <textBox refId="TXT_6C7D4E2F_9ABE_5C67_9A8C_18D11AEF6038">
+ <label>perfcount module</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A02E7761_E359_5528_A160_F2B67024244F">
+ <textBox refId="TXT_DC19A229_4604_5CC9_8C83_CA2A1323653A">
+ <label>pid directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C030CCF1_08E7_5B6F_9239_F19B792C2157">
+ <checkBox refId="CHK_0200BA53_C2E5_5136_8A69_D8561A556A50">registry shares</checkBox>
+ </presentation>
+ <presentation id="POL_ADE18BC6_D01E_58CF_98FA_BCDCC7CDDC37">
+ <textBox refId="TXT_D765EA37_D1F5_50B2_91CE_49E66F462943">
+ <label>remote announce</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2D35EC75_4D7A_533F_96C8_3A331BDEDF34">
+ <textBox refId="TXT_F44D8D8A_1E1F_5BEE_AB4F_B3DAAFB7DBA9">
+ <label>remote browse sync</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2594A0C3_CF98_5B89_B182_1BB9C275B742">
+ <checkBox refId="CHK_57B96280_EA3D_5DAC_83DE_13338587A0D6">reset on zero vc</checkBox>
+ </presentation>
+ <presentation id="POL_17837A58_88D4_5F29_8D41_479688BD8CBD">
+ <textBox refId="TXT_90158AA7_C0BE_5650_9204_2AFC0BD9D5E8">
+ <label>rpc_daemon:DAEMON</label>
+ <defaultValue>disabled</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_AC41C088_31DF_569D_8FC8_8747C4A30548">
+ <textBox refId="TXT_31E1741F_829C_5B90_9A2F_B0E0DC5F1E75">
+ <label>rpc_server:SERVER</label>
+ <defaultValue>embedded</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1233682B_A71D_5081_9CF1_F5112A62EE3B">
+ <textBox refId="TXT_B5965925_60A9_5A4E_B348_80C590F7AF7A">
+ <label>smbd profiling level</label>
+ <defaultValue>off</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C2788566_CBC3_59A3_80A2_72D92E42C276">
+ <textBox refId="TXT_58CF9CC7_1A14_55B0_8E4E_52E962A10EE4">
+ <label>state directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_6AF97A17_10D7_553C_8CEC_09C8466A2AA4">
+ <checkBox refId="CHK_2D14A430_BA96_5B3F_970F_CE1AE9F7E8AA">usershare allow guests</checkBox>
+ </presentation>
+ <presentation id="POL_35B0CCC2_C387_5AED_9345_A2E4DE654F5F">
+ <decimalTextBox defaultValue="0" refId="DXT_AD83F27E_4FF7_5E8D_A441_0A8925C9D917"/>
+ </presentation>
+ <presentation id="POL_4E1A7DA3_3014_5C3C_9B0B_1919ECADACFB">
+ <checkBox defaultChecked="true" refId="CHK_950CF79D_4898_55EB_A6A8_24F2A6867B1D">usershare owner only</checkBox>
+ </presentation>
+ <presentation id="POL_F2D66EF9_F99C_5347_A075_E8733603E83D">
+ <textBox refId="TXT_D24709D9_FFEF_5871_AF49_5E3A3466761C">
+ <label>usershare path</label>
+ <defaultValue>/usershares</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_568D23D8_683D_5E32_96B8_5CCF81F0BDEC">
+ <textBox refId="TXT_C0DF82DC_7C0A_5B7F_9B93_19D517976672">
+ <label>usershare prefix allow list</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8A095F7E_AF4C_5F23_8C6D_327CF9225A8E">
+ <textBox refId="TXT_0CE59443_3FA6_5849_9671_8D70B1EA7E50">
+ <label>usershare prefix deny list</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_ABD81045_A7F0_5D9D_93E5_0D96C0BD7AA8">
+ <textBox refId="TXT_029600AB_FD39_52B7_AE5D_AE0D7138153A">
+ <label>usershare template share</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_238B28BE_5F6B_5251_B47B_4932EA213DAE">
+ <checkBox refId="CHK_651BA339_0B8E_5456_99AA_E4CD4BE64F51">utmp</checkBox>
+ </presentation>
+ <presentation id="POL_BB0E4D55_D6E9_5FDD_A75B_59F7403CF67C">
+ <textBox refId="TXT_C85A703E_0428_51EF_8A2A_D4803BE9446E">
+ <label>utmp directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2AD1815C_5DBC_5A7E_8DC9_CEE194030C59">
+ <textBox refId="TXT_CF0F4D90_5001_57CB_A6C8_58575659305D">
+ <label>wtmp directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_63B9016C_EBE5_5EA7_85B0_493E3155F943">
+ <textBox refId="TXT_63999B72_41DB_5A45_A6DE_66574F1F442F">
+ <label>addport command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_778F868C_7119_5059_9D0D_62B468410A7D">
+ <textBox refId="TXT_5581F365_D9D7_535E_A25B_A58F2FBABCBB">
+ <label>addprinter command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E4EA6E76_DFE6_5C90_8D2F_544185E10581">
+ <decimalTextBox defaultValue="30" refId="DXT_21FF9D0E_70B9_5790_9877_F218D435CAA2"/>
+ </presentation>
+ <presentation id="POL_5A6F3F97_C655_501A_8A1D_D3B96E22D189">
+ <textBox refId="TXT_90A3BD2E_13EF_5BC9_970F_32A3CE582200">
+ <label>cups encrypt</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_713C453D_7C4E_5446_99F0_93FDC97CBD6E">
+ <textBox refId="TXT_E3EF87B6_2525_530F_96D9_36770179DBEF">
+ <label>cups server</label>
+ <defaultValue>&quot;&quot;</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_7801A389_C366_5376_9D03_631BD51C46C4">
+ <textBox refId="TXT_6477B02C_3AE4_5724_B00B_0A11F16A1ECD">
+ <label>deleteprinter command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8AEEC70D_CC12_55A5_A39F_ED0C3A3B652E">
+ <checkBox refId="CHK_BA883BE5_77CE_5478_BBC8_10B796EF09C2">disable spoolss</checkBox>
+ </presentation>
+ <presentation id="POL_D8A14125_4BEE_575E_B7A2_A6D2809A0CC9">
+ <checkBox defaultChecked="true" refId="CHK_76C31A1A_3CCA_54F4_A09B_01ED9C31465A">enable spoolss</checkBox>
+ </presentation>
+ <presentation id="POL_E95AFA3E_7680_5281_88E1_BC2B9DE7C60D">
+ <textBox refId="TXT_9B7FB891_910F_5AB1_96BC_432F871E50AA">
+ <label>enumports command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D0CE14C7_93FC_54DA_84A8_FB6579A01A95">
+ <textBox refId="TXT_CEDD5E8E_4BCB_515F_B962_7C06E9E4EBE6">
+ <label>iprint server</label>
+ <defaultValue>&quot;&quot;</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2AA9A3C9_2D35_5140_AAFD_5A6D4A8B46A9">
+ <checkBox defaultChecked="true" refId="CHK_01150395_D329_542B_8848_2D352BA599CA">load printers</checkBox>
+ </presentation>
+ <presentation id="POL_CB7375CD_3BD9_5AFF_885F_5CD41077D92A">
+ <decimalTextBox defaultValue="30" refId="DXT_86697EF6_0F2B_59EA_AC0A_2A6B16860DC2"/>
+ </presentation>
+ <presentation id="POL_6C573DCA_ADF2_503D_86F1_167FB4B20390">
+ <textBox refId="TXT_60176F30_80AE_5289_8984_1213DB736520">
+ <label>os2 driver map</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_4E996FBA_21B1_54D2_AF3E_0290231D9225">
+ <decimalTextBox defaultValue="750" refId="DXT_30FEC2C2_FB9E_59DC_86AC_0952A9904B2F"/>
+ </presentation>
+ <presentation id="POL_9E502331_FC16_56A6_BAA2_8A4F8CD7403E">
+ <textBox refId="TXT_8288D727_1C29_5CDF_A162_3F5701E803B2">
+ <label>printcap name</label>
+ <defaultValue>/etc/printcap</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_63DFC41F_0FA5_52C6_95CC_071B309E09A9">
+ <checkBox defaultChecked="true" refId="CHK_21859C56_D5DA_5C2E_9215_BA75864C9B4B">show add printer wizard</checkBox>
+ </presentation>
+ <presentation id="POL_C105B217_101D_5080_B2F2_28F453585AF3">
+ <textBox refId="TXT_C9E18177_8584_5290_8B40_37D46546DDB1">
+ <label>spoolss: architecture</label>
+ <defaultValue>Windows NT x86</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B7405490_DE98_5CC9_A096_8B6F690536A5">
+ <decimalTextBox defaultValue="5" refId="DXT_1D4352B8_DB79_5551_A486_7D4D33F8D4D9"/>
+ </presentation>
+ <presentation id="POL_5049AEF7_B2E3_5F11_BB76_CD05A0F405D1">
+ <decimalTextBox defaultValue="0" refId="DXT_6F51D95E_66DD_50B2_B62F_7665EF471B52"/>
+ </presentation>
+ <presentation id="POL_52B0D644_BD3A_5C9D_873F_3DF18D2FDB60">
+ <decimalTextBox defaultValue="2195" refId="DXT_B21A8651_347B_5648_94FA_37B943B6A547"/>
+ </presentation>
+ <presentation id="POL_4B72C056_F162_529E_A137_1F557D5FDFCE">
+ <decimalTextBox defaultValue="6" refId="DXT_6188EEA1_529A_508D_B9D5_378CAB822D89"/>
+ </presentation>
+ <presentation id="POL_1855B435_5BFA_512B_A805_E30B09CFD23F">
+ <decimalTextBox defaultValue="1" refId="DXT_A21AB0C1_D47D_5B8C_8609_171B9D2F4C27"/>
+ </presentation>
+ <presentation id="POL_F173249E_078E_531E_A8DC_85931745FBF9">
+ <decimalTextBox defaultValue="7007" refId="DXT_EC7D7A9D_C0D7_5665_9030_9C85D402BDB1"/>
+ </presentation>
+ <presentation id="POL_A3C35AAF_A7F5_5DCD_B328_C7ABD0F2FDFF">
+ <decimalTextBox defaultValue="389" refId="DXT_BCC54168_D5A8_5014_903F_D0689B350906"/>
+ </presentation>
+ <presentation id="POL_7D6BFF26_946F_5B18_B213_0B9EE147C3C9">
+ <textBox refId="TXT_BC8B7A29_65FA_5B55_BC11_A7574ECD0AA8">
+ <label>client ipc max protocol</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_4D5635CC_F944_5F32_83F0_7730FC9DE680">
+ <textBox refId="TXT_2FAFBF21_5429_5CF1_9152_921CF9CEEC6C">
+ <label>client ipc min protocol</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_79B1D2DB_C2F7_57FA_8D6F_83D756A43A40">
+ <textBox refId="TXT_6E173477_D6E4_5C47_BC6C_5961404DB0CD">
+ <label>client max protocol</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E5D3402E_7A4B_555E_AC54_E5C7AE196EF2">
+ <textBox refId="TXT_30573924_1A09_5202_8DF8_9B24FA69C14E">
+ <label>client min protocol</label>
+ <defaultValue>SMB2_02</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B86463E0_7A50_5BD1_9CD5_A43C20A5E087">
+ <checkBox defaultChecked="true" refId="CHK_5549EDCC_940D_5AEA_8465_B771FEE013BC">client use spnego</checkBox>
+ </presentation>
+ <presentation id="POL_F0990CDC_21DF_538D_9282_2749E00AF99E">
+ <textBox refId="TXT_E8C89EE3_FF60_5216_A5C7_803A3AA8D790">
+ <label>dcerpc endpoint servers</label>
+ <defaultValue>epmapper, wkssvc, rpcecho, samr, netlogon, lsarpc, drsuapi, dssetup, unixinfo, browser, eventlog6, backupkey, dnsserver</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_BD3F8921_7AF6_57F8_894A_9C73D40C6202">
+ <checkBox defaultChecked="true" refId="CHK_AA0DA4CF_4431_509C_8E2D_27BD0DD5CCAB">defer sharing violations</checkBox>
+ </presentation>
+ <presentation id="POL_0C775437_E6FD_5657_9A04_AF137F18FACE">
+ <decimalTextBox defaultValue="138" refId="DXT_8E6D975D_6C56_56F9_9853_60394A2CEFA7"/>
+ </presentation>
+ <presentation id="POL_614DA2E7_D77F_5434_9C73_137D1D89D086">
+ <checkBox refId="CHK_D433FDEC_A984_5B75_AD88_924962077009">disable netbios</checkBox>
+ </presentation>
+ <presentation id="POL_35845C32_CE1D_5395_A07C_142BCFD9744C">
+ <checkBox refId="CHK_31A76B18_E56F_57E6_BBC1_A5988C8D731C">enable asu support</checkBox>
+ </presentation>
+ <presentation id="POL_000AF517_65A2_5220_B1DD_7187EFC59AAB">
+ <textBox refId="TXT_3A3CA4FB_B0F0_5D20_AA43_D6CAECA189E1">
+ <label>eventlog list</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B4BFA8D2_FF42_5E4A_ADE8_D7829A2CC94A">
+ <checkBox defaultChecked="true" refId="CHK_21EE7A7A_DF8F_56F7_85FB_6EC5DD083DD6">large readwrite</checkBox>
+ </presentation>
+ <presentation id="POL_644A4C74_3ECB_5A01_8E2B_1FA9E74EC778">
+ <checkBox refId="CHK_52E0D939_4722_5165_AAFE_A5FD7584E12C">lsa over netlogon</checkBox>
+ </presentation>
+ <presentation id="POL_EAE8C258_343E_522B_A09C_69E9FD81B535">
+ <decimalTextBox defaultValue="50" refId="DXT_549D41B9_4692_55A3_B8C0_11D91DBCC133"/>
+ </presentation>
+ <presentation id="POL_2BAFBEFD_9CEA_53C2_9E78_04807EA6531F">
+ <decimalTextBox defaultValue="259200" refId="DXT_F5E2AC7A_E892_5316_81C3_368BC6F5E4C4"/>
+ </presentation>
+ <presentation id="POL_7D30022C_3DDE_56D1_8D07_D90741127527">
+ <decimalTextBox defaultValue="16644" refId="DXT_8A171231_CF95_5684_B665_9B1F5B046ABD"/>
+ </presentation>
+ <presentation id="POL_02E42B0E_C3F3_5E0B_83C1_6F3ABFEEF251">
+ <decimalTextBox defaultValue="0" refId="DXT_0B40F1AE_EF9C_58E0_9E35_6D119671AAE1"/>
+ </presentation>
+ <presentation id="POL_9AA4C867_EE0B_5742_94F0_4D2243C2E368">
+ <textBox refId="TXT_7C9CF069_5856_5D63_94DD_AF9530B8D495">
+ <label>name resolve order</label>
+ <defaultValue>lmhosts wins host bcast</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0EAD5917_3B68_5B59_92E1_69BD263150EA">
+ <decimalTextBox defaultValue="137" refId="DXT_F06BA6AF_533A_520F_B2E1_EA508FF26E55"/>
+ </presentation>
+ <presentation id="POL_3FA711F7_BD87_5CF6_9A5A_77CF771AAFF2">
+ <checkBox defaultChecked="true" refId="CHK_DAAC7C86_8FD9_55BF_9125_9C95E2D52AFE">nt pipe support</checkBox>
+ </presentation>
+ <presentation id="POL_85D402BD_4D59_5CE0_8EA2_3331CABD23CA">
+ <checkBox defaultChecked="true" refId="CHK_95DD62AA_03E3_5679_AD11_D5616CD25255">nt status support</checkBox>
+ </presentation>
+ <presentation id="POL_9045A4F7_5DED_5A70_B01D_D92B419B6634">
+ <checkBox defaultChecked="true" refId="CHK_B11F35D5_3196_5D92_9B1D_9C746F9162FA">read raw</checkBox>
+ </presentation>
+ <presentation id="POL_9926B5F8_3F22_569B_BB6C_06F2CDF21381">
+ <checkBox refId="CHK_CCA3E37C_1A5F_5493_BFC6_AD75B7AEF1D7">rpc big endian</checkBox>
+ </presentation>
+ <presentation id="POL_56DBEBB2_3508_5C9E_91B2_3E55EF357FFB">
+ <decimalTextBox defaultValue="0" refId="DXT_9489E35C_10BA_57DF_BCA8_E482D719B220"/>
+ </presentation>
+ <presentation id="POL_738E8CDC_C229_5926_8153_E0009CC07424">
+ <textBox refId="TXT_B22408B0_8FF5_5F41_BB61_F89CF80FB1C4">
+ <label>server max protocol</label>
+ <defaultValue>SMB3</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_00778E7A_F34D_546E_9FA8_3968A937392B">
+ <textBox refId="TXT_633970D9_6038_55ED_856F_A39492AE0173">
+ <label>server min protocol</label>
+ <defaultValue>SMB2_02</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B33A00A2_B848_59D9_9C41_582F886C008A">
+ <textBox refId="TXT_3C8506A1_3A67_58AF_BB1F_DD3A931A7FBE">
+ <label>share:fake_fscaps</label>
+ <defaultValue>0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0BC6C240_419F_5F72_9A24_DA191CFFE18E">
+ <decimalTextBox defaultValue="8192" refId="DXT_4FCC3712_A2B7_5C65_933A_621697E78E8F"/>
+ </presentation>
+ <presentation id="POL_908FC006_7CE8_5B56_A049_A3E582C281F3">
+ <decimalTextBox defaultValue="8388608" refId="DXT_8D17E70E_8AA1_5DEC_86C2_154031314317"/>
+ </presentation>
+ <presentation id="POL_84ED1A25_58B9_5C00_8261_11A7D387EAB9">
+ <decimalTextBox defaultValue="8388608" refId="DXT_0923E7AF_8C15_54FD_A360_41E09D67D24C"/>
+ </presentation>
+ <presentation id="POL_A1955D87_2287_524B_9A8C_454C8218F590">
+ <decimalTextBox defaultValue="8388608" refId="DXT_AC8EA085_B897_5581_8260_25EC8761048F"/>
+ </presentation>
+ <presentation id="POL_796581A5_F65E_5D31_BB5C_2CC641B8D03C">
+ <textBox refId="TXT_07CA0480_16BB_5E14_B1E8_716E293305F7">
+ <label>smb ports</label>
+ <defaultValue>445 139</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C141D92D_B912_54D7_88D6_CC3A12A4739D">
+ <textBox refId="TXT_7312B2B6_2E91_5D9E_BE33_A1C73675950E">
+ <label>svcctl list</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_747C776B_2150_5FD4_9A47_9832FD35EBC5">
+ <checkBox refId="CHK_838A32D7_1BA5_55CB_9FA4_95280DFB26F6">time server</checkBox>
+ </presentation>
+ <presentation id="POL_69C69BCA_D38B_54E1_817C_E6993FF1AB91">
+ <checkBox defaultChecked="true" refId="CHK_2280B94E_EB17_5A5E_80F0_B48BE0CBC2CB">unicode</checkBox>
+ </presentation>
+ <presentation id="POL_063DDC7C_E490_5F1B_866D_06D25ABAED90">
+ <checkBox defaultChecked="true" refId="CHK_E429FAE8_6D3B_5B56_8EFF_B3B7C25B3DE1">unix extensions</checkBox>
+ </presentation>
+ <presentation id="POL_CC4C4C4D_0BA2_52C2_A510_1C4F669856F3">
+ <checkBox defaultChecked="true" refId="CHK_4FD77295_65FD_5553_AB18_D6CF04394DAB">write raw</checkBox>
+ </presentation>
+ <presentation id="POL_D1D0620C_FFC1_5C7D_9733_4005F5F61A8D">
+ <checkBox refId="CHK_82B2446C_9CAB_5880_AF33_2803AE49B294">server multi channel support</checkBox>
+ </presentation>
+ <presentation id="POL_D0AC80B8_9AFD_5848_B779_1E43C144D7B3">
+ <checkBox refId="CHK_B6B60597_42F0_58D3_98BB_DB6B75D07112">smb2 disable lock sequence checking</checkBox>
+ </presentation>
+ <presentation id="POL_85DD283F_59E2_5E1D_A694_D52FD7C7627A">
+ <checkBox refId="CHK_B83E6646_94FD_5882_B57A_15B4BA0AABFD">smb2 disable oplock break retry</checkBox>
+ </presentation>
+ <presentation id="POL_9E9B6ADB_2118_5108_9C2D_9899DDDC59AF">
+ <textBox refId="TXT_28520FBC_2959_5800_B0C5_FE205973260B">
+ <label>rpc server dynamic port range</label>
+ <defaultValue>49152-65535</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_9B792D3F_06B3_5683_92D9_45D323276228">
+ <decimalTextBox defaultValue="1000" refId="DXT_9EFB50AC_B3B6_51C1_AD40_298F546733DC"/>
+ </presentation>
+ <presentation id="POL_F30A212E_4A35_5E67_8902_5D28B4E37CE7">
+ <checkBox refId="CHK_EAA911EE_CB2D_5459_AF50_DC1CA4719686">allow dcerpc auth level connect</checkBox>
+ </presentation>
+ <presentation id="POL_2725BCA8_877C_519D_A248_D6EE701DAD53">
+ <checkBox defaultChecked="true" refId="CHK_83FBBE91_8F41_5C06_BD1D_9A47A10B07FE">allow trusted domains</checkBox>
+ </presentation>
+ <presentation id="POL_92DB14AD_A920_5D74_BA74_0C51B13AECBF">
+ <textBox refId="TXT_D70FDB73_012F_5168_8371_B68B4B2FF60E">
+ <label>binddns dir</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_C95900AB_E4E2_5313_9EF5_9AC181CD63A7">
+ <textBox refId="TXT_D6E02483_EC02_52E1_AB5A_E65E2C7FD5C8">
+ <label>check password script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0DDAC1B2_5E35_5770_B177_333E21EF2A80">
+ <textBox refId="TXT_28B76952_9A9C_5E2D_89C6_28CA8ABBEFD4">
+ <label>client ipc signing</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_045DA01B_9A96_5BB1_A5AD_9EA38ECFC199">
+ <checkBox refId="CHK_5203727D_209F_5E8A_AA94_F9DC1BB27027">client lanman auth</checkBox>
+ </presentation>
+ <presentation id="POL_B1954186_3F6B_5F1F_B066_9105058C20A6">
+ <checkBox defaultChecked="true" refId="CHK_B6DB6C5E_8C6F_5288_B469_0C54B947EA2F">client NTLMv2 auth</checkBox>
+ </presentation>
+ <presentation id="POL_676B4751_B95E_5720_A513_203DC3A33B5C">
+ <checkBox refId="CHK_3DCC027B_9C81_5EDE_A64D_D6F956AFE5B8">client plaintext auth</checkBox>
+ </presentation>
+ <presentation id="POL_C3248F39_498F_5B9B_B82D_E99AB08FD0AF">
+ <textBox refId="TXT_4A77A711_9230_5D41_A77C_97123E4789B7">
+ <label>client schannel</label>
+ <defaultValue>yes</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0A922D59_F39C_57B5_82CE_E08DB4EFC5F9">
+ <textBox refId="TXT_E3513F2F_1C85_5D8C_8DEE_741059C1F393">
+ <label>client signing</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_952DF975_FF04_55BD_8C6B_1D0CF167106B">
+ <checkBox refId="CHK_E5D1CBBE_5B07_5559_8885_E8F6DBA75A18">client use spnego principal</checkBox>
+ </presentation>
+ <presentation id="POL_D9E8EB33_0AE9_5DA5_BA48_00221DCE75EB">
+ <checkBox refId="CHK_711A458E_DC58_57EC_B315_0FEF0D2354BF">debug encryption</checkBox>
+ </presentation>
+ <presentation id="POL_B7875E95_FF94_5579_956F_6E2CEB41AB91">
+ <textBox refId="TXT_F17E81EB_DEBF_56F4_B372_D6F61F5516E3">
+ <label>dedicated keytab file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1EE4C27C_051F_55A6_8385_E55B6776D7E4">
+ <checkBox defaultChecked="true" refId="CHK_EC390E59_1CA4_5C42_960E_B0EEA3B0C1F4">encrypt passwords</checkBox>
+ </presentation>
+ <presentation id="POL_59E14991_089B_550D_A563_8FB90A8333FB">
+ <textBox refId="TXT_92855060_EFF4_5BCA_B30B_10C364F30E2E">
+ <label>guest account</label>
+ <defaultValue>nobody</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_772B9223_59BD_57E8_8FA7_17AF0E0EC8EC">
+ <textBox refId="TXT_751BA79F_27EA_55BE_B787_D424CBD47CED">
+ <label>kerberos encryption types</label>
+ <defaultValue>all</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F11FAFDE_22DF_5BB6_9F63_007597D313BD">
+ <textBox refId="TXT_30977E18_9746_5A78_A6DC_82AC5157781F">
+ <label>kerberos method</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F37DD404_E28E_50F2_BFF4_90142620EA2F">
+ <decimalTextBox defaultValue="464" refId="DXT_3E0E91A2_1877_54F2_AFFE_13F912C4B534"/>
+ </presentation>
+ <presentation id="POL_E6FCD1B7_7104_5EF9_BAA7_73E15CC49EE2">
+ <decimalTextBox defaultValue="88" refId="DXT_41AD8F69_347F_58D1_9DA4_B9A600C32EAE"/>
+ </presentation>
+ <presentation id="POL_F77B9807_0B1E_5EA5_A1CB_62B310FE5034">
+ <checkBox refId="CHK_7460D4AE_3934_5090_9E10_BBF60CD5A983">lanman auth</checkBox>
+ </presentation>
+ <presentation id="POL_3D0B6848_AEF7_54A0_8FA0_B6EAD987D449">
+ <textBox refId="TXT_E576122E_9E34_5B1D_9362_2EF751F22E3F">
+ <label>log nt token command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_32F00B99_2861_5EFE_B961_1F52B4FC0530">
+ <textBox refId="TXT_12B82358_1926_5FEC_B016_946E52DDC7A7">
+ <label>map to guest</label>
+ <defaultValue>Never</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_6D23275C_279D_571C_8835_3DA99356979C">
+ <textBox refId="TXT_4C14ACC2_4652_5801_BF08_1D9E81090E16">
+ <label>mit kdc command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3AE05749_32F8_5D7C_BEF0_D0DFB206EA34">
+ <textBox refId="TXT_E71B9BA6_F3A9_510D_AE73_34CC2E7AF19F">
+ <label>ntlm auth</label>
+ <defaultValue>ntlmv2-only</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_7A4CC1D5_FF89_5D5A_9711_B783227B92CE">
+ <textBox refId="TXT_9AB44C0C_849E_55AD_BF88_30862CC83464">
+ <label>ntp signd socket directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1F95F2F6_790E_5946_8F22_F93441D1B91D">
+ <checkBox refId="CHK_905844C6_A433_5422_9020_A275A062AB6F">null passwords</checkBox>
+ </presentation>
+ <presentation id="POL_4B855392_C467_5D42_B793_3EC858462C02">
+ <checkBox refId="CHK_FFDDD176_BDAB_58E3_A455_F60861FD2C63">obey pam restrictions</checkBox>
+ </presentation>
+ <presentation id="POL_F388E520_9E19_53AC_9AFA_D6DAAE139BFE">
+ <decimalTextBox defaultValue="60" refId="DXT_1D580B43_F65E_5F39_A938_BE0D03A04F2B"/>
+ </presentation>
+ <presentation id="POL_FC62DA5F_6B94_5AD6_B9E6_51A9F5F52E2E">
+ <checkBox refId="CHK_49F56502_4B93_5C98_A4BB_327120E5F7D8">pam password change</checkBox>
+ </presentation>
+ <presentation id="POL_6F5A4F7B_B2BC_50D0_84F6_64202749462B">
+ <textBox refId="TXT_38925248_C56C_5F67_959E_45860FA3CEDE">
+ <label>passdb backend</label>
+ <defaultValue>tdbsam</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F3E8ECEA_80D4_529F_8F7B_97B8847E3101">
+ <checkBox refId="CHK_4D782AF0_E6B7_5C3E_AE8F_90D07527724B">passdb expand explicit</checkBox>
+ </presentation>
+ <presentation id="POL_EE00148B_DAEA_5039_B087_B342E865E3AE">
+ <textBox refId="TXT_9E734663_521F_5654_A01C_E8B5C19A4684">
+ <label>passwd chat</label>
+ <defaultValue>*new*password* %n\n *new*password* %n\n *changed*</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A0D04F58_1760_5152_AE42_748ABA7B15D8">
+ <checkBox refId="CHK_6F2AD6B8_489E_512B_A7CC_EDB6FA628D1E">passwd chat debug</checkBox>
+ </presentation>
+ <presentation id="POL_0F8503B0_2D17_54A4_AECA_C8954FC2F1B3">
+ <decimalTextBox defaultValue="2" refId="DXT_849C03F3_A9CF_5B20_81B9_D4EEE2435447"/>
+ </presentation>
+ <presentation id="POL_484C71CF_D856_514E_A645_C94805B51752">
+ <textBox refId="TXT_97FDEF1F_BA9C_5995_BB37_93AF59ADB59C">
+ <label>passwd program</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DE8AED8D_92DF_5DC8_A412_F374508B2DF2">
+ <textBox refId="TXT_DF9C4D42_5129_5D7A_A155_18F2DBB5B2E7">
+ <label>password hash gpg key ids</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E57A4D09_C62A_5ACB_BA14_A52FB3A14D54">
+ <textBox refId="TXT_8F89431E_D922_5610_8770_40BD094BA98D">
+ <label>password hash userPassword schemes</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8DF1C787_4DD3_5769_981D_AD98697D5FAB">
+ <textBox refId="TXT_2BD70FBF_B577_55F7_B757_5DE68D1ECB4B">
+ <label>password server</label>
+ <defaultValue>*</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_576D7547_5317_5D19_9105_4BFD5714D591">
+ <textBox refId="TXT_799A2EBA_FC4C_53C2_B724_0838399601DF">
+ <label>preload modules</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0B74AC8D_E102_5E02_9B21_D264A6662698">
+ <textBox refId="TXT_97A88495_3A90_5773_AF8C_5D35B63E672A">
+ <label>private dir</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_84F44316_118C_5460_A9E9_022AE89D6BC7">
+ <checkBox refId="CHK_C2793981_4BCD_5CDF_8F7B_7AD01E207D2C">raw NTLMv2 auth</checkBox>
+ </presentation>
+ <presentation id="POL_81A0C9F8_E865_532F_8FF6_EA55C23E6417">
+ <textBox refId="TXT_3697BE5E_8DCE_5701_A121_A7E36F07CE6C">
+ <label>rename user script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_61F81501_C5C3_5F3F_8A89_4490F25812D1">
+ <decimalTextBox defaultValue="0" refId="DXT_B5114D77_9A2D_5FB4_8862_313764FA836F"/>
+ </presentation>
+ <presentation id="POL_82E70187_3C79_5C38_837A_F6F7660F7D10">
+ <textBox refId="TXT_00392C71_F9D4_5A75_8082_F7806B6B7564">
+ <label>root directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_487E924D_1F5E_52FA_9DD7_7C893DC03299">
+ <textBox refId="TXT_98D641EC_FAA9_546B_A032_3D7D3D0B28E2">
+ <label>samba kcc command</label>
+ <defaultValue>/samba_kcc</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1D7DD262_FBC1_53B0_8981_D664D2793B98">
+ <textBox refId="TXT_94515E41_3367_514F_978D_FB02F7C7ABD1">
+ <label>security</label>
+ <defaultValue>AUTO</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E94725FD_24A2_5499_9793_E27F2E3D82AB">
+ <textBox refId="TXT_7688CBD7_E2F8_573B_AA8D_9EF8C47630F8">
+ <label>server role</label>
+ <defaultValue>AUTO</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_51A99ED6_90F2_5884_904E_FBB01AE99010">
+ <textBox refId="TXT_0DC074F0_E1DE_5232_B834_889409466FB7">
+ <label>server schannel</label>
+ <defaultValue>yes</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_5FCA2961_E0AB_5E89_8361_C30A3FBAB1EC">
+ <textBox refId="TXT_90F5A286_21F2_5FE7_97F9_88EF3C9B636C">
+ <label>server signing</label>
+ <defaultValue>default</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_619FBE76_46C6_5CD4_8FAB_F6031B681197">
+ <textBox refId="TXT_A5857127_9668_5119_9FB1_28989C19BE29">
+ <label>smb passwd file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F01FFF92_4BCB_5309_8B5C_3910D8E2EE4D">
+ <textBox refId="TXT_18E2AB7A_7B3D_5588_8E22_91549B53719E">
+ <label>tls cafile</label>
+ <defaultValue>tls/ca.pem</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_2D715716_887A_5F22_B8BF_F4D8239F9576">
+ <textBox refId="TXT_24A9FF35_91AF_50B7_9C8B_DCB8815A3B19">
+ <label>tls certfile</label>
+ <defaultValue>tls/cert.pem</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_823C796B_2B4A_5733_B90D_9179CA58C03D">
+ <textBox refId="TXT_3B707725_83FA_511D_BBC2_69122D141655">
+ <label>tls crlfile</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EE10300D_C58D_5AF3_819F_6707ACE727E9">
+ <textBox refId="TXT_EB8D2F6A_9929_5004_BD04_03EB0F381453">
+ <label>tls dh params file</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D1A081CF_40D1_5505_9E0F_1DF2B67DC69F">
+ <checkBox defaultChecked="true" refId="CHK_FBD1856B_6C06_5CF4_9A53_DDF372A2250F">tls enabled</checkBox>
+ </presentation>
+ <presentation id="POL_686F2495_B4CA_5D83_95E3_BF372A1857A3">
+ <textBox refId="TXT_45D2AB07_CCD6_5350_A04D_DB915B7B79A3">
+ <label>tls keyfile</label>
+ <defaultValue>tls/key.pem</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_869E3C32_6369_5FB5_B149_F982FB872384">
+ <textBox refId="TXT_09331402_B0D6_59B2_8C69_2758849398CE">
+ <label>tls verify peer</label>
+ <defaultValue>as_strict_as_possible</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_6B1AC895_029E_5686_B072_4BD0BD8B7C4D">
+ <checkBox refId="CHK_1E20CD87_5BB4_5449_9E0C_BFFBE014C934">unix password sync</checkBox>
+ </presentation>
+ <presentation id="POL_821FE87C_398B_5051_A106_BB4C41475FA2">
+ <decimalTextBox defaultValue="0" refId="DXT_55E19EF4_DFB4_5F5F_8DF5_D88E4874D090"/>
+ </presentation>
+ <presentation id="POL_4A737F54_FE8F_5996_AE22_5AD683E96F64">
+ <textBox refId="TXT_F413607F_E22F_5652_B367_376C260376CF">
+ <label>username map</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B01C544C_C17F_58BE_A8C5_B8B93A5D6D6B">
+ <decimalTextBox defaultValue="0" refId="DXT_54B979EE_6AB6_5CFA_9EE0_CAF728D8EC17"/>
+ </presentation>
+ <presentation id="POL_D6C75311_EF00_56FB_BB7E_2AED9360F004">
+ <textBox refId="TXT_C8B62E8A_0311_5EC2_A8CF_70B60E1BD044">
+ <label>username map script</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D915E5DA_6227_5AF7_84CC_C5FF9079D441">
+ <textBox refId="TXT_55A11C3A_195F_55F9_852D_0D62FD18327B">
+ <label>tls priority</label>
+ <defaultValue>NORMAL:-VERS-SSL3.0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_5413F647_D5E0_5620_B00D_101274974D25">
+ <decimalTextBox defaultValue="100" refId="DXT_8BBF5B06_26CE_5BCE_B851_7B1D4E5BA791"/>
+ </presentation>
+ <presentation id="POL_B9BCD3D7_045F_57C2_9347_4258B5841D4B">
+ <decimalTextBox defaultValue="10080" refId="DXT_1C7D2B97_728C_587E_880B_EDEF41300FAB"/>
+ </presentation>
+ <presentation id="POL_29E85EE4_9F4B_5824_AAD0_B71BC3AD529A">
+ <checkBox defaultChecked="true" refId="CHK_18CC19EE_D0BD_5776_9816_F100799183AB">getwd cache</checkBox>
+ </presentation>
+ <presentation id="POL_9FC38F18_A498_5A48_A001_E1C9DF302BAD">
+ <checkBox refId="CHK_04B2F1DF_E88E_5792_B491_793217A0C8C8">hostname lookups</checkBox>
+ </presentation>
+ <presentation id="POL_A09855DC_589A_515D_B123_3846F60F4908">
+ <decimalTextBox defaultValue="300" refId="DXT_3DAC248C_C8A8_5C1C_8CFB_443894213FC9"/>
+ </presentation>
+ <presentation id="POL_8C101F96_8BD1_5E91_ACA0_813AA7EB6F03">
+ <decimalTextBox defaultValue="0" refId="DXT_4DAE2123_2535_5E0D_BCD1_D5D819A750B9"/>
+ </presentation>
+ <presentation id="POL_571D0589_CE6E_50D9_A04F_4070993911D4">
+ <decimalTextBox defaultValue="16384" refId="DXT_E36137FA_C613_5FBE_B6FE_1A0554C4130E"/>
+ </presentation>
+ <presentation id="POL_4B0BF94D_F644_5874_9963_FB1DB672DFCF">
+ <decimalTextBox defaultValue="0" refId="DXT_3DC584F7_71D3_5762_BB59_FB55D524AF1D"/>
+ </presentation>
+ <presentation id="POL_CCB2A269_DED1_5A89_B0EA_AC8B9A248E01">
+ <decimalTextBox defaultValue="660" refId="DXT_23802D96_34E6_5E30_BB47_2839CFF09E5E"/>
+ </presentation>
+ <presentation id="POL_D0EACF0A_A7EC_5114_84E9_A119EAB06054">
+ <textBox refId="TXT_9F944C4E_3CCB_5C34_AC11_84D5E8AE9675">
+ <label>socket options</label>
+ <defaultValue>TCP_NODELAY</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0BEE9D62_728C_5BEC_B208_C6413ACB23CA">
+ <checkBox defaultChecked="true" refId="CHK_AE0F9277_9994_5245_9AF5_2FE2694EADB3">use mmap</checkBox>
+ </presentation>
+ <presentation id="POL_F0BBD72A_2F52_5518_978A_E4DE80EA63A7">
+ <textBox refId="TXT_1299FC9B_B974_5807_B85B_96EF03DF6E7E">
+ <label>get quota command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1B9A680B_C7D9_5909_A73A_4A88884B1A1A">
+ <checkBox defaultChecked="true" refId="CHK_D8B6A576_57BD_5C1B_8503_D7514BF9A79A">host msdfs</checkBox>
+ </presentation>
+ <presentation id="POL_23841534_EA5C_5066_9A34_A81201DFA255">
+ <textBox refId="TXT_CB4EB282_B71E_5E88_AAD0_CBE322ED1354">
+ <label>set quota command</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_A8D8A049_7017_5627_B698_79DB288ACF3D">
+ <checkBox refId="CHK_E3F6F2BF_E5EF_5ECD_B4EF_525C704252CE">apply group policies</checkBox>
+ </presentation>
+ <presentation id="POL_322C552E_7DC6_57F9_845A_F76107A65059">
+ <checkBox defaultChecked="true" refId="CHK_4D19E247_9D41_57FC_A81B_7AAA3DA70D22">create krb5 conf</checkBox>
+ </presentation>
+ <presentation id="POL_D65A78B4_B284_51E5_86B8_548907E5B99E">
+ <textBox refId="TXT_E8A538AD_C502_5298_A571_D37AF30908B1">
+ <label>idmap backend</label>
+ <defaultValue>tdb</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D9437864_AD98_5DE6_A280_76BF74DF6241">
+ <decimalTextBox defaultValue="604800" refId="DXT_9707658F_1F28_5859_A19A_74FA303C63FD"/>
+ </presentation>
+ <presentation id="POL_DADA8FE7_2FB0_5AFE_AE6F_5CDE2F6C835A">
+ <textBox refId="TXT_8E0B0FA4_3946_55DD_9AD6_B31C5AC79265">
+ <label>idmap gid</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_595CE1B7_F379_543C_99B1_DDF5DCBB2034">
+ <decimalTextBox defaultValue="120" refId="DXT_DB0243EE_0466_539F_8844_6C0FFDEC6AA3"/>
+ </presentation>
+ <presentation id="POL_1493AE04_9E17_51E3_BF56_61A594C41065">
+ <textBox refId="TXT_5BC5E3D4_DCD5_5F0A_92C3_74C651DE0CEA">
+ <label>idmap uid</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_BFD4E3E9_B3CF_5703_95C9_D5AF443628EC">
+ <checkBox defaultChecked="true" refId="CHK_09A137C2_9429_5D4A_A327_A5F475E367AE">include system krb5 conf</checkBox>
+ </presentation>
+ <presentation id="POL_B2DF30E2_2C79_5DB4_BDD4_2A72F3AAE4D1">
+ <checkBox refId="CHK_5CF9E5FF_8158_5689_9FD3_E408D710EC13">neutralize nt4 emulation</checkBox>
+ </presentation>
+ <presentation id="POL_D5D3240F_0956_5A05_8847_1B20DF57BEC8">
+ <checkBox refId="CHK_25E7D915_B85C_5F5B_9A60_056A326ED8F5">reject md5 servers</checkBox>
+ </presentation>
+ <presentation id="POL_5D72D99B_EFA5_5B2F_8616_2FBE8DBBCF81">
+ <checkBox defaultChecked="true" refId="CHK_C103A13B_7017_50F6_A337_C2A90DAE4419">require strong key</checkBox>
+ </presentation>
+ <presentation id="POL_A7D4A2B5_A2CB_5BE6_A7D2_111FFC0BB9C5">
+ <textBox refId="TXT_A6A67F77_1744_5905_9C6F_A3468BBFC424">
+ <label>template homedir</label>
+ <defaultValue>/home/%D/%U</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D7A44478_576C_554E_B31A_5316A836F68E">
+ <textBox refId="TXT_73F5972B_1879_58A0_9815_A627E1F6D5BC">
+ <label>template shell</label>
+ <defaultValue>/bin/false</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_EE40BE14_5D1D_5ED4_845C_E7E51C529C2B">
+ <decimalTextBox defaultValue="300" refId="DXT_22E52F9D_8E44_59CE_ACC2_916D022CDFA6"/>
+ </presentation>
+ <presentation id="POL_76E2E87A_908A_5F9A_AA09_FF096575D9A7">
+ <textBox refId="TXT_C06A3052_6AD2_53D9_BD21_2A738D8BB155">
+ <label>winbindd socket directory</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_91508E50_D468_5787_B9AD_BD8160522742">
+ <checkBox refId="CHK_F53BC663_D7A1_5D33_8C57_9EC32E71DC68">winbind enum groups</checkBox>
+ </presentation>
+ <presentation id="POL_F4AED7E2_E1E5_50C5_BBCA_C543EB5E383E">
+ <checkBox refId="CHK_08E1CF79_DDA7_588B_B86D_590B4967C1C0">winbind enum users</checkBox>
+ </presentation>
+ <presentation id="POL_FE94B125_13A6_5560_A963_34F8F6C8F4D6">
+ <decimalTextBox defaultValue="0" refId="DXT_B28BA151_1969_59E2_B275_C81CA16B5A23"/>
+ </presentation>
+ <presentation id="POL_7548D0E2_C166_5A7A_9701_063C15E4172D">
+ <textBox refId="TXT_3C8A3138_1C1C_5FFF_A3F7_513DEA315389">
+ <label>winbind:ignore domains</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DD3D412F_8AD9_54B9_8D5A_A0501DF3AB07">
+ <decimalTextBox defaultValue="200" refId="DXT_C2980001_BA2C_57BA_8C1B_F973C067028B"/>
+ </presentation>
+ <presentation id="POL_BE09D431_FA6A_5383_994E_1AEA3E9EEC4A">
+ <decimalTextBox defaultValue="1" refId="DXT_6F41A5F1_F003_54F4_88AF_9CC14C5B64F0"/>
+ </presentation>
+ <presentation id="POL_2ABFD1ED_23F7_5C67_8ECD_3F7EE2752B7D">
+ <checkBox defaultChecked="true" refId="CHK_EE309E41_F404_5CE1_AC86_5E795D0C979A">winbind nested groups</checkBox>
+ </presentation>
+ <presentation id="POL_4542EFF0_F19C_5215_92F8_0B006803D437">
+ <checkBox refId="CHK_E9249CF9_4820_553B_B406_5560E8B3DEFF">winbind normalize names</checkBox>
+ </presentation>
+ <presentation id="POL_62688BAF_1F03_5CF4_888F_4B88677FF4AC">
+ <textBox refId="TXT_B2B0FF5C_C714_52AC_BAFE_846EC003D31E">
+ <label>winbind nss info</label>
+ <defaultValue>template</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_053CBE3D_DD33_522A_9B34_9AFF4044D454">
+ <checkBox refId="CHK_5945AB58_D8F0_5BA1_9964_D8E69AF19CBB">winbind offline logon</checkBox>
+ </presentation>
+ <presentation id="POL_3BF15158_B942_5458_999E_4FEBCA3A2290">
+ <decimalTextBox defaultValue="30" refId="DXT_BEC37822_5BBB_56AE_B122_DFA48B55FF4A"/>
+ </presentation>
+ <presentation id="POL_46E902CB_4766_50A8_8A8A_86893347E86F">
+ <checkBox refId="CHK_9DDF19FA_7129_5F46_82E2_FED21BCF9048">winbind refresh tickets</checkBox>
+ </presentation>
+ <presentation id="POL_9F679274_5E36_5B71_BBB3_880590FFB5A4">
+ <decimalTextBox defaultValue="60" refId="DXT_542C16F7_4011_5AFF_A127_7A773681E95B"/>
+ </presentation>
+ <presentation id="POL_B5754213_7C07_59E8_BE54_44BD0B64A8ED">
+ <checkBox refId="CHK_2EB29672_8B33_566A_AFE5_41BFDBE0F72E">winbind rpc only</checkBox>
+ </presentation>
+ <presentation id="POL_923523CB_9B7D_5261_93D6_B5FD86FC39E4">
+ <checkBox defaultChecked="true" refId="CHK_3CAC88EA_556D_5AA8_8A29_282B574B2743">winbind scan trusted domains</checkBox>
+ </presentation>
+ <presentation id="POL_FFF6590E_C5E7_5680_9A62_61DC88079555">
+ <checkBox defaultChecked="true" refId="CHK_E93252A7_06C7_566B_B7E6_8D4D7AADFB8D">winbind sealed pipes</checkBox>
+ </presentation>
+ <presentation id="POL_A55D34ED_E614_5500_9F7B_A07E0EE1F7BE">
+ <textBox refId="TXT_25CC57B6_941F_525A_99F8_1C041F206D9B">
+ <label>winbind separator</label>
+ <defaultValue>\</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_14AE5941_E62F_53FC_95AE_441E7EF43F56">
+ <checkBox refId="CHK_BF4DA096_841C_5A0D_A5E3_CD564122C924">winbind use default domain</checkBox>
+ </presentation>
+ <presentation id="POL_4B5E805D_7C7A_5CCE_AAB2_FBD0B9CC6D2E">
+ <checkBox refId="CHK_7E9390CD_05D9_570F_A761_7B5A605BA1F9">winbind use krb5 enterprise principals</checkBox>
+ </presentation>
+ <presentation id="POL_DBC0E447_01F4_5B72_BA4E_E9248006FD96">
+ <checkBox defaultChecked="true" refId="CHK_243E92BD_CBA1_50BC_BD4D_87B750B6FABB">dns proxy</checkBox>
+ </presentation>
+ <presentation id="POL_2E4CDFD7_AB3A_5898_B4A1_44EDABBEE713">
+ <decimalTextBox defaultValue="518400" refId="DXT_761AB0AD_EED6_5734_BC07_88D6599EF57F"/>
+ </presentation>
+ <presentation id="POL_584FFB0D_E6B4_51B1_B65D_FBFD4D40C4D9">
+ <decimalTextBox defaultValue="21600" refId="DXT_153EA1D4_FC29_50AF_878D_5695C6C186CD"/>
+ </presentation>
+ <presentation id="POL_6D6BFEF8_655A_59B7_B17E_050ADA0FAD0F">
+ <textBox refId="TXT_4B630740_3B6C_5FCF_9B93_46CD46767198">
+ <label>nbtd:wins_prepend1Bto1Cqueries</label>
+ <defaultValue>yes</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_F145528D_6177_5DA0_9730_05420DF91116">
+ <textBox refId="TXT_A7D6BC38_6BF1_56CF_85B2_FEEA5DAB1A45">
+ <label>nbtd:wins_wins_randomize1Clist</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_1D8649CE_6826_507E_A697_A06B2B693295">
+ <textBox refId="TXT_845EC4E4_224C_5FE8_B43E_3F417E26E1F8">
+ <label>nbtd:wins_randomize1Clist_mask</label>
+ <defaultValue>255.255.255.0</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_8A6CF1A8_12F0_5EC4_B588_658C72C10C4B">
+ <textBox refId="TXT_5A9C87F1_E213_5A53_AD54_9B3AFAB13F9C">
+ <label>winsdb:local_owner</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_4B068333_B3F0_5408_A84F_05BFDB2AD521">
+ <textBox refId="TXT_DE8267A0_F6DE_5043_AFDA_3D98B6494A6D">
+ <label>winsdb:dbnosync</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_61D06DDC_5FC1_5A27_9953_0522C71D3C81">
+ <textBox refId="TXT_7AC86D1C_8F55_5202_9960_E3F76BE03021">
+ <label>wins hook</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_DA957F88_D7CE_566D_A902_4CCDEF755586">
+ <checkBox refId="CHK_F6AECF98_9DF6_5B4D_8F4C_1A262B314282">wins proxy</checkBox>
+ </presentation>
+ <presentation id="POL_8F4113F9_15A6_5E26_9F02_7CA7971BE6C9">
+ <textBox refId="TXT_C1395789_AF99_5B0A_89F7_DD274EC794EA">
+ <label>wins server</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0F35BC3D_B809_53E1_9BFD_1765E5E4E934">
+ <checkBox refId="CHK_BE0D6F0B_4FEE_5580_AD27_507FBCC53AB5">wins support</checkBox>
+ </presentation>
+ <presentation id="POL_1009764B_DAB3_56F8_A766_B45CFC524A5E">
+ <textBox refId="TXT_A8EC94D1_CDB1_5E5B_A2D7_D4FDDD78655D">
+ <label>wreplsrv:periodic_interval</label>
+ <defaultValue>15</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_17929B31_DDBB_5B79_AD9D_F0C7EB54BFFA">
+ <textBox refId="TXT_C4483400_9388_5705_BB16_A9CD61B3FC01">
+ <label>wreplsrv:propagate name releases</label>
+ <defaultValue>no</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_E9361CA3_1260_52FE_AD12_742A86788475">
+ <textBox refId="TXT_7E454192_9281_5588_8F18_A4C13837C555">
+ <label>wreplsrv:scavenging_interval</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_D3F0B860_C5A4_5E2A_983F_90B40B5AEF46">
+ <textBox refId="TXT_C4470E01_F859_5E45_B342_290D5974C4D0">
+ <label>wreplsrv:tombstone_extra_timeout</label>
+ <defaultValue>259200</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_0CA9F8A3_6092_57F4_8CCC_114358C3B9EB">
+ <textBox refId="TXT_D81F8827_96DE_500F_B1B8_D6EF10D165FE">
+ <label>wreplsrv:tombstone_interval</label>
+ <defaultValue>518400</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_B06D59DA_A8FC_53AF_AB8F_9C00812D8832">
+ <textBox refId="TXT_B8A345EA_EAA9_524C_A511_8121FD7A5EA1">
+ <label>wreplsrv:tombstone_timeout</label>
+ <defaultValue>86400</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_3F2ADB29_E0AE_5723_BC18_0B7ABC97BBE7">
+ <textBox refId="TXT_F35F7924_DBD3_5F6F_B247_7F4893C63844">
+ <label>wreplsrv:verify_interval</label>
+ <defaultValue>2073600</defaultValue>
+ </textBox>
+ </presentation>
+ <presentation id="POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07">
+ <textBox refId="TXT_609C208A_3B4D_48F1_8A15_C0DF08EAD4D6">
+ <label>Message of the day</label>
+ </textBox>
+ </presentation>
+ <presentation id="POL_68E9155C_CB49_428E_AFE0_B89316FFD948">
+ <textBox refId="TXT_8075D9EA_6E15_4B2A_833A_B918EE90856F">
+ <label>Login Prompt Message</label>
+ <defaultValue>Welcome to \s \r \l</defaultValue>
+ </textBox>
+ </presentation>
+ </presentationTable>
+ </resources>
+</policyDefinitionResources>
diff --git a/libgpo/admx/samba.admx b/libgpo/admx/samba.admx
new file mode 100755
index 0000000..8db6796
--- /dev/null
+++ b/libgpo/admx/samba.admx
@@ -0,0 +1,2549 @@
+<?xml version="1.0" ?>
+<policyDefinitions revision="1.0" schemaVersion="1.0">
+ <policyNamespaces>
+ <target prefix="fullarmor" namespace="FullArmor.Policies.98BB16AF_01EE_4D17_870D_A3311A44D6C2" />
+ <using prefix="windows" namespace="Microsoft.Policies.Windows" />
+ </policyNamespaces>
+ <supersededAdm fileName="" />
+ <resources minRequiredRevision="1.0" />
+ <categories>
+ <category name="CAT_3338C1DD_8A00_4273_8547_158D8B8C19E9" displayName="$(string.CAT_3338C1DD_8A00_4273_8547_158D8B8C19E9)" />
+ <category name="CAT_7D8D7DC8_5A9D_4BE1_8227_F09CDD5AFFC6" displayName="$(string.CAT_7D8D7DC8_5A9D_4BE1_8227_F09CDD5AFFC6)">
+ <parentCategory ref="CAT_3338C1DD_8A00_4273_8547_158D8B8C19E9" />
+ </category>
+ <category name="CAT_2B6D622C_5721_4C23_A2D6_5C70D6E059BA" displayName="$(string.CAT_2B6D622C_5721_4C23_A2D6_5C70D6E059BA)">
+ <parentCategory ref="CAT_7D8D7DC8_5A9D_4BE1_8227_F09CDD5AFFC6" />
+ </category>
+ <category name="CAT_9DEF582D_447A_47E9_A1F5_363558D03FA9" displayName="$(string.CAT_9DEF582D_447A_47E9_A1F5_363558D03FA9)">
+ <parentCategory ref="CAT_7D8D7DC8_5A9D_4BE1_8227_F09CDD5AFFC6" />
+ </category>
+ <category displayName="$(string.CAT_10827749_64ED_5052_87F7_E81AD421856A)" name="CAT_10827749_64ED_5052_87F7_E81AD421856A">
+ <parentCategory ref="CAT_3338C1DD_8A00_4273_8547_158D8B8C19E9"/>
+ </category>
+ <category name="CAT_371A8FF5_990F_47DD_B200_D436AC28A4F9" displayName="$(string.CAT_371A8FF5_990F_47DD_B200_D436AC28A4F9)">
+ <parentCategory ref="CAT_7D8D7DC8_5A9D_4BE1_8227_F09CDD5AFFC6" />
+ </category>
+ </categories>
+ <policies>
+ <policy name="POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061" class="Both" displayName="$(string.POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061)" explainText="$(string.POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061_Help)" presentation="$(presentation.POL_9320E11F_AC80_4A7D_A5C8_1C0F3F727061)" key="Software\Policies\Samba\Unix Settings">
+ <parentCategory ref="CAT_2B6D622C_5721_4C23_A2D6_5C70D6E059BA" />
+ <supportedOn ref="windows:SUPPORTED_WindowsVista" />
+ <elements>
+ <list id="LST_2E9A4684_3C0E_415B_8FD6_D4AF68BC8AC6" key="Software\Policies\Samba\Unix Settings\Daily Scripts" valueName="Daily Scripts" />
+ </elements>
+ </policy>
+ <policy name="POL_825D441F_905E_4C7E_9E4B_03013697C6C1" class="Both" displayName="$(string.POL_825D441F_905E_4C7E_9E4B_03013697C6C1)" explainText="$(string.POL_825D441F_905E_4C7E_9E4B_03013697C6C1_Help)" presentation="$(presentation.POL_825D441F_905E_4C7E_9E4B_03013697C6C1)" key="Software\Policies\Samba\Unix Settings">
+ <parentCategory ref="CAT_2B6D622C_5721_4C23_A2D6_5C70D6E059BA" />
+ <supportedOn ref="windows:SUPPORTED_WindowsVista" />
+ <elements>
+ <list id="LST_1AA93D59_6372_4F1E_90BB_D4CBBBB77238" key="Software\Policies\Samba\Unix Settings\Hourly Scripts" valueName="Hourly Scripts" />
+ </elements>
+ </policy>
+ <policy name="POL_D298F3BD_44D9_426D_AF11_3163D31582F6" class="Both" displayName="$(string.POL_D298F3BD_44D9_426D_AF11_3163D31582F6)" explainText="$(string.POL_D298F3BD_44D9_426D_AF11_3163D31582F6_Help)" presentation="$(presentation.POL_D298F3BD_44D9_426D_AF11_3163D31582F6)" key="Software\Policies\Samba\Unix Settings">
+ <parentCategory ref="CAT_2B6D622C_5721_4C23_A2D6_5C70D6E059BA" />
+ <supportedOn ref="windows:SUPPORTED_WindowsVista" />
+ <elements>
+ <list id="LST_8BC6757D_B1FB_4780_83B4_F85F27BF6E60" key="Software\Policies\Samba\Unix Settings\Monthly Scripts" valueName="Monthly Scripts" />
+ </elements>
+ </policy>
+ <policy name="POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674" class="Both" displayName="$(string.POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674)" explainText="$(string.POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674_Help)" presentation="$(presentation.POL_3ACC7ECD_8086_4F4A_96DF_85B8FDE2F674)" key="Software\Policies\Samba\Unix Settings">
+ <parentCategory ref="CAT_2B6D622C_5721_4C23_A2D6_5C70D6E059BA" />
+ <supportedOn ref="windows:SUPPORTED_WindowsVista" />
+ <elements>
+ <list id="LST_1E7198A6_7850_4CAB_B656_BC18752564FC" key="Software\Policies\Samba\Unix Settings\Weekly Scripts" valueName="Weekly Scripts" />
+ </elements>
+ </policy>
+ <policy name="POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3" class="Machine" displayName="$(string.POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3)" explainText="$(string.POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3_Help)" presentation="$(presentation.POL_DB5DF501_6F87_42D4_9FEC_E7F32C498BD3)" key="Software\Policies\Samba\Unix Settings">
+ <parentCategory ref="CAT_7D8D7DC8_5A9D_4BE1_8227_F09CDD5AFFC6" />
+ <supportedOn ref="windows:SUPPORTED_WindowsVista" />
+ <elements>
+ <list id="LST_4F4BA073_4F7B_4B64_A61D_8E75257A4B9F" key="Software\Policies\Samba\Unix Settings\Sudo Rights" valueName="Sudo Rights" />
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_33AAE399_07A8_5CC8_882A_393E4B96B259)" explainText="$(string.POL_33AAE399_07A8_5CC8_882A_393E4B96B259_Help)" key="Software\Policies\Samba\smb_conf" name="POL_33AAE399_07A8_5CC8_882A_393E4B96B259" presentation="$(presentation.POL_A3D6C2F2_2798_527E_861E_FA8BADBBE6E6)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_F940E18B_16AE_594B_9669_96417E695AC9" key="Software\Policies\Samba\smb_conf\additional dns hostnames" valueName="additional dns hostnames"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3CD2A970_826E_518E_B5F0_5E6725FF354D)" explainText="$(string.POL_3CD2A970_826E_518E_B5F0_5E6725FF354D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3CD2A970_826E_518E_B5F0_5E6725FF354D" presentation="$(presentation.POL_AC8777B4_88D7_5A1A_BB7E_E47AB5DBD6AA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_5C837672_BFBB_592A_907C_E378BEEDA2E4" key="Software\Policies\Samba\smb_conf\bind interfaces only" valueName="bind interfaces only"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_109FA3A4_0F92_5052_A7D9_D4BBCA75F765)" explainText="$(string.POL_109FA3A4_0F92_5052_A7D9_D4BBCA75F765_Help)" key="Software\Policies\Samba\smb_conf" name="POL_109FA3A4_0F92_5052_A7D9_D4BBCA75F765" presentation="$(presentation.POL_D03F1811_D0CA_56CF_9D18_B480E9B5AFAD)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_03C82812_CCD0_5E35_8FA1_2704BAF796E9" key="Software\Policies\Samba\smb_conf\config backend" valueName="config backend"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_08734B25_7265_5D0B_B857_B2E831B624F1)" explainText="$(string.POL_08734B25_7265_5D0B_B857_B2E831B624F1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_08734B25_7265_5D0B_B857_B2E831B624F1" presentation="$(presentation.POL_DE840DAF_58CD_5B21_A76B_70740BD125A1)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_CF5594A6_FA4A_5AB4_881B_AD9270CE3523" key="Software\Policies\Samba\smb_conf\dos charset" valueName="dos charset"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4CCDFFB7_07DF_58F9_904E_13A024A3F54A)" explainText="$(string.POL_4CCDFFB7_07DF_58F9_904E_13A024A3F54A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4CCDFFB7_07DF_58F9_904E_13A024A3F54A" presentation="$(presentation.POL_3783DBBE_7F1F_52B4_BECB_6176E8D43AE1)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_A51834ED_BBB9_52C3_A7C5_A566ABE7AB3D" key="Software\Policies\Samba\smb_conf\enable core files" valueName="enable core files"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5B751E57_31A9_5EC2_A3CD_A8511D74FCFB)" explainText="$(string.POL_5B751E57_31A9_5EC2_A3CD_A8511D74FCFB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5B751E57_31A9_5EC2_A3CD_A8511D74FCFB" presentation="$(presentation.POL_5EE2E645_A509_5C51_94FE_4F84668AC869)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3E2FB206_740F_580E_889D_B53C2540732C" key="Software\Policies\Samba\smb_conf\mdns name" valueName="mdns name"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_461A8AAF_F51E_5FF5_9433_A8D25BBCF783)" explainText="$(string.POL_461A8AAF_F51E_5FF5_9433_A8D25BBCF783_Help)" key="Software\Policies\Samba\smb_conf" name="POL_461A8AAF_F51E_5FF5_9433_A8D25BBCF783" presentation="$(presentation.POL_32EB220A_5721_51EC_810C_0BEF4B9EA706)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_03FFDBD4_C185_5951_954F_189B0D4C40DA" key="Software\Policies\Samba\smb_conf\multicast dns register" valueName="multicast dns register"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_04F98D09_4223_5390_B66F_A6DA05F97FCC)" explainText="$(string.POL_04F98D09_4223_5390_B66F_A6DA05F97FCC_Help)" key="Software\Policies\Samba\smb_conf" name="POL_04F98D09_4223_5390_B66F_A6DA05F97FCC" presentation="$(presentation.POL_51EEB44F_42B8_5CEA_8DA6_CB78139F4804)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_6A12C17F_F8CF_56F3_8D82_43CAB3C57F55" key="Software\Policies\Samba\smb_conf\netbios aliases" valueName="netbios aliases"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_90CE7832_31B7_51D8_9EF2_92FEF396F49B)" explainText="$(string.POL_90CE7832_31B7_51D8_9EF2_92FEF396F49B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_90CE7832_31B7_51D8_9EF2_92FEF396F49B" presentation="$(presentation.POL_4AEFFAC4_3FBE_5DFA_9D3F_D78B50416B7C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_34827D8A_E97C_590B_BD8A_6DEA6A354BE8" key="Software\Policies\Samba\smb_conf\netbios name" valueName="netbios name"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3B93FDE1_6461_572C_AD2E_6AEEAE4EA949)" explainText="$(string.POL_3B93FDE1_6461_572C_AD2E_6AEEAE4EA949_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3B93FDE1_6461_572C_AD2E_6AEEAE4EA949" presentation="$(presentation.POL_24E6BE64_5FEA_56A1_83AF_844C8A96E96D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_0ED12914_E653_5CDA_9F46_E1C3AB2FC32E" key="Software\Policies\Samba\smb_conf\netbios scope" valueName="netbios scope"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E633B0BE_9CF3_5D79_A9F1_CB782C82A19C)" explainText="$(string.POL_E633B0BE_9CF3_5D79_A9F1_CB782C82A19C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E633B0BE_9CF3_5D79_A9F1_CB782C82A19C" presentation="$(presentation.POL_0901DFB6_7C73_5D10_82CC_5D77CD14685D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_F0896598_D8F1_579A_B01D_09A48282AC76" key="Software\Policies\Samba\smb_conf\prefork backoff increment" valueName="prefork backoff increment"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B4E848BD_E606_552C_8C9F_3F8CC1AEF191)" explainText="$(string.POL_B4E848BD_E606_552C_8C9F_3F8CC1AEF191_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B4E848BD_E606_552C_8C9F_3F8CC1AEF191" presentation="$(presentation.POL_26F4B846_C66B_5649_AA7E_B06E899017CA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_BD459D8F_47F9_558D_A641_97892C9E577E" key="Software\Policies\Samba\smb_conf\prefork children" valueName="prefork children"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D721EFAF_A53D_57B7_9639_3859CF9CE31E)" explainText="$(string.POL_D721EFAF_A53D_57B7_9639_3859CF9CE31E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D721EFAF_A53D_57B7_9639_3859CF9CE31E" presentation="$(presentation.POL_9C3E188A_07B9_5354_A206_DD0FA0B4A235)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_16991D04_74C7_54C3_9E4F_52EF9C9AEDB4" key="Software\Policies\Samba\smb_conf\prefork maximum backoff" valueName="prefork maximum backoff"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_1630255E_61BA_5686_B3E0_995F8C4DAA5E)" explainText="$(string.POL_1630255E_61BA_5686_B3E0_995F8C4DAA5E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_1630255E_61BA_5686_B3E0_995F8C4DAA5E" presentation="$(presentation.POL_609F7E6F_9AAC_56B4_B098_4E63BBBB98B4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_5B075596_6622_5C89_A426_B9DA3F43AC3A" key="Software\Policies\Samba\smb_conf\realm" valueName="realm"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E1D45258_0E70_5AF8_AE28_DAB6B318BB8A)" explainText="$(string.POL_E1D45258_0E70_5AF8_AE28_DAB6B318BB8A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E1D45258_0E70_5AF8_AE28_DAB6B318BB8A" presentation="$(presentation.POL_68ED4DED_E13E_5C54_BD04_23E499D77D51)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E2BF4D58_613E_5C2D_850A_C3585BC311C2" key="Software\Policies\Samba\smb_conf\server services" valueName="server services"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_351CFFDA_9DC3_54FB_BE9A_E434F0DB9955)" explainText="$(string.POL_351CFFDA_9DC3_54FB_BE9A_E434F0DB9955_Help)" key="Software\Policies\Samba\smb_conf" name="POL_351CFFDA_9DC3_54FB_BE9A_E434F0DB9955" presentation="$(presentation.POL_584FF155_77A9_5209_AC2F_071DEAB5FA42)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_EC20B2FC_7658_536F_A876_F0B61196042C" key="Software\Policies\Samba\smb_conf\server string" valueName="server string"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_32A7428D_00FC_5203_9943_2BDCDC3D9E0D)" explainText="$(string.POL_32A7428D_00FC_5203_9943_2BDCDC3D9E0D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_32A7428D_00FC_5203_9943_2BDCDC3D9E0D" presentation="$(presentation.POL_3D10A56C_5C5B_516D_8718_0112384056DB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_682410E7_F583_5A97_BB60_6BBAA190DA1C" key="Software\Policies\Samba\smb_conf\share backend" valueName="share backend"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_ABDCEE90_90DE_55C2_A2DC_1C7D017F4B2B)" explainText="$(string.POL_ABDCEE90_90DE_55C2_A2DC_1C7D017F4B2B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_ABDCEE90_90DE_55C2_A2DC_1C7D017F4B2B" presentation="$(presentation.POL_A64B2059_EC1C_5759_94E8_CD95EEB42F35)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3F03354B_7221_5D54_8D25_FA3229D9A026" key="Software\Policies\Samba\smb_conf\unix charset" valueName="unix charset"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D1FAAF87_1E1E_596F_A915_BE72D67A5DC5)" explainText="$(string.POL_D1FAAF87_1E1E_596F_A915_BE72D67A5DC5_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D1FAAF87_1E1E_596F_A915_BE72D67A5DC5" presentation="$(presentation.POL_38764DE0_53DC_587E_A94B_7C03323B0C69)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_A1CD4626_197B_582B_9C09_E35945F84ECF" key="Software\Policies\Samba\smb_conf\workgroup" valueName="workgroup"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_163183B9_195A_5290_927E_08FBB6C76AA0)" explainText="$(string.POL_163183B9_195A_5290_927E_08FBB6C76AA0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_163183B9_195A_5290_927E_08FBB6C76AA0" presentation="$(presentation.POL_DD5ADDCF_E8DF_50F9_9847_E821787C2C3C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_18F101C1_8754_5052_8D12_3D4B3755A739" key="Software\Policies\Samba\smb_conf\interfaces" valueName="interfaces"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_25731B61_FC84_5A83_93AE_296F7D6311C4)" explainText="$(string.POL_25731B61_FC84_5A83_93AE_296F7D6311C4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_25731B61_FC84_5A83_93AE_296F7D6311C4" presentation="$(presentation.POL_EECBA792_3D9C_5624_A01E_F5876EF8224D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_1D40EF50_9DF5_5D95_B5EF_406C4F3774B8" key="Software\Policies\Samba\smb_conf\browse list" valueName="browse list"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3E9E3188_6F1A_54F8_8E13_265E2AD1BE71)" explainText="$(string.POL_3E9E3188_6F1A_54F8_8E13_265E2AD1BE71_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3E9E3188_6F1A_54F8_8E13_265E2AD1BE71" presentation="$(presentation.POL_414481A1_7B9D_551A_96F0_B235A226F141)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_69092348_8194_5EA4_9EB2_AFFFF4A2A6C8" key="Software\Policies\Samba\smb_conf\domain master" valueName="domain master"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E14519D2_9B84_5A1B_B4A4_89F6151BFCE2)" explainText="$(string.POL_E14519D2_9B84_5A1B_B4A4_89F6151BFCE2_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E14519D2_9B84_5A1B_B4A4_89F6151BFCE2" presentation="$(presentation.POL_25D5E28F_5847_5A16_8CF5_01E528D1807D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_7A02FE2C_82BF_50CE_91F0_14B1191E7258" key="Software\Policies\Samba\smb_conf\enhanced browsing" valueName="enhanced browsing"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7E8FBFDB_CBDD_5CE7_B101_07AB8AA71209)" explainText="$(string.POL_7E8FBFDB_CBDD_5CE7_B101_07AB8AA71209_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7E8FBFDB_CBDD_5CE7_B101_07AB8AA71209" presentation="$(presentation.POL_7356F015_5915_5A1E_9154_AEE48849DC85)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_9C07BE5E_EF60_51EC_B26C_CEA97CD41C69" key="Software\Policies\Samba\smb_conf\lm announce" valueName="lm announce"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6D665B21_1F08_5183_B9CD_CFD712C1D4AB)" explainText="$(string.POL_6D665B21_1F08_5183_B9CD_CFD712C1D4AB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6D665B21_1F08_5183_B9CD_CFD712C1D4AB" presentation="$(presentation.POL_37CB9A35_D06B_581B_8BBC_96F636F2DF0D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_6B8EAB54_6B9E_5EE3_BBB3_286F512AC0F9" key="Software\Policies\Samba\smb_conf\lm interval" valueName="lm interval"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_40EA4C73_20A7_580A_A830_0EDA7FC72B7D)" explainText="$(string.POL_40EA4C73_20A7_580A_A830_0EDA7FC72B7D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_40EA4C73_20A7_580A_A830_0EDA7FC72B7D" presentation="$(presentation.POL_00BB67E5_7846_53BF_990A_8B7D03F9D88E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_CFD7EF58_DD73_5465_B0CE_4C6B4E35F416" key="Software\Policies\Samba\smb_conf\local master" valueName="local master"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_95C311BC_3067_5654_A978_70326D928F48)" explainText="$(string.POL_95C311BC_3067_5654_A978_70326D928F48_Help)" key="Software\Policies\Samba\smb_conf" name="POL_95C311BC_3067_5654_A978_70326D928F48" presentation="$(presentation.POL_99809647_A4DC_5363_8E8B_A27B51B90E87)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_3DF3E95D_2453_53C1_A98D_DB040E45E676" key="Software\Policies\Samba\smb_conf\os level" valueName="os level"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_516D10CE_AECD_50DE_B4F5_D9DBF85FA582)" explainText="$(string.POL_516D10CE_AECD_50DE_B4F5_D9DBF85FA582_Help)" key="Software\Policies\Samba\smb_conf" name="POL_516D10CE_AECD_50DE_B4F5_D9DBF85FA582" presentation="$(presentation.POL_69BB8325_FE45_56C0_8D34_F23EC38D2107)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_82D47B73_2C75_5779_A283_E9A39FD54705" key="Software\Policies\Samba\smb_conf\preferred master" valueName="preferred master"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E468B4EF_D43C_572D_9A57_390D5D22F485)" explainText="$(string.POL_E468B4EF_D43C_572D_9A57_390D5D22F485_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E468B4EF_D43C_572D_9A57_390D5D22F485" presentation="$(presentation.POL_F664E709_2422_5047_BD55_E95C422B6B33)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_BEC7C085_5840_5531_9E64_A727E258569A" key="Software\Policies\Samba\smb_conf\allow dns updates" valueName="allow dns updates"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7E805DF0_F3AD_55F6_AC1E_B13987AE73FC)" explainText="$(string.POL_7E805DF0_F3AD_55F6_AC1E_B13987AE73FC_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7E805DF0_F3AD_55F6_AC1E_B13987AE73FC" presentation="$(presentation.POL_C69048CD_ABF0_5333_B5CB_7455D5F226FF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_64C9BBC7_F73A_5844_A613_08685212F33C" key="Software\Policies\Samba\smb_conf\dns forwarder" valueName="dns forwarder"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DE5786B0_C694_53AA_85F2_F9B4EB2F9923)" explainText="$(string.POL_DE5786B0_C694_53AA_85F2_F9B4EB2F9923_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DE5786B0_C694_53AA_85F2_F9B4EB2F9923" presentation="$(presentation.POL_F9D5C585_21FD_5990_BE36_3A58B7AF326B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_05BC3827_6AE7_54BF_8E0C_008D698CC732" key="Software\Policies\Samba\smb_conf\dns update command" valueName="dns update command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C5C16F87_0017_5CC1_810B_398855115BC9)" explainText="$(string.POL_C5C16F87_0017_5CC1_810B_398855115BC9_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C5C16F87_0017_5CC1_810B_398855115BC9" presentation="$(presentation.POL_2363A474_4143_52A2_A69B_05285C98E4CF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_3104780C_9730_550D_8DF9_5C5A226B2AAE" key="Software\Policies\Samba\smb_conf\dns zone scavenging" valueName="dns zone scavenging"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_23A4E426_BE59_5616_849E_94C825DDFC5B)" explainText="$(string.POL_23A4E426_BE59_5616_849E_94C825DDFC5B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_23A4E426_BE59_5616_849E_94C825DDFC5B" presentation="$(presentation.POL_F2F11B02_D190_5766_95DC_FDB846EEEB13)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_A8FD53BD_1ED7_54DB_9A7C_159348F47A6D" key="Software\Policies\Samba\smb_conf\gpo update command" valueName="gpo update command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D32F3D0B_74B1_5C8F_81B4_CC9574EAB9B7)" explainText="$(string.POL_D32F3D0B_74B1_5C8F_81B4_CC9574EAB9B7_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D32F3D0B_74B1_5C8F_81B4_CC9574EAB9B7" presentation="$(presentation.POL_A83B176D_D2FE_5F41_9977_9A16F5B8C5ED)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_E5687DEB_DB51_5266_ACDB_2E619982BAD7" key="Software\Policies\Samba\smb_conf\machine password timeout" valueName="machine password timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_07339CF8_68F5_5B5F_9207_93D2E4526C44)" explainText="$(string.POL_07339CF8_68F5_5B5F_9207_93D2E4526C44_Help)" key="Software\Policies\Samba\smb_conf" name="POL_07339CF8_68F5_5B5F_9207_93D2E4526C44" presentation="$(presentation.POL_5BD73E55_C69F_5CCF_8D91_2513716FB1C6)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3BA3F934_5C9D_5EAB_BAEB_7FBDAE0268F5" key="Software\Policies\Samba\smb_conf\nsupdate command" valueName="nsupdate command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D0F6F805_6160_55CF_9B8B_F5AD874B1E2C)" explainText="$(string.POL_D0F6F805_6160_55CF_9B8B_F5AD874B1E2C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D0F6F805_6160_55CF_9B8B_F5AD874B1E2C" presentation="$(presentation.POL_E38856B0_C9B1_5577_9055_C48A4CCE499C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_041114D6_313A_501F_BFC9_FD004546248B" key="Software\Policies\Samba\smb_conf\spn update command" valueName="spn update command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6FFBB02C_6B3E_5D0E_9193_15F9B38E487D)" explainText="$(string.POL_6FFBB02C_6B3E_5D0E_9193_15F9B38E487D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6FFBB02C_6B3E_5D0E_9193_15F9B38E487D" presentation="$(presentation.POL_C2FCADD1_1EF0_5726_9CDE_0E155B0B6575)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_0BA0C537_293A_525C_AC5C_9BB5C0524277" key="Software\Policies\Samba\smb_conf\mangle prefix" valueName="mangle prefix"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_BE8F8AE7_99AC_582E_8105_00326D511339)" explainText="$(string.POL_BE8F8AE7_99AC_582E_8105_00326D511339_Help)" key="Software\Policies\Samba\smb_conf" name="POL_BE8F8AE7_99AC_582E_8105_00326D511339" presentation="$(presentation.POL_620B56BA_84B7_5E72_AC2D_4F0574FBB199)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_241061E9_3BDA_5AFE_87CB_13C53A164649" key="Software\Policies\Samba\smb_conf\mangling method" valueName="mangling method"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_62095050_5FA9_5E4F_8792_595D30BEF047)" explainText="$(string.POL_62095050_5FA9_5E4F_8792_595D30BEF047_Help)" key="Software\Policies\Samba\smb_conf" name="POL_62095050_5FA9_5E4F_8792_595D30BEF047" presentation="$(presentation.POL_E59D859C_7C78_5AB6_8DE3_27F672637189)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_EA859956_0483_500A_9962_8A26A8B81BB4" key="Software\Policies\Samba\smb_conf\max stat cache size" valueName="max stat cache size"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_63F6A053_E2E9_57D0_A0F8_003024AD6470)" explainText="$(string.POL_63F6A053_E2E9_57D0_A0F8_003024AD6470_Help)" key="Software\Policies\Samba\smb_conf" name="POL_63F6A053_E2E9_57D0_A0F8_003024AD6470" presentation="$(presentation.POL_6BB5939F_7CE6_588E_A6E2_B114EF17F60F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_45471F8A_D0BD_53A3_B51F_393DE6CC03D2" key="Software\Policies\Samba\smb_conf\stat cache" valueName="stat cache"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_FBDCB316_EDD2_526C_AE9F_32F50A97A72F)" explainText="$(string.POL_FBDCB316_EDD2_526C_AE9F_32F50A97A72F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_FBDCB316_EDD2_526C_AE9F_32F50A97A72F" presentation="$(presentation.POL_BE2B9E4A_5ABE_543F_8564_4CBDD1AF9179)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_4A85EF32_894F_50AF_9917_B7F431720A82" key="Software\Policies\Samba\smb_conf\client ldap sasl wrapping" valueName="client ldap sasl wrapping"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_712CFB73_7887_55DD_975B_48DEDBDB9441)" explainText="$(string.POL_712CFB73_7887_55DD_975B_48DEDBDB9441_Help)" key="Software\Policies\Samba\smb_conf" name="POL_712CFB73_7887_55DD_975B_48DEDBDB9441" presentation="$(presentation.POL_F4937393_B88E_5B26_89F5_F9933BEBEF8B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_4B00C10F_7EBB_52D5_9AD1_C893F9C094C5" key="Software\Policies\Samba\smb_conf\ldap admin dn" valueName="ldap admin dn"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_CEAB52CA_95EB_5DE5_863B_2399BEF5C727)" explainText="$(string.POL_CEAB52CA_95EB_5DE5_863B_2399BEF5C727_Help)" key="Software\Policies\Samba\smb_conf" name="POL_CEAB52CA_95EB_5DE5_863B_2399BEF5C727" presentation="$(presentation.POL_5187BD6B_3008_59FC_887D_1C89E807B11E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_87AD8E93_91B6_5439_B928_9776BF986ED0" key="Software\Policies\Samba\smb_conf\ldap connection timeout" valueName="ldap connection timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4750A945_176C_5FFF_AB50_DF2BE31C3FBB)" explainText="$(string.POL_4750A945_176C_5FFF_AB50_DF2BE31C3FBB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4750A945_176C_5FFF_AB50_DF2BE31C3FBB" presentation="$(presentation.POL_96311867_A4DE_5B57_BD8C_3D25B5084F68)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_2BC96AC0_ECEF_55D4_AEA4_039FDD24C999" key="Software\Policies\Samba\smb_conf\ldap delete dn" valueName="ldap delete dn"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_27BBF4DB_E2AE_58D3_8018_E83C4B185A3C)" explainText="$(string.POL_27BBF4DB_E2AE_58D3_8018_E83C4B185A3C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_27BBF4DB_E2AE_58D3_8018_E83C4B185A3C" presentation="$(presentation.POL_193E7C6B_E70E_55EB_AB50_3788B93F4607)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_FCC83065_2F1A_585B_A998_85AA52D99537" key="Software\Policies\Samba\smb_conf\ldap deref" valueName="ldap deref"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B383A7ED_F6A4_5BD3_B85E_E6B6527D8D79)" explainText="$(string.POL_B383A7ED_F6A4_5BD3_B85E_E6B6527D8D79_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B383A7ED_F6A4_5BD3_B85E_E6B6527D8D79" presentation="$(presentation.POL_E6D23CDA_DABC_5749_BEF1_D15FF80E02BF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_DEC758B4_6B3C_5882_B0B8_386473EECFD3" key="Software\Policies\Samba\smb_conf\ldap follow referral" valueName="ldap follow referral"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E31CD0A8_5A4A_5657_8ACA_123A200C6E06)" explainText="$(string.POL_E31CD0A8_5A4A_5657_8ACA_123A200C6E06_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E31CD0A8_5A4A_5657_8ACA_123A200C6E06" presentation="$(presentation.POL_6C44A469_31FA_512A_AB08_ACDADD5B7238)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B51FB55F_3A49_539E_A77A_7F7F2AF2CC39" key="Software\Policies\Samba\smb_conf\ldap group suffix" valueName="ldap group suffix"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_FC4495FC_4C6E_50C8_9B37_08D9955A883B)" explainText="$(string.POL_FC4495FC_4C6E_50C8_9B37_08D9955A883B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_FC4495FC_4C6E_50C8_9B37_08D9955A883B" presentation="$(presentation.POL_83D7A344_AE69_5DCA_A3D9_A79DF817A7D4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E49CAB56_E62A_5930_99DE_EEC0B04DBCF4" key="Software\Policies\Samba\smb_conf\ldap idmap suffix" valueName="ldap idmap suffix"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_2ED1402F_4CF6_5CED_BE40_9B112E1238DC)" explainText="$(string.POL_2ED1402F_4CF6_5CED_BE40_9B112E1238DC_Help)" key="Software\Policies\Samba\smb_conf" name="POL_2ED1402F_4CF6_5CED_BE40_9B112E1238DC" presentation="$(presentation.POL_07D748C7_B6EA_558D_B652_62F9BC2E9A1B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_2B9911E2_33DC_5CB0_A9CC_E7DD7B2A5799" key="Software\Policies\Samba\smb_conf\ldap machine suffix" valueName="ldap machine suffix"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_12C5B04D_D734_576A_99F1_7475BC9E90D7)" explainText="$(string.POL_12C5B04D_D734_576A_99F1_7475BC9E90D7_Help)" key="Software\Policies\Samba\smb_conf" name="POL_12C5B04D_D734_576A_99F1_7475BC9E90D7" presentation="$(presentation.POL_F831F898_66A7_53D3_B6EA_B90065F7EF41)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_1C52332B_FC98_54CA_8C3D_64E63D450DD7" key="Software\Policies\Samba\smb_conf\ldap page size" valueName="ldap page size"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DB427B53_CF02_5410_AE37_5BD4E8B968CE)" explainText="$(string.POL_DB427B53_CF02_5410_AE37_5BD4E8B968CE_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DB427B53_CF02_5410_AE37_5BD4E8B968CE" presentation="$(presentation.POL_068B0430_6CF2_5CAC_BDC8_F7074411AA6C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_03529C2D_378A_5BE4_A342_9FF088AC8396" key="Software\Policies\Samba\smb_conf\ldap passwd sync" valueName="ldap passwd sync"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0C51A40C_E06E_5A0A_B160_5EB21289B17D)" explainText="$(string.POL_0C51A40C_E06E_5A0A_B160_5EB21289B17D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0C51A40C_E06E_5A0A_B160_5EB21289B17D" presentation="$(presentation.POL_DC0C1ABD_D8CE_5175_A9AB_D58661AACFB1)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_B21A5F63_507D_5407_B582_DA64138C6B97" key="Software\Policies\Samba\smb_conf\ldap replication sleep" valueName="ldap replication sleep"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_763BAFE2_3FE0_5C25_B3DC_34AE48F2F569)" explainText="$(string.POL_763BAFE2_3FE0_5C25_B3DC_34AE48F2F569_Help)" key="Software\Policies\Samba\smb_conf" name="POL_763BAFE2_3FE0_5C25_B3DC_34AE48F2F569" presentation="$(presentation.POL_F12B9752_4939_52A6_9A5E_52FFF53FC34F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3ADB0A83_AA24_5C68_BD2E_3723FC2F2268" key="Software\Policies\Samba\smb_conf\ldapsam:editposix" valueName="ldapsam:editposix"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F7979912_0010_5656_BC3A_08876A56418C)" explainText="$(string.POL_F7979912_0010_5656_BC3A_08876A56418C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F7979912_0010_5656_BC3A_08876A56418C" presentation="$(presentation.POL_90ECE51D_8CF8_50F9_809F_87A024DDCAAE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B10770E9_1959_5A4A_8D44_F070923C2A12" key="Software\Policies\Samba\smb_conf\ldapsam:trusted" valueName="ldapsam:trusted"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_04D79AF3_042D_5ABC_BE8F_4C6628E0F703)" explainText="$(string.POL_04D79AF3_042D_5ABC_BE8F_4C6628E0F703_Help)" key="Software\Policies\Samba\smb_conf" name="POL_04D79AF3_042D_5ABC_BE8F_4C6628E0F703" presentation="$(presentation.POL_B58FAA75_79BA_53E3_A895_69D6DE3E547E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_9F11612E_1A6E_5CF7_BC96_4ADBD123A76D" key="Software\Policies\Samba\smb_conf\ldap server require strong auth" valueName="ldap server require strong auth"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5B8B9520_4858_5C2F_AA85_F972FF86784A)" explainText="$(string.POL_5B8B9520_4858_5C2F_AA85_F972FF86784A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5B8B9520_4858_5C2F_AA85_F972FF86784A" presentation="$(presentation.POL_D6465FAC_2205_59C0_A3E6_1F1DE4C50A58)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_950B2F92_3A19_5FC4_839A_3226C858811C" key="Software\Policies\Samba\smb_conf\ldap ssl" valueName="ldap ssl"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_42494B88_7254_5F5F_B738_D5D10BCFBC6C)" explainText="$(string.POL_42494B88_7254_5F5F_B738_D5D10BCFBC6C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_42494B88_7254_5F5F_B738_D5D10BCFBC6C" presentation="$(presentation.POL_EAF3D0F1_C7E5_5864_AE5D_FBF9F6102FF4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_0D06C9D8_3A6A_509E_9B4A_DE497AFA6B58" key="Software\Policies\Samba\smb_conf\ldap ssl ads" valueName="ldap ssl ads"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_9B071174_FBD3_5CA8_82AA_3BD1EB7BCF45)" explainText="$(string.POL_9B071174_FBD3_5CA8_82AA_3BD1EB7BCF45_Help)" key="Software\Policies\Samba\smb_conf" name="POL_9B071174_FBD3_5CA8_82AA_3BD1EB7BCF45" presentation="$(presentation.POL_208E2789_E8A9_53CA_B756_2694096B8DAF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_ABB81954_F41C_5FAD_BD35_873007549C27" key="Software\Policies\Samba\smb_conf\ldap suffix" valueName="ldap suffix"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_40F4D046_B9E1_53B0_9DC9_1AE4DE9B1976)" explainText="$(string.POL_40F4D046_B9E1_53B0_9DC9_1AE4DE9B1976_Help)" key="Software\Policies\Samba\smb_conf" name="POL_40F4D046_B9E1_53B0_9DC9_1AE4DE9B1976" presentation="$(presentation.POL_D76D653B_C2A3_5939_BF95_9BAE0CF6C88C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_8B73DF13_A7A3_57B4_A4BE_AC816E59EBAB" key="Software\Policies\Samba\smb_conf\ldap timeout" valueName="ldap timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_26984E46_7C64_57A4_B4BF_C2C2B13C330E)" explainText="$(string.POL_26984E46_7C64_57A4_B4BF_C2C2B13C330E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_26984E46_7C64_57A4_B4BF_C2C2B13C330E" presentation="$(presentation.POL_B3FBC8E2_DD5D_5CEA_9FC5_44687CF36BB5)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B9F4F586_8F61_53D2_AFEE_B2011D0DFF43" key="Software\Policies\Samba\smb_conf\ldap user suffix" valueName="ldap user suffix"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_AB95F2C5_BFBC_5955_8062_8B446AF7E84C)" explainText="$(string.POL_AB95F2C5_BFBC_5955_8062_8B446AF7E84C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_AB95F2C5_BFBC_5955_8062_8B446AF7E84C" presentation="$(presentation.POL_94ABA1F3_F411_52AE_ADAA_72B53F9198CA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_B7AEDDC2_0B5A_5C1C_AFA0_7518773C5F5F" key="Software\Policies\Samba\smb_conf\ldap max anonymous request size" valueName="ldap max anonymous request size"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_23FFECD5_A3C4_566C_AEB3_015F25B1A978)" explainText="$(string.POL_23FFECD5_A3C4_566C_AEB3_015F25B1A978_Help)" key="Software\Policies\Samba\smb_conf" name="POL_23FFECD5_A3C4_566C_AEB3_015F25B1A978" presentation="$(presentation.POL_A2C8FD60_A284_5409_B130_B135DEE4B615)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_1B597D08_FFDB_5BA4_ABD9_31A8446A3625" key="Software\Policies\Samba\smb_conf\ldap max authenticated request size" valueName="ldap max authenticated request size"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F7C651B1_70B4_5047_BC65_2E4D382CBD15)" explainText="$(string.POL_F7C651B1_70B4_5047_BC65_2E4D382CBD15_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F7C651B1_70B4_5047_BC65_2E4D382CBD15" presentation="$(presentation.POL_695C7E25_8C69_519C_907E_9A71D1FE2EC3)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_6FA557BE_E2D9_54CC_9A8D_FAA4BFCD552A" key="Software\Policies\Samba\smb_conf\ldap max search request size" valueName="ldap max search request size"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B3B2B9CC_3DBC_5C45_AA31_7C1E52AFEFAF)" explainText="$(string.POL_B3B2B9CC_3DBC_5C45_AA31_7C1E52AFEFAF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B3B2B9CC_3DBC_5C45_AA31_7C1E52AFEFAF" presentation="$(presentation.POL_60E126C5_9E79_54DC_B201_A3E643352D00)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_8D517C10_BE65_5D58_AC86_8A21017F479A" key="Software\Policies\Samba\smb_conf\lock spin time" valueName="lock spin time"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4A0366F2_6815_5654_8DC2_F68E840E53F4)" explainText="$(string.POL_4A0366F2_6815_5654_8DC2_F68E840E53F4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4A0366F2_6815_5654_8DC2_F68E840E53F4" presentation="$(presentation.POL_6B50B6B6_D038_54C5_BD82_9D377C2E8C0C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_14C326D8_5326_5883_95FA_D903E07A457A" key="Software\Policies\Samba\smb_conf\oplock break wait time" valueName="oplock break wait time"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B49FAE41_B4C1_5AFA_870E_9E1C35F9A96F)" explainText="$(string.POL_B49FAE41_B4C1_5AFA_870E_9E1C35F9A96F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B49FAE41_B4C1_5AFA_870E_9E1C35F9A96F" presentation="$(presentation.POL_D9E75BB0_F19B_5F72_A58E_22718E614EB3)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_8649286E_DE5D_5DE7_A836_AA15E736A911" key="Software\Policies\Samba\smb_conf\smb2 leases" valueName="smb2 leases"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_1E9B5BE6_8C81_5141_88CD_B5AC0E8D964B)" explainText="$(string.POL_1E9B5BE6_8C81_5141_88CD_B5AC0E8D964B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_1E9B5BE6_8C81_5141_88CD_B5AC0E8D964B" presentation="$(presentation.POL_D7003A7B_D00A_51AE_8D40_7446533B2974)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_4915975F_60D1_5187_9E6A_F835D1086622" key="Software\Policies\Samba\smb_conf\debug class" valueName="debug class"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_07D2E039_C5A0_5123_BD71_0C74E2569310)" explainText="$(string.POL_07D2E039_C5A0_5123_BD71_0C74E2569310_Help)" key="Software\Policies\Samba\smb_conf" name="POL_07D2E039_C5A0_5123_BD71_0C74E2569310" presentation="$(presentation.POL_CF714212_43A8_52ED_BDAD_B1D6F82A6EF9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_ADDEF100_7619_5056_B632_ECEF204DBEC8" key="Software\Policies\Samba\smb_conf\debug hires timestamp" valueName="debug hires timestamp"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E066DF4A_5BA1_5B35_A96F_90DE6CF27132)" explainText="$(string.POL_E066DF4A_5BA1_5B35_A96F_90DE6CF27132_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E066DF4A_5BA1_5B35_A96F_90DE6CF27132" presentation="$(presentation.POL_CF524D7E_11CA_5027_9777_5398DD2804B4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_6D39A340_480D_596C_A9F5_3412FC28765D" key="Software\Policies\Samba\smb_conf\debug pid" valueName="debug pid"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4B4EF8B5_3526_5583_8174_E3E332727970)" explainText="$(string.POL_4B4EF8B5_3526_5583_8174_E3E332727970_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4B4EF8B5_3526_5583_8174_E3E332727970" presentation="$(presentation.POL_BDF671C9_3811_5B19_AB78_5F12B25CEC84)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_2367747B_4E47_503A_A92C_1EA98AC3D5CC" key="Software\Policies\Samba\smb_conf\debug prefix timestamp" valueName="debug prefix timestamp"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_571A8B87_3CCC_5725_BA33_BDEE367BB740)" explainText="$(string.POL_571A8B87_3CCC_5725_BA33_BDEE367BB740_Help)" key="Software\Policies\Samba\smb_conf" name="POL_571A8B87_3CCC_5725_BA33_BDEE367BB740" presentation="$(presentation.POL_B76DE893_21E7_5B6A_81AB_23B8F00D782D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_5BD4217F_5C51_59D6_9582_3037FB4B6E4F" key="Software\Policies\Samba\smb_conf\debug uid" valueName="debug uid"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_2167CEE9_B2C9_5574_8F7D_F38DA9EBBFF1)" explainText="$(string.POL_2167CEE9_B2C9_5574_8F7D_F38DA9EBBFF1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_2167CEE9_B2C9_5574_8F7D_F38DA9EBBFF1" presentation="$(presentation.POL_BACB061C_C7A0_5830_80FE_15FA009DEAA2)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_DBF1992F_D735_55E7_9029_AE5D9EBA66FB" key="Software\Policies\Samba\smb_conf\ldap debug level" valueName="ldap debug level"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F324946B_9B0D_53F0_AD4F_56800DD63085)" explainText="$(string.POL_F324946B_9B0D_53F0_AD4F_56800DD63085_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F324946B_9B0D_53F0_AD4F_56800DD63085" presentation="$(presentation.POL_B51CE2D4_7EFD_577E_97EC_8EEA650C0F0F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_2D488F55_5DE8_5AC6_85AE_F77BE4429364" key="Software\Policies\Samba\smb_conf\ldap debug threshold" valueName="ldap debug threshold"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3A601C55_A5EB_5E86_817B_38DACFD45CF9)" explainText="$(string.POL_3A601C55_A5EB_5E86_817B_38DACFD45CF9_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3A601C55_A5EB_5E86_817B_38DACFD45CF9" presentation="$(presentation.POL_1C03B9BE_5E74_58CF_A649_CDFD9E91F6CC)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_2C83A41B_5CDA_5130_8343_1278307321CD" key="Software\Policies\Samba\smb_conf\log file" valueName="log file"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A3E0303F_93B5_5C1F_8C01_362881F843CC)" explainText="$(string.POL_A3E0303F_93B5_5C1F_8C01_362881F843CC_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A3E0303F_93B5_5C1F_8C01_362881F843CC" presentation="$(presentation.POL_FA6B22DA_628C_5C5E_8BAD_97BBCE0E4F1F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_2533346E_4C1C_5ACB_9355_B40495EB63CD" key="Software\Policies\Samba\smb_conf\logging" valueName="logging"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E077BD91_3587_5DBA_A7CB_13044D97E451)" explainText="$(string.POL_E077BD91_3587_5DBA_A7CB_13044D97E451_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E077BD91_3587_5DBA_A7CB_13044D97E451" presentation="$(presentation.POL_C4E11396_B289_5D98_9F39_6BD19BBB4330)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_60E8D3F6_8EC7_5FDC_8645_3E4E3EF85512" key="Software\Policies\Samba\smb_conf\log level" valueName="log level"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7E7EB779_098F_5383_A0B3_66216F434918)" explainText="$(string.POL_7E7EB779_098F_5383_A0B3_66216F434918_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7E7EB779_098F_5383_A0B3_66216F434918" presentation="$(presentation.POL_EA5127A5_4C6A_5B8A_9D52_D5D17D9E8AFE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_60E6F44F_5185_576D_91C2_9B10FB853416" key="Software\Policies\Samba\smb_conf\max log size" valueName="max log size"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_57C1D731_63A4_519D_BD0B_05683B94BFDB)" explainText="$(string.POL_57C1D731_63A4_519D_BD0B_05683B94BFDB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_57C1D731_63A4_519D_BD0B_05683B94BFDB" presentation="$(presentation.POL_69FD7A6B_0BA2_570F_9BB1_B869C7404630)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_FCD3912D_FD93_54A5_91E4_A834457B8F2E" key="Software\Policies\Samba\smb_conf\syslog" valueName="syslog"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_07C28AF5_BA9B_5B55_A018_28B10E803B26)" explainText="$(string.POL_07C28AF5_BA9B_5B55_A018_28B10E803B26_Help)" key="Software\Policies\Samba\smb_conf" name="POL_07C28AF5_BA9B_5B55_A018_28B10E803B26" presentation="$(presentation.POL_FD3A0B38_1664_58B4_983A_3A21EC4A76EA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_88778A4E_D102_588A_A01C_E930BEE81D6C" key="Software\Policies\Samba\smb_conf\syslog only" valueName="syslog only"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C2541812_F829_51FC_93D7_75BA34C1F487)" explainText="$(string.POL_C2541812_F829_51FC_93D7_75BA34C1F487_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C2541812_F829_51FC_93D7_75BA34C1F487" presentation="$(presentation.POL_AB153BC2_9291_51D0_81AC_1A78B1A0DE6F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_16FD7E9E_1FCF_58D9_940E_42D45860825B" key="Software\Policies\Samba\smb_conf\timestamp logs" valueName="timestamp logs"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3B7BF4ED_04E2_5466_9368_8610A5657F8F)" explainText="$(string.POL_3B7BF4ED_04E2_5466_9368_8610A5657F8F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3B7BF4ED_04E2_5466_9368_8610A5657F8F" presentation="$(presentation.POL_7C7A3857_7762_5F1F_BDB5_A621FEBD0E99)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_6716C37B_3C84_5AB4_8A8D_B6D070787CEB" key="Software\Policies\Samba\smb_conf\abort shutdown script" valueName="abort shutdown script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7EEBACBA_ED90_5C68_826F_737212B364EF)" explainText="$(string.POL_7EEBACBA_ED90_5C68_826F_737212B364EF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7EEBACBA_ED90_5C68_826F_737212B364EF" presentation="$(presentation.POL_A6105481_F59A_5B08_8B4C_B100EF112BD9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_BB6CFFBF_3E2F_5FDF_A2CC_E255231A3370" key="Software\Policies\Samba\smb_conf\add group script" valueName="add group script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_96F9DA59_163C_56B8_9F66_40CAAD868F91)" explainText="$(string.POL_96F9DA59_163C_56B8_9F66_40CAAD868F91_Help)" key="Software\Policies\Samba\smb_conf" name="POL_96F9DA59_163C_56B8_9F66_40CAAD868F91" presentation="$(presentation.POL_01C79ED8_2727_54DF_AF75_96E5A25722DD)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C3FD37B5_A643_57DF_AE57_048E75B21BDF" key="Software\Policies\Samba\smb_conf\add machine script" valueName="add machine script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4AEC4EDA_3303_57E2_BC12_784F40DACA8F)" explainText="$(string.POL_4AEC4EDA_3303_57E2_BC12_784F40DACA8F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4AEC4EDA_3303_57E2_BC12_784F40DACA8F" presentation="$(presentation.POL_BA7787E8_0D26_5963_8F44_498B278A4703)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_56C28546_216A_5AFF_B212_FFEC207F3FFD" key="Software\Policies\Samba\smb_conf\add user script" valueName="add user script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5268249C_58BD_59DA_B44F_DA9109370C58)" explainText="$(string.POL_5268249C_58BD_59DA_B44F_DA9109370C58_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5268249C_58BD_59DA_B44F_DA9109370C58" presentation="$(presentation.POL_077466DB_CB4D_5489_8934_C2F22592D94A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_218549FC_FD8A_5036_8199_9B2AB628624F" key="Software\Policies\Samba\smb_conf\add user to group script" valueName="add user to group script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_89206841_7524_5BFF_872C_444F45C82318)" explainText="$(string.POL_89206841_7524_5BFF_872C_444F45C82318_Help)" key="Software\Policies\Samba\smb_conf" name="POL_89206841_7524_5BFF_872C_444F45C82318" presentation="$(presentation.POL_8F632169_4F0C_500B_BE8B_88960312C345)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_61299541_E6C3_50AD_9CCD_409DBABC3DA2" key="Software\Policies\Samba\smb_conf\allow nt4 crypto" valueName="allow nt4 crypto"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_9A41AF51_88E9_5566_B12E_36DEA5C42D49)" explainText="$(string.POL_9A41AF51_88E9_5566_B12E_36DEA5C42D49_Help)" key="Software\Policies\Samba\smb_conf" name="POL_9A41AF51_88E9_5566_B12E_36DEA5C42D49" presentation="$(presentation.POL_5A6DC206_1A48_5FFE_8B2D_897EF95CCBAD)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_F34DA878_4D45_5E26_8454_77BAE0D9FCAA" key="Software\Policies\Samba\smb_conf\auth event notification" valueName="auth event notification"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_1CAC5DAB_3CB5_586A_AB6F_84E39DDF4796)" explainText="$(string.POL_1CAC5DAB_3CB5_586A_AB6F_84E39DDF4796_Help)" key="Software\Policies\Samba\smb_conf" name="POL_1CAC5DAB_3CB5_586A_AB6F_84E39DDF4796" presentation="$(presentation.POL_3152501B_87A8_5907_AAD5_00B3F7752516)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_F75A550B_6B11_57A4_9EAD_27361359E4CB" key="Software\Policies\Samba\smb_conf\delete group script" valueName="delete group script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_789E0632_E8D7_5FD6_86C6_0EBD079D28C4)" explainText="$(string.POL_789E0632_E8D7_5FD6_86C6_0EBD079D28C4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_789E0632_E8D7_5FD6_86C6_0EBD079D28C4" presentation="$(presentation.POL_676F211D_0B27_54F6_9FF0_1B6F6CC88CA6)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E6287F6E_CDD6_57CC_A6CF_59E26391473A" key="Software\Policies\Samba\smb_conf\delete user from group script" valueName="delete user from group script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A399CF3E_C0C6_594B_8F31_F2AA4A18B5AC)" explainText="$(string.POL_A399CF3E_C0C6_594B_8F31_F2AA4A18B5AC_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A399CF3E_C0C6_594B_8F31_F2AA4A18B5AC" presentation="$(presentation.POL_3033EDC8_8938_5A64_A8B9_1F7349DC1149)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_1FC62BD1_6541_5C03_B233_B5DE1B987775" key="Software\Policies\Samba\smb_conf\delete user script" valueName="delete user script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B35B056A_EEB8_5B89_9FCC_127565F4A6AC)" explainText="$(string.POL_B35B056A_EEB8_5B89_9FCC_127565F4A6AC_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B35B056A_EEB8_5B89_9FCC_127565F4A6AC" presentation="$(presentation.POL_27365CD7_D0DF_5A41_9140_A1C6970CB3D0)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_B67618DB_ED7B_5A2E_AC14_C2E808E1A927" key="Software\Policies\Samba\smb_conf\domain logons" valueName="domain logons"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3B3E3AD6_FB80_5225_8EDA_6066E5987CE1)" explainText="$(string.POL_3B3E3AD6_FB80_5225_8EDA_6066E5987CE1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3B3E3AD6_FB80_5225_8EDA_6066E5987CE1" presentation="$(presentation.POL_49526C11_2F64_5D85_A25D_A90D2152195E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_A6532133_05F0_5D5F_983E_8924AB2334D5" key="Software\Policies\Samba\smb_conf\enable privileges" valueName="enable privileges"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_130E1C0E_9AED_52F5_B1AB_20FD88C999E8)" explainText="$(string.POL_130E1C0E_9AED_52F5_B1AB_20FD88C999E8_Help)" key="Software\Policies\Samba\smb_conf" name="POL_130E1C0E_9AED_52F5_B1AB_20FD88C999E8" presentation="$(presentation.POL_026CF0E2_B95C_5B67_BBAA_E95C5F809B28)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_1FD373A1_8A61_5884_9208_07A886F6334F" key="Software\Policies\Samba\smb_conf\init logon delay" valueName="init logon delay"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_EEBDC4C9_64BA_58DF_B7A3_C384D6972690)" explainText="$(string.POL_EEBDC4C9_64BA_58DF_B7A3_C384D6972690_Help)" key="Software\Policies\Samba\smb_conf" name="POL_EEBDC4C9_64BA_58DF_B7A3_C384D6972690" presentation="$(presentation.POL_B9587C82_562E_5CA5_8BBD_835B3940D00D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_633A0D2D_C7E6_54EF_BCE0_46ECFB6B2C1E" key="Software\Policies\Samba\smb_conf\init logon delayed hosts" valueName="init logon delayed hosts"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_2FCE2207_11A6_5B55_9ECC_49D171438176)" explainText="$(string.POL_2FCE2207_11A6_5B55_9ECC_49D171438176_Help)" key="Software\Policies\Samba\smb_conf" name="POL_2FCE2207_11A6_5B55_9ECC_49D171438176" presentation="$(presentation.POL_84F161E0_6C65_55C2_9DB5_CC61E66CEA9F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_8F910181_D80D_58A5_937D_186E347E6433" key="Software\Policies\Samba\smb_conf\logon drive" valueName="logon drive"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_12DCA5BB_14ED_5BC6_AB9D_E6A57E943B24)" explainText="$(string.POL_12DCA5BB_14ED_5BC6_AB9D_E6A57E943B24_Help)" key="Software\Policies\Samba\smb_conf" name="POL_12DCA5BB_14ED_5BC6_AB9D_E6A57E943B24" presentation="$(presentation.POL_508CD547_53D7_59ED_BB1F_E6EE939C1AF2)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3C94DDFB_94DD_598E_BC0D_B70465DA9C0C" key="Software\Policies\Samba\smb_conf\logon home" valueName="logon home"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6C04D9F3_27E3_51A9_82B5_BEB5265E1236)" explainText="$(string.POL_6C04D9F3_27E3_51A9_82B5_BEB5265E1236_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6C04D9F3_27E3_51A9_82B5_BEB5265E1236" presentation="$(presentation.POL_204A522A_CF55_5E96_A2AD_B58E105AA80C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_05B40781_B875_53DD_B1DD_4CA590B56E4A" key="Software\Policies\Samba\smb_conf\logon path" valueName="logon path"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D354C217_6C18_5AD8_B0A2_DDC89463D0C6)" explainText="$(string.POL_D354C217_6C18_5AD8_B0A2_DDC89463D0C6_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D354C217_6C18_5AD8_B0A2_DDC89463D0C6" presentation="$(presentation.POL_A1B5FFEC_19C2_5415_ACE0_38E5D118E369)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C1B894A7_BDF5_52B8_AC59_900953D453AC" key="Software\Policies\Samba\smb_conf\logon script" valueName="logon script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0AABECB8_5A60_50DA_973A_7EED1138DB0C)" explainText="$(string.POL_0AABECB8_5A60_50DA_973A_7EED1138DB0C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0AABECB8_5A60_50DA_973A_7EED1138DB0C" presentation="$(presentation.POL_DD7A32CE_6F63_596B_8E15_43B11C82E2AF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_805FD143_5242_56DE_BD51_0B514A588E9F" key="Software\Policies\Samba\smb_conf\reject md5 clients" valueName="reject md5 clients"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_68A94D8F_DA35_5CEC_90E6_4FB245FF32D3)" explainText="$(string.POL_68A94D8F_DA35_5CEC_90E6_4FB245FF32D3_Help)" key="Software\Policies\Samba\smb_conf" name="POL_68A94D8F_DA35_5CEC_90E6_4FB245FF32D3" presentation="$(presentation.POL_2AD85924_5D09_571B_B048_E996EC819C57)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B00F123E_2430_5EA0_A543_92D22A0F5FD4" key="Software\Policies\Samba\smb_conf\set primary group script" valueName="set primary group script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5CDF89E1_F318_5495_BEA0_DA44F0542D49)" explainText="$(string.POL_5CDF89E1_F318_5495_BEA0_DA44F0542D49_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5CDF89E1_F318_5495_BEA0_DA44F0542D49" presentation="$(presentation.POL_A8F30942_8D30_583F_8C0F_877BD20D9B26)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_74A021FE_F97F_5D54_9C4E_023D1964D37E" key="Software\Policies\Samba\smb_conf\shutdown script" valueName="shutdown script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3F1B0630_F3F0_5FDE_B66B_1A315CC059B3)" explainText="$(string.POL_3F1B0630_F3F0_5FDE_B66B_1A315CC059B3_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3F1B0630_F3F0_5FDE_B66B_1A315CC059B3" presentation="$(presentation.POL_F0D581AB_54B4_58AA_9B84_6794FB8D3D55)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C77D6CE7_BED5_52A8_BD8C_0259439992FA" key="Software\Policies\Samba\smb_conf\add share command" valueName="add share command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_66A8EC32_6235_5E7C_A085_189166239268)" explainText="$(string.POL_66A8EC32_6235_5E7C_A085_189166239268_Help)" key="Software\Policies\Samba\smb_conf" name="POL_66A8EC32_6235_5E7C_A085_189166239268" presentation="$(presentation.POL_91CEEB79_E73B_563E_84CC_0C1483141142)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_FBB1DAD6_26B9_5FB1_9678_EB499E48CC26" key="Software\Policies\Samba\smb_conf\afs token lifetime" valueName="afs token lifetime"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_78946CAB_73BD_507E_96D5_C643814290D0)" explainText="$(string.POL_78946CAB_73BD_507E_96D5_C643814290D0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_78946CAB_73BD_507E_96D5_C643814290D0" presentation="$(presentation.POL_77D04206_AF73_51DE_9BE8_63524E440826)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_22E4592F_8119_5A26_AF4F_0624F1AC5E0E" key="Software\Policies\Samba\smb_conf\afs username map" valueName="afs username map"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DEF84B6C_B415_56EB_B3E7_1ED683BFEDE5)" explainText="$(string.POL_DEF84B6C_B415_56EB_B3E7_1ED683BFEDE5_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DEF84B6C_B415_56EB_B3E7_1ED683BFEDE5" presentation="$(presentation.POL_5FA91D1E_B675_5681_9FE8_E14B3E1BA737)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_AC4E2E8E_74FE_5FD1_B6F4_3637B4582348" key="Software\Policies\Samba\smb_conf\allow insecure wide links" valueName="allow insecure wide links"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_8539DC0B_8971_5145_8173_C77681F13A94)" explainText="$(string.POL_8539DC0B_8971_5145_8173_C77681F13A94_Help)" key="Software\Policies\Samba\smb_conf" name="POL_8539DC0B_8971_5145_8173_C77681F13A94" presentation="$(presentation.POL_153D9711_80CD_56CD_8A51_DDA71A3800C0)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_D36441A8_7E2F_5174_8483_4DFE0503C16D" key="Software\Policies\Samba\smb_conf\allow unsafe cluster upgrade" valueName="allow unsafe cluster upgrade"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A05EAA54_C6F4_567A_8DE6_7541F9B11046)" explainText="$(string.POL_A05EAA54_C6F4_567A_8DE6_7541F9B11046_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A05EAA54_C6F4_567A_8DE6_7541F9B11046" presentation="$(presentation.POL_DFD4B19F_8874_5AE7_83CE_F8F507F26D51)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_E37B6C82_F04E_5025_B457_01D9296753BE" key="Software\Policies\Samba\smb_conf\async smb echo handler" valueName="async smb echo handler"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_087EEAB6_7F83_50CF_A3D0_97B4C6F94F67)" explainText="$(string.POL_087EEAB6_7F83_50CF_A3D0_97B4C6F94F67_Help)" key="Software\Policies\Samba\smb_conf" name="POL_087EEAB6_7F83_50CF_A3D0_97B4C6F94F67" presentation="$(presentation.POL_AA42E677_62D1_5408_A8B7_98222854E79B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_34B124B0_A219_5575_BFDC_EAC426D7A3A5" key="Software\Policies\Samba\smb_conf\auto services" valueName="auto services"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5518624A_7DB9_51BA_A891_F00A40152354)" explainText="$(string.POL_5518624A_7DB9_51BA_A891_F00A40152354_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5518624A_7DB9_51BA_A891_F00A40152354" presentation="$(presentation.POL_2099F7FC_F033_5E2F_B2D0_17E1CCB2969A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_07FAF490_385F_5A63_8A03_BF34531D019D" key="Software\Policies\Samba\smb_conf\cache directory" valueName="cache directory"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3E23F826_A699_511F_9370_F79DBB4977A9)" explainText="$(string.POL_3E23F826_A699_511F_9370_F79DBB4977A9_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3E23F826_A699_511F_9370_F79DBB4977A9" presentation="$(presentation.POL_2CD315A0_5DDA_5123_A973_79C1DE40BC82)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_1A966B04_20C5_5E97_8C75_71519DB4783C" key="Software\Policies\Samba\smb_conf\change notify" valueName="change notify"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3EF254FF_4CC2_58A5_9A1B_4E0655610DCA)" explainText="$(string.POL_3EF254FF_4CC2_58A5_9A1B_4E0655610DCA_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3EF254FF_4CC2_58A5_9A1B_4E0655610DCA" presentation="$(presentation.POL_2D514759_876D_5B59_B854_8DC51888BB02)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B8991748_9729_56D2_8DAD_5BAFEC5A7A8A" key="Software\Policies\Samba\smb_conf\change share command" valueName="change share command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_93ADB149_A45A_56A2_9462_0BE437084E47)" explainText="$(string.POL_93ADB149_A45A_56A2_9462_0BE437084E47_Help)" key="Software\Policies\Samba\smb_conf" name="POL_93ADB149_A45A_56A2_9462_0BE437084E47" presentation="$(presentation.POL_239BABBB_C9C7_538A_B6CF_0FA2FC980562)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E05A6480_11BB_5FF4_8E6E_37E281DA95F6" key="Software\Policies\Samba\smb_conf\cluster addresses" valueName="cluster addresses"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_306A8E87_1400_5208_8ABF_B9802BFA685B)" explainText="$(string.POL_306A8E87_1400_5208_8ABF_B9802BFA685B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_306A8E87_1400_5208_8ABF_B9802BFA685B" presentation="$(presentation.POL_92925554_781D_56B7_958E_DD33A753ED22)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_D800E6F3_FB17_5561_9C47_88EB4384129D" key="Software\Policies\Samba\smb_conf\clustering" valueName="clustering"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_2D29302D_8AD7_5BC3_B681_8C54D0A61E68)" explainText="$(string.POL_2D29302D_8AD7_5BC3_B681_8C54D0A61E68_Help)" key="Software\Policies\Samba\smb_conf" name="POL_2D29302D_8AD7_5BC3_B681_8C54D0A61E68" presentation="$(presentation.POL_F2210D02_1B94_561B_9B05_1C5B896AF6D4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_EB6161C1_BF92_5E6F_A106_AAE90FBD9EBD" key="Software\Policies\Samba\smb_conf\config file" valueName="config file"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3838911B_D4E6_50BD_B168_85F113E29165)" explainText="$(string.POL_3838911B_D4E6_50BD_B168_85F113E29165_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3838911B_D4E6_50BD_B168_85F113E29165" presentation="$(presentation.POL_2EED8B7C_AF41_514A_A33D_8100A5F831AC)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E56A7A49_B6A1_502F_AF0E_A3944A5DBFFA" key="Software\Policies\Samba\smb_conf\ctdbd socket" valueName="ctdbd socket"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_57D6924C_3F94_5C29_8F63_39808A84FA0F)" explainText="$(string.POL_57D6924C_3F94_5C29_8F63_39808A84FA0F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_57D6924C_3F94_5C29_8F63_39808A84FA0F" presentation="$(presentation.POL_0DE178AC_0A5A_5CDD_8BE6_0E24150CF2BA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_BB942009_69C3_5BAD_8507_AF692DF05CA1" key="Software\Policies\Samba\smb_conf\ctdb locktime warn threshold" valueName="ctdb locktime warn threshold"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6392B974_5997_5E87_916F_FCDCCCCA6069)" explainText="$(string.POL_6392B974_5997_5E87_916F_FCDCCCCA6069_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6392B974_5997_5E87_916F_FCDCCCCA6069" presentation="$(presentation.POL_026C959C_5371_5698_903A_03F46EEDEBE9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_8A4C2887_09B3_542A_A22B_EEC3404DBEF8" key="Software\Policies\Samba\smb_conf\ctdb timeout" valueName="ctdb timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_65E02D5E_EC95_5CD1_9976_6FF4E023ADDD)" explainText="$(string.POL_65E02D5E_EC95_5CD1_9976_6FF4E023ADDD_Help)" key="Software\Policies\Samba\smb_conf" name="POL_65E02D5E_EC95_5CD1_9976_6FF4E023ADDD" presentation="$(presentation.POL_C16447B8_9E34_57E6_A1F7_A6F87E66CF73)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_70112D53_C921_5D1F_9AFC_15D4890131CE" key="Software\Policies\Samba\smb_conf\default service" valueName="default service"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6CD86A19_3EBF_5E3B_A686_462CA044C5D8)" explainText="$(string.POL_6CD86A19_3EBF_5E3B_A686_462CA044C5D8_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6CD86A19_3EBF_5E3B_A686_462CA044C5D8" presentation="$(presentation.POL_41887133_D321_5526_B73E_2D5BEDA6B644)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_7B81ED14_1277_5697_B4DE_2CCFB8F79BC3" key="Software\Policies\Samba\smb_conf\delete share command" valueName="delete share command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_EA272781_6D7D_5FD5_96BF_069193C67F65)" explainText="$(string.POL_EA272781_6D7D_5FD5_96BF_069193C67F65_Help)" key="Software\Policies\Samba\smb_conf" name="POL_EA272781_6D7D_5FD5_96BF_069193C67F65" presentation="$(presentation.POL_B93F17F1_6F2A_5D04_AC96_EA043AC87144)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_3D317248_E078_5FDD_B3C7_B7051C10506D" key="Software\Policies\Samba\smb_conf\dsdb event notification" valueName="dsdb event notification"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_560BC356_6AEC_5D1A_9859_6479FE0F97C0)" explainText="$(string.POL_560BC356_6AEC_5D1A_9859_6479FE0F97C0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_560BC356_6AEC_5D1A_9859_6479FE0F97C0" presentation="$(presentation.POL_ED5A8D54_C086_5C46_985E_746D4ED62FEA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_F76A8EFA_4388_54E3_B283_976BA2DD2A2E" key="Software\Policies\Samba\smb_conf\dsdb group change notification" valueName="dsdb group change notification"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_2CF8E791_3F03_5CE3_AC93_0B8078E9667D)" explainText="$(string.POL_2CF8E791_3F03_5CE3_AC93_0B8078E9667D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_2CF8E791_3F03_5CE3_AC93_0B8078E9667D" presentation="$(presentation.POL_5B2313F4_5239_57E8_88E9_822DBB4C0E77)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_4B61A9A1_8E18_56CF_9B9E_6904A78328A0" key="Software\Policies\Samba\smb_conf\dsdb password event notification" valueName="dsdb password event notification"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C8A040D9_B798_5FE4_A736_BAD9C81CE976)" explainText="$(string.POL_C8A040D9_B798_5FE4_A736_BAD9C81CE976_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C8A040D9_B798_5FE4_A736_BAD9C81CE976" presentation="$(presentation.POL_B86BF972_B64C_57B2_9E82_96C5EECFAFA7)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_7AB84D08_FB4A_5676_B106_B4DB68C5F577" key="Software\Policies\Samba\smb_conf\elasticsearch:mappings" valueName="elasticsearch:mappings"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_66C9072D_C818_5DFB_AB72_5EDDD4CAE999)" explainText="$(string.POL_66C9072D_C818_5DFB_AB72_5EDDD4CAE999_Help)" key="Software\Policies\Samba\smb_conf" name="POL_66C9072D_C818_5DFB_AB72_5EDDD4CAE999" presentation="$(presentation.POL_444019F3_369A_5807_805C_AB00E59CDD4B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_9EA28A80_4AA6_5D4A_8A14_E22205D488CD" key="Software\Policies\Samba\smb_conf\fss: prune stale" valueName="fss: prune stale"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A7F4325A_910F_5437_B911_6D94050EF882)" explainText="$(string.POL_A7F4325A_910F_5437_B911_6D94050EF882_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A7F4325A_910F_5437_B911_6D94050EF882" presentation="$(presentation.POL_472F0591_240C_5E5D_827C_49E760A75B8E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_D5D56481_74EE_5D10_8476_B3FDB82AE518" key="Software\Policies\Samba\smb_conf\fss: sequence timeout" valueName="fss: sequence timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_529A6287_1697_57CA_A6D0_811F61A441A0)" explainText="$(string.POL_529A6287_1697_57CA_A6D0_811F61A441A0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_529A6287_1697_57CA_A6D0_811F61A441A0" presentation="$(presentation.POL_DADF0887_C19B_5B14_9CEF_6721596557EB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B001AD6C_7FA0_5EE0_8C4D_D506EECFF497" key="Software\Policies\Samba\smb_conf\homedir map" valueName="homedir map"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3EE25C0A_C920_54B4_8B7B_D0A91CF3E3F1)" explainText="$(string.POL_3EE25C0A_C920_54B4_8B7B_D0A91CF3E3F1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3EE25C0A_C920_54B4_8B7B_D0A91CF3E3F1" presentation="$(presentation.POL_AFF4FEEA_8C88_5AED_9414_F4A320074A99)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_F273132D_C805_596F_A0E1_B6ECB4752ADB" key="Software\Policies\Samba\smb_conf\kernel change notify" valueName="kernel change notify"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_15EAB330_0CF4_537E_AD96_8FCECB55194F)" explainText="$(string.POL_15EAB330_0CF4_537E_AD96_8FCECB55194F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_15EAB330_0CF4_537E_AD96_8FCECB55194F" presentation="$(presentation.POL_4F279322_30AA_564B_844F_7827454574D2)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_A384C210_BD62_5E63_B7EB_BC26844F51C8" key="Software\Policies\Samba\smb_conf\lock directory" valueName="lock directory"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A53007F8_7951_51F3_9753_B6FA4B38B9B7)" explainText="$(string.POL_A53007F8_7951_51F3_9753_B6FA4B38B9B7_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A53007F8_7951_51F3_9753_B6FA4B38B9B7" presentation="$(presentation.POL_1120E96A_0F8E_5827_A6D2_3CA7AD66D689)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_EB18668D_E754_524B_B2D7_CC74BA90421D" key="Software\Policies\Samba\smb_conf\log writeable files on exit" valueName="log writeable files on exit"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7DD9B43E_A2B8_59F8_9927_2B56698E65B6)" explainText="$(string.POL_7DD9B43E_A2B8_59F8_9927_2B56698E65B6_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7DD9B43E_A2B8_59F8_9927_2B56698E65B6" presentation="$(presentation.POL_63067D3C_4F00_5193_92FE_A58651D4BACC)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_18DDFF0D_D5DB_5617_AE32_D93BE7E38C4B" key="Software\Policies\Samba\smb_conf\message command" valueName="message command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3BDFEE33_A965_5CA9_BC8C_7E5FDA1BB1D5)" explainText="$(string.POL_3BDFEE33_A965_5CA9_BC8C_7E5FDA1BB1D5_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3BDFEE33_A965_5CA9_BC8C_7E5FDA1BB1D5" presentation="$(presentation.POL_8765A188_6EFA_515B_B602_8F67140CFE7F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C551A0C4_E3B9_5985_9492_C7F42D10E75C" key="Software\Policies\Samba\smb_conf\nbt client socket address" valueName="nbt client socket address"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C4D98472_F115_59FD_A3E6_A7984D662B99)" explainText="$(string.POL_C4D98472_F115_59FD_A3E6_A7984D662B99_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C4D98472_F115_59FD_A3E6_A7984D662B99" presentation="$(presentation.POL_D7C62F7B_B1B6_57B3_AE48_34D09A88ECFE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_1A090CE6_58F5_56F0_A29C_175CADD196D7" key="Software\Policies\Samba\smb_conf\ncalrpc dir" valueName="ncalrpc dir"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4308D035_8B4B_575A_8984_BAC33A169EBA)" explainText="$(string.POL_4308D035_8B4B_575A_8984_BAC33A169EBA_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4308D035_8B4B_575A_8984_BAC33A169EBA" presentation="$(presentation.POL_CCC72421_6131_58BC_BFE1_D9EC7399CD57)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_8E5A65B4_42A2_5F00_8558_E69C28758E1B" key="Software\Policies\Samba\smb_conf\NIS homedir" valueName="NIS homedir"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_359CDEF8_9711_56A5_8621_C50718A5B8A1)" explainText="$(string.POL_359CDEF8_9711_56A5_8621_C50718A5B8A1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_359CDEF8_9711_56A5_8621_C50718A5B8A1" presentation="$(presentation.POL_3E9DEECC_9015_5720_9251_CF804FAB2602)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_49457A99_B4CF_594B_B796_916B9AB74838" key="Software\Policies\Samba\smb_conf\nmbd bind explicit broadcast" valueName="nmbd bind explicit broadcast"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_23418947_2DAF_54B3_812C_D9B43F49CFCB)" explainText="$(string.POL_23418947_2DAF_54B3_812C_D9B43F49CFCB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_23418947_2DAF_54B3_812C_D9B43F49CFCB" presentation="$(presentation.POL_5A63DA17_F433_5414_A47F_26C5B9BE57C2)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_A21115E3_D3E1_505B_9D2C_84A3DC428246" key="Software\Policies\Samba\smb_conf\panic action" valueName="panic action"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C5C3267E_6E80_5311_96A5_B492C8C3C0AF)" explainText="$(string.POL_C5C3267E_6E80_5311_96A5_B492C8C3C0AF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C5C3267E_6E80_5311_96A5_B492C8C3C0AF" presentation="$(presentation.POL_50CDC71F_7927_5631_A40A_C0BD12899CA1)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_6C7D4E2F_9ABE_5C67_9A8C_18D11AEF6038" key="Software\Policies\Samba\smb_conf\perfcount module" valueName="perfcount module"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_02EAE588_9ED7_589C_A454_5B168B65A48A)" explainText="$(string.POL_02EAE588_9ED7_589C_A454_5B168B65A48A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_02EAE588_9ED7_589C_A454_5B168B65A48A" presentation="$(presentation.POL_A02E7761_E359_5528_A160_F2B67024244F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_DC19A229_4604_5CC9_8C83_CA2A1323653A" key="Software\Policies\Samba\smb_conf\pid directory" valueName="pid directory"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_77C5FC2D_BBFA_5B4E_906F_ED49B11BF069)" explainText="$(string.POL_77C5FC2D_BBFA_5B4E_906F_ED49B11BF069_Help)" key="Software\Policies\Samba\smb_conf" name="POL_77C5FC2D_BBFA_5B4E_906F_ED49B11BF069" presentation="$(presentation.POL_C030CCF1_08E7_5B6F_9239_F19B792C2157)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_0200BA53_C2E5_5136_8A69_D8561A556A50" key="Software\Policies\Samba\smb_conf\registry shares" valueName="registry shares"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0FB22970_94A4_5403_888E_3CF8242A955C)" explainText="$(string.POL_0FB22970_94A4_5403_888E_3CF8242A955C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0FB22970_94A4_5403_888E_3CF8242A955C" presentation="$(presentation.POL_ADE18BC6_D01E_58CF_98FA_BCDCC7CDDC37)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_D765EA37_D1F5_50B2_91CE_49E66F462943" key="Software\Policies\Samba\smb_conf\remote announce" valueName="remote announce"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B570A06A_7945_5818_B81D_D27007986548)" explainText="$(string.POL_B570A06A_7945_5818_B81D_D27007986548_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B570A06A_7945_5818_B81D_D27007986548" presentation="$(presentation.POL_2D35EC75_4D7A_533F_96C8_3A331BDEDF34)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_F44D8D8A_1E1F_5BEE_AB4F_B3DAAFB7DBA9" key="Software\Policies\Samba\smb_conf\remote browse sync" valueName="remote browse sync"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_BA134175_B8C1_5781_9585_AF3A47C44354)" explainText="$(string.POL_BA134175_B8C1_5781_9585_AF3A47C44354_Help)" key="Software\Policies\Samba\smb_conf" name="POL_BA134175_B8C1_5781_9585_AF3A47C44354" presentation="$(presentation.POL_2594A0C3_CF98_5B89_B182_1BB9C275B742)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_57B96280_EA3D_5DAC_83DE_13338587A0D6" key="Software\Policies\Samba\smb_conf\reset on zero vc" valueName="reset on zero vc"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F0071286_C011_5F1C_A520_2DD14DF7682C)" explainText="$(string.POL_F0071286_C011_5F1C_A520_2DD14DF7682C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F0071286_C011_5F1C_A520_2DD14DF7682C" presentation="$(presentation.POL_17837A58_88D4_5F29_8D41_479688BD8CBD)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_90158AA7_C0BE_5650_9204_2AFC0BD9D5E8" key="Software\Policies\Samba\smb_conf\rpc_daemon:DAEMON" valueName="rpc_daemon:DAEMON"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_820BF686_A78C_5314_A371_3633A8448DC2)" explainText="$(string.POL_820BF686_A78C_5314_A371_3633A8448DC2_Help)" key="Software\Policies\Samba\smb_conf" name="POL_820BF686_A78C_5314_A371_3633A8448DC2" presentation="$(presentation.POL_AC41C088_31DF_569D_8FC8_8747C4A30548)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_31E1741F_829C_5B90_9A2F_B0E0DC5F1E75" key="Software\Policies\Samba\smb_conf\rpc_server:SERVER" valueName="rpc_server:SERVER"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_70434A64_4979_53D2_80EE_09FBF1562741)" explainText="$(string.POL_70434A64_4979_53D2_80EE_09FBF1562741_Help)" key="Software\Policies\Samba\smb_conf" name="POL_70434A64_4979_53D2_80EE_09FBF1562741" presentation="$(presentation.POL_1233682B_A71D_5081_9CF1_F5112A62EE3B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B5965925_60A9_5A4E_B348_80C590F7AF7A" key="Software\Policies\Samba\smb_conf\smbd profiling level" valueName="smbd profiling level"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_9598A191_3D22_5B49_8188_8D6901A5B4CE)" explainText="$(string.POL_9598A191_3D22_5B49_8188_8D6901A5B4CE_Help)" key="Software\Policies\Samba\smb_conf" name="POL_9598A191_3D22_5B49_8188_8D6901A5B4CE" presentation="$(presentation.POL_C2788566_CBC3_59A3_80A2_72D92E42C276)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_58CF9CC7_1A14_55B0_8E4E_52E962A10EE4" key="Software\Policies\Samba\smb_conf\state directory" valueName="state directory"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_73FD8B56_579A_5BC6_A49A_4000BE94A02F)" explainText="$(string.POL_73FD8B56_579A_5BC6_A49A_4000BE94A02F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_73FD8B56_579A_5BC6_A49A_4000BE94A02F" presentation="$(presentation.POL_6AF97A17_10D7_553C_8CEC_09C8466A2AA4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_2D14A430_BA96_5B3F_970F_CE1AE9F7E8AA" key="Software\Policies\Samba\smb_conf\usershare allow guests" valueName="usershare allow guests"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A0CE47E8_AE8A_5602_8265_1C8D3AEC6064)" explainText="$(string.POL_A0CE47E8_AE8A_5602_8265_1C8D3AEC6064_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A0CE47E8_AE8A_5602_8265_1C8D3AEC6064" presentation="$(presentation.POL_35B0CCC2_C387_5AED_9345_A2E4DE654F5F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_AD83F27E_4FF7_5E8D_A441_0A8925C9D917" key="Software\Policies\Samba\smb_conf\usershare max shares" valueName="usershare max shares"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_411611B5_93F6_546F_B68B_05167A064628)" explainText="$(string.POL_411611B5_93F6_546F_B68B_05167A064628_Help)" key="Software\Policies\Samba\smb_conf" name="POL_411611B5_93F6_546F_B68B_05167A064628" presentation="$(presentation.POL_4E1A7DA3_3014_5C3C_9B0B_1919ECADACFB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_950CF79D_4898_55EB_A6A8_24F2A6867B1D" key="Software\Policies\Samba\smb_conf\usershare owner only" valueName="usershare owner only"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DD97B40A_CB2A_5818_8D39_F94911EB3F13)" explainText="$(string.POL_DD97B40A_CB2A_5818_8D39_F94911EB3F13_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DD97B40A_CB2A_5818_8D39_F94911EB3F13" presentation="$(presentation.POL_F2D66EF9_F99C_5347_A075_E8733603E83D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_D24709D9_FFEF_5871_AF49_5E3A3466761C" key="Software\Policies\Samba\smb_conf\usershare path" valueName="usershare path"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4AAFAB11_EB55_5600_A574_08E074B5DC28)" explainText="$(string.POL_4AAFAB11_EB55_5600_A574_08E074B5DC28_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4AAFAB11_EB55_5600_A574_08E074B5DC28" presentation="$(presentation.POL_568D23D8_683D_5E32_96B8_5CCF81F0BDEC)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C0DF82DC_7C0A_5B7F_9B93_19D517976672" key="Software\Policies\Samba\smb_conf\usershare prefix allow list" valueName="usershare prefix allow list"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_1D783E13_3E5A_5FEB_B1C0_486FF385960E)" explainText="$(string.POL_1D783E13_3E5A_5FEB_B1C0_486FF385960E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_1D783E13_3E5A_5FEB_B1C0_486FF385960E" presentation="$(presentation.POL_8A095F7E_AF4C_5F23_8C6D_327CF9225A8E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_0CE59443_3FA6_5849_9671_8D70B1EA7E50" key="Software\Policies\Samba\smb_conf\usershare prefix deny list" valueName="usershare prefix deny list"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_2974E59A_2225_59CA_A4C8_C967FDB0E588)" explainText="$(string.POL_2974E59A_2225_59CA_A4C8_C967FDB0E588_Help)" key="Software\Policies\Samba\smb_conf" name="POL_2974E59A_2225_59CA_A4C8_C967FDB0E588" presentation="$(presentation.POL_ABD81045_A7F0_5D9D_93E5_0D96C0BD7AA8)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_029600AB_FD39_52B7_AE5D_AE0D7138153A" key="Software\Policies\Samba\smb_conf\usershare template share" valueName="usershare template share"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_99ADA47F_F025_52B8_B8F5_DDFA0EEFEF31)" explainText="$(string.POL_99ADA47F_F025_52B8_B8F5_DDFA0EEFEF31_Help)" key="Software\Policies\Samba\smb_conf" name="POL_99ADA47F_F025_52B8_B8F5_DDFA0EEFEF31" presentation="$(presentation.POL_238B28BE_5F6B_5251_B47B_4932EA213DAE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_651BA339_0B8E_5456_99AA_E4CD4BE64F51" key="Software\Policies\Samba\smb_conf\utmp" valueName="utmp"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_21565354_4253_5482_97D2_9C2558461C47)" explainText="$(string.POL_21565354_4253_5482_97D2_9C2558461C47_Help)" key="Software\Policies\Samba\smb_conf" name="POL_21565354_4253_5482_97D2_9C2558461C47" presentation="$(presentation.POL_BB0E4D55_D6E9_5FDD_A75B_59F7403CF67C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C85A703E_0428_51EF_8A2A_D4803BE9446E" key="Software\Policies\Samba\smb_conf\utmp directory" valueName="utmp directory"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4F8E9BC0_CFAB_52F8_9C49_B8BB7400E60A)" explainText="$(string.POL_4F8E9BC0_CFAB_52F8_9C49_B8BB7400E60A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4F8E9BC0_CFAB_52F8_9C49_B8BB7400E60A" presentation="$(presentation.POL_2AD1815C_5DBC_5A7E_8DC9_CEE194030C59)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_CF0F4D90_5001_57CB_A6C8_58575659305D" key="Software\Policies\Samba\smb_conf\wtmp directory" valueName="wtmp directory"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_83F826D3_2069_552C_8376_C0512E99728D)" explainText="$(string.POL_83F826D3_2069_552C_8376_C0512E99728D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_83F826D3_2069_552C_8376_C0512E99728D" presentation="$(presentation.POL_63B9016C_EBE5_5EA7_85B0_493E3155F943)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_63999B72_41DB_5A45_A6DE_66574F1F442F" key="Software\Policies\Samba\smb_conf\addport command" valueName="addport command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B4BE84FF_FB13_5496_AC34_B15BF764F654)" explainText="$(string.POL_B4BE84FF_FB13_5496_AC34_B15BF764F654_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B4BE84FF_FB13_5496_AC34_B15BF764F654" presentation="$(presentation.POL_778F868C_7119_5059_9D0D_62B468410A7D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_5581F365_D9D7_535E_A25B_A58F2FBABCBB" key="Software\Policies\Samba\smb_conf\addprinter command" valueName="addprinter command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D9D048A2_779C_5D85_A26E_131535508B70)" explainText="$(string.POL_D9D048A2_779C_5D85_A26E_131535508B70_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D9D048A2_779C_5D85_A26E_131535508B70" presentation="$(presentation.POL_E4EA6E76_DFE6_5C90_8D2F_544185E10581)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_21FF9D0E_70B9_5790_9877_F218D435CAA2" key="Software\Policies\Samba\smb_conf\cups connection timeout" valueName="cups connection timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_AB9D00A2_AB72_5D21_94C6_8EC1238F2793)" explainText="$(string.POL_AB9D00A2_AB72_5D21_94C6_8EC1238F2793_Help)" key="Software\Policies\Samba\smb_conf" name="POL_AB9D00A2_AB72_5D21_94C6_8EC1238F2793" presentation="$(presentation.POL_5A6F3F97_C655_501A_8A1D_D3B96E22D189)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_90A3BD2E_13EF_5BC9_970F_32A3CE582200" key="Software\Policies\Samba\smb_conf\cups encrypt" valueName="cups encrypt"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_CDEAD263_A87A_550A_A067_3FF8C0C60986)" explainText="$(string.POL_CDEAD263_A87A_550A_A067_3FF8C0C60986_Help)" key="Software\Policies\Samba\smb_conf" name="POL_CDEAD263_A87A_550A_A067_3FF8C0C60986" presentation="$(presentation.POL_713C453D_7C4E_5446_99F0_93FDC97CBD6E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E3EF87B6_2525_530F_96D9_36770179DBEF" key="Software\Policies\Samba\smb_conf\cups server" valueName="cups server"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7CC90037_633A_5C8D_99C5_380E6B2E1EF0)" explainText="$(string.POL_7CC90037_633A_5C8D_99C5_380E6B2E1EF0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7CC90037_633A_5C8D_99C5_380E6B2E1EF0" presentation="$(presentation.POL_7801A389_C366_5376_9D03_631BD51C46C4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_6477B02C_3AE4_5724_B00B_0A11F16A1ECD" key="Software\Policies\Samba\smb_conf\deleteprinter command" valueName="deleteprinter command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_60B548F0_E8B3_576F_B520_D4954AF3ED8E)" explainText="$(string.POL_60B548F0_E8B3_576F_B520_D4954AF3ED8E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_60B548F0_E8B3_576F_B520_D4954AF3ED8E" presentation="$(presentation.POL_8AEEC70D_CC12_55A5_A39F_ED0C3A3B652E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_BA883BE5_77CE_5478_BBC8_10B796EF09C2" key="Software\Policies\Samba\smb_conf\disable spoolss" valueName="disable spoolss"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_EAFBD5E6_54EC_5776_A757_5401DE77BBCE)" explainText="$(string.POL_EAFBD5E6_54EC_5776_A757_5401DE77BBCE_Help)" key="Software\Policies\Samba\smb_conf" name="POL_EAFBD5E6_54EC_5776_A757_5401DE77BBCE" presentation="$(presentation.POL_D8A14125_4BEE_575E_B7A2_A6D2809A0CC9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_76C31A1A_3CCA_54F4_A09B_01ED9C31465A" key="Software\Policies\Samba\smb_conf\enable spoolss" valueName="enable spoolss"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_88C2E1AE_E15B_561A_83B3_A7A7610CB3A2)" explainText="$(string.POL_88C2E1AE_E15B_561A_83B3_A7A7610CB3A2_Help)" key="Software\Policies\Samba\smb_conf" name="POL_88C2E1AE_E15B_561A_83B3_A7A7610CB3A2" presentation="$(presentation.POL_E95AFA3E_7680_5281_88E1_BC2B9DE7C60D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_9B7FB891_910F_5AB1_96BC_432F871E50AA" key="Software\Policies\Samba\smb_conf\enumports command" valueName="enumports command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5247D3AE_60E1_526B_B3A0_956818E2EA49)" explainText="$(string.POL_5247D3AE_60E1_526B_B3A0_956818E2EA49_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5247D3AE_60E1_526B_B3A0_956818E2EA49" presentation="$(presentation.POL_D0CE14C7_93FC_54DA_84A8_FB6579A01A95)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_CEDD5E8E_4BCB_515F_B962_7C06E9E4EBE6" key="Software\Policies\Samba\smb_conf\iprint server" valueName="iprint server"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A6ACC104_2480_55A0_A53C_D38DFF7A093B)" explainText="$(string.POL_A6ACC104_2480_55A0_A53C_D38DFF7A093B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A6ACC104_2480_55A0_A53C_D38DFF7A093B" presentation="$(presentation.POL_2AA9A3C9_2D35_5140_AAFD_5A6D4A8B46A9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_01150395_D329_542B_8848_2D352BA599CA" key="Software\Policies\Samba\smb_conf\load printers" valueName="load printers"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5CC89C3B_45B2_5C52_ADE0_79FB968E5EDE)" explainText="$(string.POL_5CC89C3B_45B2_5C52_ADE0_79FB968E5EDE_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5CC89C3B_45B2_5C52_ADE0_79FB968E5EDE" presentation="$(presentation.POL_CB7375CD_3BD9_5AFF_885F_5CD41077D92A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_86697EF6_0F2B_59EA_AC0A_2A6B16860DC2" key="Software\Policies\Samba\smb_conf\lpq cache time" valueName="lpq cache time"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_45819251_B577_5069_AA0C_AD798BFDC903)" explainText="$(string.POL_45819251_B577_5069_AA0C_AD798BFDC903_Help)" key="Software\Policies\Samba\smb_conf" name="POL_45819251_B577_5069_AA0C_AD798BFDC903" presentation="$(presentation.POL_6C573DCA_ADF2_503D_86F1_167FB4B20390)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_60176F30_80AE_5289_8984_1213DB736520" key="Software\Policies\Samba\smb_conf\os2 driver map" valueName="os2 driver map"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_40CAC79E_549A_5AAA_8FD3_DDF6FDC3EF35)" explainText="$(string.POL_40CAC79E_549A_5AAA_8FD3_DDF6FDC3EF35_Help)" key="Software\Policies\Samba\smb_conf" name="POL_40CAC79E_549A_5AAA_8FD3_DDF6FDC3EF35" presentation="$(presentation.POL_4E996FBA_21B1_54D2_AF3E_0290231D9225)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_30FEC2C2_FB9E_59DC_86AC_0952A9904B2F" key="Software\Policies\Samba\smb_conf\printcap cache time" valueName="printcap cache time"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A0530959_BE77_53B1_82AC_B3E11CA6D2D8)" explainText="$(string.POL_A0530959_BE77_53B1_82AC_B3E11CA6D2D8_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A0530959_BE77_53B1_82AC_B3E11CA6D2D8" presentation="$(presentation.POL_9E502331_FC16_56A6_BAA2_8A4F8CD7403E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_8288D727_1C29_5CDF_A162_3F5701E803B2" key="Software\Policies\Samba\smb_conf\printcap name" valueName="printcap name"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_73B2297D_6138_544A_BAF8_A31CC8192C22)" explainText="$(string.POL_73B2297D_6138_544A_BAF8_A31CC8192C22_Help)" key="Software\Policies\Samba\smb_conf" name="POL_73B2297D_6138_544A_BAF8_A31CC8192C22" presentation="$(presentation.POL_63DFC41F_0FA5_52C6_95CC_071B309E09A9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_21859C56_D5DA_5C2E_9215_BA75864C9B4B" key="Software\Policies\Samba\smb_conf\show add printer wizard" valueName="show add printer wizard"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3CD8EF2C_23D9_58C5_A92C_3E1C2E4F3A4A)" explainText="$(string.POL_3CD8EF2C_23D9_58C5_A92C_3E1C2E4F3A4A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3CD8EF2C_23D9_58C5_A92C_3E1C2E4F3A4A" presentation="$(presentation.POL_C105B217_101D_5080_B2F2_28F453585AF3)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C9E18177_8584_5290_8B40_37D46546DDB1" key="Software\Policies\Samba\smb_conf\spoolss: architecture" valueName="spoolss: architecture"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DE5BD97B_EB5B_571A_98EE_814B2C006262)" explainText="$(string.POL_DE5BD97B_EB5B_571A_98EE_814B2C006262_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DE5BD97B_EB5B_571A_98EE_814B2C006262" presentation="$(presentation.POL_B7405490_DE98_5CC9_A096_8B6F690536A5)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_1D4352B8_DB79_5551_A486_7D4D33F8D4D9" key="Software\Policies\Samba\smb_conf\spoolss: os_major" valueName="spoolss: os_major"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5EB4315D_6DDE_50E9_A228_2F5062CB23B9)" explainText="$(string.POL_5EB4315D_6DDE_50E9_A228_2F5062CB23B9_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5EB4315D_6DDE_50E9_A228_2F5062CB23B9" presentation="$(presentation.POL_5049AEF7_B2E3_5F11_BB76_CD05A0F405D1)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_6F51D95E_66DD_50B2_B62F_7665EF471B52" key="Software\Policies\Samba\smb_conf\spoolss: os_minor" valueName="spoolss: os_minor"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_FEE2B5DC_E367_5173_8A6A_43EB82F22680)" explainText="$(string.POL_FEE2B5DC_E367_5173_8A6A_43EB82F22680_Help)" key="Software\Policies\Samba\smb_conf" name="POL_FEE2B5DC_E367_5173_8A6A_43EB82F22680" presentation="$(presentation.POL_52B0D644_BD3A_5C9D_873F_3DF18D2FDB60)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_B21A8651_347B_5648_94FA_37B943B6A547" key="Software\Policies\Samba\smb_conf\spoolss: os_build" valueName="spoolss: os_build"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6E7AC428_65F6_5006_97A7_B985AE445E43)" explainText="$(string.POL_6E7AC428_65F6_5006_97A7_B985AE445E43_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6E7AC428_65F6_5006_97A7_B985AE445E43" presentation="$(presentation.POL_4B72C056_F162_529E_A137_1F557D5FDFCE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_6188EEA1_529A_508D_B9D5_378CAB822D89" key="Software\Policies\Samba\smb_conf\spoolss_client: os_major" valueName="spoolss_client: os_major"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_732E108C_5701_547E_903E_6112EDF3E999)" explainText="$(string.POL_732E108C_5701_547E_903E_6112EDF3E999_Help)" key="Software\Policies\Samba\smb_conf" name="POL_732E108C_5701_547E_903E_6112EDF3E999" presentation="$(presentation.POL_1855B435_5BFA_512B_A805_E30B09CFD23F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_A21AB0C1_D47D_5B8C_8609_171B9D2F4C27" key="Software\Policies\Samba\smb_conf\spoolss_client: os_minor" valueName="spoolss_client: os_minor"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_CBC8563A_7BEB_54F3_8554_74815EF130DF)" explainText="$(string.POL_CBC8563A_7BEB_54F3_8554_74815EF130DF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_CBC8563A_7BEB_54F3_8554_74815EF130DF" presentation="$(presentation.POL_F173249E_078E_531E_A8DC_85931745FBF9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_EC7D7A9D_C0D7_5665_9030_9C85D402BDB1" key="Software\Policies\Samba\smb_conf\spoolss_client: os_build" valueName="spoolss_client: os_build"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A51777A2_FA82_5D61_B7E1_9B223537A750)" explainText="$(string.POL_A51777A2_FA82_5D61_B7E1_9B223537A750_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A51777A2_FA82_5D61_B7E1_9B223537A750" presentation="$(presentation.POL_A3C35AAF_A7F5_5DCD_B328_C7ABD0F2FDFF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_BCC54168_D5A8_5014_903F_D0689B350906" key="Software\Policies\Samba\smb_conf\cldap port" valueName="cldap port"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E2162FCB_2AF4_5BED_8254_84C87787CAA8)" explainText="$(string.POL_E2162FCB_2AF4_5BED_8254_84C87787CAA8_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E2162FCB_2AF4_5BED_8254_84C87787CAA8" presentation="$(presentation.POL_7D6BFF26_946F_5B18_B213_0B9EE147C3C9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_BC8B7A29_65FA_5B55_BC11_A7574ECD0AA8" key="Software\Policies\Samba\smb_conf\client ipc max protocol" valueName="client ipc max protocol"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_86DD41DB_D3AE_5445_8E2D_335E8182ECDF)" explainText="$(string.POL_86DD41DB_D3AE_5445_8E2D_335E8182ECDF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_86DD41DB_D3AE_5445_8E2D_335E8182ECDF" presentation="$(presentation.POL_4D5635CC_F944_5F32_83F0_7730FC9DE680)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_2FAFBF21_5429_5CF1_9152_921CF9CEEC6C" key="Software\Policies\Samba\smb_conf\client ipc min protocol" valueName="client ipc min protocol"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_8E18914D_E4D5_5B9E_8641_02F84DEA8092)" explainText="$(string.POL_8E18914D_E4D5_5B9E_8641_02F84DEA8092_Help)" key="Software\Policies\Samba\smb_conf" name="POL_8E18914D_E4D5_5B9E_8641_02F84DEA8092" presentation="$(presentation.POL_79B1D2DB_C2F7_57FA_8D6F_83D756A43A40)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_6E173477_D6E4_5C47_BC6C_5961404DB0CD" key="Software\Policies\Samba\smb_conf\client max protocol" valueName="client max protocol"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_277C30D1_A2C2_5AB4_8748_A9ECC063AE91)" explainText="$(string.POL_277C30D1_A2C2_5AB4_8748_A9ECC063AE91_Help)" key="Software\Policies\Samba\smb_conf" name="POL_277C30D1_A2C2_5AB4_8748_A9ECC063AE91" presentation="$(presentation.POL_E5D3402E_7A4B_555E_AC54_E5C7AE196EF2)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_30573924_1A09_5202_8DF8_9B24FA69C14E" key="Software\Policies\Samba\smb_conf\client min protocol" valueName="client min protocol"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_89A40B64_721B_55DF_841D_C3481F32C2FF)" explainText="$(string.POL_89A40B64_721B_55DF_841D_C3481F32C2FF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_89A40B64_721B_55DF_841D_C3481F32C2FF" presentation="$(presentation.POL_B86463E0_7A50_5BD1_9CD5_A43C20A5E087)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_5549EDCC_940D_5AEA_8465_B771FEE013BC" key="Software\Policies\Samba\smb_conf\client use spnego" valueName="client use spnego"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_FCF4AF88_1B2D_5A6E_B630_7E88FA13F4EB)" explainText="$(string.POL_FCF4AF88_1B2D_5A6E_B630_7E88FA13F4EB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_FCF4AF88_1B2D_5A6E_B630_7E88FA13F4EB" presentation="$(presentation.POL_F0990CDC_21DF_538D_9282_2749E00AF99E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E8C89EE3_FF60_5216_A5C7_803A3AA8D790" key="Software\Policies\Samba\smb_conf\dcerpc endpoint servers" valueName="dcerpc endpoint servers"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_73CE9581_7CF3_5CD8_ABBD_3DD273E7ED10)" explainText="$(string.POL_73CE9581_7CF3_5CD8_ABBD_3DD273E7ED10_Help)" key="Software\Policies\Samba\smb_conf" name="POL_73CE9581_7CF3_5CD8_ABBD_3DD273E7ED10" presentation="$(presentation.POL_BD3F8921_7AF6_57F8_894A_9C73D40C6202)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_AA0DA4CF_4431_509C_8E2D_27BD0DD5CCAB" key="Software\Policies\Samba\smb_conf\defer sharing violations" valueName="defer sharing violations"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_951C9DAC_2C21_58B0_8B22_D9D2CCEB1755)" explainText="$(string.POL_951C9DAC_2C21_58B0_8B22_D9D2CCEB1755_Help)" key="Software\Policies\Samba\smb_conf" name="POL_951C9DAC_2C21_58B0_8B22_D9D2CCEB1755" presentation="$(presentation.POL_0C775437_E6FD_5657_9A04_AF137F18FACE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_8E6D975D_6C56_56F9_9853_60394A2CEFA7" key="Software\Policies\Samba\smb_conf\dgram port" valueName="dgram port"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_401F735E_7E1F_5EBC_A3E3_9642A9F023DA)" explainText="$(string.POL_401F735E_7E1F_5EBC_A3E3_9642A9F023DA_Help)" key="Software\Policies\Samba\smb_conf" name="POL_401F735E_7E1F_5EBC_A3E3_9642A9F023DA" presentation="$(presentation.POL_614DA2E7_D77F_5434_9C73_137D1D89D086)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_D433FDEC_A984_5B75_AD88_924962077009" key="Software\Policies\Samba\smb_conf\disable netbios" valueName="disable netbios"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6BB5884D_D948_5765_B165_FCB496E3A64A)" explainText="$(string.POL_6BB5884D_D948_5765_B165_FCB496E3A64A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6BB5884D_D948_5765_B165_FCB496E3A64A" presentation="$(presentation.POL_35845C32_CE1D_5395_A07C_142BCFD9744C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_31A76B18_E56F_57E6_BBC1_A5988C8D731C" key="Software\Policies\Samba\smb_conf\enable asu support" valueName="enable asu support"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D389B35D_C2C8_5971_A195_FBD8C0AAC94C)" explainText="$(string.POL_D389B35D_C2C8_5971_A195_FBD8C0AAC94C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D389B35D_C2C8_5971_A195_FBD8C0AAC94C" presentation="$(presentation.POL_000AF517_65A2_5220_B1DD_7187EFC59AAB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3A3CA4FB_B0F0_5D20_AA43_D6CAECA189E1" key="Software\Policies\Samba\smb_conf\eventlog list" valueName="eventlog list"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_04CE2D0D_386E_5CA3_B450_F1BC9FC9CC9B)" explainText="$(string.POL_04CE2D0D_386E_5CA3_B450_F1BC9FC9CC9B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_04CE2D0D_386E_5CA3_B450_F1BC9FC9CC9B" presentation="$(presentation.POL_B4BFA8D2_FF42_5E4A_ADE8_D7829A2CC94A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_21EE7A7A_DF8F_56F7_85FB_6EC5DD083DD6" key="Software\Policies\Samba\smb_conf\large readwrite" valueName="large readwrite"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_63F5048E_6174_5012_8637_738DD79034E5)" explainText="$(string.POL_63F5048E_6174_5012_8637_738DD79034E5_Help)" key="Software\Policies\Samba\smb_conf" name="POL_63F5048E_6174_5012_8637_738DD79034E5" presentation="$(presentation.POL_644A4C74_3ECB_5A01_8E2B_1FA9E74EC778)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_52E0D939_4722_5165_AAFE_A5FD7584E12C" key="Software\Policies\Samba\smb_conf\lsa over netlogon" valueName="lsa over netlogon"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_87E8C778_F6AC_5666_8855_D40F11853504)" explainText="$(string.POL_87E8C778_F6AC_5666_8855_D40F11853504_Help)" key="Software\Policies\Samba\smb_conf" name="POL_87E8C778_F6AC_5666_8855_D40F11853504" presentation="$(presentation.POL_EAE8C258_343E_522B_A09C_69E9FD81B535)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_549D41B9_4692_55A3_B8C0_11D91DBCC133" key="Software\Policies\Samba\smb_conf\max mux" valueName="max mux"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E754670E_4295_5CAC_8817_8C848E31BA0B)" explainText="$(string.POL_E754670E_4295_5CAC_8817_8C848E31BA0B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E754670E_4295_5CAC_8817_8C848E31BA0B" presentation="$(presentation.POL_2BAFBEFD_9CEA_53C2_9E78_04807EA6531F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_F5E2AC7A_E892_5316_81C3_368BC6F5E4C4" key="Software\Policies\Samba\smb_conf\max ttl" valueName="max ttl"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0AAACA11_DE41_5664_A306_F44D752598C5)" explainText="$(string.POL_0AAACA11_DE41_5664_A306_F44D752598C5_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0AAACA11_DE41_5664_A306_F44D752598C5" presentation="$(presentation.POL_7D30022C_3DDE_56D1_8D07_D90741127527)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_8A171231_CF95_5684_B665_9B1F5B046ABD" key="Software\Policies\Samba\smb_conf\max xmit" valueName="max xmit"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_24E58521_FFD2_5ADE_A9C8_4050EE408BC2)" explainText="$(string.POL_24E58521_FFD2_5ADE_A9C8_4050EE408BC2_Help)" key="Software\Policies\Samba\smb_conf" name="POL_24E58521_FFD2_5ADE_A9C8_4050EE408BC2" presentation="$(presentation.POL_02E42B0E_C3F3_5E0B_83C1_6F3ABFEEF251)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_0B40F1AE_EF9C_58E0_9E35_6D119671AAE1" key="Software\Policies\Samba\smb_conf\min receivefile size" valueName="min receivefile size"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_1DDE423B_1CCB_5179_87D3_1FEE7D4CA621)" explainText="$(string.POL_1DDE423B_1CCB_5179_87D3_1FEE7D4CA621_Help)" key="Software\Policies\Samba\smb_conf" name="POL_1DDE423B_1CCB_5179_87D3_1FEE7D4CA621" presentation="$(presentation.POL_9AA4C867_EE0B_5742_94F0_4D2243C2E368)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_7C9CF069_5856_5D63_94DD_AF9530B8D495" key="Software\Policies\Samba\smb_conf\name resolve order" valueName="name resolve order"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B1C3F6FC_E4FB_58A7_9CE4_50090EF8FF17)" explainText="$(string.POL_B1C3F6FC_E4FB_58A7_9CE4_50090EF8FF17_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B1C3F6FC_E4FB_58A7_9CE4_50090EF8FF17" presentation="$(presentation.POL_0EAD5917_3B68_5B59_92E1_69BD263150EA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_F06BA6AF_533A_520F_B2E1_EA508FF26E55" key="Software\Policies\Samba\smb_conf\nbt port" valueName="nbt port"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E2A4C01A_1EFC_5826_9D3A_A4AD065518EF)" explainText="$(string.POL_E2A4C01A_1EFC_5826_9D3A_A4AD065518EF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E2A4C01A_1EFC_5826_9D3A_A4AD065518EF" presentation="$(presentation.POL_3FA711F7_BD87_5CF6_9A5A_77CF771AAFF2)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_DAAC7C86_8FD9_55BF_9125_9C95E2D52AFE" key="Software\Policies\Samba\smb_conf\nt pipe support" valueName="nt pipe support"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C1F0941D_67B4_55EA_A915_6F5E9A945E57)" explainText="$(string.POL_C1F0941D_67B4_55EA_A915_6F5E9A945E57_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C1F0941D_67B4_55EA_A915_6F5E9A945E57" presentation="$(presentation.POL_85D402BD_4D59_5CE0_8EA2_3331CABD23CA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_95DD62AA_03E3_5679_AD11_D5616CD25255" key="Software\Policies\Samba\smb_conf\nt status support" valueName="nt status support"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_CDB6A4B8_D076_5332_9EA2_CC994C8B45C7)" explainText="$(string.POL_CDB6A4B8_D076_5332_9EA2_CC994C8B45C7_Help)" key="Software\Policies\Samba\smb_conf" name="POL_CDB6A4B8_D076_5332_9EA2_CC994C8B45C7" presentation="$(presentation.POL_9045A4F7_5DED_5A70_B01D_D92B419B6634)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_B11F35D5_3196_5D92_9B1D_9C746F9162FA" key="Software\Policies\Samba\smb_conf\read raw" valueName="read raw"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F9AD06B5_1870_5BE4_87A9_08E3821667E4)" explainText="$(string.POL_F9AD06B5_1870_5BE4_87A9_08E3821667E4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F9AD06B5_1870_5BE4_87A9_08E3821667E4" presentation="$(presentation.POL_9926B5F8_3F22_569B_BB6C_06F2CDF21381)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_CCA3E37C_1A5F_5493_BFC6_AD75B7AEF1D7" key="Software\Policies\Samba\smb_conf\rpc big endian" valueName="rpc big endian"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_380E7843_58D7_505E_9092_392FE1FC4BA2)" explainText="$(string.POL_380E7843_58D7_505E_9092_392FE1FC4BA2_Help)" key="Software\Policies\Samba\smb_conf" name="POL_380E7843_58D7_505E_9092_392FE1FC4BA2" presentation="$(presentation.POL_56DBEBB2_3508_5C9E_91B2_3E55EF357FFB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_9489E35C_10BA_57DF_BCA8_E482D719B220" key="Software\Policies\Samba\smb_conf\rpc server port" valueName="rpc server port"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D910FC29_975B_5105_97C8_BD75D68FDC5F)" explainText="$(string.POL_D910FC29_975B_5105_97C8_BD75D68FDC5F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D910FC29_975B_5105_97C8_BD75D68FDC5F" presentation="$(presentation.POL_738E8CDC_C229_5926_8153_E0009CC07424)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B22408B0_8FF5_5F41_BB61_F89CF80FB1C4" key="Software\Policies\Samba\smb_conf\server max protocol" valueName="server max protocol"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_98D56061_466A_5DDE_BFF3_8A194DE5FE2E)" explainText="$(string.POL_98D56061_466A_5DDE_BFF3_8A194DE5FE2E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_98D56061_466A_5DDE_BFF3_8A194DE5FE2E" presentation="$(presentation.POL_00778E7A_F34D_546E_9FA8_3968A937392B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_633970D9_6038_55ED_856F_A39492AE0173" key="Software\Policies\Samba\smb_conf\server min protocol" valueName="server min protocol"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_2A034462_D418_5914_B24C_6535DD368A66)" explainText="$(string.POL_2A034462_D418_5914_B24C_6535DD368A66_Help)" key="Software\Policies\Samba\smb_conf" name="POL_2A034462_D418_5914_B24C_6535DD368A66" presentation="$(presentation.POL_B33A00A2_B848_59D9_9C41_582F886C008A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3C8506A1_3A67_58AF_BB1F_DD3A931A7FBE" key="Software\Policies\Samba\smb_conf\share:fake_fscaps" valueName="share:fake_fscaps"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A3F9ABC7_494B_5007_B5A1_1DA0B9FC345D)" explainText="$(string.POL_A3F9ABC7_494B_5007_B5A1_1DA0B9FC345D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A3F9ABC7_494B_5007_B5A1_1DA0B9FC345D" presentation="$(presentation.POL_0BC6C240_419F_5F72_9A24_DA191CFFE18E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_4FCC3712_A2B7_5C65_933A_621697E78E8F" key="Software\Policies\Samba\smb_conf\smb2 max credits" valueName="smb2 max credits"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_209C2DE8_5843_50FC_9B61_A3F3EBFE95B5)" explainText="$(string.POL_209C2DE8_5843_50FC_9B61_A3F3EBFE95B5_Help)" key="Software\Policies\Samba\smb_conf" name="POL_209C2DE8_5843_50FC_9B61_A3F3EBFE95B5" presentation="$(presentation.POL_908FC006_7CE8_5B56_A049_A3E582C281F3)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_8D17E70E_8AA1_5DEC_86C2_154031314317" key="Software\Policies\Samba\smb_conf\smb2 max read" valueName="smb2 max read"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0696582B_7928_558B_B4DA_9A0C647CFBB8)" explainText="$(string.POL_0696582B_7928_558B_B4DA_9A0C647CFBB8_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0696582B_7928_558B_B4DA_9A0C647CFBB8" presentation="$(presentation.POL_84ED1A25_58B9_5C00_8261_11A7D387EAB9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_0923E7AF_8C15_54FD_A360_41E09D67D24C" key="Software\Policies\Samba\smb_conf\smb2 max trans" valueName="smb2 max trans"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DA17FE47_6637_50D0_9AD1_A95AAA49F717)" explainText="$(string.POL_DA17FE47_6637_50D0_9AD1_A95AAA49F717_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DA17FE47_6637_50D0_9AD1_A95AAA49F717" presentation="$(presentation.POL_A1955D87_2287_524B_9A8C_454C8218F590)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_AC8EA085_B897_5581_8260_25EC8761048F" key="Software\Policies\Samba\smb_conf\smb2 max write" valueName="smb2 max write"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_97C2005C_F45B_5675_B450_75842A4139F0)" explainText="$(string.POL_97C2005C_F45B_5675_B450_75842A4139F0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_97C2005C_F45B_5675_B450_75842A4139F0" presentation="$(presentation.POL_796581A5_F65E_5D31_BB5C_2CC641B8D03C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_07CA0480_16BB_5E14_B1E8_716E293305F7" key="Software\Policies\Samba\smb_conf\smb ports" valueName="smb ports"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5B8B1A0B_AC6B_5E89_8FDE_4CBE538A9CB8)" explainText="$(string.POL_5B8B1A0B_AC6B_5E89_8FDE_4CBE538A9CB8_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5B8B1A0B_AC6B_5E89_8FDE_4CBE538A9CB8" presentation="$(presentation.POL_C141D92D_B912_54D7_88D6_CC3A12A4739D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_7312B2B6_2E91_5D9E_BE33_A1C73675950E" key="Software\Policies\Samba\smb_conf\svcctl list" valueName="svcctl list"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0E701672_524B_56CE_9C43_D9DE631558EA)" explainText="$(string.POL_0E701672_524B_56CE_9C43_D9DE631558EA_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0E701672_524B_56CE_9C43_D9DE631558EA" presentation="$(presentation.POL_747C776B_2150_5FD4_9A47_9832FD35EBC5)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_838A32D7_1BA5_55CB_9FA4_95280DFB26F6" key="Software\Policies\Samba\smb_conf\time server" valueName="time server"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B8322D3C_E4C4_5EAD_AE99_B912C35C56C8)" explainText="$(string.POL_B8322D3C_E4C4_5EAD_AE99_B912C35C56C8_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B8322D3C_E4C4_5EAD_AE99_B912C35C56C8" presentation="$(presentation.POL_69C69BCA_D38B_54E1_817C_E6993FF1AB91)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_2280B94E_EB17_5A5E_80F0_B48BE0CBC2CB" key="Software\Policies\Samba\smb_conf\unicode" valueName="unicode"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4A31BF60_B9E4_5E35_B979_A1C15754CA9A)" explainText="$(string.POL_4A31BF60_B9E4_5E35_B979_A1C15754CA9A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4A31BF60_B9E4_5E35_B979_A1C15754CA9A" presentation="$(presentation.POL_063DDC7C_E490_5F1B_866D_06D25ABAED90)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_E429FAE8_6D3B_5B56_8EFF_B3B7C25B3DE1" key="Software\Policies\Samba\smb_conf\unix extensions" valueName="unix extensions"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_911349A8_68E0_5370_B0C8_1E5D4DD47DA4)" explainText="$(string.POL_911349A8_68E0_5370_B0C8_1E5D4DD47DA4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_911349A8_68E0_5370_B0C8_1E5D4DD47DA4" presentation="$(presentation.POL_CC4C4C4D_0BA2_52C2_A510_1C4F669856F3)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_4FD77295_65FD_5553_AB18_D6CF04394DAB" key="Software\Policies\Samba\smb_conf\write raw" valueName="write raw"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_585034D0_C9E6_568C_AF40_354A01C24E02)" explainText="$(string.POL_585034D0_C9E6_568C_AF40_354A01C24E02_Help)" key="Software\Policies\Samba\smb_conf" name="POL_585034D0_C9E6_568C_AF40_354A01C24E02" presentation="$(presentation.POL_D1D0620C_FFC1_5C7D_9733_4005F5F61A8D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_82B2446C_9CAB_5880_AF33_2803AE49B294" key="Software\Policies\Samba\smb_conf\server multi channel support" valueName="server multi channel support"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4553EC0B_4966_52CE_83C6_948DAC67A281)" explainText="$(string.POL_4553EC0B_4966_52CE_83C6_948DAC67A281_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4553EC0B_4966_52CE_83C6_948DAC67A281" presentation="$(presentation.POL_D0AC80B8_9AFD_5848_B779_1E43C144D7B3)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_B6B60597_42F0_58D3_98BB_DB6B75D07112" key="Software\Policies\Samba\smb_conf\smb2 disable lock sequence checking" valueName="smb2 disable lock sequence checking"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_690A701E_D101_57E5_A180_30E9E54B8B38)" explainText="$(string.POL_690A701E_D101_57E5_A180_30E9E54B8B38_Help)" key="Software\Policies\Samba\smb_conf" name="POL_690A701E_D101_57E5_A180_30E9E54B8B38" presentation="$(presentation.POL_85DD283F_59E2_5E1D_A694_D52FD7C7627A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_B83E6646_94FD_5882_B57A_15B4BA0AABFD" key="Software\Policies\Samba\smb_conf\smb2 disable oplock break retry" valueName="smb2 disable oplock break retry"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7564C5C4_88AA_576B_A9E8_091901A3D6E0)" explainText="$(string.POL_7564C5C4_88AA_576B_A9E8_091901A3D6E0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7564C5C4_88AA_576B_A9E8_091901A3D6E0" presentation="$(presentation.POL_9E9B6ADB_2118_5108_9C2D_9899DDDC59AF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_28520FBC_2959_5800_B0C5_FE205973260B" key="Software\Policies\Samba\smb_conf\rpc server dynamic port range" valueName="rpc server dynamic port range"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_8D3A68BB_46F0_55A8_B53F_A4AA70C39B46)" explainText="$(string.POL_8D3A68BB_46F0_55A8_B53F_A4AA70C39B46_Help)" key="Software\Policies\Samba\smb_conf" name="POL_8D3A68BB_46F0_55A8_B53F_A4AA70C39B46" presentation="$(presentation.POL_9B792D3F_06B3_5683_92D9_45D323276228)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_9EFB50AC_B3B6_51C1_AD40_298F546733DC" key="Software\Policies\Samba\smb_conf\algorithmic rid base" valueName="algorithmic rid base"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4A36DCFC_E9DB_5CD6_A67B_F94F3D95224F)" explainText="$(string.POL_4A36DCFC_E9DB_5CD6_A67B_F94F3D95224F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4A36DCFC_E9DB_5CD6_A67B_F94F3D95224F" presentation="$(presentation.POL_F30A212E_4A35_5E67_8902_5D28B4E37CE7)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_EAA911EE_CB2D_5459_AF50_DC1CA4719686" key="Software\Policies\Samba\smb_conf\allow dcerpc auth level connect" valueName="allow dcerpc auth level connect"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F3A8A539_E774_5498_B8B7_5D295841A159)" explainText="$(string.POL_F3A8A539_E774_5498_B8B7_5D295841A159_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F3A8A539_E774_5498_B8B7_5D295841A159" presentation="$(presentation.POL_2725BCA8_877C_519D_A248_D6EE701DAD53)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_83FBBE91_8F41_5C06_BD1D_9A47A10B07FE" key="Software\Policies\Samba\smb_conf\allow trusted domains" valueName="allow trusted domains"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DF7112E5_5322_5A42_A1AD_45085CB6EC86)" explainText="$(string.POL_DF7112E5_5322_5A42_A1AD_45085CB6EC86_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DF7112E5_5322_5A42_A1AD_45085CB6EC86" presentation="$(presentation.POL_92DB14AD_A920_5D74_BA74_0C51B13AECBF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_D70FDB73_012F_5168_8371_B68B4B2FF60E" key="Software\Policies\Samba\smb_conf\binddns dir" valueName="binddns dir"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_41C0408D_BF8C_5BA3_992E_6D58CF58FF84)" explainText="$(string.POL_41C0408D_BF8C_5BA3_992E_6D58CF58FF84_Help)" key="Software\Policies\Samba\smb_conf" name="POL_41C0408D_BF8C_5BA3_992E_6D58CF58FF84" presentation="$(presentation.POL_C95900AB_E4E2_5313_9EF5_9AC181CD63A7)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_D6E02483_EC02_52E1_AB5A_E65E2C7FD5C8" key="Software\Policies\Samba\smb_conf\check password script" valueName="check password script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_9869726F_8F58_512B_A708_C7360AC9146F)" explainText="$(string.POL_9869726F_8F58_512B_A708_C7360AC9146F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_9869726F_8F58_512B_A708_C7360AC9146F" presentation="$(presentation.POL_0DDAC1B2_5E35_5770_B177_333E21EF2A80)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_28B76952_9A9C_5E2D_89C6_28CA8ABBEFD4" key="Software\Policies\Samba\smb_conf\client ipc signing" valueName="client ipc signing"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_309DB173_58D7_5326_B21D_8DF044225CB9)" explainText="$(string.POL_309DB173_58D7_5326_B21D_8DF044225CB9_Help)" key="Software\Policies\Samba\smb_conf" name="POL_309DB173_58D7_5326_B21D_8DF044225CB9" presentation="$(presentation.POL_045DA01B_9A96_5BB1_A5AD_9EA38ECFC199)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_5203727D_209F_5E8A_AA94_F9DC1BB27027" key="Software\Policies\Samba\smb_conf\client lanman auth" valueName="client lanman auth"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0F39ED01_BB64_5653_839C_CB26A70EC531)" explainText="$(string.POL_0F39ED01_BB64_5653_839C_CB26A70EC531_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0F39ED01_BB64_5653_839C_CB26A70EC531" presentation="$(presentation.POL_B1954186_3F6B_5F1F_B066_9105058C20A6)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_B6DB6C5E_8C6F_5288_B469_0C54B947EA2F" key="Software\Policies\Samba\smb_conf\client NTLMv2 auth" valueName="client NTLMv2 auth"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_94342D11_937E_5F14_BBEA_C9B370F6A523)" explainText="$(string.POL_94342D11_937E_5F14_BBEA_C9B370F6A523_Help)" key="Software\Policies\Samba\smb_conf" name="POL_94342D11_937E_5F14_BBEA_C9B370F6A523" presentation="$(presentation.POL_676B4751_B95E_5720_A513_203DC3A33B5C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_3DCC027B_9C81_5EDE_A64D_D6F956AFE5B8" key="Software\Policies\Samba\smb_conf\client plaintext auth" valueName="client plaintext auth"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DCB591D5_0F63_58EC_A0BB_F5F81064B714)" explainText="$(string.POL_DCB591D5_0F63_58EC_A0BB_F5F81064B714_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DCB591D5_0F63_58EC_A0BB_F5F81064B714" presentation="$(presentation.POL_C3248F39_498F_5B9B_B82D_E99AB08FD0AF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_4A77A711_9230_5D41_A77C_97123E4789B7" key="Software\Policies\Samba\smb_conf\client schannel" valueName="client schannel"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F35419AB_2114_5382_8060_B1AAED24F2A1)" explainText="$(string.POL_F35419AB_2114_5382_8060_B1AAED24F2A1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F35419AB_2114_5382_8060_B1AAED24F2A1" presentation="$(presentation.POL_0A922D59_F39C_57B5_82CE_E08DB4EFC5F9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E3513F2F_1C85_5D8C_8DEE_741059C1F393" key="Software\Policies\Samba\smb_conf\client signing" valueName="client signing"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F761A7A7_2852_560C_B6D7_A50C613C5431)" explainText="$(string.POL_F761A7A7_2852_560C_B6D7_A50C613C5431_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F761A7A7_2852_560C_B6D7_A50C613C5431" presentation="$(presentation.POL_952DF975_FF04_55BD_8C6B_1D0CF167106B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_E5D1CBBE_5B07_5559_8885_E8F6DBA75A18" key="Software\Policies\Samba\smb_conf\client use spnego principal" valueName="client use spnego principal"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_158C42B4_685B_5FDE_BF9D_C42504E8C09C)" explainText="$(string.POL_158C42B4_685B_5FDE_BF9D_C42504E8C09C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_158C42B4_685B_5FDE_BF9D_C42504E8C09C" presentation="$(presentation.POL_D9E8EB33_0AE9_5DA5_BA48_00221DCE75EB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_711A458E_DC58_57EC_B315_0FEF0D2354BF" key="Software\Policies\Samba\smb_conf\debug encryption" valueName="debug encryption"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_8853D1A2_6482_58E1_9748_192D92523750)" explainText="$(string.POL_8853D1A2_6482_58E1_9748_192D92523750_Help)" key="Software\Policies\Samba\smb_conf" name="POL_8853D1A2_6482_58E1_9748_192D92523750" presentation="$(presentation.POL_B7875E95_FF94_5579_956F_6E2CEB41AB91)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_F17E81EB_DEBF_56F4_B372_D6F61F5516E3" key="Software\Policies\Samba\smb_conf\dedicated keytab file" valueName="dedicated keytab file"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3C1941B5_4894_501A_A7FD_F0C6BCE77DA9)" explainText="$(string.POL_3C1941B5_4894_501A_A7FD_F0C6BCE77DA9_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3C1941B5_4894_501A_A7FD_F0C6BCE77DA9" presentation="$(presentation.POL_1EE4C27C_051F_55A6_8385_E55B6776D7E4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_EC390E59_1CA4_5C42_960E_B0EEA3B0C1F4" key="Software\Policies\Samba\smb_conf\encrypt passwords" valueName="encrypt passwords"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_99472FC1_E6CE_5476_9EC3_EB2EF52862AE)" explainText="$(string.POL_99472FC1_E6CE_5476_9EC3_EB2EF52862AE_Help)" key="Software\Policies\Samba\smb_conf" name="POL_99472FC1_E6CE_5476_9EC3_EB2EF52862AE" presentation="$(presentation.POL_59E14991_089B_550D_A563_8FB90A8333FB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_92855060_EFF4_5BCA_B30B_10C364F30E2E" key="Software\Policies\Samba\smb_conf\guest account" valueName="guest account"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_75BBDBCB_46D1_55DE_9A7C_9EEA7DD026BF)" explainText="$(string.POL_75BBDBCB_46D1_55DE_9A7C_9EEA7DD026BF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_75BBDBCB_46D1_55DE_9A7C_9EEA7DD026BF" presentation="$(presentation.POL_772B9223_59BD_57E8_8FA7_17AF0E0EC8EC)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_751BA79F_27EA_55BE_B787_D424CBD47CED" key="Software\Policies\Samba\smb_conf\kerberos encryption types" valueName="kerberos encryption types"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4AE746EE_4A10_55CC_8934_7E4FEF028E4D)" explainText="$(string.POL_4AE746EE_4A10_55CC_8934_7E4FEF028E4D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4AE746EE_4A10_55CC_8934_7E4FEF028E4D" presentation="$(presentation.POL_F11FAFDE_22DF_5BB6_9F63_007597D313BD)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_30977E18_9746_5A78_A6DC_82AC5157781F" key="Software\Policies\Samba\smb_conf\kerberos method" valueName="kerberos method"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C0E75830_A92F_5E76_A2CF_8E864DF58497)" explainText="$(string.POL_C0E75830_A92F_5E76_A2CF_8E864DF58497_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C0E75830_A92F_5E76_A2CF_8E864DF58497" presentation="$(presentation.POL_F37DD404_E28E_50F2_BFF4_90142620EA2F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_3E0E91A2_1877_54F2_AFFE_13F912C4B534" key="Software\Policies\Samba\smb_conf\kpasswd port" valueName="kpasswd port"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_37987863_7B25_5531_81BE_8EB427F3D0E1)" explainText="$(string.POL_37987863_7B25_5531_81BE_8EB427F3D0E1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_37987863_7B25_5531_81BE_8EB427F3D0E1" presentation="$(presentation.POL_E6FCD1B7_7104_5EF9_BAA7_73E15CC49EE2)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_41AD8F69_347F_58D1_9DA4_B9A600C32EAE" key="Software\Policies\Samba\smb_conf\krb5 port" valueName="krb5 port"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_91CB69F0_B95B_565D_B50D_0BC441ED9E34)" explainText="$(string.POL_91CB69F0_B95B_565D_B50D_0BC441ED9E34_Help)" key="Software\Policies\Samba\smb_conf" name="POL_91CB69F0_B95B_565D_B50D_0BC441ED9E34" presentation="$(presentation.POL_F77B9807_0B1E_5EA5_A1CB_62B310FE5034)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_7460D4AE_3934_5090_9E10_BBF60CD5A983" key="Software\Policies\Samba\smb_conf\lanman auth" valueName="lanman auth"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_89CBBE4F_9104_594C_88D1_F9C11246B21F)" explainText="$(string.POL_89CBBE4F_9104_594C_88D1_F9C11246B21F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_89CBBE4F_9104_594C_88D1_F9C11246B21F" presentation="$(presentation.POL_3D0B6848_AEF7_54A0_8FA0_B6EAD987D449)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E576122E_9E34_5B1D_9362_2EF751F22E3F" key="Software\Policies\Samba\smb_conf\log nt token command" valueName="log nt token command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6BE3D165_D5BE_5252_A0A2_31CD0E777478)" explainText="$(string.POL_6BE3D165_D5BE_5252_A0A2_31CD0E777478_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6BE3D165_D5BE_5252_A0A2_31CD0E777478" presentation="$(presentation.POL_32F00B99_2861_5EFE_B961_1F52B4FC0530)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_12B82358_1926_5FEC_B016_946E52DDC7A7" key="Software\Policies\Samba\smb_conf\map to guest" valueName="map to guest"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_56EEE2C2_6458_524A_95A8_C59B86A453E0)" explainText="$(string.POL_56EEE2C2_6458_524A_95A8_C59B86A453E0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_56EEE2C2_6458_524A_95A8_C59B86A453E0" presentation="$(presentation.POL_6D23275C_279D_571C_8835_3DA99356979C)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_4C14ACC2_4652_5801_BF08_1D9E81090E16" key="Software\Policies\Samba\smb_conf\mit kdc command" valueName="mit kdc command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E82BE4E4_3F51_5B03_9809_03101186CE80)" explainText="$(string.POL_E82BE4E4_3F51_5B03_9809_03101186CE80_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E82BE4E4_3F51_5B03_9809_03101186CE80" presentation="$(presentation.POL_3AE05749_32F8_5D7C_BEF0_D0DFB206EA34)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E71B9BA6_F3A9_510D_AE73_34CC2E7AF19F" key="Software\Policies\Samba\smb_conf\ntlm auth" valueName="ntlm auth"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_BEB01EAD_B60E_5832_BDD5_5C8ACE276FD4)" explainText="$(string.POL_BEB01EAD_B60E_5832_BDD5_5C8ACE276FD4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_BEB01EAD_B60E_5832_BDD5_5C8ACE276FD4" presentation="$(presentation.POL_7A4CC1D5_FF89_5D5A_9711_B783227B92CE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_9AB44C0C_849E_55AD_BF88_30862CC83464" key="Software\Policies\Samba\smb_conf\ntp signd socket directory" valueName="ntp signd socket directory"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C04AB7ED_DBC2_50A6_8082_AD0D6CCB758A)" explainText="$(string.POL_C04AB7ED_DBC2_50A6_8082_AD0D6CCB758A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C04AB7ED_DBC2_50A6_8082_AD0D6CCB758A" presentation="$(presentation.POL_1F95F2F6_790E_5946_8F22_F93441D1B91D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_905844C6_A433_5422_9020_A275A062AB6F" key="Software\Policies\Samba\smb_conf\null passwords" valueName="null passwords"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E305251F_7C82_54A6_8F9D_CFBB7934B1DF)" explainText="$(string.POL_E305251F_7C82_54A6_8F9D_CFBB7934B1DF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E305251F_7C82_54A6_8F9D_CFBB7934B1DF" presentation="$(presentation.POL_4B855392_C467_5D42_B793_3EC858462C02)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_FFDDD176_BDAB_58E3_A455_F60861FD2C63" key="Software\Policies\Samba\smb_conf\obey pam restrictions" valueName="obey pam restrictions"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DD8E3C33_F1AE_59CB_B2B6_3358FFBF41AF)" explainText="$(string.POL_DD8E3C33_F1AE_59CB_B2B6_3358FFBF41AF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DD8E3C33_F1AE_59CB_B2B6_3358FFBF41AF" presentation="$(presentation.POL_F388E520_9E19_53AC_9AFA_D6DAAE139BFE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_1D580B43_F65E_5F39_A938_BE0D03A04F2B" key="Software\Policies\Samba\smb_conf\old password allowed period" valueName="old password allowed period"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B65F086B_4235_5646_8C8B_AF4C16B6E4AD)" explainText="$(string.POL_B65F086B_4235_5646_8C8B_AF4C16B6E4AD_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B65F086B_4235_5646_8C8B_AF4C16B6E4AD" presentation="$(presentation.POL_FC62DA5F_6B94_5AD6_B9E6_51A9F5F52E2E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_49F56502_4B93_5C98_A4BB_327120E5F7D8" key="Software\Policies\Samba\smb_conf\pam password change" valueName="pam password change"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_755D3500_5D11_5DF0_82AC_E5E964C7707B)" explainText="$(string.POL_755D3500_5D11_5DF0_82AC_E5E964C7707B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_755D3500_5D11_5DF0_82AC_E5E964C7707B" presentation="$(presentation.POL_6F5A4F7B_B2BC_50D0_84F6_64202749462B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_38925248_C56C_5F67_959E_45860FA3CEDE" key="Software\Policies\Samba\smb_conf\passdb backend" valueName="passdb backend"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_2F42A35D_FAD2_545A_9ACE_84CD88BEBDB4)" explainText="$(string.POL_2F42A35D_FAD2_545A_9ACE_84CD88BEBDB4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_2F42A35D_FAD2_545A_9ACE_84CD88BEBDB4" presentation="$(presentation.POL_F3E8ECEA_80D4_529F_8F7B_97B8847E3101)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_4D782AF0_E6B7_5C3E_AE8F_90D07527724B" key="Software\Policies\Samba\smb_conf\passdb expand explicit" valueName="passdb expand explicit"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_87D22064_A317_506A_8057_62D7EB06E246)" explainText="$(string.POL_87D22064_A317_506A_8057_62D7EB06E246_Help)" key="Software\Policies\Samba\smb_conf" name="POL_87D22064_A317_506A_8057_62D7EB06E246" presentation="$(presentation.POL_EE00148B_DAEA_5039_B087_B342E865E3AE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_9E734663_521F_5654_A01C_E8B5C19A4684" key="Software\Policies\Samba\smb_conf\passwd chat" valueName="passwd chat"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_FB5B5BAF_88EA_547F_B6C1_C26EF698C89B)" explainText="$(string.POL_FB5B5BAF_88EA_547F_B6C1_C26EF698C89B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_FB5B5BAF_88EA_547F_B6C1_C26EF698C89B" presentation="$(presentation.POL_A0D04F58_1760_5152_AE42_748ABA7B15D8)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_6F2AD6B8_489E_512B_A7CC_EDB6FA628D1E" key="Software\Policies\Samba\smb_conf\passwd chat debug" valueName="passwd chat debug"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_885CA09B_77E8_5E63_85E8_108397557B0B)" explainText="$(string.POL_885CA09B_77E8_5E63_85E8_108397557B0B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_885CA09B_77E8_5E63_85E8_108397557B0B" presentation="$(presentation.POL_0F8503B0_2D17_54A4_AECA_C8954FC2F1B3)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_849C03F3_A9CF_5B20_81B9_D4EEE2435447" key="Software\Policies\Samba\smb_conf\passwd chat timeout" valueName="passwd chat timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E710453F_700A_5430_BE8D_5364117F7E85)" explainText="$(string.POL_E710453F_700A_5430_BE8D_5364117F7E85_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E710453F_700A_5430_BE8D_5364117F7E85" presentation="$(presentation.POL_484C71CF_D856_514E_A645_C94805B51752)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_97FDEF1F_BA9C_5995_BB37_93AF59ADB59C" key="Software\Policies\Samba\smb_conf\passwd program" valueName="passwd program"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_77F6400F_03D4_53F9_AB7B_E0464F72E61F)" explainText="$(string.POL_77F6400F_03D4_53F9_AB7B_E0464F72E61F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_77F6400F_03D4_53F9_AB7B_E0464F72E61F" presentation="$(presentation.POL_DE8AED8D_92DF_5DC8_A412_F374508B2DF2)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_DF9C4D42_5129_5D7A_A155_18F2DBB5B2E7" key="Software\Policies\Samba\smb_conf\password hash gpg key ids" valueName="password hash gpg key ids"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5EA8345D_5B61_554F_AAF5_2C069A37DFCA)" explainText="$(string.POL_5EA8345D_5B61_554F_AAF5_2C069A37DFCA_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5EA8345D_5B61_554F_AAF5_2C069A37DFCA" presentation="$(presentation.POL_E57A4D09_C62A_5ACB_BA14_A52FB3A14D54)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_8F89431E_D922_5610_8770_40BD094BA98D" key="Software\Policies\Samba\smb_conf\password hash userPassword schemes" valueName="password hash userPassword schemes"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_1D36B51B_8AB7_593A_95D8_93B12C9F9EFA)" explainText="$(string.POL_1D36B51B_8AB7_593A_95D8_93B12C9F9EFA_Help)" key="Software\Policies\Samba\smb_conf" name="POL_1D36B51B_8AB7_593A_95D8_93B12C9F9EFA" presentation="$(presentation.POL_8DF1C787_4DD3_5769_981D_AD98697D5FAB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_2BD70FBF_B577_55F7_B757_5DE68D1ECB4B" key="Software\Policies\Samba\smb_conf\password server" valueName="password server"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_4605CA34_85F3_51DB_8BCE_C56B51AA39BF)" explainText="$(string.POL_4605CA34_85F3_51DB_8BCE_C56B51AA39BF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_4605CA34_85F3_51DB_8BCE_C56B51AA39BF" presentation="$(presentation.POL_576D7547_5317_5D19_9105_4BFD5714D591)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_799A2EBA_FC4C_53C2_B724_0838399601DF" key="Software\Policies\Samba\smb_conf\preload modules" valueName="preload modules"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_5103CDE2_436D_5FB9_8633_6BB5EBB59406)" explainText="$(string.POL_5103CDE2_436D_5FB9_8633_6BB5EBB59406_Help)" key="Software\Policies\Samba\smb_conf" name="POL_5103CDE2_436D_5FB9_8633_6BB5EBB59406" presentation="$(presentation.POL_0B74AC8D_E102_5E02_9B21_D264A6662698)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_97A88495_3A90_5773_AF8C_5D35B63E672A" key="Software\Policies\Samba\smb_conf\private dir" valueName="private dir"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7DB136EF_7DAD_5A4F_8C40_F3079FCB925F)" explainText="$(string.POL_7DB136EF_7DAD_5A4F_8C40_F3079FCB925F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7DB136EF_7DAD_5A4F_8C40_F3079FCB925F" presentation="$(presentation.POL_84F44316_118C_5460_A9E9_022AE89D6BC7)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_C2793981_4BCD_5CDF_8F7B_7AD01E207D2C" key="Software\Policies\Samba\smb_conf\raw NTLMv2 auth" valueName="raw NTLMv2 auth"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E4D542FC_3D67_5397_9AC3_3868BB017F03)" explainText="$(string.POL_E4D542FC_3D67_5397_9AC3_3868BB017F03_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E4D542FC_3D67_5397_9AC3_3868BB017F03" presentation="$(presentation.POL_81A0C9F8_E865_532F_8FF6_EA55C23E6417)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3697BE5E_8DCE_5701_A121_A7E36F07CE6C" key="Software\Policies\Samba\smb_conf\rename user script" valueName="rename user script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7D42E3F0_DE0E_57E0_8EAF_F56111560EA3)" explainText="$(string.POL_7D42E3F0_DE0E_57E0_8EAF_F56111560EA3_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7D42E3F0_DE0E_57E0_8EAF_F56111560EA3" presentation="$(presentation.POL_61F81501_C5C3_5F3F_8A89_4490F25812D1)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_B5114D77_9A2D_5FB4_8862_313764FA836F" key="Software\Policies\Samba\smb_conf\restrict anonymous" valueName="restrict anonymous"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6745DAC3_A866_5519_83C8_8086C063AAB7)" explainText="$(string.POL_6745DAC3_A866_5519_83C8_8086C063AAB7_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6745DAC3_A866_5519_83C8_8086C063AAB7" presentation="$(presentation.POL_82E70187_3C79_5C38_837A_F6F7660F7D10)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_00392C71_F9D4_5A75_8082_F7806B6B7564" key="Software\Policies\Samba\smb_conf\root directory" valueName="root directory"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_9218F54E_BE22_57C0_BEF2_489F89B7D3BA)" explainText="$(string.POL_9218F54E_BE22_57C0_BEF2_489F89B7D3BA_Help)" key="Software\Policies\Samba\smb_conf" name="POL_9218F54E_BE22_57C0_BEF2_489F89B7D3BA" presentation="$(presentation.POL_487E924D_1F5E_52FA_9DD7_7C893DC03299)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_98D641EC_FAA9_546B_A032_3D7D3D0B28E2" key="Software\Policies\Samba\smb_conf\samba kcc command" valueName="samba kcc command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_86AEEBA8_5181_54A2_A436_FD35443F7C03)" explainText="$(string.POL_86AEEBA8_5181_54A2_A436_FD35443F7C03_Help)" key="Software\Policies\Samba\smb_conf" name="POL_86AEEBA8_5181_54A2_A436_FD35443F7C03" presentation="$(presentation.POL_1D7DD262_FBC1_53B0_8981_D664D2793B98)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_94515E41_3367_514F_978D_FB02F7C7ABD1" key="Software\Policies\Samba\smb_conf\security" valueName="security"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_925F9081_BDD3_5BE8_BB73_89EBE3A0A8F0)" explainText="$(string.POL_925F9081_BDD3_5BE8_BB73_89EBE3A0A8F0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_925F9081_BDD3_5BE8_BB73_89EBE3A0A8F0" presentation="$(presentation.POL_E94725FD_24A2_5499_9793_E27F2E3D82AB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_7688CBD7_E2F8_573B_AA8D_9EF8C47630F8" key="Software\Policies\Samba\smb_conf\server role" valueName="server role"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6B0930DB_3CC7_57DB_8798_A6B6D3AF05B9)" explainText="$(string.POL_6B0930DB_3CC7_57DB_8798_A6B6D3AF05B9_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6B0930DB_3CC7_57DB_8798_A6B6D3AF05B9" presentation="$(presentation.POL_51A99ED6_90F2_5884_904E_FBB01AE99010)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_0DC074F0_E1DE_5232_B834_889409466FB7" key="Software\Policies\Samba\smb_conf\server schannel" valueName="server schannel"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6DC4F5E8_3493_5D3C_8E35_D928C38C2604)" explainText="$(string.POL_6DC4F5E8_3493_5D3C_8E35_D928C38C2604_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6DC4F5E8_3493_5D3C_8E35_D928C38C2604" presentation="$(presentation.POL_5FCA2961_E0AB_5E89_8361_C30A3FBAB1EC)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_90F5A286_21F2_5FE7_97F9_88EF3C9B636C" key="Software\Policies\Samba\smb_conf\server signing" valueName="server signing"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7C0D1957_E0F4_5B60_805D_FBA7399D8737)" explainText="$(string.POL_7C0D1957_E0F4_5B60_805D_FBA7399D8737_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7C0D1957_E0F4_5B60_805D_FBA7399D8737" presentation="$(presentation.POL_619FBE76_46C6_5CD4_8FAB_F6031B681197)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_A5857127_9668_5119_9FB1_28989C19BE29" key="Software\Policies\Samba\smb_conf\smb passwd file" valueName="smb passwd file"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_94D60BE2_185E_5EC1_8E58_146C4B17C1E7)" explainText="$(string.POL_94D60BE2_185E_5EC1_8E58_146C4B17C1E7_Help)" key="Software\Policies\Samba\smb_conf" name="POL_94D60BE2_185E_5EC1_8E58_146C4B17C1E7" presentation="$(presentation.POL_F01FFF92_4BCB_5309_8B5C_3910D8E2EE4D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_18E2AB7A_7B3D_5588_8E22_91549B53719E" key="Software\Policies\Samba\smb_conf\tls cafile" valueName="tls cafile"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A9FA5D2E_2052_5A81_812D_83A2952DF38B)" explainText="$(string.POL_A9FA5D2E_2052_5A81_812D_83A2952DF38B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A9FA5D2E_2052_5A81_812D_83A2952DF38B" presentation="$(presentation.POL_2D715716_887A_5F22_B8BF_F4D8239F9576)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_24A9FF35_91AF_50B7_9C8B_DCB8815A3B19" key="Software\Policies\Samba\smb_conf\tls certfile" valueName="tls certfile"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C3E30BBB_123E_55E6_9693_7FF6CCF7488D)" explainText="$(string.POL_C3E30BBB_123E_55E6_9693_7FF6CCF7488D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C3E30BBB_123E_55E6_9693_7FF6CCF7488D" presentation="$(presentation.POL_823C796B_2B4A_5733_B90D_9179CA58C03D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3B707725_83FA_511D_BBC2_69122D141655" key="Software\Policies\Samba\smb_conf\tls crlfile" valueName="tls crlfile"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_ABFC90A0_6AA2_5372_85E6_FCD989E458EE)" explainText="$(string.POL_ABFC90A0_6AA2_5372_85E6_FCD989E458EE_Help)" key="Software\Policies\Samba\smb_conf" name="POL_ABFC90A0_6AA2_5372_85E6_FCD989E458EE" presentation="$(presentation.POL_EE10300D_C58D_5AF3_819F_6707ACE727E9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_EB8D2F6A_9929_5004_BD04_03EB0F381453" key="Software\Policies\Samba\smb_conf\tls dh params file" valueName="tls dh params file"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0F91E806_ADD5_59A1_B4FA_E99A51FED659)" explainText="$(string.POL_0F91E806_ADD5_59A1_B4FA_E99A51FED659_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0F91E806_ADD5_59A1_B4FA_E99A51FED659" presentation="$(presentation.POL_D1A081CF_40D1_5505_9E0F_1DF2B67DC69F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_FBD1856B_6C06_5CF4_9A53_DDF372A2250F" key="Software\Policies\Samba\smb_conf\tls enabled" valueName="tls enabled"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D245CE57_C525_5967_A452_F28BFDB9509B)" explainText="$(string.POL_D245CE57_C525_5967_A452_F28BFDB9509B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D245CE57_C525_5967_A452_F28BFDB9509B" presentation="$(presentation.POL_686F2495_B4CA_5D83_95E3_BF372A1857A3)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_45D2AB07_CCD6_5350_A04D_DB915B7B79A3" key="Software\Policies\Samba\smb_conf\tls keyfile" valueName="tls keyfile"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6DB833DB_F8B8_5A20_8E2A_6B7D8E298B9D)" explainText="$(string.POL_6DB833DB_F8B8_5A20_8E2A_6B7D8E298B9D_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6DB833DB_F8B8_5A20_8E2A_6B7D8E298B9D" presentation="$(presentation.POL_869E3C32_6369_5FB5_B149_F982FB872384)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_09331402_B0D6_59B2_8C69_2758849398CE" key="Software\Policies\Samba\smb_conf\tls verify peer" valueName="tls verify peer"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_82913C09_64C3_59C3_8303_3A815661F70E)" explainText="$(string.POL_82913C09_64C3_59C3_8303_3A815661F70E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_82913C09_64C3_59C3_8303_3A815661F70E" presentation="$(presentation.POL_6B1AC895_029E_5686_B072_4BD0BD8B7C4D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_1E20CD87_5BB4_5449_9E0C_BFFBE014C934" key="Software\Policies\Samba\smb_conf\unix password sync" valueName="unix password sync"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_37EE4890_B571_50D5_B6D7_3462FF89BCE1)" explainText="$(string.POL_37EE4890_B571_50D5_B6D7_3462FF89BCE1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_37EE4890_B571_50D5_B6D7_3462FF89BCE1" presentation="$(presentation.POL_821FE87C_398B_5051_A106_BB4C41475FA2)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_55E19EF4_DFB4_5F5F_8DF5_D88E4874D090" key="Software\Policies\Samba\smb_conf\username level" valueName="username level"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_086EBC7E_1D72_5C67_9447_F5F6E36EFA8F)" explainText="$(string.POL_086EBC7E_1D72_5C67_9447_F5F6E36EFA8F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_086EBC7E_1D72_5C67_9447_F5F6E36EFA8F" presentation="$(presentation.POL_4A737F54_FE8F_5996_AE22_5AD683E96F64)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_F413607F_E22F_5652_B367_376C260376CF" key="Software\Policies\Samba\smb_conf\username map" valueName="username map"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0FE7956E_5744_5658_A2ED_8433C45918D7)" explainText="$(string.POL_0FE7956E_5744_5658_A2ED_8433C45918D7_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0FE7956E_5744_5658_A2ED_8433C45918D7" presentation="$(presentation.POL_B01C544C_C17F_58BE_A8C5_B8B93A5D6D6B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_54B979EE_6AB6_5CFA_9EE0_CAF728D8EC17" key="Software\Policies\Samba\smb_conf\username map cache time" valueName="username map cache time"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7C2B49D9_45DE_5D97_B844_9F509F86D211)" explainText="$(string.POL_7C2B49D9_45DE_5D97_B844_9F509F86D211_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7C2B49D9_45DE_5D97_B844_9F509F86D211" presentation="$(presentation.POL_D6C75311_EF00_56FB_BB7E_2AED9360F004)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C8B62E8A_0311_5EC2_A8CF_70B60E1BD044" key="Software\Policies\Samba\smb_conf\username map script" valueName="username map script"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_22AAB8AC_4E62_5B51_BC38_C9340E8AC56E)" explainText="$(string.POL_22AAB8AC_4E62_5B51_BC38_C9340E8AC56E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_22AAB8AC_4E62_5B51_BC38_C9340E8AC56E" presentation="$(presentation.POL_D915E5DA_6227_5AF7_84CC_C5FF9079D441)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_55A11C3A_195F_55F9_852D_0D62FD18327B" key="Software\Policies\Samba\smb_conf\tls priority" valueName="tls priority"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_08DDB9FE_1D88_5264_BEB0_6D60420CE12B)" explainText="$(string.POL_08DDB9FE_1D88_5264_BEB0_6D60420CE12B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_08DDB9FE_1D88_5264_BEB0_6D60420CE12B" presentation="$(presentation.POL_5413F647_D5E0_5620_B00D_101274974D25)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_8BBF5B06_26CE_5BCE_B851_7B1D4E5BA791" key="Software\Policies\Samba\smb_conf\aio max threads" valueName="aio max threads"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0F98F240_9B2D_5788_AC7C_7B2ECDAE60A2)" explainText="$(string.POL_0F98F240_9B2D_5788_AC7C_7B2ECDAE60A2_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0F98F240_9B2D_5788_AC7C_7B2ECDAE60A2" presentation="$(presentation.POL_B9BCD3D7_045F_57C2_9347_4258B5841D4B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_1C7D2B97_728C_587E_880B_EDEF41300FAB" key="Software\Policies\Samba\smb_conf\deadtime" valueName="deadtime"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_BAC6D3CB_A32D_5702_93FD_289B714016C3)" explainText="$(string.POL_BAC6D3CB_A32D_5702_93FD_289B714016C3_Help)" key="Software\Policies\Samba\smb_conf" name="POL_BAC6D3CB_A32D_5702_93FD_289B714016C3" presentation="$(presentation.POL_29E85EE4_9F4B_5824_AAD0_B71BC3AD529A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_18CC19EE_D0BD_5776_9816_F100799183AB" key="Software\Policies\Samba\smb_conf\getwd cache" valueName="getwd cache"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0FB07FB9_33B4_5ECF_9725_9B7A38F863AF)" explainText="$(string.POL_0FB07FB9_33B4_5ECF_9725_9B7A38F863AF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0FB07FB9_33B4_5ECF_9725_9B7A38F863AF" presentation="$(presentation.POL_9FC38F18_A498_5A48_A001_E1C9DF302BAD)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_04B2F1DF_E88E_5792_B491_793217A0C8C8" key="Software\Policies\Samba\smb_conf\hostname lookups" valueName="hostname lookups"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C2D014CF_45D1_5A08_9727_3F2B500A4D58)" explainText="$(string.POL_C2D014CF_45D1_5A08_9727_3F2B500A4D58_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C2D014CF_45D1_5A08_9727_3F2B500A4D58" presentation="$(presentation.POL_A09855DC_589A_515D_B123_3846F60F4908)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_3DAC248C_C8A8_5C1C_8CFB_443894213FC9" key="Software\Policies\Samba\smb_conf\keepalive" valueName="keepalive"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_AF4738EE_230C_5D39_A4CE_F270B28FE9AB)" explainText="$(string.POL_AF4738EE_230C_5D39_A4CE_F270B28FE9AB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_AF4738EE_230C_5D39_A4CE_F270B28FE9AB" presentation="$(presentation.POL_8C101F96_8BD1_5E91_ACA0_813AA7EB6F03)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_4DAE2123_2535_5E0D_BCD1_D5D819A750B9" key="Software\Policies\Samba\smb_conf\max disk size" valueName="max disk size"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_21C3BE22_42E5_544F_97AB_732B2163839B)" explainText="$(string.POL_21C3BE22_42E5_544F_97AB_732B2163839B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_21C3BE22_42E5_544F_97AB_732B2163839B" presentation="$(presentation.POL_571D0589_CE6E_50D9_A04F_4070993911D4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_E36137FA_C613_5FBE_B6FE_1A0554C4130E" key="Software\Policies\Samba\smb_conf\max open files" valueName="max open files"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_67BA8388_A439_54EA_8A1B_B6D2CCD8BB9B)" explainText="$(string.POL_67BA8388_A439_54EA_8A1B_B6D2CCD8BB9B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_67BA8388_A439_54EA_8A1B_B6D2CCD8BB9B" presentation="$(presentation.POL_4B0BF94D_F644_5874_9963_FB1DB672DFCF)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_3DC584F7_71D3_5762_BB59_FB55D524AF1D" key="Software\Policies\Samba\smb_conf\max smbd processes" valueName="max smbd processes"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7CB978B4_3314_5AE7_9821_574DC024294B)" explainText="$(string.POL_7CB978B4_3314_5AE7_9821_574DC024294B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7CB978B4_3314_5AE7_9821_574DC024294B" presentation="$(presentation.POL_CCB2A269_DED1_5A89_B0EA_AC8B9A248E01)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_23802D96_34E6_5E30_BB47_2839CFF09E5E" key="Software\Policies\Samba\smb_conf\name cache timeout" valueName="name cache timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_93A78BFD_8C1E_5643_8329_A90FF5CE5A6B)" explainText="$(string.POL_93A78BFD_8C1E_5643_8329_A90FF5CE5A6B_Help)" key="Software\Policies\Samba\smb_conf" name="POL_93A78BFD_8C1E_5643_8329_A90FF5CE5A6B" presentation="$(presentation.POL_D0EACF0A_A7EC_5114_84E9_A119EAB06054)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_9F944C4E_3CCB_5C34_AC11_84D5E8AE9675" key="Software\Policies\Samba\smb_conf\socket options" valueName="socket options"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3FD02174_8A27_5426_848C_B3123EA8C4C3)" explainText="$(string.POL_3FD02174_8A27_5426_848C_B3123EA8C4C3_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3FD02174_8A27_5426_848C_B3123EA8C4C3" presentation="$(presentation.POL_0BEE9D62_728C_5BEC_B208_C6413ACB23CA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_AE0F9277_9994_5245_9AF5_2FE2694EADB3" key="Software\Policies\Samba\smb_conf\use mmap" valueName="use mmap"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_77FC1090_5D4B_587E_BD3B_DAE9F7A9682F)" explainText="$(string.POL_77FC1090_5D4B_587E_BD3B_DAE9F7A9682F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_77FC1090_5D4B_587E_BD3B_DAE9F7A9682F" presentation="$(presentation.POL_F0BBD72A_2F52_5518_978A_E4DE80EA63A7)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_1299FC9B_B974_5807_B85B_96EF03DF6E7E" key="Software\Policies\Samba\smb_conf\get quota command" valueName="get quota command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B093DF52_6C77_5327_AC90_AAC6AF6CB126)" explainText="$(string.POL_B093DF52_6C77_5327_AC90_AAC6AF6CB126_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B093DF52_6C77_5327_AC90_AAC6AF6CB126" presentation="$(presentation.POL_1B9A680B_C7D9_5909_A73A_4A88884B1A1A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_D8B6A576_57BD_5C1B_8503_D7514BF9A79A" key="Software\Policies\Samba\smb_conf\host msdfs" valueName="host msdfs"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6B9A8C91_49AF_58C8_931C_0304B60491D2)" explainText="$(string.POL_6B9A8C91_49AF_58C8_931C_0304B60491D2_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6B9A8C91_49AF_58C8_931C_0304B60491D2" presentation="$(presentation.POL_23841534_EA5C_5066_9A34_A81201DFA255)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_CB4EB282_B71E_5E88_AAD0_CBE322ED1354" key="Software\Policies\Samba\smb_conf\set quota command" valueName="set quota command"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6A683A86_8075_55FF_B1E6_D7874A3539AA)" explainText="$(string.POL_6A683A86_8075_55FF_B1E6_D7874A3539AA_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6A683A86_8075_55FF_B1E6_D7874A3539AA" presentation="$(presentation.POL_A8D8A049_7017_5627_B698_79DB288ACF3D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_E3F6F2BF_E5EF_5ECD_B4EF_525C704252CE" key="Software\Policies\Samba\smb_conf\apply group policies" valueName="apply group policies"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_0471CC71_51D5_58F6_A00A_6E8B283C3AF5)" explainText="$(string.POL_0471CC71_51D5_58F6_A00A_6E8B283C3AF5_Help)" key="Software\Policies\Samba\smb_conf" name="POL_0471CC71_51D5_58F6_A00A_6E8B283C3AF5" presentation="$(presentation.POL_322C552E_7DC6_57F9_845A_F76107A65059)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_4D19E247_9D41_57FC_A81B_7AAA3DA70D22" key="Software\Policies\Samba\smb_conf\create krb5 conf" valueName="create krb5 conf"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_46FF92BD_F484_5B2C_A639_ACBE73F15F3A)" explainText="$(string.POL_46FF92BD_F484_5B2C_A639_ACBE73F15F3A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_46FF92BD_F484_5B2C_A639_ACBE73F15F3A" presentation="$(presentation.POL_D65A78B4_B284_51E5_86B8_548907E5B99E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_E8A538AD_C502_5298_A571_D37AF30908B1" key="Software\Policies\Samba\smb_conf\idmap backend" valueName="idmap backend"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_309434B4_68BA_53E0_BDF9_CA589711EA29)" explainText="$(string.POL_309434B4_68BA_53E0_BDF9_CA589711EA29_Help)" key="Software\Policies\Samba\smb_conf" name="POL_309434B4_68BA_53E0_BDF9_CA589711EA29" presentation="$(presentation.POL_D9437864_AD98_5DE6_A280_76BF74DF6241)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_9707658F_1F28_5859_A19A_74FA303C63FD" key="Software\Policies\Samba\smb_conf\idmap cache time" valueName="idmap cache time"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_066B06D4_3BC0_5CFA_80A9_D2B1C046B5B0)" explainText="$(string.POL_066B06D4_3BC0_5CFA_80A9_D2B1C046B5B0_Help)" key="Software\Policies\Samba\smb_conf" name="POL_066B06D4_3BC0_5CFA_80A9_D2B1C046B5B0" presentation="$(presentation.POL_DADA8FE7_2FB0_5AFE_AE6F_5CDE2F6C835A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_8E0B0FA4_3946_55DD_9AD6_B31C5AC79265" key="Software\Policies\Samba\smb_conf\idmap gid" valueName="idmap gid"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_9B5D009F_1EBE_5E94_A46B_8644157A6061)" explainText="$(string.POL_9B5D009F_1EBE_5E94_A46B_8644157A6061_Help)" key="Software\Policies\Samba\smb_conf" name="POL_9B5D009F_1EBE_5E94_A46B_8644157A6061" presentation="$(presentation.POL_595CE1B7_F379_543C_99B1_DDF5DCBB2034)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_DB0243EE_0466_539F_8844_6C0FFDEC6AA3" key="Software\Policies\Samba\smb_conf\idmap negative cache time" valueName="idmap negative cache time"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_37D1856A_CAF9_5395_AC8E_8E0F3E9C03E4)" explainText="$(string.POL_37D1856A_CAF9_5395_AC8E_8E0F3E9C03E4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_37D1856A_CAF9_5395_AC8E_8E0F3E9C03E4" presentation="$(presentation.POL_1493AE04_9E17_51E3_BF56_61A594C41065)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_5BC5E3D4_DCD5_5F0A_92C3_74C651DE0CEA" key="Software\Policies\Samba\smb_conf\idmap uid" valueName="idmap uid"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_283F0A5F_5841_5D1D_8EE3_D2715805A463)" explainText="$(string.POL_283F0A5F_5841_5D1D_8EE3_D2715805A463_Help)" key="Software\Policies\Samba\smb_conf" name="POL_283F0A5F_5841_5D1D_8EE3_D2715805A463" presentation="$(presentation.POL_BFD4E3E9_B3CF_5703_95C9_D5AF443628EC)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_09A137C2_9429_5D4A_A327_A5F475E367AE" key="Software\Policies\Samba\smb_conf\include system krb5 conf" valueName="include system krb5 conf"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_61C9E6AE_96EF_5E8D_9AB8_7598584D391E)" explainText="$(string.POL_61C9E6AE_96EF_5E8D_9AB8_7598584D391E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_61C9E6AE_96EF_5E8D_9AB8_7598584D391E" presentation="$(presentation.POL_B2DF30E2_2C79_5DB4_BDD4_2A72F3AAE4D1)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_5CF9E5FF_8158_5689_9FD3_E408D710EC13" key="Software\Policies\Samba\smb_conf\neutralize nt4 emulation" valueName="neutralize nt4 emulation"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D8459DE9_6E91_58A6_8E4E_83BFBB41AE4E)" explainText="$(string.POL_D8459DE9_6E91_58A6_8E4E_83BFBB41AE4E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D8459DE9_6E91_58A6_8E4E_83BFBB41AE4E" presentation="$(presentation.POL_D5D3240F_0956_5A05_8847_1B20DF57BEC8)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_25E7D915_B85C_5F5B_9A60_056A326ED8F5" key="Software\Policies\Samba\smb_conf\reject md5 servers" valueName="reject md5 servers"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_E3A88031_AF89_5D12_9F48_5BD36B25F58C)" explainText="$(string.POL_E3A88031_AF89_5D12_9F48_5BD36B25F58C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_E3A88031_AF89_5D12_9F48_5BD36B25F58C" presentation="$(presentation.POL_5D72D99B_EFA5_5B2F_8616_2FBE8DBBCF81)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_C103A13B_7017_50F6_A337_C2A90DAE4419" key="Software\Policies\Samba\smb_conf\require strong key" valueName="require strong key"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D55FF104_CF84_512D_9962_D01784923C49)" explainText="$(string.POL_D55FF104_CF84_512D_9962_D01784923C49_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D55FF104_CF84_512D_9962_D01784923C49" presentation="$(presentation.POL_A7D4A2B5_A2CB_5BE6_A7D2_111FFC0BB9C5)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_A6A67F77_1744_5905_9C6F_A3468BBFC424" key="Software\Policies\Samba\smb_conf\template homedir" valueName="template homedir"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A317595E_2C79_5B73_9043_CEB7525F6692)" explainText="$(string.POL_A317595E_2C79_5B73_9043_CEB7525F6692_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A317595E_2C79_5B73_9043_CEB7525F6692" presentation="$(presentation.POL_D7A44478_576C_554E_B31A_5316A836F68E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_73F5972B_1879_58A0_9815_A627E1F6D5BC" key="Software\Policies\Samba\smb_conf\template shell" valueName="template shell"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F8F9B8BF_2D26_5079_928E_7168BBCA91BE)" explainText="$(string.POL_F8F9B8BF_2D26_5079_928E_7168BBCA91BE_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F8F9B8BF_2D26_5079_928E_7168BBCA91BE" presentation="$(presentation.POL_EE40BE14_5D1D_5ED4_845C_E7E51C529C2B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_22E52F9D_8E44_59CE_ACC2_916D022CDFA6" key="Software\Policies\Samba\smb_conf\winbind cache time" valueName="winbind cache time"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_07E24EA1_B340_5215_BDBB_5248537F9540)" explainText="$(string.POL_07E24EA1_B340_5215_BDBB_5248537F9540_Help)" key="Software\Policies\Samba\smb_conf" name="POL_07E24EA1_B340_5215_BDBB_5248537F9540" presentation="$(presentation.POL_76E2E87A_908A_5F9A_AA09_FF096575D9A7)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C06A3052_6AD2_53D9_BD21_2A738D8BB155" key="Software\Policies\Samba\smb_conf\winbindd socket directory" valueName="winbindd socket directory"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_8FEAD8B9_8097_5BA2_BD78_7BB0AA8691C1)" explainText="$(string.POL_8FEAD8B9_8097_5BA2_BD78_7BB0AA8691C1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_8FEAD8B9_8097_5BA2_BD78_7BB0AA8691C1" presentation="$(presentation.POL_91508E50_D468_5787_B9AD_BD8160522742)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_F53BC663_D7A1_5D33_8C57_9EC32E71DC68" key="Software\Policies\Samba\smb_conf\winbind enum groups" valueName="winbind enum groups"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_FAB1BAAD_85CD_5FE6_B0AA_AC48B77ACCCC)" explainText="$(string.POL_FAB1BAAD_85CD_5FE6_B0AA_AC48B77ACCCC_Help)" key="Software\Policies\Samba\smb_conf" name="POL_FAB1BAAD_85CD_5FE6_B0AA_AC48B77ACCCC" presentation="$(presentation.POL_F4AED7E2_E1E5_50C5_BBCA_C543EB5E383E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_08E1CF79_DDA7_588B_B86D_590B4967C1C0" key="Software\Policies\Samba\smb_conf\winbind enum users" valueName="winbind enum users"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_2B331ECE_5A4A_5DE9_8DBF_EFBCE108F070)" explainText="$(string.POL_2B331ECE_5A4A_5DE9_8DBF_EFBCE108F070_Help)" key="Software\Policies\Samba\smb_conf" name="POL_2B331ECE_5A4A_5DE9_8DBF_EFBCE108F070" presentation="$(presentation.POL_FE94B125_13A6_5560_A963_34F8F6C8F4D6)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_B28BA151_1969_59E2_B275_C81CA16B5A23" key="Software\Policies\Samba\smb_conf\winbind expand groups" valueName="winbind expand groups"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7F3A4DCD_923C_5586_AFFB_1BA559F399CB)" explainText="$(string.POL_7F3A4DCD_923C_5586_AFFB_1BA559F399CB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7F3A4DCD_923C_5586_AFFB_1BA559F399CB" presentation="$(presentation.POL_7548D0E2_C166_5A7A_9701_063C15E4172D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_3C8A3138_1C1C_5FFF_A3F7_513DEA315389" key="Software\Policies\Samba\smb_conf\winbind:ignore domains" valueName="winbind:ignore domains"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_FE5A1763_2311_55A2_AB2E_10D92C3A7FC4)" explainText="$(string.POL_FE5A1763_2311_55A2_AB2E_10D92C3A7FC4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_FE5A1763_2311_55A2_AB2E_10D92C3A7FC4" presentation="$(presentation.POL_DD3D412F_8AD9_54B9_8D5A_A0501DF3AB07)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_C2980001_BA2C_57BA_8C1B_F973C067028B" key="Software\Policies\Samba\smb_conf\winbind max clients" valueName="winbind max clients"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_57855ED8_E596_52E6_A8F8_B710E76BD0F6)" explainText="$(string.POL_57855ED8_E596_52E6_A8F8_B710E76BD0F6_Help)" key="Software\Policies\Samba\smb_conf" name="POL_57855ED8_E596_52E6_A8F8_B710E76BD0F6" presentation="$(presentation.POL_BE09D431_FA6A_5383_994E_1AEA3E9EEC4A)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_6F41A5F1_F003_54F4_88AF_9CC14C5B64F0" key="Software\Policies\Samba\smb_conf\winbind max domain connections" valueName="winbind max domain connections"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6C096F2D_4DB1_5E05_84BB_9E9E3E0708BB)" explainText="$(string.POL_6C096F2D_4DB1_5E05_84BB_9E9E3E0708BB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6C096F2D_4DB1_5E05_84BB_9E9E3E0708BB" presentation="$(presentation.POL_2ABFD1ED_23F7_5C67_8ECD_3F7EE2752B7D)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_EE309E41_F404_5CE1_AC86_5E795D0C979A" key="Software\Policies\Samba\smb_conf\winbind nested groups" valueName="winbind nested groups"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7C9859FE_6BA0_526D_A308_9454D3063550)" explainText="$(string.POL_7C9859FE_6BA0_526D_A308_9454D3063550_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7C9859FE_6BA0_526D_A308_9454D3063550" presentation="$(presentation.POL_4542EFF0_F19C_5215_92F8_0B006803D437)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_E9249CF9_4820_553B_B406_5560E8B3DEFF" key="Software\Policies\Samba\smb_conf\winbind normalize names" valueName="winbind normalize names"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_3D3D280A_1D60_58AA_A7BD_54D13DDBE1A6)" explainText="$(string.POL_3D3D280A_1D60_58AA_A7BD_54D13DDBE1A6_Help)" key="Software\Policies\Samba\smb_conf" name="POL_3D3D280A_1D60_58AA_A7BD_54D13DDBE1A6" presentation="$(presentation.POL_62688BAF_1F03_5CF4_888F_4B88677FF4AC)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B2B0FF5C_C714_52AC_BAFE_846EC003D31E" key="Software\Policies\Samba\smb_conf\winbind nss info" valueName="winbind nss info"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_34B48F10_7723_5E77_A57B_AE606BBB43B7)" explainText="$(string.POL_34B48F10_7723_5E77_A57B_AE606BBB43B7_Help)" key="Software\Policies\Samba\smb_conf" name="POL_34B48F10_7723_5E77_A57B_AE606BBB43B7" presentation="$(presentation.POL_053CBE3D_DD33_522A_9B34_9AFF4044D454)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_5945AB58_D8F0_5BA1_9964_D8E69AF19CBB" key="Software\Policies\Samba\smb_conf\winbind offline logon" valueName="winbind offline logon"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_05A14875_99EE_5000_A1E2_100D2F7B079F)" explainText="$(string.POL_05A14875_99EE_5000_A1E2_100D2F7B079F_Help)" key="Software\Policies\Samba\smb_conf" name="POL_05A14875_99EE_5000_A1E2_100D2F7B079F" presentation="$(presentation.POL_3BF15158_B942_5458_999E_4FEBCA3A2290)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_BEC37822_5BBB_56AE_B122_DFA48B55FF4A" key="Software\Policies\Samba\smb_conf\winbind reconnect delay" valueName="winbind reconnect delay"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_98A94538_AA09_51C8_A96D_ACB0B314F5F4)" explainText="$(string.POL_98A94538_AA09_51C8_A96D_ACB0B314F5F4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_98A94538_AA09_51C8_A96D_ACB0B314F5F4" presentation="$(presentation.POL_46E902CB_4766_50A8_8A8A_86893347E86F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_9DDF19FA_7129_5F46_82E2_FED21BCF9048" key="Software\Policies\Samba\smb_conf\winbind refresh tickets" valueName="winbind refresh tickets"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_96B1E9F8_5418_5EA0_8B87_614B45822D92)" explainText="$(string.POL_96B1E9F8_5418_5EA0_8B87_614B45822D92_Help)" key="Software\Policies\Samba\smb_conf" name="POL_96B1E9F8_5418_5EA0_8B87_614B45822D92" presentation="$(presentation.POL_9F679274_5E36_5B71_BBB3_880590FFB5A4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_542C16F7_4011_5AFF_A127_7A773681E95B" key="Software\Policies\Samba\smb_conf\winbind request timeout" valueName="winbind request timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_FEC015B1_6B0B_5D76_B23D_71363578FAF7)" explainText="$(string.POL_FEC015B1_6B0B_5D76_B23D_71363578FAF7_Help)" key="Software\Policies\Samba\smb_conf" name="POL_FEC015B1_6B0B_5D76_B23D_71363578FAF7" presentation="$(presentation.POL_B5754213_7C07_59E8_BE54_44BD0B64A8ED)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_2EB29672_8B33_566A_AFE5_41BFDBE0F72E" key="Software\Policies\Samba\smb_conf\winbind rpc only" valueName="winbind rpc only"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_412B470E_EC88_556F_B9DE_1952C70E45B1)" explainText="$(string.POL_412B470E_EC88_556F_B9DE_1952C70E45B1_Help)" key="Software\Policies\Samba\smb_conf" name="POL_412B470E_EC88_556F_B9DE_1952C70E45B1" presentation="$(presentation.POL_923523CB_9B7D_5261_93D6_B5FD86FC39E4)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_3CAC88EA_556D_5AA8_8A29_282B574B2743" key="Software\Policies\Samba\smb_conf\winbind scan trusted domains" valueName="winbind scan trusted domains"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_6247DEB4_05CC_51B8_A8CB_1FF7DEDA741C)" explainText="$(string.POL_6247DEB4_05CC_51B8_A8CB_1FF7DEDA741C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_6247DEB4_05CC_51B8_A8CB_1FF7DEDA741C" presentation="$(presentation.POL_FFF6590E_C5E7_5680_9A62_61DC88079555)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_E93252A7_06C7_566B_B7E6_8D4D7AADFB8D" key="Software\Policies\Samba\smb_conf\winbind sealed pipes" valueName="winbind sealed pipes"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_7E1E179F_7E0D_5CB4_BDAA_B8EDF41428CC)" explainText="$(string.POL_7E1E179F_7E0D_5CB4_BDAA_B8EDF41428CC_Help)" key="Software\Policies\Samba\smb_conf" name="POL_7E1E179F_7E0D_5CB4_BDAA_B8EDF41428CC" presentation="$(presentation.POL_A55D34ED_E614_5500_9F7B_A07E0EE1F7BE)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_25CC57B6_941F_525A_99F8_1C041F206D9B" key="Software\Policies\Samba\smb_conf\winbind separator" valueName="winbind separator"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_1780A1A5_0535_5D0B_8105_2129879E3C40)" explainText="$(string.POL_1780A1A5_0535_5D0B_8105_2129879E3C40_Help)" key="Software\Policies\Samba\smb_conf" name="POL_1780A1A5_0535_5D0B_8105_2129879E3C40" presentation="$(presentation.POL_14AE5941_E62F_53FC_95AE_441E7EF43F56)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_BF4DA096_841C_5A0D_A5E3_CD564122C924" key="Software\Policies\Samba\smb_conf\winbind use default domain" valueName="winbind use default domain"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_71A1842A_9526_5BF9_A0FC_07322D2C6C81)" explainText="$(string.POL_71A1842A_9526_5BF9_A0FC_07322D2C6C81_Help)" key="Software\Policies\Samba\smb_conf" name="POL_71A1842A_9526_5BF9_A0FC_07322D2C6C81" presentation="$(presentation.POL_4B5E805D_7C7A_5CCE_AAB2_FBD0B9CC6D2E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_7E9390CD_05D9_570F_A761_7B5A605BA1F9" key="Software\Policies\Samba\smb_conf\winbind use krb5 enterprise principals" valueName="winbind use krb5 enterprise principals"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_B05D0593_B0CE_52A9_977C_E7A897EEA307)" explainText="$(string.POL_B05D0593_B0CE_52A9_977C_E7A897EEA307_Help)" key="Software\Policies\Samba\smb_conf" name="POL_B05D0593_B0CE_52A9_977C_E7A897EEA307" presentation="$(presentation.POL_DBC0E447_01F4_5B72_BA4E_E9248006FD96)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_243E92BD_CBA1_50BC_BD4D_87B750B6FABB" key="Software\Policies\Samba\smb_conf\dns proxy" valueName="dns proxy"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_C1A54865_BE76_5627_B737_BBB708AEC44C)" explainText="$(string.POL_C1A54865_BE76_5627_B737_BBB708AEC44C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_C1A54865_BE76_5627_B737_BBB708AEC44C" presentation="$(presentation.POL_2E4CDFD7_AB3A_5898_B4A1_44EDABBEE713)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_761AB0AD_EED6_5734_BC07_88D6599EF57F" key="Software\Policies\Samba\smb_conf\max wins ttl" valueName="max wins ttl"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_BEE0A696_13BD_578B_B448_1E0A01AB915A)" explainText="$(string.POL_BEE0A696_13BD_578B_B448_1E0A01AB915A_Help)" key="Software\Policies\Samba\smb_conf" name="POL_BEE0A696_13BD_578B_B448_1E0A01AB915A" presentation="$(presentation.POL_584FFB0D_E6B4_51B1_B65D_FBFD4D40C4D9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <decimal id="DXT_153EA1D4_FC29_50AF_878D_5695C6C186CD" key="Software\Policies\Samba\smb_conf\min wins ttl" valueName="min wins ttl"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_890DE0DC_C0FC_565A_A1D3_AD06EFAC41ED)" explainText="$(string.POL_890DE0DC_C0FC_565A_A1D3_AD06EFAC41ED_Help)" key="Software\Policies\Samba\smb_conf" name="POL_890DE0DC_C0FC_565A_A1D3_AD06EFAC41ED" presentation="$(presentation.POL_6D6BFEF8_655A_59B7_B17E_050ADA0FAD0F)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_4B630740_3B6C_5FCF_9B93_46CD46767198" key="Software\Policies\Samba\smb_conf\nbtd:wins_prepend1Bto1Cqueries" valueName="nbtd:wins_prepend1Bto1Cqueries"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_06F0FFB1_F595_57BB_B964_6D419A02F468)" explainText="$(string.POL_06F0FFB1_F595_57BB_B964_6D419A02F468_Help)" key="Software\Policies\Samba\smb_conf" name="POL_06F0FFB1_F595_57BB_B964_6D419A02F468" presentation="$(presentation.POL_F145528D_6177_5DA0_9730_05420DF91116)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_A7D6BC38_6BF1_56CF_85B2_FEEA5DAB1A45" key="Software\Policies\Samba\smb_conf\nbtd:wins_wins_randomize1Clist" valueName="nbtd:wins_wins_randomize1Clist"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F63D2A1E_D6BA_516E_995D_F9FEE05D49DB)" explainText="$(string.POL_F63D2A1E_D6BA_516E_995D_F9FEE05D49DB_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F63D2A1E_D6BA_516E_995D_F9FEE05D49DB" presentation="$(presentation.POL_1D8649CE_6826_507E_A697_A06B2B693295)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_845EC4E4_224C_5FE8_B43E_3F417E26E1F8" key="Software\Policies\Samba\smb_conf\nbtd:wins_randomize1Clist_mask" valueName="nbtd:wins_randomize1Clist_mask"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_D0A83CCC_07AF_553B_84AE_4824377AE692)" explainText="$(string.POL_D0A83CCC_07AF_553B_84AE_4824377AE692_Help)" key="Software\Policies\Samba\smb_conf" name="POL_D0A83CCC_07AF_553B_84AE_4824377AE692" presentation="$(presentation.POL_8A6CF1A8_12F0_5EC4_B588_658C72C10C4B)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_5A9C87F1_E213_5A53_AD54_9B3AFAB13F9C" key="Software\Policies\Samba\smb_conf\winsdb:local_owner" valueName="winsdb:local_owner"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_06442D20_4739_5DE0_820F_516416AD0ECF)" explainText="$(string.POL_06442D20_4739_5DE0_820F_516416AD0ECF_Help)" key="Software\Policies\Samba\smb_conf" name="POL_06442D20_4739_5DE0_820F_516416AD0ECF" presentation="$(presentation.POL_4B068333_B3F0_5408_A84F_05BFDB2AD521)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_DE8267A0_F6DE_5043_AFDA_3D98B6494A6D" key="Software\Policies\Samba\smb_conf\winsdb:dbnosync" valueName="winsdb:dbnosync"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F7271C08_2949_53E0_809D_9B976AB9DE2E)" explainText="$(string.POL_F7271C08_2949_53E0_809D_9B976AB9DE2E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F7271C08_2949_53E0_809D_9B976AB9DE2E" presentation="$(presentation.POL_61D06DDC_5FC1_5A27_9953_0522C71D3C81)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_7AC86D1C_8F55_5202_9960_E3F76BE03021" key="Software\Policies\Samba\smb_conf\wins hook" valueName="wins hook"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_A1E6C0E7_38BA_5583_816D_73C91FCAADB4)" explainText="$(string.POL_A1E6C0E7_38BA_5583_816D_73C91FCAADB4_Help)" key="Software\Policies\Samba\smb_conf" name="POL_A1E6C0E7_38BA_5583_816D_73C91FCAADB4" presentation="$(presentation.POL_DA957F88_D7CE_566D_A902_4CCDEF755586)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_F6AECF98_9DF6_5B4D_8F4C_1A262B314282" key="Software\Policies\Samba\smb_conf\wins proxy" valueName="wins proxy"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_31C40FB1_1B0A_5AA3_80F9_7914AC38FD99)" explainText="$(string.POL_31C40FB1_1B0A_5AA3_80F9_7914AC38FD99_Help)" key="Software\Policies\Samba\smb_conf" name="POL_31C40FB1_1B0A_5AA3_80F9_7914AC38FD99" presentation="$(presentation.POL_8F4113F9_15A6_5E26_9F02_7CA7971BE6C9)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C1395789_AF99_5B0A_89F7_DD274EC794EA" key="Software\Policies\Samba\smb_conf\wins server" valueName="wins server"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_44517D2D_845B_5F7B_90F2_F7BD0DA063A9)" explainText="$(string.POL_44517D2D_845B_5F7B_90F2_F7BD0DA063A9_Help)" key="Software\Policies\Samba\smb_conf" name="POL_44517D2D_845B_5F7B_90F2_F7BD0DA063A9" presentation="$(presentation.POL_0F35BC3D_B809_53E1_9BFD_1765E5E4E934)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <boolean id="CHK_BE0D6F0B_4FEE_5580_AD27_507FBCC53AB5" key="Software\Policies\Samba\smb_conf\wins support" valueName="wins support"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_8A035569_9C85_59DC_9BF8_241994D4E947)" explainText="$(string.POL_8A035569_9C85_59DC_9BF8_241994D4E947_Help)" key="Software\Policies\Samba\smb_conf" name="POL_8A035569_9C85_59DC_9BF8_241994D4E947" presentation="$(presentation.POL_1009764B_DAB3_56F8_A766_B45CFC524A5E)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_A8EC94D1_CDB1_5E5B_A2D7_D4FDDD78655D" key="Software\Policies\Samba\smb_conf\wreplsrv:periodic_interval" valueName="wreplsrv:periodic_interval"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_186864AE_CE31_5628_BA4E_6B9F06F087E5)" explainText="$(string.POL_186864AE_CE31_5628_BA4E_6B9F06F087E5_Help)" key="Software\Policies\Samba\smb_conf" name="POL_186864AE_CE31_5628_BA4E_6B9F06F087E5" presentation="$(presentation.POL_17929B31_DDBB_5B79_AD9D_F0C7EB54BFFA)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C4483400_9388_5705_BB16_A9CD61B3FC01" key="Software\Policies\Samba\smb_conf\wreplsrv:propagate name releases" valueName="wreplsrv:propagate name releases"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_8DC9CC59_A490_5F52_8C69_A9EEC802C48C)" explainText="$(string.POL_8DC9CC59_A490_5F52_8C69_A9EEC802C48C_Help)" key="Software\Policies\Samba\smb_conf" name="POL_8DC9CC59_A490_5F52_8C69_A9EEC802C48C" presentation="$(presentation.POL_E9361CA3_1260_52FE_AD12_742A86788475)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_7E454192_9281_5588_8F18_A4C13837C555" key="Software\Policies\Samba\smb_conf\wreplsrv:scavenging_interval" valueName="wreplsrv:scavenging_interval"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_DB737BF2_9B47_5895_A3F8_D51BBD764222)" explainText="$(string.POL_DB737BF2_9B47_5895_A3F8_D51BBD764222_Help)" key="Software\Policies\Samba\smb_conf" name="POL_DB737BF2_9B47_5895_A3F8_D51BBD764222" presentation="$(presentation.POL_D3F0B860_C5A4_5E2A_983F_90B40B5AEF46)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_C4470E01_F859_5E45_B342_290D5974C4D0" key="Software\Policies\Samba\smb_conf\wreplsrv:tombstone_extra_timeout" valueName="wreplsrv:tombstone_extra_timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_30D1C3B2_BDCD_5A5C_A131_11E1E6DA2A76)" explainText="$(string.POL_30D1C3B2_BDCD_5A5C_A131_11E1E6DA2A76_Help)" key="Software\Policies\Samba\smb_conf" name="POL_30D1C3B2_BDCD_5A5C_A131_11E1E6DA2A76" presentation="$(presentation.POL_0CA9F8A3_6092_57F4_8CCC_114358C3B9EB)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_D81F8827_96DE_500F_B1B8_D6EF10D165FE" key="Software\Policies\Samba\smb_conf\wreplsrv:tombstone_interval" valueName="wreplsrv:tombstone_interval"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_F19C445A_AFD5_51B6_B87A_E42499C3C5D8)" explainText="$(string.POL_F19C445A_AFD5_51B6_B87A_E42499C3C5D8_Help)" key="Software\Policies\Samba\smb_conf" name="POL_F19C445A_AFD5_51B6_B87A_E42499C3C5D8" presentation="$(presentation.POL_B06D59DA_A8FC_53AF_AB8F_9C00812D8832)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_B8A345EA_EAA9_524C_A511_8121FD7A5EA1" key="Software\Policies\Samba\smb_conf\wreplsrv:tombstone_timeout" valueName="wreplsrv:tombstone_timeout"/>
+ </elements>
+ </policy>
+ <policy class="Machine" displayName="$(string.POL_8CF1FEA3_BD3E_53C0_9F73_34050187A91E)" explainText="$(string.POL_8CF1FEA3_BD3E_53C0_9F73_34050187A91E_Help)" key="Software\Policies\Samba\smb_conf" name="POL_8CF1FEA3_BD3E_53C0_9F73_34050187A91E" presentation="$(presentation.POL_3F2ADB29_E0AE_5723_BC18_0B7ABC97BBE7)">
+ <parentCategory ref="CAT_10827749_64ED_5052_87F7_E81AD421856A"/>
+ <supportedOn ref="SUPPORTED_WIN7"/>
+ <elements>
+ <text id="TXT_F35F7924_DBD3_5F6F_B247_7F4893C63844" key="Software\Policies\Samba\smb_conf\wreplsrv:verify_interval" valueName="wreplsrv:verify_interval"/>
+ </elements>
+ </policy>
+ <policy name="POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07" class="Machine" displayName="$(string.POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07)" explainText="$(string.POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07_Help)" presentation="$(presentation.POL_38DA04F0_3FD6_4425_8924_1CEEA685FD07)" key="Software\Policies\Samba\Unix Settings\Messages">
+ <parentCategory ref="CAT_9DEF582D_447A_47E9_A1F5_363558D03FA9" />
+ <supportedOn ref="windows:SUPPORTED_WindowsVista" />
+ <elements>
+ <text id="TXT_609C208A_3B4D_48F1_8A15_C0DF08EAD4D6" key="Software\Policies\Samba\Unix Settings\Messages" valueName="motd" />
+ </elements>
+ </policy>
+ <policy name="POL_68E9155C_CB49_428E_AFE0_B89316FFD948" class="Machine" displayName="$(string.POL_68E9155C_CB49_428E_AFE0_B89316FFD948)" explainText="$(string.POL_68E9155C_CB49_428E_AFE0_B89316FFD948_Help)" presentation="$(presentation.POL_68E9155C_CB49_428E_AFE0_B89316FFD948)" key="Software\Policies\Samba\Unix Settings\Messages">
+ <parentCategory ref="CAT_9DEF582D_447A_47E9_A1F5_363558D03FA9" />
+ <supportedOn ref="windows:SUPPORTED_WindowsVista" />
+ <elements>
+ <text id="TXT_8075D9EA_6E15_4B2A_833A_B918EE90856F" key="Software\Policies\Samba\Unix Settings\Messages" valueName="issue" />
+ </elements>
+ </policy>
+ <policy name="POL_ADABE9E0_FFF9_4FFE_A105_03E646C79978" class="Machine" displayName="$(string.POL_ADABE9E0_FFF9_4FFE_A105_03E646C79978)" explainText="$(string.POL_ADABE9E0_FFF9_4FFE_A105_03E646C79978_Help)" presentation="$(presentation.POL_ADABE9E0_FFF9_4FFE_A105_03E646C79978)" key="Software\Policies\Samba\Unix Settings\Firewalld" valueName="Zones">
+ <parentCategory ref="CAT_371A8FF5_990F_47DD_B200_D436AC28A4F9" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_16" />
+ <elements>
+ <list id="LST_5B9AE80A_6529_4313_A9A1_764DF5320930" key="Software\Policies\Samba\Unix Settings\Firewalld\Zones" />
+ </elements>
+ </policy>
+ <policy name="POL_B21F349F_4BF6_473E_8452_047D714F156C" class="Machine" displayName="$(string.POL_B21F349F_4BF6_473E_8452_047D714F156C)" explainText="$(string.POL_B21F349F_4BF6_473E_8452_047D714F156C_Help)" presentation="$(presentation.POL_B21F349F_4BF6_473E_8452_047D714F156C)" key="Software\Policies\Samba\Unix Settings\Firewalld" valueName="Rules">
+ <parentCategory ref="CAT_371A8FF5_990F_47DD_B200_D436AC28A4F9" />
+ <supportedOn ref="SUPPORTED_SAMBA_4_16" />
+ <elements>
+ <text id="TXT_76109A0B_AA79_4F69_ADFC_2B3CA52763D2" key="Software\Policies\Samba\Unix Settings\Firewalld\Rules" valueName="Rules" />
+ </elements>
+ </policy>
+ </policies>
+</policyDefinitions>
diff --git a/libgpo/admx/wscript_build b/libgpo/admx/wscript_build
new file mode 100644
index 0000000..3d51336
--- /dev/null
+++ b/libgpo/admx/wscript_build
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+bld.INSTALL_FILES('${DATADIR}/samba/admx', ['samba.admx',
+ 'en-US/samba.adml',
+ 'GNOME_Settings.admx',
+ 'en-US/GNOME_Settings.adml',
+ 'ru-RU/GNOME_Settings.adml'
+ ])
diff --git a/libgpo/gpext/gpext.c b/libgpo/gpext/gpext.c
new file mode 100644
index 0000000..45c8970
--- /dev/null
+++ b/libgpo/gpext/gpext.c
@@ -0,0 +1,882 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * Copyright (C) Guenther Deschner 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 "../libgpo/gpo.h"
+#include "../libgpo/gpext/gpext.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "lib/util/dlinklist.h"
+#include "../libcli/registry/util_reg.h"
+#include "libgpo/gpo_proto.h"
+#include "registry.h"
+#include "registry/reg_api.h"
+#include "lib/util/util_paths.h"
+#include "lib/util/string_wrappers.h"
+
+static struct gp_extension *extensions = NULL;
+
+/****************************************************************
+****************************************************************/
+
+struct gp_extension *gpext_get_gp_extension_list(void)
+{
+ return extensions;
+}
+
+/****************************************************************
+****************************************************************/
+
+
+struct gp_extension_reg_table gpext_reg_vals[] = {
+ {
+ .val = "DllName",
+ .type = REG_EXPAND_SZ,
+ },
+ {
+ .val = "ProcessGroupPolicy",
+ .type = REG_SZ,
+ },
+ {
+ .val = "NoMachinePolicy",
+ .type = REG_DWORD,
+ },
+ {
+ .val = "NoUserPolicy",
+ .type = REG_DWORD,
+ },
+ {
+ .val = "NoSlowLink",
+ .type = REG_DWORD,
+ },
+ {
+ .val = "NoBackgroundPolicy",
+ .type = REG_DWORD,
+ },
+ {
+ .val = "NoGPOListChanges",
+ .type = REG_DWORD,
+ },
+ {
+ .val = "PerUserLocalSettings",
+ .type = REG_DWORD,
+ },
+ {
+ .val = "RequiresSuccessfulRegistry",
+ .type = REG_DWORD,
+ },
+ {
+ .val = "EnableAsynchronousProcessing",
+ .type = REG_DWORD,
+ },
+ {
+ .val = "ExtensionDebugLevel",
+ .type = REG_DWORD,
+ },
+ /* new */
+ {
+ .val = "GenerateGroupPolicy", /* not supported on w2k */
+ .type = REG_SZ,
+ },
+ {
+ .val = "NotifyLinkTransition",
+ .type = REG_DWORD,
+ },
+ {
+ .val = "ProcessGroupPolicyEx", /* not supported on w2k */
+ .type = REG_SZ,
+ },
+ {
+ .val = "ExtensionEventSource", /* not supported on w2k */
+ .type = REG_MULTI_SZ,
+ },
+ {
+ .val = "MaxNoGPOListChangesInterval",
+ .type = REG_DWORD,
+ },
+ { .type = REG_NONE }
+};
+
+/****************************************************************
+****************************************************************/
+
+static struct gp_extension *get_extension_by_name(struct gp_extension *be,
+ const char *name)
+{
+ struct gp_extension *b;
+
+ for (b = be; b; b = b->next) {
+ if (strequal(b->name, name)) {
+ return b;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************
+****************************************************************/
+
+static struct gp_extension_methods *get_methods_by_name(struct gp_extension *be,
+ const char *name)
+{
+ struct gp_extension *b;
+
+ for (b = be; b; b = b->next) {
+ if (strequal(b->name, name)) {
+ return b->methods;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_unregister_gp_extension(const char *name)
+{
+ struct gp_extension *ext;
+
+ ext = get_extension_by_name(extensions, name);
+ if (!ext) {
+ return NT_STATUS_OK;
+ }
+
+ DLIST_REMOVE(extensions, ext);
+ talloc_free(ext);
+
+ DEBUG(2,("Successfully removed GP extension '%s'\n", name));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_register_gp_extension(TALLOC_CTX *gpext_ctx,
+ int version,
+ const char *name,
+ const char *guid,
+ struct gp_extension_methods *methods)
+{
+ struct gp_extension_methods *test;
+ struct gp_extension *entry;
+ NTSTATUS status;
+
+ if (!gpext_ctx) {
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ if ((version != SMB_GPEXT_INTERFACE_VERSION)) {
+ DEBUG(0,("Failed to register gp extension.\n"
+ "The module was compiled against "
+ "SMB_GPEXT_INTERFACE_VERSION %d,\n"
+ "current SMB_GPEXT_INTERFACE_VERSION is %d.\n"
+ "Please recompile against the current "
+ "version of samba!\n",
+ version, SMB_GPEXT_INTERFACE_VERSION));
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ if (!guid || !name || !name[0] || !methods) {
+ DEBUG(0,("Called with NULL pointer or empty name!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ test = get_methods_by_name(extensions, name);
+ if (test) {
+ DEBUG(0,("GP extension module %s already registered!\n",
+ name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ entry = talloc_zero(gpext_ctx, struct gp_extension);
+ NT_STATUS_HAVE_NO_MEMORY(entry);
+
+ entry->name = talloc_strdup(gpext_ctx, name);
+ NT_STATUS_HAVE_NO_MEMORY(entry->name);
+
+ entry->guid = talloc_zero(gpext_ctx, struct GUID);
+ NT_STATUS_HAVE_NO_MEMORY(entry->guid);
+ status = GUID_from_string(guid, entry->guid);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ entry->methods = methods;
+ DLIST_ADD(extensions, entry);
+
+ DEBUG(2,("Successfully added GP extension '%s' %s\n",
+ name, GUID_string2(gpext_ctx, entry->guid)));
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gp_extension_init_module(TALLOC_CTX *mem_ctx,
+ const char *name,
+ struct gp_extension **gpext)
+{
+ NTSTATUS status;
+ struct gp_extension *ext = NULL;
+
+ ext = talloc_zero(mem_ctx, struct gp_extension);
+ NT_STATUS_HAVE_NO_MEMORY(gpext);
+
+ ext->methods = get_methods_by_name(extensions, name);
+ if (!ext->methods) {
+
+ status = smb_probe_module(SAMBA_SUBSYSTEM_GPEXT,
+ name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ext->methods = get_methods_by_name(extensions, name);
+ if (!ext->methods) {
+ return NT_STATUS_DLL_INIT_FAILED;
+ }
+ }
+
+ *gpext = ext;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool add_gp_extension_reg_entry_to_array(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_entry *entry,
+ struct gp_extension_reg_entry **entries,
+ size_t *num)
+{
+ *entries = talloc_realloc(mem_ctx, *entries,
+ struct gp_extension_reg_entry,
+ (*num)+1);
+ if (*entries == NULL) {
+ *num = 0;
+ return false;
+ }
+
+ (*entries)[*num].value = entry->value;
+ (*entries)[*num].data = entry->data;
+
+ *num += 1;
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool add_gp_extension_reg_info_entry_to_array(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_info_entry *entry,
+ struct gp_extension_reg_info_entry **entries,
+ size_t *num)
+{
+ *entries = talloc_realloc(mem_ctx, *entries,
+ struct gp_extension_reg_info_entry,
+ (*num)+1);
+ if (*entries == NULL) {
+ *num = 0;
+ return false;
+ }
+
+ (*entries)[*num].guid = entry->guid;
+ (*entries)[*num].num_entries = entry->num_entries;
+ (*entries)[*num].entries = entry->entries;
+
+ *num += 1;
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gp_ext_info_add_reg(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_info_entry *entry,
+ const char *value,
+ enum winreg_Type type,
+ const char *data_s)
+{
+ struct gp_extension_reg_entry *reg_entry = NULL;
+ struct registry_value *data = NULL;
+
+ reg_entry = talloc_zero(mem_ctx, struct gp_extension_reg_entry);
+ NT_STATUS_HAVE_NO_MEMORY(reg_entry);
+
+ data = talloc_zero(mem_ctx, struct registry_value);
+ NT_STATUS_HAVE_NO_MEMORY(data);
+
+ data->type = type;
+
+ switch (type) {
+ case REG_SZ:
+ case REG_EXPAND_SZ:
+ if (!push_reg_sz(mem_ctx, &data->data, data_s)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ break;
+ case REG_DWORD: {
+ uint32_t v = atoi(data_s);
+ data->data = data_blob_talloc(mem_ctx, NULL, 4);
+ SIVAL(data->data.data, 0, v);
+ break;
+ }
+ default:
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ reg_entry->value = value;
+ reg_entry->data = data;
+
+ if (!add_gp_extension_reg_entry_to_array(mem_ctx, reg_entry,
+ &entry->entries,
+ &entry->num_entries)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gp_ext_info_add_reg_table(TALLOC_CTX *mem_ctx,
+ const char *module,
+ struct gp_extension_reg_info_entry *entry,
+ struct gp_extension_reg_table *table)
+{
+ NTSTATUS status;
+ const char *module_name = NULL;
+ int i;
+
+ module_name = talloc_asprintf(mem_ctx, "%s.%s", module, shlib_ext());
+ NT_STATUS_HAVE_NO_MEMORY(module_name);
+
+ status = gp_ext_info_add_reg(mem_ctx, entry,
+ "DllName", REG_EXPAND_SZ, module_name);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ for (i=0; table[i].val; i++) {
+ status = gp_ext_info_add_reg(mem_ctx, entry,
+ table[i].val,
+ table[i].type,
+ table[i].data);
+ NT_STATUS_NOT_OK_RETURN(status);
+ }
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_info_add_entry(TALLOC_CTX *mem_ctx,
+ const char *module,
+ const char *ext_guid,
+ struct gp_extension_reg_table *table,
+ struct gp_extension_reg_info *info)
+{
+ NTSTATUS status;
+ struct gp_extension_reg_info_entry *entry = NULL;
+
+ entry = talloc_zero(mem_ctx, struct gp_extension_reg_info_entry);
+ NT_STATUS_HAVE_NO_MEMORY(entry);
+
+ status = GUID_from_string(ext_guid, &entry->guid);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = gp_ext_info_add_reg_table(mem_ctx, module, entry, table);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ if (!add_gp_extension_reg_info_entry_to_array(mem_ctx, entry,
+ &info->entries,
+ &info->num_entries)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool gp_extension_reg_info_verify_entry(struct gp_extension_reg_entry *entry)
+{
+ int i;
+
+ for (i=0; gpext_reg_vals[i].val; i++) {
+
+ if ((strequal(entry->value, gpext_reg_vals[i].val)) &&
+ (entry->data->type == gpext_reg_vals[i].type)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool gp_extension_reg_info_verify(struct gp_extension_reg_info_entry *entry)
+{
+ int i;
+
+ for (i=0; i < entry->num_entries; i++) {
+ if (!gp_extension_reg_info_verify_entry(&entry->entries[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_extension_store_reg_vals(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ struct gp_extension_reg_info_entry *entry)
+{
+ WERROR werr = WERR_OK;
+ size_t i;
+
+ for (i=0; i < entry->num_entries; i++) {
+
+ werr = reg_setvalue(key,
+ entry->entries[i].value,
+ entry->entries[i].data);
+ W_ERROR_NOT_OK_RETURN(werr);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_extension_store_reg_entry(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ struct gp_extension_reg_info_entry *entry)
+{
+ WERROR werr;
+ struct registry_key *key = NULL;
+ const char *subkeyname = NULL;
+
+ if (!gp_extension_reg_info_verify(entry)) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ subkeyname = GUID_string2(mem_ctx, &entry->guid);
+ W_ERROR_HAVE_NO_MEMORY(subkeyname);
+
+ if (!strupper_m(discard_const_p(char, subkeyname))) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ werr = gp_store_reg_subkey(mem_ctx,
+ subkeyname,
+ reg_ctx->curr_key,
+ &key);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_extension_store_reg_vals(mem_ctx,
+ key,
+ entry);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_extension_store_reg(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ struct gp_extension_reg_info *info)
+{
+ WERROR werr = WERR_OK;
+ int i;
+
+ if (!info) {
+ return WERR_OK;
+ }
+
+ for (i=0; i < info->num_entries; i++) {
+ werr = gp_extension_store_reg_entry(mem_ctx,
+ reg_ctx,
+ &info->entries[i]);
+ W_ERROR_NOT_OK_RETURN(werr);
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gp_glob_ext_list(TALLOC_CTX *mem_ctx,
+ const char ***ext_list,
+ size_t *ext_list_len)
+{
+ DIR *dir = NULL;
+ struct dirent *dirent = NULL;
+
+ dir = opendir(modules_path(talloc_tos(),
+ SAMBA_SUBSYSTEM_GPEXT));
+ if (!dir) {
+ return map_nt_error_from_unix_common(errno);
+ }
+
+ while ((dirent = readdir(dir))) {
+
+ fstring name; /* forgive me... */
+ char *p;
+
+ if ((strequal(dirent->d_name, ".")) ||
+ (strequal(dirent->d_name, ".."))) {
+ continue;
+ }
+
+ p = strrchr(dirent->d_name, '.');
+ if (!p) {
+ closedir(dir);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!strcsequal(p+1, shlib_ext())) {
+ DEBUG(10,("gp_glob_ext_list: not a *.so file: %s\n",
+ dirent->d_name));
+ continue;
+ }
+
+ fstrcpy(name, dirent->d_name);
+ name[PTR_DIFF(p, dirent->d_name)] = 0;
+
+ if (!add_string_to_array(mem_ctx, name, ext_list,
+ ext_list_len)) {
+ closedir(dir);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ closedir(dir);
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_shutdown_gp_extensions(void)
+{
+ struct gp_extension *ext = NULL;
+
+ for (ext = extensions; ext; ext = ext->next) {
+ if (ext->methods && ext->methods->shutdown) {
+ ext->methods->shutdown();
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_init_gp_extensions(TALLOC_CTX *mem_ctx)
+{
+ NTSTATUS status;
+ WERROR werr;
+ int i = 0;
+ const char **ext_array = NULL;
+ size_t ext_array_len = 0;
+ struct gp_extension *gpext = NULL;
+ struct gp_registry_context *reg_ctx = NULL;
+
+ if (gpext_get_gp_extension_list()) {
+ return NT_STATUS_OK;
+ }
+
+ status = gp_glob_ext_list(mem_ctx, &ext_array, &ext_array_len);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ for (i=0; i<ext_array_len; i++) {
+
+ struct gp_extension_reg_info *info = NULL;
+
+ status = gp_extension_init_module(mem_ctx, ext_array[i],
+ &gpext);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ if (gpext->methods->get_reg_config) {
+
+ status = gpext->methods->initialize(mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ gpext->methods->shutdown();
+ goto out;
+ }
+
+ status = gpext->methods->get_reg_config(mem_ctx,
+ &info);
+ if (!NT_STATUS_IS_OK(status)) {
+ gpext->methods->shutdown();
+ goto out;
+ }
+
+ if (!reg_ctx) {
+ struct security_token *token;
+
+ token = registry_create_system_token(mem_ctx);
+ NT_STATUS_HAVE_NO_MEMORY(token);
+
+ werr = gp_init_reg_ctx(mem_ctx,
+ KEY_WINLOGON_GPEXT_PATH,
+ REG_KEY_WRITE,
+ token,
+ &reg_ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ status = werror_to_ntstatus(werr);
+ gpext->methods->shutdown();
+ goto out;
+ }
+ }
+
+ werr = gp_extension_store_reg(mem_ctx, reg_ctx, info);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(1,("gp_extension_store_reg failed: %s\n",
+ win_errstr(werr)));
+ TALLOC_FREE(info);
+ gpext->methods->shutdown();
+ status = werror_to_ntstatus(werr);
+ goto out;
+ }
+ TALLOC_FREE(info);
+ }
+
+ }
+
+ out:
+ TALLOC_FREE(reg_ctx);
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_free_gp_extensions(void)
+{
+ struct gp_extension *ext, *ext_next = NULL;
+
+ for (ext = extensions; ext; ext = ext_next) {
+ ext_next = ext->next;
+ DLIST_REMOVE(extensions, ext);
+ TALLOC_FREE(ext);
+ }
+
+ extensions = NULL;
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+void gpext_debug_header(int lvl,
+ const char *name,
+ uint32_t flags,
+ const struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid,
+ const char *snapin_guid)
+{
+ char *flags_str = NULL;
+
+ DEBUG(lvl,("%s\n", name));
+ DEBUGADD(lvl,("\tgpo: %s (%s)\n", gpo->name,
+ gpo->display_name));
+ DEBUGADD(lvl,("\tcse extension: %s (%s)\n", extension_guid,
+ cse_gpo_guid_string_to_name(extension_guid)));
+ DEBUGADD(lvl,("\tgplink: %s\n", gpo->link));
+ DEBUGADD(lvl,("\tsnapin: %s (%s)\n", snapin_guid,
+ cse_snapin_gpo_guid_string_to_name(snapin_guid)));
+
+ flags_str = gpo_flag_str(NULL, flags);
+ DEBUGADD(lvl,("\tflags: 0x%08x %s\n", flags, flags_str));
+ TALLOC_FREE(flags_str);
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gpext_check_gpo_for_gpext_presence(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct GROUP_POLICY_OBJECT *gpo,
+ const struct GUID *guid,
+ bool *gpext_guid_present)
+{
+ struct GP_EXT *gp_ext = NULL;
+ int i;
+ bool ok;
+
+ *gpext_guid_present = false;
+
+
+ if (gpo->link_type == GP_LINK_LOCAL) {
+ return NT_STATUS_OK;
+ }
+
+ ok = gpo_get_gp_ext_from_gpo(mem_ctx, flags, gpo, &gp_ext);
+ if (!ok) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (gp_ext == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ for (i = 0; i < gp_ext->num_exts; i++) {
+ struct GUID guid2;
+ NTSTATUS status;
+
+ status = GUID_from_string(gp_ext->extensions_guid[i], &guid2);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ if (GUID_equal(guid, &guid2)) {
+ *gpext_guid_present = true;
+ return NT_STATUS_OK;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpext_process_extension(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct security_token *token,
+ struct registry_key *root_key,
+ const struct GROUP_POLICY_OBJECT *deleted_gpo_list,
+ const struct GROUP_POLICY_OBJECT *changed_gpo_list,
+ const char *extension_guid_filter)
+{
+ NTSTATUS status;
+ struct gp_extension *ext = NULL;
+ const struct GROUP_POLICY_OBJECT *gpo;
+ struct GUID extension_guid_filter_guid;
+
+ status = gpext_init_gp_extensions(mem_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1,("gpext_init_gp_extensions failed: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ if (extension_guid_filter) {
+ status = GUID_from_string(extension_guid_filter,
+ &extension_guid_filter_guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ for (ext = extensions; ext; ext = ext->next) {
+
+ struct GROUP_POLICY_OBJECT *deleted_gpo_list_filtered = NULL;
+ struct GROUP_POLICY_OBJECT *changed_gpo_list_filtered = NULL;
+
+ if (extension_guid_filter) {
+ if (!GUID_equal(&extension_guid_filter_guid, ext->guid)) {
+ continue;
+ }
+ }
+
+ for (gpo = deleted_gpo_list; gpo; gpo = gpo->next) {
+
+ bool is_present = false;
+
+ status = gpext_check_gpo_for_gpext_presence(mem_ctx,
+ flags,
+ gpo,
+ ext->guid,
+ &is_present);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (is_present) {
+ struct GROUP_POLICY_OBJECT *new_gpo;
+
+ status = gpo_copy(mem_ctx, gpo, &new_gpo);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DLIST_ADD(deleted_gpo_list_filtered, new_gpo);
+ }
+ }
+
+ for (gpo = changed_gpo_list; gpo; gpo = gpo->next) {
+
+ bool is_present = false;
+
+ status = gpext_check_gpo_for_gpext_presence(mem_ctx,
+ flags,
+ gpo,
+ ext->guid,
+ &is_present);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (is_present) {
+ struct GROUP_POLICY_OBJECT *new_gpo;
+
+ status = gpo_copy(mem_ctx, gpo, &new_gpo);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ DLIST_ADD(changed_gpo_list_filtered, new_gpo);
+ }
+ }
+
+ status = ext->methods->initialize(mem_ctx);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = ext->methods->process_group_policy(mem_ctx,
+ flags,
+ root_key,
+ token,
+ deleted_gpo_list_filtered,
+ changed_gpo_list_filtered);
+ if (!NT_STATUS_IS_OK(status)) {
+ ext->methods->shutdown();
+ }
+ }
+
+ return status;
+}
diff --git a/libgpo/gpext/gpext.h b/libgpo/gpext/gpext.h
new file mode 100644
index 0000000..0f5139d
--- /dev/null
+++ b/libgpo/gpext/gpext.h
@@ -0,0 +1,109 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * Copyright (C) Guenther Deschner 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 __GPEXT_H__
+#define __GPEXT_H__
+
+#include "librpc/gen_ndr/winreg.h"
+
+#define KEY_WINLOGON_GPEXT_PATH "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions"
+
+#define SAMBA_SUBSYSTEM_GPEXT "gpext"
+
+#define SMB_GPEXT_INTERFACE_VERSION 1
+
+struct gp_extension {
+ struct GUID *guid;
+ const char *name;
+ struct gp_extension_methods *methods;
+ struct gp_extension *prev, *next;
+};
+
+struct gp_extension_reg_table {
+ const char *val;
+ enum winreg_Type type;
+ const char *data;
+};
+
+struct gp_extension_reg_entry {
+ const char *value;
+ struct registry_value *data;
+};
+
+struct gp_extension_reg_info_entry {
+ struct GUID guid;
+ size_t num_entries;
+ struct gp_extension_reg_entry *entries;
+};
+
+struct gp_extension_reg_info {
+ size_t num_entries;
+ struct gp_extension_reg_info_entry *entries;
+};
+
+struct gp_extension_methods {
+
+ NTSTATUS (*initialize)(TALLOC_CTX *mem_ctx);
+
+ NTSTATUS (*process_group_policy)(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct registry_key *root_key,
+ const struct security_token *token,
+ const struct GROUP_POLICY_OBJECT *deleted_gpo_list,
+ const struct GROUP_POLICY_OBJECT *changed_gpo_list);
+
+ NTSTATUS (*get_reg_config)(TALLOC_CTX *mem_ctx,
+ struct gp_extension_reg_info **info);
+
+ NTSTATUS (*shutdown)(void);
+};
+
+/* The following definitions come from libgpo/gpext/gpext.c */
+
+struct gp_extension *gpext_get_gp_extension_list(void);
+NTSTATUS gpext_unregister_gp_extension(const char *name);
+NTSTATUS gpext_register_gp_extension(TALLOC_CTX *gpext_ctx,
+ int version,
+ const char *name,
+ const char *guid,
+ struct gp_extension_methods *methods);
+NTSTATUS gpext_info_add_entry(TALLOC_CTX *mem_ctx,
+ const char *module,
+ const char *ext_guid,
+ struct gp_extension_reg_table *table,
+ struct gp_extension_reg_info *info);
+NTSTATUS gpext_shutdown_gp_extensions(void);
+NTSTATUS gpext_init_gp_extensions(TALLOC_CTX *mem_ctx);
+NTSTATUS gpext_free_gp_extensions(void);
+void gpext_debug_header(int lvl,
+ const char *name,
+ uint32_t flags,
+ const struct GROUP_POLICY_OBJECT *gpo,
+ const char *extension_guid,
+ const char *snapin_guid);
+NTSTATUS gpext_process_extension(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct security_token *token,
+ struct registry_key *root_key,
+ const struct GROUP_POLICY_OBJECT *deleted_gpo_list,
+ const struct GROUP_POLICY_OBJECT *changed_gpo_list,
+ const char *extension_guid);
+
+
+#endif /* __GPEXT_H__ */
diff --git a/libgpo/gpo.h b/libgpo/gpo.h
new file mode 100644
index 0000000..740a558
--- /dev/null
+++ b/libgpo/gpo.h
@@ -0,0 +1,254 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2005-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 __GPO_H__
+#define __GPO_H__
+
+#include "ads.h"
+
+enum GPO_LINK_TYPE {
+ GP_LINK_UNKOWN = 0,
+ GP_LINK_MACHINE = 1,
+ GP_LINK_SITE = 2,
+ GP_LINK_DOMAIN = 3,
+ GP_LINK_OU = 4,
+ GP_LINK_LOCAL = 5 /* for convenience */
+};
+
+/* GPO_OPTIONS */
+#define GPO_FLAG_DISABLE 0x00000001
+#define GPO_FLAG_FORCE 0x00000002
+
+/* GPO_LIST_FLAGS */
+#define GPO_LIST_FLAG_MACHINE 0x00000001
+#define GPO_LIST_FLAG_SITEONLY 0x00000002
+
+/* following flags from http://support.microsoft.com/kb/312164/EN-US/ */
+#define GPO_INFO_FLAG_MACHINE 0x00000001
+#define GPO_INFO_FLAG_BACKGROUND 0x00000010
+#define GPO_INFO_FLAG_SLOWLINK 0x00000020
+#define GPO_INFO_FLAG_VERBOSE 0x00000040
+#define GPO_INFO_FLAG_NOCHANGES 0x00000080
+#define GPO_INFO_FLAG_LINKTRANSITION 0x00000100
+#define GPO_INFO_FLAG_LOGRSOP_TRANSITION 0x00000200
+#define GPO_INFO_FLAG_FORCED_REFRESH 0x00000400
+#define GPO_INFO_FLAG_SAFEMODE_BOOT 0x00000800
+
+#define GPO_VERSION_USER(x) (x >> 16)
+#define GPO_VERSION_MACHINE(x) (x & 0xffff)
+
+struct GROUP_POLICY_OBJECT {
+ uint32_t options; /* GPFLAGS_* */
+ uint32_t version;
+ const char *ds_path;
+ const char *file_sys_path;
+ const char *display_name;
+ const char *name;
+ const char *link;
+ enum GPO_LINK_TYPE link_type;
+ const char *user_extensions;
+ const char *machine_extensions;
+ struct security_descriptor *security_descriptor;
+ struct GROUP_POLICY_OBJECT *next, *prev;
+};
+
+/* the following is seen on the DS (see adssearch.pl for details) */
+
+/* the type field in a 'gPLink', the same as GPO_FLAG ? */
+#define GPO_LINK_OPT_NONE 0x00000000
+#define GPO_LINK_OPT_DISABLED 0x00000001
+#define GPO_LINK_OPT_ENFORCED 0x00000002
+
+/* GPO_LINK_OPT_ENFORCED takes precedence over GPOPTIONS_BLOCK_INHERITANCE */
+
+/* 'gPOptions', maybe a bitmask as well */
+enum GPO_INHERIT {
+ GPOPTIONS_INHERIT = 0,
+ GPOPTIONS_BLOCK_INHERITANCE = 1
+};
+
+/* 'flags' in a 'groupPolicyContainer' object */
+#define GPFLAGS_ALL_ENABLED 0x00000000
+#define GPFLAGS_USER_SETTINGS_DISABLED 0x00000001
+#define GPFLAGS_MACHINE_SETTINGS_DISABLED 0x00000002
+#define GPFLAGS_ALL_DISABLED (GPFLAGS_USER_SETTINGS_DISABLED | \
+ GPFLAGS_MACHINE_SETTINGS_DISABLED)
+
+struct GP_LINK {
+ const char *gp_link; /* raw link name */
+ uint32_t gp_opts; /* inheritance options GPO_INHERIT */
+ uint32_t num_links; /* number of links */
+ char **link_names; /* array of parsed link names */
+ uint32_t *link_opts; /* array of parsed link opts GPO_LINK_OPT_* */
+};
+
+struct GP_EXT {
+ const char *gp_extension; /* raw extension name */
+ uint32_t num_exts;
+ char **extensions;
+ char **extensions_guid;
+ char **snapins;
+ char **snapins_guid;
+ struct GP_EXT *next, *prev;
+};
+
+#define GPO_CACHE_DIR "gpo_cache"
+#define GPT_INI "GPT.INI"
+#define GPO_REFRESH_INTERVAL 60*90
+
+#define GPO_REG_STATE_MACHINE "State\\Machine"
+
+enum gp_reg_action {
+ GP_REG_ACTION_NONE = 0,
+ GP_REG_ACTION_ADD_VALUE = 1,
+ GP_REG_ACTION_ADD_KEY = 2,
+ GP_REG_ACTION_DEL_VALUES = 3,
+ GP_REG_ACTION_DEL_VALUE = 4,
+ GP_REG_ACTION_DEL_ALL_VALUES = 5,
+ GP_REG_ACTION_DEL_KEYS = 6,
+ GP_REG_ACTION_SEC_KEY_SET = 7,
+ GP_REG_ACTION_SEC_KEY_RESET = 8
+};
+
+struct gp_registry_entry {
+ enum gp_reg_action action;
+ const char *key;
+ const char *value;
+ struct registry_value *data;
+};
+
+struct gp_registry_value {
+ const char *value;
+ struct registry_value *data;
+};
+
+struct gp_registry_entries {
+ size_t num_entries;
+ struct gp_registry_entry **entries;
+};
+
+struct gp_registry_context {
+ const struct security_token *token;
+ const char *path;
+ struct registry_key *curr_key;
+};
+
+#define GP_EXT_GUID_SECURITY "827D319E-6EAC-11D2-A4EA-00C04F79F83A"
+#define GP_EXT_GUID_REGISTRY "35378EAC-683F-11D2-A89A-00C04FBBCFA2"
+#define GP_EXT_GUID_SCRIPTS "42B5FAAE-6536-11D2-AE5A-0000F87571E3"
+#define ADS_EXTENDED_RIGHT_APPLY_GROUP_POLICY "edacfd8f-ffb3-11d1-b41d-00a0c968f939"
+
+
+struct cli_state;
+
+/* The following definitions come from libgpo/gpo_fetch.c */
+
+NTSTATUS gpo_explode_filesyspath(TALLOC_CTX *mem_ctx,
+ const char *cache_dir,
+ const char *file_sys_path,
+ char **server,
+ char **service,
+ char **nt_path,
+ char **unix_path);
+NTSTATUS gpo_get_sysvol_gpt_version(TALLOC_CTX *mem_ctx,
+ const char *unix_path,
+ uint32_t *sysvol_version,
+ char **display_name);
+
+/* The following definitions come from libgpo/gpo_ldap.c */
+
+bool ads_parse_gp_ext(TALLOC_CTX *mem_ctx,
+ const char *extension_raw,
+ struct GP_EXT **gp_ext);
+ADS_STATUS ads_get_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ struct GP_LINK *gp_link_struct);
+ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ const char *gpo_dn,
+ uint32_t gpo_opt);
+ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ const char *gpo_dn);
+ADS_STATUS ads_get_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *gpo_dn,
+ const char *display_name,
+ const char *guid_name,
+ struct GROUP_POLICY_OBJECT *gpo);
+ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ struct security_token **token);
+ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ uint32_t flags,
+ const struct security_token *token,
+ struct GROUP_POLICY_OBJECT **gpo_list);
+
+/* The following definitions come from libgpo/gpo_sec.c */
+
+NTSTATUS gpo_apply_security_filtering(const struct GROUP_POLICY_OBJECT *gpo,
+ const struct security_token *token);
+
+/* The following definitions come from libgpo/gpo_util.c */
+
+const char *cse_gpo_guid_string_to_name(const char *guid);
+const char *cse_gpo_name_to_guid_string(const char *name);
+const char *cse_snapin_gpo_guid_string_to_name(const char *guid);
+void dump_gp_ext(struct GP_EXT *gp_ext, int debuglevel);
+void dump_gpo(const struct GROUP_POLICY_OBJECT *gpo,
+ int debuglevel);
+void dump_gpo_list(const struct GROUP_POLICY_OBJECT *gpo_list,
+ int debuglevel);
+void dump_gplink(const struct GP_LINK *gp_link);
+NTSTATUS gpo_process_gpo_list(TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ const struct GROUP_POLICY_OBJECT *deleted_gpo_list,
+ const struct GROUP_POLICY_OBJECT *changed_gpo_list,
+ const char *extensions_guid_filter,
+ uint32_t flags);
+NTSTATUS gpo_get_unix_path(TALLOC_CTX *mem_ctx,
+ const char *cache_dir,
+ const struct GROUP_POLICY_OBJECT *gpo,
+ char **unix_path);
+char *gpo_flag_str(TALLOC_CTX *mem_ctx, uint32_t flags);
+NTSTATUS gp_find_file(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *filename,
+ const char *suffix,
+ const char **filename_out);
+ADS_STATUS gp_get_machine_token(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ struct security_token **token);
+
+bool gpo_get_gp_ext_from_gpo(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct GROUP_POLICY_OBJECT *gpo,
+ struct GP_EXT **gp_ext);
+NTSTATUS gpo_copy(TALLOC_CTX *mem_ctx,
+ const struct GROUP_POLICY_OBJECT *gpo_src,
+ struct GROUP_POLICY_OBJECT **gpo_dst);
+
+#endif
diff --git a/libgpo/gpo_fetch.c b/libgpo/gpo_fetch.c
new file mode 100644
index 0000000..31d510d
--- /dev/null
+++ b/libgpo/gpo_fetch.c
@@ -0,0 +1,124 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2005-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 "includes.h"
+#include "system/filesys.h"
+#include "../libgpo/gpo.h"
+#include "../libgpo/gpo_ini.h"
+
+#include "libgpo/gpo_proto.h"
+#include "libsmb/libsmb.h"
+
+/****************************************************************
+ explode the GPO CIFS URI into their components
+****************************************************************/
+
+NTSTATUS gpo_explode_filesyspath(TALLOC_CTX *mem_ctx,
+ const char *cache_dir,
+ const char *file_sys_path,
+ char **server,
+ char **service,
+ char **nt_path,
+ char **unix_path)
+{
+ char *path = NULL;
+
+ *server = NULL;
+ *service = NULL;
+ *nt_path = NULL;
+ *unix_path = NULL;
+
+ if (!file_sys_path) {
+ return NT_STATUS_OK;
+ }
+
+ if (!next_token_talloc(mem_ctx, &file_sys_path, server, "\\")) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ NT_STATUS_HAVE_NO_MEMORY(*server);
+
+ if (!next_token_talloc(mem_ctx, &file_sys_path, service, "\\")) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ NT_STATUS_HAVE_NO_MEMORY(*service);
+
+ if ((*nt_path = talloc_asprintf(mem_ctx, "\\%s", file_sys_path))
+ == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ NT_STATUS_HAVE_NO_MEMORY(*nt_path);
+
+ if ((path = talloc_asprintf(mem_ctx,
+ "%s/%s",
+ cache_dir,
+ file_sys_path)) == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ path = talloc_string_sub(mem_ctx, path, "\\", "/");
+ if (!path) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *unix_path = talloc_strdup(mem_ctx, path);
+ NT_STATUS_HAVE_NO_MEMORY(*unix_path);
+
+ talloc_free(path);
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+ get the locally stored gpt.ini version number
+****************************************************************/
+
+NTSTATUS gpo_get_sysvol_gpt_version(TALLOC_CTX *mem_ctx,
+ const char *unix_path,
+ uint32_t *sysvol_version,
+ char **display_name)
+{
+ NTSTATUS status;
+ uint32_t version = 0;
+ char *local_path = NULL;
+ char *name = NULL;
+
+ if (!unix_path) {
+ return NT_STATUS_OK;
+ }
+
+ local_path = talloc_asprintf(mem_ctx, "%s/%s", unix_path, GPT_INI);
+ NT_STATUS_HAVE_NO_MEMORY(local_path);
+
+ status = parse_gpt_ini(mem_ctx, local_path, &version, &name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("gpo_get_sysvol_gpt_version: "
+ "failed to parse ini [%s]: %s\n",
+ local_path, nt_errstr(status)));
+ return status;
+ }
+
+ if (sysvol_version) {
+ *sysvol_version = version;
+ }
+
+ if (name && *display_name) {
+ *display_name = talloc_strdup(mem_ctx, name);
+ NT_STATUS_HAVE_NO_MEMORY(*display_name);
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/libgpo/gpo_filesync.c b/libgpo/gpo_filesync.c
new file mode 100644
index 0000000..b0d1447
--- /dev/null
+++ b/libgpo/gpo_filesync.c
@@ -0,0 +1,245 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 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 "includes.h"
+#include "system/filesys.h"
+#include "libsmb/libsmb.h"
+#include "../libgpo/gpo.h"
+#include "libgpo/gpo_proto.h"
+#include "lib/util/string_wrappers.h"
+
+struct sync_context {
+ TALLOC_CTX *mem_ctx;
+ struct cli_state *cli;
+ char *remote_path;
+ char *local_path;
+ char *mask;
+ uint16_t attribute;
+};
+
+static NTSTATUS gpo_sync_func(struct file_info *info,
+ const char *mask,
+ void *state);
+
+NTSTATUS gpo_copy_file(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const char *nt_path,
+ const char *unix_path)
+{
+ NTSTATUS result;
+ uint16_t fnum;
+ int fd = -1;
+ char *data = NULL;
+ static int io_bufsize = 64512;
+ int read_size = io_bufsize;
+ off_t nread = 0;
+
+ result = cli_open(cli, nt_path, O_RDONLY, DENY_NONE, &fnum);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto out;
+ }
+
+ if ((fd = open(unix_path, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
+ result = map_nt_error_from_unix(errno);
+ goto out;
+ }
+
+ if ((data = (char *)SMB_MALLOC(read_size)) == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ while (1) {
+ size_t n = 0;
+
+ result = cli_read(cli, fnum, data, nread, read_size, &n);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto out;
+ }
+
+ if (n == 0)
+ break;
+
+ if (write(fd, data, n) != n) {
+ break;
+ }
+
+ nread += n;
+ }
+
+ result = NT_STATUS_OK;
+
+ out:
+ SAFE_FREE(data);
+ if (fnum) {
+ cli_close(cli, fnum);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+
+ return result;
+}
+
+/****************************************************************
+ copy dir
+****************************************************************/
+
+static NTSTATUS gpo_copy_dir(const char *unix_path)
+{
+ if ((mkdir(unix_path, 0644)) < 0 && errno != EEXIST) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+ sync files
+****************************************************************/
+
+static NTSTATUS gpo_sync_files(struct sync_context *ctx)
+{
+ NTSTATUS status;
+
+ DEBUG(3,("calling cli_list with mask: %s\n", ctx->mask));
+
+ status = cli_list(ctx->cli, ctx->mask, ctx->attribute, gpo_sync_func,
+ ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("listing [%s] failed with error: %s\n",
+ ctx->mask, nt_errstr(status)));
+ return status;
+ }
+
+ return status;
+}
+
+/****************************************************************
+ synchronisation callback
+****************************************************************/
+
+static NTSTATUS gpo_sync_func(struct file_info *info,
+ const char *mask,
+ void *state)
+{
+ NTSTATUS result;
+ struct sync_context *ctx;
+ fstring nt_filename, unix_filename;
+ fstring nt_dir, unix_dir;
+ char *old_nt_dir, *old_unix_dir;
+
+ ctx = (struct sync_context *)state;
+
+ if (strequal(info->name, ".") || strequal(info->name, "..")) {
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(5,("gpo_sync_func: got mask: [%s], name: [%s]\n",
+ mask, info->name));
+
+ if (info->attr & FILE_ATTRIBUTE_DIRECTORY) {
+
+ DEBUG(3,("got dir: [%s]\n", info->name));
+
+ fstrcpy(nt_dir, ctx->remote_path);
+ fstrcat(nt_dir, "\\");
+ fstrcat(nt_dir, info->name);
+
+ fstrcpy(unix_dir, ctx->local_path);
+ fstrcat(unix_dir, "/");
+ fstrcat(unix_dir, info->name);
+
+ result = gpo_copy_dir(unix_dir);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1,("failed to copy dir: %s\n",
+ nt_errstr(result)));
+ return result;
+ }
+
+ old_nt_dir = ctx->remote_path;
+ ctx->remote_path = talloc_strdup(ctx->mem_ctx, nt_dir);
+
+ old_unix_dir = ctx->local_path;
+ ctx->local_path = talloc_strdup(ctx->mem_ctx, unix_dir);
+
+ ctx->mask = talloc_asprintf(ctx->mem_ctx,
+ "%s\\*",
+ nt_dir);
+ if (!ctx->local_path || !ctx->mask || !ctx->remote_path) {
+ DEBUG(0,("gpo_sync_func: ENOMEM\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ result = gpo_sync_files(ctx);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(0,("could not sync files\n"));
+ return result;
+ }
+
+ ctx->remote_path = old_nt_dir;
+ ctx->local_path = old_unix_dir;
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(3,("got file: [%s]\n", info->name));
+
+ fstrcpy(nt_filename, ctx->remote_path);
+ fstrcat(nt_filename, "\\");
+ fstrcat(nt_filename, info->name);
+
+ fstrcpy(unix_filename, ctx->local_path);
+ fstrcat(unix_filename, "/");
+ fstrcat(unix_filename, info->name);
+
+ result = gpo_copy_file(ctx->mem_ctx, ctx->cli,
+ nt_filename, unix_filename);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1,("failed to copy file: %s\n",
+ nt_errstr(result)));
+ }
+ return result;
+}
+
+
+/****************************************************************
+ list a remote directory and download recursively
+****************************************************************/
+
+NTSTATUS gpo_sync_directories(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const char *nt_path,
+ const char *local_path)
+{
+ struct sync_context ctx;
+
+ ctx.mem_ctx = mem_ctx;
+ ctx.cli = cli;
+ ctx.remote_path = discard_const_p(char, nt_path);
+ ctx.local_path = discard_const_p(char, local_path);
+ ctx.attribute = (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
+
+ ctx.mask = talloc_asprintf(mem_ctx,
+ "%s\\*",
+ nt_path);
+ if (!ctx.mask) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return gpo_sync_files(&ctx);
+}
diff --git a/libgpo/gpo_ini.c b/libgpo/gpo_ini.c
new file mode 100644
index 0000000..66f743e
--- /dev/null
+++ b/libgpo/gpo_ini.c
@@ -0,0 +1,468 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * Copyright (C) Guenther Deschner 2007
+ * Copyright (C) Wilco Baan Hofman 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 "gpo.h"
+#include "gpo_ini.h"
+#include "system/filesys.h"
+
+
+static bool change_section(const char *section, void *ctx_ptr)
+{
+ struct gp_inifile_context *ctx = (struct gp_inifile_context *) ctx_ptr;
+
+ if (ctx->current_section) {
+ talloc_free(ctx->current_section);
+ }
+ ctx->current_section = talloc_strdup(ctx, section);
+ if (!ctx->current_section) {
+ return false;
+ }
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool store_keyval_pair(const char *key, const char *value, void *ctx_ptr)
+{
+ struct gp_inifile_context *ctx = (struct gp_inifile_context *) ctx_ptr;
+
+ ctx->data = talloc_realloc(ctx, ctx->data, struct keyval_pair *, ctx->keyval_count+1);
+ if (!ctx->data) {
+ return false;
+ }
+
+ ctx->data[ctx->keyval_count] = talloc_zero(ctx, struct keyval_pair);
+ if (!ctx->data[ctx->keyval_count]) {
+ return false;
+ }
+
+ ctx->data[ctx->keyval_count]->key = talloc_asprintf(ctx, "%s:%s", ctx->current_section, key);
+ ctx->data[ctx->keyval_count]->val = talloc_strdup(ctx, value ? value : "");
+
+ if (!ctx->data[ctx->keyval_count]->key ||
+ !ctx->data[ctx->keyval_count]->val) {
+ return false;
+ }
+
+ ctx->keyval_count++;
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS convert_file_from_ucs2(TALLOC_CTX *mem_ctx,
+ const char *filename_in,
+ char **filename_out)
+{
+ int tmp_fd = -1;
+ uint8_t *data_in = NULL;
+ uint8_t *data_out = NULL;
+ char *tmp_name = NULL;
+ NTSTATUS status;
+ size_t n = 0;
+ size_t converted_size;
+ mode_t mask;
+
+ if (!filename_out) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ data_in = (uint8_t *)file_load(filename_in, &n, 0, mem_ctx);
+ if (!data_in) {
+ status = NT_STATUS_NO_SUCH_FILE;
+ goto out;
+ }
+
+ DEBUG(11,("convert_file_from_ucs2: "
+ "data_in[0]: 0x%x, data_in[1]: 0x%x, data_in[2]: 0x%x\n",
+ data_in[0], data_in[1], data_in[2]));
+
+ if ((data_in[0] != 0xff) || (data_in[1] != 0xfe) || (data_in[2] != 0x0d)) {
+ *filename_out = NULL;
+ status = NT_STATUS_OK;
+ goto out;
+ }
+
+ tmp_name = talloc_asprintf(mem_ctx, "%s/convert_file_from_ucs2.XXXXXX",
+ tmpdir());
+ if (!tmp_name) {
+ status = NT_STATUS_NO_MEMORY;
+ goto out;
+ }
+
+ mask = umask(S_IRWXO | S_IRWXG);
+ tmp_fd = mkstemp(tmp_name);
+ umask(mask);
+ if (tmp_fd == -1) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto out;
+ }
+
+ if (!convert_string_talloc(mem_ctx, CH_UTF16LE, CH_UNIX, data_in, n,
+ &data_out, &converted_size))
+ {
+ status = NT_STATUS_INVALID_BUFFER_SIZE;
+ goto out;
+ }
+
+ DEBUG(11,("convert_file_from_ucs2: "
+ "%s skipping utf16-le BOM\n", tmp_name));
+
+ converted_size -= 3;
+
+ if (write(tmp_fd, data_out + 3, converted_size) != converted_size) {
+ status = map_nt_error_from_unix_common(errno);
+ goto out;
+ }
+
+ *filename_out = tmp_name;
+
+ status = NT_STATUS_OK;
+
+ out:
+ if (tmp_fd != -1) {
+ close(tmp_fd);
+ }
+
+ talloc_free(data_in);
+ talloc_free(data_out);
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gp_inifile_getstring(struct gp_inifile_context *ctx, const char *key, const char **ret)
+{
+ int i;
+
+ for (i = 0; i < ctx->keyval_count; i++) {
+ if (strcmp(ctx->data[i]->key, key) == 0) {
+ if (ret) {
+ *ret = ctx->data[i]->val;
+ }
+ return NT_STATUS_OK;
+ }
+ }
+ return NT_STATUS_NOT_FOUND;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gp_inifile_getint(struct gp_inifile_context *ctx, const char *key, int *ret)
+{
+ const char *value;
+ NTSTATUS result;
+
+ result = gp_inifile_getstring(ctx,key, &value);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if (ret) {
+ *ret = (int)strtol(value, NULL, 10);
+ }
+ return NT_STATUS_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gp_inifile_getbool(struct gp_inifile_context *ctx, const char *key, bool *ret)
+{
+ const char *value;
+ NTSTATUS result;
+
+ result = gp_inifile_getstring(ctx,key, &value);
+ if (!NT_STATUS_IS_OK(result)) {
+ return result;
+ }
+
+ if (strequal(value, "Yes") ||
+ strequal(value, "True")) {
+ if (ret) {
+ *ret = true;
+ }
+ return NT_STATUS_OK;
+ } else if (strequal(value, "No") ||
+ strequal(value, "False")) {
+ if (ret) {
+ *ret = false;
+ }
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_NOT_FOUND;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gp_inifile_enum_section(struct gp_inifile_context *ctx,
+ const char *section,
+ size_t *num_ini_keys,
+ const char ***ini_keys,
+ const char ***ini_values)
+{
+ NTSTATUS status;
+ int i;
+ size_t num_keys = 0, num_vals = 0;
+ const char **keys = NULL;
+ const char **values = NULL;
+
+ if (section == NULL || num_ini_keys == NULL ||
+ ini_keys == NULL || ini_values == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ for (i = 0; i < ctx->keyval_count; i++) {
+
+ bool ok;
+
+ /*
+ * section: KEYNAME
+ * KEYNAME:value matches
+ * KEYNAME_OEM:value not
+ */
+
+ if (strlen(section)+1 > strlen(ctx->data[i]->key)) {
+ continue;
+ }
+
+ if (!strnequal(section, ctx->data[i]->key, strlen(section))) {
+ continue;
+ }
+
+ if (ctx->data[i]->key[strlen(section)] != ':') {
+ continue;
+ }
+
+ ok = add_string_to_array(ctx, ctx->data[i]->key, &keys, &num_keys);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ ok = add_string_to_array(ctx, ctx->data[i]->val, &values, &num_vals);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ if (num_keys != num_vals) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ goto failed;
+ }
+ }
+
+ *num_ini_keys = num_keys;
+ *ini_keys = keys;
+ *ini_values = values;
+
+ return NT_STATUS_OK;
+
+ failed:
+ talloc_free(keys);
+ talloc_free(values);
+
+ return status;
+}
+
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gp_inifile_init_context(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *unix_path,
+ const char *suffix,
+ struct gp_inifile_context **ctx_ret)
+{
+ struct gp_inifile_context *ctx = NULL;
+ NTSTATUS status;
+ int rv;
+ char *tmp_filename = NULL;
+ const char *ini_filename = NULL;
+
+ if (!unix_path || !ctx_ret) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ctx = talloc_zero(mem_ctx, struct gp_inifile_context);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ status = gp_find_file(mem_ctx, flags, unix_path, suffix,
+ &ini_filename);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ status = convert_file_from_ucs2(mem_ctx, ini_filename,
+ &tmp_filename);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ rv = pm_process(tmp_filename != NULL ? tmp_filename : ini_filename,
+ change_section, store_keyval_pair, ctx);
+ if (!rv) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+
+ ctx->generated_filename = tmp_filename;
+ ctx->mem_ctx = mem_ctx;
+
+ *ctx_ret = ctx;
+
+ return NT_STATUS_OK;
+
+ failed:
+
+ DEBUG(1,("gp_inifile_init_context failed: %s\n",
+ nt_errstr(status)));
+
+ talloc_free(ctx);
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gp_inifile_init_context_direct(TALLOC_CTX *mem_ctx,
+ const char *unix_path,
+ struct gp_inifile_context **pgp_ctx)
+{
+ struct gp_inifile_context *gp_ctx = NULL;
+ NTSTATUS status;
+ bool rv;
+ char *tmp_filename = NULL;
+
+ if (unix_path == NULL || pgp_ctx == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ gp_ctx = talloc_zero(mem_ctx, struct gp_inifile_context);
+ if (gp_ctx == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = convert_file_from_ucs2(mem_ctx, unix_path,
+ &tmp_filename);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ rv = pm_process_with_flags(tmp_filename != NULL ? tmp_filename : unix_path,
+ true,
+ change_section,
+ store_keyval_pair,
+ gp_ctx);
+ if (!rv) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ gp_ctx->generated_filename = tmp_filename;
+ gp_ctx->mem_ctx = mem_ctx;
+
+ *pgp_ctx = gp_ctx;
+
+ return NT_STATUS_OK;
+
+ failed:
+
+ DEBUG(1,("gp_inifile_init_context_direct failed: %s\n",
+ nt_errstr(status)));
+
+ talloc_free(gp_ctx);
+
+ return status;
+}
+
+
+/****************************************************************
+ parse the local gpt.ini file
+****************************************************************/
+
+#define GPT_INI_SECTION_GENERAL "General"
+#define GPT_INI_PARAMETER_VERSION "Version"
+#define GPT_INI_PARAMETER_DISPLAYNAME "displayName"
+
+NTSTATUS parse_gpt_ini(TALLOC_CTX *mem_ctx,
+ const char *filename,
+ uint32_t *version,
+ char **display_name)
+{
+ NTSTATUS result;
+ int rv;
+ int v = 0;
+ const char *name = NULL;
+ struct gp_inifile_context *ctx;
+
+ if (!filename) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ctx = talloc_zero(mem_ctx, struct gp_inifile_context);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ rv = pm_process(filename, change_section, store_keyval_pair, ctx);
+ if (!rv) {
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+
+ result = gp_inifile_getstring(ctx, GPT_INI_SECTION_GENERAL
+ ":"GPT_INI_PARAMETER_DISPLAYNAME, &name);
+ if (!NT_STATUS_IS_OK(result)) {
+ /* the default domain policy and the default domain controller
+ * policy never have a displayname in their gpt.ini file */
+ DEBUG(10,("parse_gpt_ini: no name in %s\n", filename));
+ }
+
+ if (name && display_name) {
+ *display_name = talloc_strdup(ctx, name);
+ if (*display_name == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ result = gp_inifile_getint(ctx, GPT_INI_SECTION_GENERAL
+ ":"GPT_INI_PARAMETER_VERSION, &v);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("parse_gpt_ini: no version\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ if (version) {
+ *version = v;
+ }
+
+ talloc_free(ctx);
+
+ return NT_STATUS_OK;
+}
diff --git a/libgpo/gpo_ini.h b/libgpo/gpo_ini.h
new file mode 100644
index 0000000..0bfe5b1
--- /dev/null
+++ b/libgpo/gpo_ini.h
@@ -0,0 +1,53 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Support
+ * 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/>.
+ */
+
+struct keyval_pair {
+ const char *key;
+ const char *val;
+};
+
+struct gp_inifile_context {
+ TALLOC_CTX *mem_ctx;
+ uint32_t keyval_count;
+ struct keyval_pair **data;
+ char *current_section;
+ const char *generated_filename;
+};
+
+/* prototypes */
+
+NTSTATUS gp_inifile_init_context(TALLOC_CTX *mem_ctx, uint32_t flags,
+ const char *unix_path, const char *suffix,
+ struct gp_inifile_context **ctx_ret);
+NTSTATUS gp_inifile_init_context_direct(TALLOC_CTX *mem_ctx,
+ const char *unix_path,
+ struct gp_inifile_context **ctx_ret);
+NTSTATUS parse_gpt_ini(TALLOC_CTX *ctx,
+ const char *filename,
+ uint32_t *version,
+ char **display_name);
+NTSTATUS gp_inifile_getstring(struct gp_inifile_context *ctx, const char *key, const char **ret);
+NTSTATUS gp_inifile_getint(struct gp_inifile_context *ctx, const char *key, int *ret);
+NTSTATUS gp_inifile_getbool(struct gp_inifile_context *ctx, const char *key, bool *ret);
+
+NTSTATUS gp_inifile_enum_section(struct gp_inifile_context *ctx,
+ const char *section,
+ size_t *num_ini_keys,
+ const char ***ini_keys,
+ const char ***ini_values);
diff --git a/libgpo/gpo_ldap.c b/libgpo/gpo_ldap.c
new file mode 100644
index 0000000..2d95f74
--- /dev/null
+++ b/libgpo/gpo_ldap.c
@@ -0,0 +1,956 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 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 "libgpo/gpo.h"
+#include "auth.h"
+#include "../libcli/security/security.h"
+
+/****************************************************************
+ parse the raw extension string into a GP_EXT structure
+****************************************************************/
+
+bool ads_parse_gp_ext(TALLOC_CTX *mem_ctx,
+ const char *extension_raw,
+ struct GP_EXT **gp_ext)
+{
+ bool ret = false;
+ struct GP_EXT *ext = NULL;
+ char **ext_list = NULL;
+ char **ext_strings = NULL;
+ int i;
+
+ if (!extension_raw) {
+ goto parse_error;
+ }
+
+ DEBUG(20,("ads_parse_gp_ext: %s\n", extension_raw));
+
+ ext = talloc_zero(mem_ctx, struct GP_EXT);
+ if (!ext) {
+ goto parse_error;
+ }
+
+ ext_list = str_list_make(mem_ctx, extension_raw, "]");
+ if (!ext_list) {
+ goto parse_error;
+ }
+
+ for (i = 0; ext_list[i] != NULL; i++) {
+ /* no op */
+ }
+
+ ext->num_exts = i;
+
+ if (ext->num_exts) {
+ ext->extensions = talloc_zero_array(mem_ctx, char *,
+ ext->num_exts);
+ ext->extensions_guid = talloc_zero_array(mem_ctx, char *,
+ ext->num_exts);
+ ext->snapins = talloc_zero_array(mem_ctx, char *,
+ ext->num_exts);
+ ext->snapins_guid = talloc_zero_array(mem_ctx, char *,
+ ext->num_exts);
+ }
+
+ ext->gp_extension = talloc_strdup(mem_ctx, extension_raw);
+
+ if (!ext->extensions || !ext->extensions_guid ||
+ !ext->snapins || !ext->snapins_guid ||
+ !ext->gp_extension) {
+ goto parse_error;
+ }
+
+ for (i = 0; ext_list[i] != NULL; i++) {
+
+ int k;
+ char *p, *q;
+
+ DEBUGADD(10,("extension #%d\n", i));
+
+ p = ext_list[i];
+
+ if (p[0] == '[') {
+ p++;
+ }
+
+ ext_strings = str_list_make(mem_ctx, p, "}");
+ if (ext_strings == NULL) {
+ goto parse_error;
+ }
+
+ for (k = 0; ext_strings[k] != NULL; k++) {
+ /* no op */
+ }
+ if (k == 0) {
+ goto parse_error;
+ }
+ q = ext_strings[0];
+
+ if (q[0] == '{') {
+ q++;
+ }
+
+ ext->extensions[i] = talloc_strdup(mem_ctx,
+ cse_gpo_guid_string_to_name(q));
+ ext->extensions_guid[i] = talloc_strdup(mem_ctx, q);
+
+ /* we might have no name for the guid */
+ if (ext->extensions_guid[i] == NULL) {
+ goto parse_error;
+ }
+
+ for (k = 1; ext_strings[k] != NULL; k++) {
+
+ char *m = ext_strings[k];
+
+ if (m[0] == '{') {
+ m++;
+ }
+
+ /* FIXME: theoretically there could be more than one
+ * snapin per extension */
+ ext->snapins[i] = talloc_strdup(mem_ctx,
+ cse_snapin_gpo_guid_string_to_name(m));
+ ext->snapins_guid[i] = talloc_strdup(mem_ctx, m);
+
+ /* we might have no name for the guid */
+ if (ext->snapins_guid[i] == NULL) {
+ goto parse_error;
+ }
+ }
+ }
+
+ *gp_ext = ext;
+
+ ret = true;
+
+ parse_error:
+ talloc_free(ext_list);
+ talloc_free(ext_strings);
+
+ return ret;
+}
+
+#ifdef HAVE_LDAP
+
+/****************************************************************
+ parse the raw link string into a GP_LINK structure
+****************************************************************/
+
+static ADS_STATUS gpo_parse_gplink(TALLOC_CTX *mem_ctx,
+ const char *gp_link_raw,
+ uint32_t options,
+ struct GP_LINK *gp_link)
+{
+ ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ char **link_list;
+ int i;
+
+ ZERO_STRUCTP(gp_link);
+
+ DEBUG(10,("gpo_parse_gplink: gPLink: %s\n", gp_link_raw));
+
+ link_list = str_list_make_v3(mem_ctx, gp_link_raw, "]");
+ if (!link_list) {
+ goto parse_error;
+ }
+
+ for (i = 0; link_list[i] != NULL; i++) {
+ /* no op */
+ }
+
+ gp_link->gp_opts = options;
+ gp_link->num_links = i;
+
+ if (gp_link->num_links) {
+ gp_link->link_names = talloc_zero_array(mem_ctx, char *,
+ gp_link->num_links);
+ gp_link->link_opts = talloc_zero_array(mem_ctx, uint32_t,
+ gp_link->num_links);
+ }
+
+ gp_link->gp_link = talloc_strdup(mem_ctx, gp_link_raw);
+
+ if (!gp_link->link_names || !gp_link->link_opts || !gp_link->gp_link) {
+ goto parse_error;
+ }
+
+ for (i = 0; link_list[i] != NULL; i++) {
+
+ char *p, *q;
+
+ DEBUGADD(10,("gpo_parse_gplink: processing link #%d\n", i));
+
+ q = link_list[i];
+ if (q[0] == '[') {
+ q++;
+ };
+
+ p = strchr(q, ';');
+
+ if (p == NULL) {
+ goto parse_error;
+ }
+
+ gp_link->link_names[i] = talloc_strdup(mem_ctx, q);
+ if (gp_link->link_names[i] == NULL) {
+ goto parse_error;
+ }
+ gp_link->link_names[i][PTR_DIFF(p, q)] = 0;
+
+ gp_link->link_opts[i] = atoi(p + 1);
+
+ DEBUGADD(10,("gpo_parse_gplink: link: %s\n",
+ gp_link->link_names[i]));
+ DEBUGADD(10,("gpo_parse_gplink: opt: %d\n",
+ gp_link->link_opts[i]));
+
+ }
+
+ status = ADS_SUCCESS;
+
+ parse_error:
+ talloc_free(link_list);
+
+ return status;
+}
+
+/****************************************************************
+ helper call to get a GP_LINK structure from a linkdn
+****************************************************************/
+
+ADS_STATUS ads_get_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ struct GP_LINK *gp_link_struct)
+{
+ ADS_STATUS status;
+ const char *attrs[] = {"gPLink", "gPOptions", NULL};
+ LDAPMessage *res = NULL;
+ const char *gp_link;
+ uint32_t gp_options;
+
+ ZERO_STRUCTP(gp_link_struct);
+
+ status = ads_search_dn(ads, &res, link_dn, attrs);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_get_gpo_link: search failed with %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ DEBUG(10,("ads_get_gpo_link: no result\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink");
+ if (gp_link == NULL) {
+ DEBUG(10,("ads_get_gpo_link: no 'gPLink' attribute found\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ /* perfectly legal to have no options */
+ if (!ads_pull_uint32(ads, res, "gPOptions", &gp_options)) {
+ DEBUG(10,("ads_get_gpo_link: "
+ "no 'gPOptions' attribute found\n"));
+ gp_options = 0;
+ }
+
+ ads_msgfree(ads, res);
+
+ return gpo_parse_gplink(mem_ctx, gp_link, gp_options, gp_link_struct);
+}
+
+/****************************************************************
+ helper call to add a gp link
+****************************************************************/
+
+ADS_STATUS ads_add_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ const char *gpo_dn,
+ uint32_t gpo_opt)
+{
+ ADS_STATUS status;
+ const char *attrs[] = {"gPLink", NULL};
+ LDAPMessage *res = NULL;
+ const char *gp_link, *gp_link_new;
+ ADS_MODLIST mods;
+
+ /* although ADS allows one to set anything here, we better check here if
+ * the gpo_dn is sane */
+
+ if (!strnequal(gpo_dn, "LDAP://CN={", strlen("LDAP://CN={")) != 0) {
+ return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ status = ads_search_dn(ads, &res, link_dn, attrs);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_add_gpo_link: search failed with %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ DEBUG(10,("ads_add_gpo_link: no result\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink");
+ if (gp_link == NULL) {
+ gp_link_new = talloc_asprintf(mem_ctx, "[%s;%d]",
+ gpo_dn, gpo_opt);
+ } else {
+ gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]",
+ gp_link, gpo_dn, gpo_opt);
+ }
+
+ ads_msgfree(ads, res);
+ ADS_ERROR_HAVE_NO_MEMORY(gp_link_new);
+
+ mods = ads_init_mods(mem_ctx);
+ ADS_ERROR_HAVE_NO_MEMORY(mods);
+
+ status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ return ads_gen_mod(ads, link_dn, mods);
+}
+
+/****************************************************************
+ helper call to delete add a gp link
+****************************************************************/
+
+/* untested & broken */
+ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *link_dn,
+ const char *gpo_dn)
+{
+ ADS_STATUS status;
+ const char *attrs[] = {"gPLink", NULL};
+ LDAPMessage *res = NULL;
+ const char *gp_link, *gp_link_new = NULL;
+ ADS_MODLIST mods;
+
+ /* check for a sane gpo_dn */
+ if (gpo_dn[0] != '[') {
+ DEBUG(10,("ads_delete_gpo_link: first char not: [\n"));
+ return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ if (gpo_dn[strlen(gpo_dn)] != ']') {
+ DEBUG(10,("ads_delete_gpo_link: last char not: ]\n"));
+ return ADS_ERROR(LDAP_INVALID_DN_SYNTAX);
+ }
+
+ status = ads_search_dn(ads, &res, link_dn, attrs);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_delete_gpo_link: search failed with %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ DEBUG(10,("ads_delete_gpo_link: no result\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ gp_link = ads_pull_string(ads, mem_ctx, res, "gPLink");
+ if (gp_link == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ /* find link to delete */
+ /* gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", gp_link,
+ gpo_dn, gpo_opt); */
+
+ ads_msgfree(ads, res);
+ ADS_ERROR_HAVE_NO_MEMORY(gp_link_new);
+
+ mods = ads_init_mods(mem_ctx);
+ ADS_ERROR_HAVE_NO_MEMORY(mods);
+
+ status = ads_mod_str(mem_ctx, &mods, "gPLink", gp_link_new);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ return ads_gen_mod(ads, link_dn, mods);
+}
+
+/****************************************************************
+ parse a GROUP_POLICY_OBJECT structure from an LDAPMessage result
+****************************************************************/
+
+ ADS_STATUS ads_parse_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ LDAPMessage *res,
+ const char *gpo_dn,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ ZERO_STRUCTP(gpo);
+
+ ADS_ERROR_HAVE_NO_MEMORY(res);
+
+ if (gpo_dn) {
+ gpo->ds_path = talloc_strdup(mem_ctx, gpo_dn);
+ } else {
+ gpo->ds_path = ads_get_dn(ads, mem_ctx, res);
+ }
+
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->ds_path);
+
+ if (!ads_pull_uint32(ads, res, "versionNumber", &gpo->version)) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ if (!ads_pull_uint32(ads, res, "flags", &gpo->options)) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ gpo->file_sys_path = ads_pull_string(ads, mem_ctx, res,
+ "gPCFileSysPath");
+ if (gpo->file_sys_path == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ gpo->display_name = ads_pull_string(ads, mem_ctx, res,
+ "displayName");
+ if (gpo->display_name == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ gpo->name = ads_pull_string(ads, mem_ctx, res,
+ "name");
+ if (gpo->name == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ gpo->machine_extensions = ads_pull_string(ads, mem_ctx, res,
+ "gPCMachineExtensionNames");
+ gpo->user_extensions = ads_pull_string(ads, mem_ctx, res,
+ "gPCUserExtensionNames");
+
+ ads_pull_sd(ads, mem_ctx, res, "ntSecurityDescriptor",
+ &gpo->security_descriptor);
+ if (gpo->security_descriptor == NULL) {
+ return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ }
+
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+/****************************************************************
+ get a GROUP_POLICY_OBJECT structure based on different input parameters
+****************************************************************/
+
+ADS_STATUS ads_get_gpo(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *gpo_dn,
+ const char *display_name,
+ const char *guid_name,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ ADS_STATUS status = ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ LDAPMessage *res = NULL;
+ char *dn;
+ const char *filter;
+ const char *attrs[] = {
+ "cn",
+ "displayName",
+ "flags",
+ "gPCFileSysPath",
+ "gPCFunctionalityVersion",
+ "gPCMachineExtensionNames",
+ "gPCUserExtensionNames",
+ "gPCWQLFilter",
+ "name",
+ "ntSecurityDescriptor",
+ "versionNumber",
+ NULL};
+ uint32_t sd_flags = SECINFO_DACL;
+
+ ZERO_STRUCTP(gpo);
+
+ if (!gpo_dn && !display_name && !guid_name) {
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ if (gpo_dn) {
+
+ if (strnequal(gpo_dn, "LDAP://", strlen("LDAP://")) != 0) {
+ gpo_dn = gpo_dn + strlen("LDAP://");
+ }
+
+ status = ads_search_retry_dn_sd_flags(ads, &res,
+ sd_flags,
+ gpo_dn, attrs);
+
+ } else if (display_name || guid_name) {
+
+ filter = talloc_asprintf(mem_ctx,
+ "(&(objectclass=groupPolicyContainer)(%s=%s))",
+ display_name ? "displayName" : "name",
+ display_name ? display_name : guid_name);
+ ADS_ERROR_HAVE_NO_MEMORY(filter);
+
+ status = ads_do_search_all_sd_flags(ads, ads->config.bind_path,
+ LDAP_SCOPE_SUBTREE, filter,
+ attrs, sd_flags, &res);
+ }
+
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("ads_get_gpo: search failed with %s\n",
+ ads_errstr(status)));
+ return status;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ DEBUG(10,("ads_get_gpo: no result\n"));
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
+ }
+
+ dn = ads_get_dn(ads, mem_ctx, res);
+ if (dn == NULL) {
+ ads_msgfree(ads, res);
+ return ADS_ERROR(LDAP_NO_MEMORY);
+ }
+
+ status = ads_parse_gpo(ads, mem_ctx, res, dn, gpo);
+ ads_msgfree(ads, res);
+ TALLOC_FREE(dn);
+
+ return status;
+}
+
+/****************************************************************
+ add a gplink to the GROUP_POLICY_OBJECT linked list
+****************************************************************/
+
+static ADS_STATUS add_gplink_to_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT **gpo_list,
+ struct GROUP_POLICY_OBJECT **forced_gpo_list,
+ const char *link_dn,
+ struct GP_LINK *gp_link,
+ enum GPO_LINK_TYPE link_type,
+ bool only_add_forced_gpos,
+ const struct security_token *token)
+{
+ ADS_STATUS status;
+ uint32_t count;
+
+ /*
+ * Note: DLIST_ADD pushes to the front,
+ * so loop from last to first to get the
+ * order right.
+ */
+ for (count = gp_link->num_links; count > 0; count--) {
+ /* NB. Index into arrays is one less than counter. */
+ uint32_t i = count - 1;
+ struct GROUP_POLICY_OBJECT **target_list = NULL;
+ struct GROUP_POLICY_OBJECT *new_gpo = NULL;
+ bool is_forced =
+ (gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED) != 0;
+
+ if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) {
+ DEBUG(10,("skipping disabled GPO\n"));
+ continue;
+ }
+
+ if (only_add_forced_gpos) {
+
+ if (!is_forced) {
+ DEBUG(10,("skipping nonenforced GPO link "
+ "because GPOPTIONS_BLOCK_INHERITANCE "
+ "has been set\n"));
+ continue;
+ } else {
+ DEBUG(10,("adding enforced GPO link although "
+ "the GPOPTIONS_BLOCK_INHERITANCE "
+ "has been set\n"));
+ }
+ }
+
+ new_gpo = talloc_zero(mem_ctx, struct GROUP_POLICY_OBJECT);
+ ADS_ERROR_HAVE_NO_MEMORY(new_gpo);
+
+ status = ads_get_gpo(ads, mem_ctx, gp_link->link_names[i],
+ NULL, NULL, new_gpo);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("failed to get gpo: %s\n",
+ gp_link->link_names[i]));
+ if ((status.error_type == ENUM_ADS_ERROR_LDAP) &&
+ (status.err.rc == LDAP_NO_SUCH_ATTRIBUTE)) {
+ DEBUG(10,("skipping empty gpo: %s\n",
+ gp_link->link_names[i]));
+ talloc_free(new_gpo);
+ continue;
+ }
+ return status;
+ }
+
+ status = ADS_ERROR_NT(gpo_apply_security_filtering(new_gpo,
+ token));
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(10,("skipping GPO \"%s\" as object "
+ "has no access to it\n",
+ new_gpo->display_name));
+ talloc_free(new_gpo);
+ continue;
+ }
+
+ new_gpo->link = link_dn;
+ new_gpo->link_type = link_type;
+
+ target_list = is_forced ? forced_gpo_list : gpo_list;
+ DLIST_ADD(*target_list, new_gpo);
+
+ DEBUG(10,("add_gplink_to_gplist: added GPLINK #%d %s "
+ "to GPO list\n", i, gp_link->link_names[i]));
+ }
+
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+/****************************************************************
+****************************************************************/
+
+ADS_STATUS ads_get_sid_token(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ struct security_token **token)
+{
+ ADS_STATUS status;
+ struct dom_sid object_sid;
+ struct dom_sid primary_group_sid;
+ struct dom_sid *ad_token_sids;
+ size_t num_ad_token_sids = 0;
+ struct dom_sid *token_sids;
+ uint32_t num_token_sids = 0;
+ struct security_token *new_token = NULL;
+ int i;
+
+ status = ads_get_tokensids(ads, mem_ctx, dn,
+ &object_sid, &primary_group_sid,
+ &ad_token_sids, &num_ad_token_sids);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ token_sids = talloc_array(mem_ctx, struct dom_sid, 1);
+ ADS_ERROR_HAVE_NO_MEMORY(token_sids);
+
+ status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx,
+ &primary_group_sid,
+ &token_sids,
+ &num_token_sids));
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ for (i = 0; i < num_ad_token_sids; i++) {
+
+ if (sid_check_is_in_builtin(&ad_token_sids[i])) {
+ continue;
+ }
+
+ status = ADS_ERROR_NT(add_sid_to_array_unique(mem_ctx,
+ &ad_token_sids[i],
+ &token_sids,
+ &num_token_sids));
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ }
+
+ status = ADS_ERROR_NT(create_local_nt_token(mem_ctx,
+ &object_sid, false,
+ num_token_sids, token_sids, &new_token));
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ *token = new_token;
+
+ security_token_debug(DBGC_CLASS, 5, *token);
+
+ return ADS_ERROR_LDAP(LDAP_SUCCESS);
+}
+
+/****************************************************************
+****************************************************************/
+
+static ADS_STATUS add_local_policy_to_gpo_list(TALLOC_CTX *mem_ctx,
+ struct GROUP_POLICY_OBJECT **gpo_list,
+ enum GPO_LINK_TYPE link_type)
+{
+ struct GROUP_POLICY_OBJECT *gpo = NULL;
+
+ ADS_ERROR_HAVE_NO_MEMORY(gpo_list);
+
+ gpo = talloc_zero(mem_ctx, struct GROUP_POLICY_OBJECT);
+ ADS_ERROR_HAVE_NO_MEMORY(gpo);
+
+ gpo->name = talloc_strdup(mem_ctx, "Local Policy");
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->name);
+
+ gpo->display_name = talloc_strdup(mem_ctx, "Local Policy");
+ ADS_ERROR_HAVE_NO_MEMORY(gpo->display_name);
+
+ gpo->link_type = link_type;
+
+ DLIST_ADD(*gpo_list, gpo);
+
+ return ADS_ERROR_NT(NT_STATUS_OK);
+}
+
+/****************************************************************
+ Get the full list of GROUP_POLICY_OBJECTs for a given dn.
+****************************************************************/
+
+static ADS_STATUS ads_get_gpo_list_internal(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ uint32_t flags,
+ const struct security_token *token,
+ struct GROUP_POLICY_OBJECT **gpo_list,
+ struct GROUP_POLICY_OBJECT **forced_gpo_list)
+{
+ /*
+ * Push GPOs to gpo_list so that the traversal order of the list matches
+ * the order of application:
+ * (L)ocal (S)ite (D)omain (O)rganizational(U)nit
+ * For different domains and OUs: parent-to-child.
+ * Within same level of domains and OUs: Link order.
+ * Since GPOs are pushed to the front of gpo_list, GPOs have to be
+ * pushed in the opposite order of application (OUs first, local last,
+ * child-to-parent).
+ * Forced GPOs are appended in the end since they override all others.
+ */
+
+ ADS_STATUS status;
+ struct GP_LINK gp_link;
+ const char *parent_dn, *site_dn, *tmp_dn;
+ bool add_only_forced_gpos = false;
+
+ ZERO_STRUCTP(gpo_list);
+ ZERO_STRUCTP(forced_gpo_list);
+
+ if (!dn) {
+ return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+ }
+
+ if (!ads_set_sasl_wrap_flags(ads, ADS_AUTH_SASL_SIGN)) {
+ return ADS_ERROR(LDAP_INVALID_CREDENTIALS);
+ }
+
+ DEBUG(10,("ads_get_gpo_list: getting GPO list for [%s]\n", dn));
+
+ tmp_dn = dn;
+
+ while ((parent_dn = ads_parent_dn(tmp_dn)) &&
+ (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) {
+
+
+ /* (O)rganizational(U)nit */
+
+ /* An account can be a member of more OUs */
+ if (strncmp(parent_dn, "OU=", strlen("OU=")) == 0) {
+
+ DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n",
+ parent_dn));
+
+ status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
+ &gp_link);
+ if (ADS_ERR_OK(status)) {
+
+ if (DEBUGLEVEL >= 100) {
+ dump_gplink(&gp_link);
+ }
+
+ status = add_gplink_to_gpo_list(ads,
+ mem_ctx,
+ gpo_list,
+ forced_gpo_list,
+ parent_dn,
+ &gp_link,
+ GP_LINK_OU,
+ add_only_forced_gpos,
+ token);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ /* block inheritance from now on */
+ if (gp_link.gp_opts &
+ GPOPTIONS_BLOCK_INHERITANCE) {
+ add_only_forced_gpos = true;
+ }
+ }
+ }
+
+ tmp_dn = parent_dn;
+
+ }
+
+ /* reset dn again */
+ tmp_dn = dn;
+
+ while ((parent_dn = ads_parent_dn(tmp_dn)) &&
+ (!strequal(parent_dn, ads_parent_dn(ads->config.bind_path)))) {
+
+ /* (D)omain */
+
+ /* An account can just be a member of one domain */
+ if (strncmp(parent_dn, "DC=", strlen("DC=")) == 0) {
+
+ DEBUG(10,("ads_get_gpo_list: query DC: [%s] for GPOs\n",
+ parent_dn));
+
+ status = ads_get_gpo_link(ads, mem_ctx, parent_dn,
+ &gp_link);
+ if (ADS_ERR_OK(status)) {
+
+ if (DEBUGLEVEL >= 100) {
+ dump_gplink(&gp_link);
+ }
+
+ status = add_gplink_to_gpo_list(ads,
+ mem_ctx,
+ gpo_list,
+ forced_gpo_list,
+ parent_dn,
+ &gp_link,
+ GP_LINK_DOMAIN,
+ add_only_forced_gpos,
+ token);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ /* block inheritance from now on */
+ if (gp_link.gp_opts &
+ GPOPTIONS_BLOCK_INHERITANCE) {
+ add_only_forced_gpos = true;
+ }
+ }
+ }
+
+ tmp_dn = parent_dn;
+ }
+
+ /* (S)ite */
+
+ /* are site GPOs valid for users as well ??? */
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+
+ status = ads_site_dn_for_machine(ads, mem_ctx,
+ ads->config.ldap_server_name,
+ &site_dn);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n",
+ site_dn));
+
+ status = ads_get_gpo_link(ads, mem_ctx, site_dn, &gp_link);
+ if (ADS_ERR_OK(status)) {
+
+ if (DEBUGLEVEL >= 100) {
+ dump_gplink(&gp_link);
+ }
+
+ status = add_gplink_to_gpo_list(ads,
+ mem_ctx,
+ gpo_list,
+ forced_gpo_list,
+ site_dn,
+ &gp_link,
+ GP_LINK_SITE,
+ add_only_forced_gpos,
+ token);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ if (flags & GPO_LIST_FLAG_SITEONLY) {
+ return ADS_ERROR(LDAP_SUCCESS);
+ }
+
+ /* inheritance can't be blocked at the site level */
+ }
+ }
+
+ /* (L)ocal */
+ status = add_local_policy_to_gpo_list(mem_ctx, gpo_list,
+ GP_LINK_LOCAL);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+/****************************************************************
+ Get the full list of GROUP_POLICY_OBJECTs for a given dn, wrapper
+ around ads_get_gpo_list_internal() that ensures correct ordering.
+****************************************************************/
+
+ADS_STATUS ads_get_gpo_list(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ uint32_t flags,
+ const struct security_token *token,
+ struct GROUP_POLICY_OBJECT **gpo_list)
+{
+ struct GROUP_POLICY_OBJECT *forced_gpo_list = NULL;
+ ADS_STATUS status;
+
+ status = ads_get_gpo_list_internal(ads,
+ mem_ctx,
+ dn,
+ flags,
+ token,
+ gpo_list,
+ &forced_gpo_list);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ /*
+ * Append |forced_gpo_list| at the end of |gpo_list|,
+ * so that forced GPOs are applied on top of non enforced GPOs.
+ */
+ DLIST_CONCATENATE(*gpo_list, forced_gpo_list);
+
+ return ADS_ERROR(LDAP_SUCCESS);
+}
+
+#endif /* HAVE_LDAP */
diff --git a/libgpo/gpo_proto.h b/libgpo/gpo_proto.h
new file mode 100644
index 0000000..32a61ea
--- /dev/null
+++ b/libgpo/gpo_proto.h
@@ -0,0 +1,94 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ *
+ * Copyright (C) Guenther Deschner 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/>.
+ */
+
+#ifndef _LIBGPO_GPO_PROTO_H_
+#define _LIBGPO_GPO_PROTO_H_
+
+/* The following definitions come from libgpo/gpo_filesync.c */
+
+NTSTATUS gpo_copy_file(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const char *nt_path,
+ const char *unix_path);
+NTSTATUS gpo_sync_directories(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ const char *nt_path,
+ const char *local_path);
+
+/* The following definitions come from libgpo/gpo_reg.c */
+
+struct security_token *registry_create_system_token(TALLOC_CTX *mem_ctx);
+WERROR gp_init_reg_ctx(TALLOC_CTX *mem_ctx,
+ const char *initial_path,
+ uint32_t desired_access,
+ const struct security_token *token,
+ struct gp_registry_context **reg_ctx);
+void gp_free_reg_ctx(struct gp_registry_context *reg_ctx);
+WERROR gp_store_reg_subkey(TALLOC_CTX *mem_ctx,
+ const char *subkeyname,
+ struct registry_key *curr_key,
+ struct registry_key **new_key);
+WERROR gp_read_reg_subkey(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ const char *subkeyname,
+ struct registry_key **key);
+WERROR gp_store_reg_val_sz(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ const char *val);
+WERROR gp_read_reg_val_sz(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ const char **val);
+WERROR gp_reg_state_store(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *dn,
+ const struct security_token *token,
+ struct GROUP_POLICY_OBJECT *gpo_list);
+WERROR gp_reg_state_read(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct dom_sid *sid,
+ struct GROUP_POLICY_OBJECT **gpo_list);
+WERROR gp_secure_key(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct registry_key *key,
+ const struct dom_sid *sid);
+void dump_reg_val(int lvl, const char *direction,
+ const char *key, const char *subkey,
+ struct registry_value *val);
+void dump_reg_entry(uint32_t flags,
+ const char *dir,
+ struct gp_registry_entry *entry);
+void dump_reg_entries(uint32_t flags,
+ const char *dir,
+ struct gp_registry_entry *entries,
+ size_t num_entries);
+bool add_gp_registry_entry_to_array(TALLOC_CTX *mem_ctx,
+ struct gp_registry_entry *entry,
+ struct gp_registry_entry **entries,
+ size_t *num);
+WERROR reg_apply_registry_entry(TALLOC_CTX *mem_ctx,
+ struct registry_key *root_key,
+ struct gp_registry_context *reg_ctx,
+ struct gp_registry_entry *entry,
+ const struct security_token *token,
+ uint32_t flags);
+
+#endif /* _LIBGPO_GPO_PROTO_H_ */
diff --git a/libgpo/gpo_reg.c b/libgpo/gpo_reg.c
new file mode 100644
index 0000000..a1a8d7d
--- /dev/null
+++ b/libgpo/gpo_reg.c
@@ -0,0 +1,1047 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 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 "../libgpo/gpo.h"
+#include "libgpo/gpo_proto.h"
+#include "registry.h"
+#include "registry/reg_api.h"
+#include "registry/reg_backend_db.h"
+#include "registry/reg_api_util.h"
+#include "registry/reg_init_basic.h"
+#include "../libcli/security/security.h"
+#include "libcli/security/dom_sid.h"
+#include "../libcli/registry/util_reg.h"
+
+
+/****************************************************************
+****************************************************************/
+
+struct security_token *registry_create_system_token(TALLOC_CTX *mem_ctx)
+{
+ const struct security_token *system_token = get_system_token();
+
+ struct security_token *dup_token
+ = security_token_duplicate(mem_ctx, system_token);
+
+ if (dup_token == NULL) {
+ DBG_WARNING("security_token_duplicate() failed\n");
+ return NULL;
+ }
+
+ return dup_token;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_init_reg_ctx(TALLOC_CTX *mem_ctx,
+ const char *initial_path,
+ uint32_t desired_access,
+ const struct security_token *token,
+ struct gp_registry_context **reg_ctx)
+{
+ struct gp_registry_context *tmp_ctx;
+ WERROR werr;
+
+ if (!reg_ctx) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ werr = registry_init_basic();
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ tmp_ctx = talloc_zero(mem_ctx, struct gp_registry_context);
+ W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
+
+ if (token) {
+ tmp_ctx->token = token;
+ } else {
+ tmp_ctx->token = registry_create_system_token(mem_ctx);
+ }
+ if (!tmp_ctx->token) {
+ TALLOC_FREE(tmp_ctx);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ werr = regdb_open();
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ if (initial_path) {
+ tmp_ctx->path = talloc_strdup(mem_ctx, initial_path);
+ if (!tmp_ctx->path) {
+ TALLOC_FREE(tmp_ctx);
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ werr = reg_open_path(mem_ctx, tmp_ctx->path, desired_access,
+ tmp_ctx->token, &tmp_ctx->curr_key);
+ if (!W_ERROR_IS_OK(werr)) {
+ TALLOC_FREE(tmp_ctx);
+ return werr;
+ }
+ }
+
+ *reg_ctx = tmp_ctx;
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+void gp_free_reg_ctx(struct gp_registry_context *reg_ctx)
+{
+ TALLOC_FREE(reg_ctx);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_store_reg_subkey(TALLOC_CTX *mem_ctx,
+ const char *subkeyname,
+ struct registry_key *curr_key,
+ struct registry_key **new_key)
+{
+ enum winreg_CreateAction action = REG_ACTION_NONE;
+ WERROR werr;
+
+ werr = reg_createkey(mem_ctx, curr_key, subkeyname,
+ REG_KEY_WRITE, new_key, &action);
+ if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) {
+ return WERR_OK;
+ }
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_read_reg_subkey(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ const char *subkeyname,
+ struct registry_key **key)
+{
+ const char *tmp = NULL;
+
+ if (!reg_ctx || !subkeyname || !key) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ tmp = talloc_asprintf(mem_ctx, "%s\\%s", reg_ctx->path, subkeyname);
+ W_ERROR_HAVE_NO_MEMORY(tmp);
+
+ return reg_open_path(mem_ctx, tmp, REG_KEY_READ,
+ reg_ctx->token, key);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_store_reg_val_sz(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ const char *val)
+{
+ struct registry_value reg_val;
+
+ reg_val.type = REG_SZ;
+ if (!push_reg_sz(mem_ctx, &reg_val.data, val)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ return reg_setvalue(key, val_name, &reg_val);
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_store_reg_val_dword(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ uint32_t val)
+{
+ struct registry_value reg_val;
+
+ reg_val.type = REG_DWORD;
+ reg_val.data = data_blob_talloc(mem_ctx, NULL, 4);
+ SIVAL(reg_val.data.data, 0, val);
+
+ return reg_setvalue(key, val_name, &reg_val);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_read_reg_val_sz(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ const char **val)
+{
+ WERROR werr;
+ struct registry_value *reg_val = NULL;
+
+ werr = reg_queryvalue(mem_ctx, key, val_name, &reg_val);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (reg_val->type != REG_SZ) {
+ return WERR_INVALID_DATATYPE;
+ }
+
+ if (!pull_reg_sz(mem_ctx, &reg_val->data, val)) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_read_reg_val_dword(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *val_name,
+ uint32_t *val)
+{
+ WERROR werr;
+ struct registry_value *reg_val = NULL;
+
+ werr = reg_queryvalue(mem_ctx, key, val_name, &reg_val);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (reg_val->type != REG_DWORD) {
+ return WERR_INVALID_DATATYPE;
+ }
+
+ if (reg_val->data.length < 4) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+ *val = IVAL(reg_val->data.data, 0);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_store_reg_gpovals(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ WERROR werr;
+
+ if (!key || !gpo) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "Version",
+ gpo->version);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "WQLFilterPass",
+ true); /* fake */
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "AccessDenied",
+ false); /* fake */
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "GPO-Disabled",
+ (gpo->options & GPO_FLAG_DISABLE));
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "Options",
+ gpo->options);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "GPOID",
+ gpo->name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "SOM",
+ gpo->link ? gpo->link : "");
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "DisplayName",
+ gpo->display_name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_store_reg_val_sz(mem_ctx, key, "WQL-Id",
+ "");
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *gp_reg_groupmembership_path(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid,
+ uint32_t flags)
+{
+ struct dom_sid_buf sidbuf;
+
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+ return "GroupMembership";
+ }
+
+ return talloc_asprintf(
+ mem_ctx,
+ "%s\\%s",
+ dom_sid_str_buf(sid, &sidbuf),
+ "GroupMembership");
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_reg_del_groupmembership(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const struct security_token *token,
+ uint32_t flags)
+{
+ const char *path = NULL;
+
+ path = gp_reg_groupmembership_path(mem_ctx, &token->sids[PRIMARY_USER_SID_INDEX],
+ flags);
+ W_ERROR_HAVE_NO_MEMORY(path);
+
+ return reg_deletekey_recursive(key, path);
+
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_reg_store_groupmembership(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ const struct security_token *token,
+ uint32_t flags)
+{
+ struct registry_key *key = NULL;
+ WERROR werr;
+ uint32_t i = 0;
+ const char *valname = NULL;
+ const char *path = NULL;
+ int count = 0;
+
+ path = gp_reg_groupmembership_path(mem_ctx, &token->sids[PRIMARY_USER_SID_INDEX],
+ flags);
+ W_ERROR_HAVE_NO_MEMORY(path);
+
+ gp_reg_del_groupmembership(mem_ctx, reg_ctx->curr_key, token, flags);
+
+ werr = gp_store_reg_subkey(mem_ctx, path,
+ reg_ctx->curr_key, &key);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ for (i=0; i<token->num_sids; i++) {
+ struct dom_sid_buf buf;
+
+ valname = talloc_asprintf(mem_ctx, "Group%d", count++);
+ W_ERROR_HAVE_NO_MEMORY(valname);
+
+ werr = gp_store_reg_val_sz(
+ mem_ctx,
+ key,
+ valname,
+ dom_sid_str_buf(&token->sids[i], &buf));
+ W_ERROR_NOT_OK_RETURN(werr);
+ }
+
+ werr = gp_store_reg_val_dword(mem_ctx, key, "Count", count);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+#if 0
+/* not used yet */
+static WERROR gp_reg_read_groupmembership(TALLOC_CTX *mem_ctx,
+ struct gp_registry_context *reg_ctx,
+ const struct dom_sid *object_sid,
+ struct security_token **token,
+ uint32_t flags)
+{
+ struct registry_key *key = NULL;
+ WERROR werr;
+ int i = 0;
+ const char *valname = NULL;
+ const char *val = NULL;
+ const char *path = NULL;
+ uint32_t count = 0;
+ int num_token_sids = 0;
+ struct security_token *tmp_token = NULL;
+
+ tmp_token = talloc_zero(mem_ctx, struct security_token);
+ W_ERROR_HAVE_NO_MEMORY(tmp_token);
+
+ path = gp_reg_groupmembership_path(mem_ctx, object_sid, flags);
+ W_ERROR_HAVE_NO_MEMORY(path);
+
+ werr = gp_read_reg_subkey(mem_ctx, reg_ctx, path, &key);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_dword(mem_ctx, key, "Count", &count);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ for (i=0; i<count; i++) {
+
+ valname = talloc_asprintf(mem_ctx, "Group%d", i);
+ W_ERROR_HAVE_NO_MEMORY(valname);
+
+ werr = gp_read_reg_val_sz(mem_ctx, key, valname, &val);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ if (!string_to_sid(&tmp_token->sids[num_token_sids++],
+ val)) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+ }
+
+ tmp_token->num_sids = num_token_sids;
+
+ *token = tmp_token;
+
+ return WERR_OK;
+}
+#endif
+/****************************************************************
+****************************************************************/
+
+static const char *gp_req_state_path(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid,
+ uint32_t flags)
+{
+ struct dom_sid_buf sidbuf;
+
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+ return GPO_REG_STATE_MACHINE;
+ }
+
+ return talloc_asprintf(
+ mem_ctx,
+ "%s\\%s",
+ "State",
+ dom_sid_str_buf(sid, &sidbuf));
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_del_reg_state(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ const char *path)
+{
+ return reg_deletesubkeys_recursive(key, path);
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_reg_state_store(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *dn,
+ const struct security_token *token,
+ struct GROUP_POLICY_OBJECT *gpo_list)
+{
+ struct gp_registry_context *reg_ctx = NULL;
+ WERROR werr = WERR_GEN_FAILURE;
+ const char *subkeyname = NULL;
+ struct GROUP_POLICY_OBJECT *gpo;
+ int count = 0;
+ struct registry_key *key;
+
+ werr = gp_init_reg_ctx(mem_ctx, KEY_GROUP_POLICY, REG_KEY_WRITE,
+ token, &reg_ctx);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_secure_key(mem_ctx, flags, reg_ctx->curr_key,
+ &token->sids[PRIMARY_USER_SID_INDEX]);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("failed to secure key: %s\n", win_errstr(werr)));
+ goto done;
+ }
+
+ werr = gp_reg_store_groupmembership(mem_ctx, reg_ctx, token, flags);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("failed to store group membership: %s\n", win_errstr(werr)));
+ goto done;
+ }
+
+ subkeyname = gp_req_state_path(mem_ctx, &token->sids[PRIMARY_USER_SID_INDEX], flags);
+ if (!subkeyname) {
+ werr = WERR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ werr = gp_del_reg_state(mem_ctx, reg_ctx->curr_key, subkeyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("failed to delete old state: %s\n", win_errstr(werr)));
+ /* goto done; */
+ }
+
+ werr = gp_store_reg_subkey(mem_ctx, subkeyname,
+ reg_ctx->curr_key, &reg_ctx->curr_key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = gp_store_reg_val_sz(mem_ctx, reg_ctx->curr_key,
+ "Distinguished-Name", dn);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ /* store link list */
+
+ werr = gp_store_reg_subkey(mem_ctx, "GPLink-List",
+ reg_ctx->curr_key, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ /* store gpo list */
+
+ werr = gp_store_reg_subkey(mem_ctx, "GPO-List",
+ reg_ctx->curr_key, &reg_ctx->curr_key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ for (gpo = gpo_list; gpo; gpo = gpo->next) {
+
+ subkeyname = talloc_asprintf(mem_ctx, "%d", count++);
+ if (!subkeyname) {
+ werr = WERR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ werr = gp_store_reg_subkey(mem_ctx, subkeyname,
+ reg_ctx->curr_key, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ werr = gp_store_reg_gpovals(mem_ctx, key, gpo);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("gp_reg_state_store: "
+ "gp_store_reg_gpovals failed for %s: %s\n",
+ gpo->display_name, win_errstr(werr)));
+ goto done;
+ }
+ }
+ done:
+ gp_free_reg_ctx(reg_ctx);
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_read_reg_gpovals(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ struct GROUP_POLICY_OBJECT *gpo)
+{
+ WERROR werr;
+
+ if (!key || !gpo) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ werr = gp_read_reg_val_dword(mem_ctx, key, "Version",
+ &gpo->version);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_dword(mem_ctx, key, "Options",
+ &gpo->options);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_sz(mem_ctx, key, "GPOID",
+ &gpo->name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_sz(mem_ctx, key, "SOM",
+ &gpo->link);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ werr = gp_read_reg_val_sz(mem_ctx, key, "DisplayName",
+ &gpo->display_name);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_read_reg_gpo(TALLOC_CTX *mem_ctx,
+ struct registry_key *key,
+ struct GROUP_POLICY_OBJECT **gpo_ret)
+{
+ struct GROUP_POLICY_OBJECT *gpo = NULL;
+ WERROR werr;
+
+ if (!gpo_ret || !key) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ gpo = talloc_zero(mem_ctx, struct GROUP_POLICY_OBJECT);
+ W_ERROR_HAVE_NO_MEMORY(gpo);
+
+ werr = gp_read_reg_gpovals(mem_ctx, key, gpo);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ *gpo_ret = gpo;
+
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_reg_state_read(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct dom_sid *sid,
+ struct GROUP_POLICY_OBJECT **gpo_list)
+{
+ struct gp_registry_context *reg_ctx = NULL;
+ WERROR werr = WERR_GEN_FAILURE;
+ const char *subkeyname = NULL;
+ struct GROUP_POLICY_OBJECT *gpo = NULL;
+ int count = 0;
+ struct registry_key *key = NULL;
+ const char *path = NULL;
+ const char *gp_state_path = NULL;
+
+ if (!gpo_list) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ ZERO_STRUCTP(gpo_list);
+
+ gp_state_path = gp_req_state_path(mem_ctx, sid, flags);
+ if (!gp_state_path) {
+ werr = WERR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ path = talloc_asprintf(mem_ctx, "%s\\%s\\%s",
+ KEY_GROUP_POLICY,
+ gp_state_path,
+ "GPO-List");
+ if (!path) {
+ werr = WERR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ werr = gp_init_reg_ctx(mem_ctx, path, REG_KEY_READ, NULL, &reg_ctx);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ while (1) {
+
+ subkeyname = talloc_asprintf(mem_ctx, "%d", count++);
+ if (!subkeyname) {
+ werr = WERR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ werr = gp_read_reg_subkey(mem_ctx, reg_ctx, subkeyname, &key);
+ if (W_ERROR_EQUAL(werr, WERR_FILE_NOT_FOUND)) {
+ werr = WERR_OK;
+ break;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("gp_reg_state_read: "
+ "gp_read_reg_subkey gave: %s\n",
+ win_errstr(werr)));
+ goto done;
+ }
+
+ werr = gp_read_reg_gpo(mem_ctx, key, &gpo);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ DLIST_ADD(*gpo_list, gpo);
+ }
+
+ done:
+ gp_free_reg_ctx(reg_ctx);
+ return werr;
+}
+
+/****************************************************************
+****************************************************************/
+
+static WERROR gp_reg_generate_sd(TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid,
+ struct security_descriptor **sd,
+ size_t *sd_size)
+{
+ struct security_ace ace[6];
+ uint32_t mask;
+
+ struct security_acl *theacl = NULL;
+
+ uint8_t inherit_flags;
+
+ mask = REG_KEY_ALL;
+ init_sec_ace(&ace[0],
+ &global_sid_System,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, 0);
+
+ mask = REG_KEY_ALL;
+ init_sec_ace(&ace[1],
+ &global_sid_Builtin_Administrators,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, 0);
+
+ mask = REG_KEY_READ;
+ init_sec_ace(&ace[2],
+ sid ? sid : &global_sid_Authenticated_Users,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, 0);
+
+ inherit_flags = SEC_ACE_FLAG_OBJECT_INHERIT |
+ SEC_ACE_FLAG_CONTAINER_INHERIT |
+ SEC_ACE_FLAG_INHERIT_ONLY;
+
+ mask = REG_KEY_ALL;
+ init_sec_ace(&ace[3],
+ &global_sid_System,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, inherit_flags);
+
+ mask = REG_KEY_ALL;
+ init_sec_ace(&ace[4],
+ &global_sid_Builtin_Administrators,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, inherit_flags);
+
+ mask = REG_KEY_READ;
+ init_sec_ace(&ace[5],
+ sid ? sid : &global_sid_Authenticated_Users,
+ SEC_ACE_TYPE_ACCESS_ALLOWED,
+ mask, inherit_flags);
+
+ theacl = make_sec_acl(mem_ctx, NT4_ACL_REVISION, 6, ace);
+ W_ERROR_HAVE_NO_MEMORY(theacl);
+
+ *sd = make_sec_desc(mem_ctx, SD_REVISION,
+ SEC_DESC_SELF_RELATIVE |
+ SEC_DESC_DACL_AUTO_INHERITED | /* really ? */
+ SEC_DESC_DACL_AUTO_INHERIT_REQ, /* really ? */
+ NULL, NULL, NULL,
+ theacl, sd_size);
+ W_ERROR_HAVE_NO_MEMORY(*sd);
+
+ return WERR_OK;
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR gp_secure_key(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ struct registry_key *key,
+ const struct dom_sid *sid)
+{
+ struct security_descriptor *sd = NULL;
+ size_t sd_size = 0;
+ const struct dom_sid *sd_sid = NULL;
+ WERROR werr;
+
+ if (!(flags & GPO_LIST_FLAG_MACHINE)) {
+ sd_sid = sid;
+ }
+
+ werr = gp_reg_generate_sd(mem_ctx, sd_sid, &sd, &sd_size);
+ W_ERROR_NOT_OK_RETURN(werr);
+
+ return reg_setkeysecurity(key, sd);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_reg_val(int lvl, const char *direction,
+ const char *key, const char *subkey,
+ struct registry_value *val)
+{
+ int i = 0;
+ const char *type_str = NULL;
+
+ if (!val) {
+ DEBUG(lvl,("no val!\n"));
+ return;
+ }
+
+ type_str = str_regtype(val->type);
+
+ DEBUG(lvl,("\tdump_reg_val:\t%s '%s'\n\t\t\t'%s' %s: ",
+ direction, key, subkey, type_str));
+
+ switch (val->type) {
+ case REG_DWORD: {
+ uint32_t v;
+ if (val->data.length < 4) {
+ break;
+ }
+ v = IVAL(val->data.data, 0);
+ DEBUG(lvl,("%d (0x%08x)\n",
+ (int)v, v));
+ break;
+ }
+ case REG_QWORD: {
+ uint64_t v;
+ if (val->data.length < 8) {
+ break;
+ }
+ v = BVAL(val->data.data, 0);
+ DEBUG(lvl,("%d (0x%016llx)\n",
+ (int)v,
+ (unsigned long long)v));
+ break;
+ }
+ case REG_SZ: {
+ const char *s;
+ if (!pull_reg_sz(talloc_tos(), &val->data, &s)) {
+ break;
+ }
+ DEBUG(lvl,("%s (length: %d)\n",
+ s, (int)strlen_m(s)));
+ break;
+ }
+ case REG_MULTI_SZ: {
+ const char **a;
+ if (!pull_reg_multi_sz(talloc_tos(), &val->data, &a)) {
+ break;
+ }
+ for (i=0; a[i] != NULL; i++) {
+ ;;
+ }
+ DEBUG(lvl,("(num_strings: %d)\n", i));
+ for (i=0; a[i] != NULL; i++) {
+ DEBUGADD(lvl,("\t%s\n", a[i]));
+ }
+ break;
+ }
+ case REG_NONE:
+ DEBUG(lvl,("\n"));
+ break;
+ case REG_BINARY:
+ dump_data(lvl, val->data.data,
+ val->data.length);
+ break;
+ default:
+ DEBUG(lvl,("unsupported type: %d\n", val->type));
+ break;
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_reg_entry(uint32_t flags,
+ const char *dir,
+ struct gp_registry_entry *entry)
+{
+ if (!(flags & GPO_INFO_FLAG_VERBOSE))
+ return;
+
+ dump_reg_val(1, dir,
+ entry->key,
+ entry->value,
+ entry->data);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_reg_entries(uint32_t flags,
+ const char *dir,
+ struct gp_registry_entry *entries,
+ size_t num_entries)
+{
+ size_t i;
+
+ if (!(flags & GPO_INFO_FLAG_VERBOSE))
+ return;
+
+ for (i=0; i < num_entries; i++) {
+ dump_reg_entry(flags, dir, &entries[i]);
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+bool add_gp_registry_entry_to_array(TALLOC_CTX *mem_ctx,
+ struct gp_registry_entry *entry,
+ struct gp_registry_entry **entries,
+ size_t *num)
+{
+ *entries = talloc_realloc(mem_ctx, *entries,
+ struct gp_registry_entry,
+ (*num)+1);
+
+ if (*entries == NULL) {
+ *num = 0;
+ return false;
+ }
+
+ (*entries)[*num].action = entry->action;
+ (*entries)[*num].key = entry->key;
+ (*entries)[*num].value = entry->value;
+ (*entries)[*num].data = entry->data;
+
+ *num += 1;
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *gp_reg_action_str(enum gp_reg_action action)
+{
+ switch (action) {
+ case GP_REG_ACTION_NONE:
+ return "GP_REG_ACTION_NONE";
+ case GP_REG_ACTION_ADD_VALUE:
+ return "GP_REG_ACTION_ADD_VALUE";
+ case GP_REG_ACTION_ADD_KEY:
+ return "GP_REG_ACTION_ADD_KEY";
+ case GP_REG_ACTION_DEL_VALUES:
+ return "GP_REG_ACTION_DEL_VALUES";
+ case GP_REG_ACTION_DEL_VALUE:
+ return "GP_REG_ACTION_DEL_VALUE";
+ case GP_REG_ACTION_DEL_ALL_VALUES:
+ return "GP_REG_ACTION_DEL_ALL_VALUES";
+ case GP_REG_ACTION_DEL_KEYS:
+ return "GP_REG_ACTION_DEL_KEYS";
+ case GP_REG_ACTION_SEC_KEY_SET:
+ return "GP_REG_ACTION_SEC_KEY_SET";
+ case GP_REG_ACTION_SEC_KEY_RESET:
+ return "GP_REG_ACTION_SEC_KEY_RESET";
+ default:
+ return "unknown";
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR reg_apply_registry_entry(TALLOC_CTX *mem_ctx,
+ struct registry_key *root_key,
+ struct gp_registry_context *reg_ctx,
+ struct gp_registry_entry *entry,
+ const struct security_token *token,
+ uint32_t flags)
+{
+ WERROR werr;
+ struct registry_key *key = NULL;
+
+ if (flags & GPO_INFO_FLAG_VERBOSE) {
+ printf("about to store key: [%s]\n", entry->key);
+ printf(" value: [%s]\n", entry->value);
+ printf(" data: [%s]\n", str_regtype(entry->data->type));
+ printf(" action: [%s]\n", gp_reg_action_str(entry->action));
+ }
+
+ werr = gp_store_reg_subkey(mem_ctx, entry->key,
+ root_key, &key);
+ /* reg_ctx->curr_key, &key); */
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("gp_store_reg_subkey failed: %s\n", win_errstr(werr)));
+ return werr;
+ }
+
+ switch (entry->action) {
+ case GP_REG_ACTION_NONE:
+ case GP_REG_ACTION_ADD_KEY:
+ return WERR_OK;
+
+ case GP_REG_ACTION_SEC_KEY_SET:
+ werr = gp_secure_key(mem_ctx, flags,
+ key,
+ &token->sids[PRIMARY_USER_SID_INDEX]);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("reg_apply_registry_entry: "
+ "gp_secure_key failed: %s\n",
+ win_errstr(werr)));
+ return werr;
+ }
+ break;
+ case GP_REG_ACTION_ADD_VALUE:
+ werr = reg_setvalue(key, entry->value, entry->data);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("reg_apply_registry_entry: "
+ "reg_setvalue failed: %s\n",
+ win_errstr(werr)));
+ dump_reg_entry(flags, "STORE", entry);
+ return werr;
+ }
+ break;
+ case GP_REG_ACTION_DEL_VALUE:
+ werr = reg_deletevalue(key, entry->value);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("reg_apply_registry_entry: "
+ "reg_deletevalue failed: %s\n",
+ win_errstr(werr)));
+ dump_reg_entry(flags, "STORE", entry);
+ return werr;
+ }
+ break;
+ case GP_REG_ACTION_DEL_ALL_VALUES:
+ werr = reg_deleteallvalues(key);
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(0,("reg_apply_registry_entry: "
+ "reg_deleteallvalues failed: %s\n",
+ win_errstr(werr)));
+ dump_reg_entry(flags, "STORE", entry);
+ return werr;
+ }
+ break;
+ case GP_REG_ACTION_DEL_VALUES:
+ case GP_REG_ACTION_DEL_KEYS:
+ case GP_REG_ACTION_SEC_KEY_RESET:
+ DEBUG(0,("reg_apply_registry_entry: "
+ "not yet supported: %s (%d)\n",
+ gp_reg_action_str(entry->action),
+ entry->action));
+ return WERR_NOT_SUPPORTED;
+ default:
+ DEBUG(0,("invalid action: %d\n", entry->action));
+ return WERR_INVALID_PARAMETER;
+ }
+
+ return werr;
+}
diff --git a/libgpo/gpo_sec.c b/libgpo/gpo_sec.c
new file mode 100644
index 0000000..82887bc
--- /dev/null
+++ b/libgpo/gpo_sec.c
@@ -0,0 +1,196 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * 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 "libcli/security/security.h"
+#include "../libgpo/gpo.h"
+#include "auth.h"
+#include "../librpc/ndr/libndr.h"
+
+/****************************************************************
+****************************************************************/
+
+static bool gpo_sd_check_agp_object_guid(const struct security_ace_object *object)
+{
+ struct GUID ext_right_apg_guid;
+ NTSTATUS status;
+
+ if (!object) {
+ return false;
+ }
+
+ status = GUID_from_string(ADS_EXTENDED_RIGHT_APPLY_GROUP_POLICY,
+ &ext_right_apg_guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ switch (object->flags) {
+ case SEC_ACE_OBJECT_TYPE_PRESENT:
+ if (GUID_equal(&object->type.type,
+ &ext_right_apg_guid)) {
+ return true;
+ }
+
+ FALL_THROUGH;
+ case SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT:
+ if (GUID_equal(&object->inherited_type.inherited_type,
+ &ext_right_apg_guid)) {
+ return true;
+ }
+
+ FALL_THROUGH;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool gpo_sd_check_agp_object(const struct security_ace *ace)
+{
+ if (!sec_ace_object(ace->type)) {
+ return false;
+ }
+
+ return gpo_sd_check_agp_object_guid(&ace->object.object);
+}
+
+/****************************************************************
+****************************************************************/
+
+static bool gpo_sd_check_agp_access_bits(uint32_t access_mask)
+{
+ return (access_mask & SEC_ADS_CONTROL_ACCESS);
+}
+
+#if 0
+/****************************************************************
+****************************************************************/
+
+static bool gpo_sd_check_read_access_bits(uint32_t access_mask)
+{
+ uint32_t read_bits = SEC_RIGHTS_LIST_CONTENTS |
+ SEC_RIGHTS_READ_ALL_PROP |
+ SEC_RIGHTS_READ_PERMS;
+
+ return (read_bits == (access_mask & read_bits));
+}
+#endif
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gpo_sd_check_ace_denied_object(const struct security_ace *ace,
+ const struct security_token *token)
+{
+ if (gpo_sd_check_agp_object(ace) &&
+ gpo_sd_check_agp_access_bits(ace->access_mask) &&
+ security_token_has_sid(token, &ace->trustee)) {
+ struct dom_sid_buf sid_str;
+ DEBUG(10,("gpo_sd_check_ace_denied_object: "
+ "Access denied as of ace for %s\n",
+ dom_sid_str_buf(&ace->trustee, &sid_str)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return STATUS_MORE_ENTRIES;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gpo_sd_check_ace_allowed_object(const struct security_ace *ace,
+ const struct security_token *token)
+{
+ if (gpo_sd_check_agp_object(ace) &&
+ gpo_sd_check_agp_access_bits(ace->access_mask) &&
+ security_token_has_sid(token, &ace->trustee)) {
+ struct dom_sid_buf sid_str;
+ DEBUG(10,("gpo_sd_check_ace_allowed_object: "
+ "Access granted as of ace for %s\n",
+ dom_sid_str_buf(&ace->trustee, &sid_str)));
+ return NT_STATUS_OK;
+ }
+
+ return STATUS_MORE_ENTRIES;
+}
+
+/****************************************************************
+****************************************************************/
+
+static NTSTATUS gpo_sd_check_ace(const struct security_ace *ace,
+ const struct security_token *token)
+{
+ switch (ace->type) {
+ case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+ return gpo_sd_check_ace_denied_object(ace, token);
+ case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+ return gpo_sd_check_ace_allowed_object(ace, token);
+ default:
+ return STATUS_MORE_ENTRIES;
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpo_apply_security_filtering(const struct GROUP_POLICY_OBJECT *gpo,
+ const struct security_token *token)
+{
+ struct security_descriptor *sd = gpo->security_descriptor;
+ struct security_acl *dacl = NULL;
+ NTSTATUS status = NT_STATUS_ACCESS_DENIED;
+ int i;
+
+ if (!token) {
+ return NT_STATUS_INVALID_USER_BUFFER;
+ }
+
+ if (!sd) {
+ return NT_STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ dacl = sd->dacl;
+ if (!dacl) {
+ return NT_STATUS_INVALID_SECURITY_DESCR;
+ }
+
+ /* check all aces and only return NT_STATUS_OK (== Access granted) or
+ * NT_STATUS_ACCESS_DENIED ( == Access denied) - the default is to
+ * deny access */
+
+ for (i = 0; i < dacl->num_aces; i ++) {
+
+ status = gpo_sd_check_ace(&dacl->aces[i], token);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ return status;
+ } else if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ continue;
+ }
+
+ return NT_STATUS_ACCESS_DENIED;
+}
diff --git a/libgpo/gpo_util.c b/libgpo/gpo_util.c
new file mode 100644
index 0000000..0c72340
--- /dev/null
+++ b/libgpo/gpo_util.c
@@ -0,0 +1,672 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Group Policy Object Support
+ * Copyright (C) Guenther Deschner 2005-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 "system/filesys.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "../librpc/gen_ndr/ndr_security.h"
+#include "../libgpo/gpo.h"
+#include "../libcli/security/security.h"
+#include "registry.h"
+#include "libgpo/gpo_proto.h"
+#include "libgpo/gpext/gpext.h"
+
+#if 0
+#define DEFAULT_DOMAIN_POLICY "Default Domain Policy"
+#define DEFAULT_DOMAIN_CONTROLLERS_POLICY "Default Domain Controllers Policy"
+#endif
+
+/* should we store a parsed guid ? */
+struct gp_table {
+ const char *name;
+ const char *guid_string;
+};
+
+#if 0 /* unused */
+static struct gp_table gpo_default_policy[] = {
+ { DEFAULT_DOMAIN_POLICY,
+ "31B2F340-016D-11D2-945F-00C04FB984F9" },
+ { DEFAULT_DOMAIN_CONTROLLERS_POLICY,
+ "6AC1786C-016F-11D2-945F-00C04fB984F9" },
+ { NULL, NULL }
+};
+#endif
+
+/* the following is seen in gPCMachineExtensionNames / gPCUserExtensionNames */
+
+static struct gp_table gpo_cse_extensions[] = {
+ /* used to be "Administrative Templates Extension" */
+ /* "Registry Settings"
+ (http://support.microsoft.com/kb/216357/EN-US/) */
+ { "Registry Settings",
+ GP_EXT_GUID_REGISTRY },
+ { "Microsoft Disc Quota",
+ "3610EDA5-77EF-11D2-8DC5-00C04FA31A66" },
+ { "EFS recovery",
+ "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A" },
+ { "Folder Redirection",
+ "25537BA6-77A8-11D2-9B6C-0000F8080861" },
+ { "IP Security",
+ "E437BC1C-AA7D-11D2-A382-00C04F991E27" },
+ { "Internet Explorer Branding",
+ "A2E30F80-D7DE-11d2-BBDE-00C04F86AE3B" },
+ { "QoS Packet Scheduler",
+ "426031c0-0b47-4852-b0ca-ac3d37bfcb39" },
+ { "Scripts",
+ GP_EXT_GUID_SCRIPTS },
+ { "Security",
+ GP_EXT_GUID_SECURITY },
+ { "Software Installation",
+ "C6DC5466-785A-11D2-84D0-00C04FB169F7" },
+ { "Wireless Group Policy",
+ "0ACDD40C-75AC-BAA0-BF6DE7E7FE63" },
+ { "Application Management",
+ "C6DC5466-785A-11D2-84D0-00C04FB169F7" },
+ { "unknown",
+ "3060E8D0-7020-11D2-842D-00C04FA372D4" },
+ { NULL, NULL }
+};
+
+/* guess work */
+static struct gp_table gpo_cse_snapin_extensions[] = {
+ { "Administrative Templates",
+ "0F6B957D-509E-11D1-A7CC-0000F87571E3" },
+ { "Certificates",
+ "53D6AB1D-2488-11D1-A28C-00C04FB94F17" },
+ { "EFS recovery policy processing",
+ "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A" },
+ { "Folder Redirection policy processing",
+ "25537BA6-77A8-11D2-9B6C-0000F8080861" },
+ { "Folder Redirection",
+ "88E729D6-BDC1-11D1-BD2A-00C04FB9603F" },
+ { "Registry policy processing",
+ "35378EAC-683F-11D2-A89A-00C04FBBCFA2" },
+ { "Remote Installation Services",
+ "3060E8CE-7020-11D2-842D-00C04FA372D4" },
+ { "Security Settings",
+ "803E14A0-B4FB-11D0-A0D0-00A0C90F574B" },
+ { "Security policy processing",
+ "827D319E-6EAC-11D2-A4EA-00C04F79F83A" },
+ { "unknown",
+ "3060E8D0-7020-11D2-842D-00C04FA372D4" },
+ { "unknown2",
+ "53D6AB1B-2488-11D1-A28C-00C04FB94F17" },
+ { NULL, NULL }
+};
+
+/****************************************************************
+****************************************************************/
+
+static const char *name_to_guid_string(const char *name,
+ struct gp_table *table)
+{
+ int i;
+
+ for (i = 0; table[i].name; i++) {
+ if (strequal(name, table[i].name)) {
+ return table[i].guid_string;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *guid_string_to_name(const char *guid_string,
+ struct gp_table *table)
+{
+ int i;
+
+ for (i = 0; table[i].guid_string; i++) {
+ if (strequal(guid_string, table[i].guid_string)) {
+ return table[i].name;
+ }
+ }
+
+ return NULL;
+}
+
+/****************************************************************
+****************************************************************/
+
+static const char *snapin_guid_string_to_name(const char *guid_string,
+ struct gp_table *table)
+{
+ int i;
+ for (i = 0; table[i].guid_string; i++) {
+ if (strequal(guid_string, table[i].guid_string)) {
+ return table[i].name;
+ }
+ }
+ return NULL;
+}
+
+#if 0 /* unused */
+static const char *default_gpo_name_to_guid_string(const char *name)
+{
+ return name_to_guid_string(name, gpo_default_policy);
+}
+
+static const char *default_gpo_guid_string_to_name(const char *guid)
+{
+ return guid_string_to_name(guid, gpo_default_policy);
+}
+#endif
+
+/****************************************************************
+****************************************************************/
+
+const char *cse_gpo_guid_string_to_name(const char *guid)
+{
+ return guid_string_to_name(guid, gpo_cse_extensions);
+}
+
+/****************************************************************
+****************************************************************/
+
+const char *cse_gpo_name_to_guid_string(const char *name)
+{
+ return name_to_guid_string(name, gpo_cse_extensions);
+}
+
+/****************************************************************
+****************************************************************/
+
+const char *cse_snapin_gpo_guid_string_to_name(const char *guid)
+{
+ return snapin_guid_string_to_name(guid, gpo_cse_snapin_extensions);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_gp_ext(struct GP_EXT *gp_ext, int debuglevel)
+{
+ int lvl = debuglevel;
+ int i;
+
+ if (gp_ext == NULL) {
+ return;
+ }
+
+ DEBUG(lvl,("\t---------------------\n\n"));
+ DEBUGADD(lvl,("\tname:\t\t\t%s\n", gp_ext->gp_extension));
+
+ for (i=0; i< gp_ext->num_exts; i++) {
+
+ DEBUGADD(lvl,("\textension:\t\t\t%s\n",
+ gp_ext->extensions_guid[i]));
+ DEBUGADD(lvl,("\textension (name):\t\t\t%s\n",
+ gp_ext->extensions[i]));
+
+ DEBUGADD(lvl,("\tsnapin:\t\t\t%s\n",
+ gp_ext->snapins_guid[i]));
+ DEBUGADD(lvl,("\tsnapin (name):\t\t\t%s\n",
+ gp_ext->snapins[i]));
+ }
+}
+
+#ifdef HAVE_LDAP
+
+/****************************************************************
+****************************************************************/
+
+void dump_gpo(const struct GROUP_POLICY_OBJECT *gpo,
+ int debuglevel)
+{
+ int lvl = debuglevel;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (gpo == NULL) {
+ goto out;
+ }
+
+ DEBUG(lvl,("---------------------\n\n"));
+
+ DEBUGADD(lvl,("name:\t\t\t%s\n", gpo->name));
+ DEBUGADD(lvl,("displayname:\t\t%s\n", gpo->display_name));
+ DEBUGADD(lvl,("version:\t\t%d (0x%08x)\n", gpo->version, gpo->version));
+ DEBUGADD(lvl,("version_user:\t\t%d (0x%04x)\n",
+ GPO_VERSION_USER(gpo->version),
+ GPO_VERSION_USER(gpo->version)));
+ DEBUGADD(lvl,("version_machine:\t%d (0x%04x)\n",
+ GPO_VERSION_MACHINE(gpo->version),
+ GPO_VERSION_MACHINE(gpo->version)));
+ DEBUGADD(lvl,("filesyspath:\t\t%s\n", gpo->file_sys_path));
+ DEBUGADD(lvl,("dspath:\t\t%s\n", gpo->ds_path));
+
+ DEBUGADD(lvl,("options:\t\t%d ", gpo->options));
+ switch (gpo->options) {
+ case GPFLAGS_ALL_ENABLED:
+ DEBUGADD(lvl,("GPFLAGS_ALL_ENABLED\n"));
+ break;
+ case GPFLAGS_USER_SETTINGS_DISABLED:
+ DEBUGADD(lvl,("GPFLAGS_USER_SETTINGS_DISABLED\n"));
+ break;
+ case GPFLAGS_MACHINE_SETTINGS_DISABLED:
+ DEBUGADD(lvl,("GPFLAGS_MACHINE_SETTINGS_DISABLED\n"));
+ break;
+ case GPFLAGS_ALL_DISABLED:
+ DEBUGADD(lvl,("GPFLAGS_ALL_DISABLED\n"));
+ break;
+ default:
+ DEBUGADD(lvl,("unknown option: %d\n", gpo->options));
+ break;
+ }
+
+ DEBUGADD(lvl,("link:\t\t\t%s\n", gpo->link));
+ DEBUGADD(lvl,("link_type:\t\t%d ", gpo->link_type));
+ switch (gpo->link_type) {
+ case GP_LINK_UNKOWN:
+ DEBUGADD(lvl,("GP_LINK_UNKOWN\n"));
+ break;
+ case GP_LINK_OU:
+ DEBUGADD(lvl,("GP_LINK_OU\n"));
+ break;
+ case GP_LINK_DOMAIN:
+ DEBUGADD(lvl,("GP_LINK_DOMAIN\n"));
+ break;
+ case GP_LINK_SITE:
+ DEBUGADD(lvl,("GP_LINK_SITE\n"));
+ break;
+ case GP_LINK_MACHINE:
+ DEBUGADD(lvl,("GP_LINK_MACHINE\n"));
+ break;
+ default:
+ break;
+ }
+
+ DEBUGADD(lvl,("machine_extensions:\t%s\n", gpo->machine_extensions));
+
+ if (gpo->machine_extensions) {
+
+ struct GP_EXT *gp_ext = NULL;
+
+ if (!ads_parse_gp_ext(frame, gpo->machine_extensions,
+ &gp_ext)) {
+ goto out;
+ }
+ dump_gp_ext(gp_ext, lvl);
+ }
+
+ DEBUGADD(lvl,("user_extensions:\t%s\n", gpo->user_extensions));
+
+ if (gpo->user_extensions) {
+
+ struct GP_EXT *gp_ext = NULL;
+
+ if (!ads_parse_gp_ext(frame, gpo->user_extensions,
+ &gp_ext)) {
+ goto out;
+ }
+ dump_gp_ext(gp_ext, lvl);
+ }
+ if (gpo->security_descriptor) {
+ DEBUGADD(lvl,("security descriptor:\n"));
+
+ NDR_PRINT_DEBUG(security_descriptor, gpo->security_descriptor);
+ }
+ out:
+ talloc_free(frame);
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_gpo_list(const struct GROUP_POLICY_OBJECT *gpo_list,
+ int debuglevel)
+{
+ const struct GROUP_POLICY_OBJECT *gpo = NULL;
+
+ for (gpo = gpo_list; gpo; gpo = gpo->next) {
+ dump_gpo(gpo, debuglevel);
+ }
+}
+
+/****************************************************************
+****************************************************************/
+
+void dump_gplink(const struct GP_LINK *gp_link)
+{
+ int i;
+ int lvl = 10;
+
+ if (gp_link == NULL) {
+ return;
+ }
+
+ DEBUG(lvl,("---------------------\n\n"));
+
+ DEBUGADD(lvl,("gplink: %s\n", gp_link->gp_link));
+ DEBUGADD(lvl,("gpopts: %d ", gp_link->gp_opts));
+ switch (gp_link->gp_opts) {
+ case GPOPTIONS_INHERIT:
+ DEBUGADD(lvl,("GPOPTIONS_INHERIT\n"));
+ break;
+ case GPOPTIONS_BLOCK_INHERITANCE:
+ DEBUGADD(lvl,("GPOPTIONS_BLOCK_INHERITANCE\n"));
+ break;
+ default:
+ break;
+ }
+
+ DEBUGADD(lvl,("num links: %d\n", gp_link->num_links));
+
+ for (i = 0; i < gp_link->num_links; i++) {
+
+ DEBUGADD(lvl,("---------------------\n\n"));
+
+ DEBUGADD(lvl,("link: #%d\n", i + 1));
+ DEBUGADD(lvl,("name: %s\n", gp_link->link_names[i]));
+
+ DEBUGADD(lvl,("opt: %d ", gp_link->link_opts[i]));
+ if (gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED) {
+ DEBUGADD(lvl,("GPO_LINK_OPT_ENFORCED "));
+ }
+ if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) {
+ DEBUGADD(lvl,("GPO_LINK_OPT_DISABLED"));
+ }
+ DEBUGADD(lvl,("\n"));
+ }
+}
+
+#endif /* HAVE_LDAP */
+
+/****************************************************************
+****************************************************************/
+
+bool gpo_get_gp_ext_from_gpo(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const struct GROUP_POLICY_OBJECT *gpo,
+ struct GP_EXT **gp_ext)
+{
+ ZERO_STRUCTP(*gp_ext);
+
+ if (flags & GPO_INFO_FLAG_MACHINE) {
+
+ if (gpo->machine_extensions) {
+
+ if (!ads_parse_gp_ext(mem_ctx, gpo->machine_extensions,
+ gp_ext)) {
+ return false;
+ }
+ }
+ } else {
+
+ if (gpo->user_extensions) {
+
+ if (!ads_parse_gp_ext(mem_ctx, gpo->user_extensions,
+ gp_ext)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpo_process_gpo_list(TALLOC_CTX *mem_ctx,
+ const struct security_token *token,
+ const struct GROUP_POLICY_OBJECT *deleted_gpo_list,
+ const struct GROUP_POLICY_OBJECT *changed_gpo_list,
+ const char *extensions_guid_filter,
+ uint32_t flags)
+{
+ NTSTATUS status = NT_STATUS_OK;
+ struct registry_key *root_key = NULL;
+ struct gp_registry_context *reg_ctx = NULL;
+ WERROR werr;
+
+ /* get the key here */
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+ werr = gp_init_reg_ctx(mem_ctx, KEY_HKLM, REG_KEY_WRITE,
+ get_system_token(),
+ &reg_ctx);
+ } else {
+ werr = gp_init_reg_ctx(mem_ctx, KEY_HKCU, REG_KEY_WRITE,
+ token,
+ &reg_ctx);
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ talloc_free(reg_ctx);
+ return werror_to_ntstatus(werr);
+ }
+
+ root_key = reg_ctx->curr_key;
+
+ status = gpext_process_extension(mem_ctx,
+ flags, token, root_key,
+ deleted_gpo_list,
+ changed_gpo_list,
+ extensions_guid_filter);
+ talloc_free(reg_ctx);
+ talloc_free(root_key);
+ gpext_free_gp_extensions();
+
+ return status;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpo_get_unix_path(TALLOC_CTX *mem_ctx,
+ const char *cache_dir,
+ const struct GROUP_POLICY_OBJECT *gpo,
+ char **unix_path)
+{
+ char *server, *share, *nt_path;
+ return gpo_explode_filesyspath(mem_ctx, cache_dir, gpo->file_sys_path,
+ &server, &share, &nt_path, unix_path);
+}
+
+/****************************************************************
+****************************************************************/
+
+char *gpo_flag_str(TALLOC_CTX *ctx, uint32_t flags)
+{
+ char *str = NULL;
+
+ if (flags == 0) {
+ return NULL;
+ }
+
+ str = talloc_strdup(ctx, "");
+ if (!str) {
+ return NULL;
+ }
+
+ if (flags & GPO_INFO_FLAG_SLOWLINK)
+ str = talloc_strdup_append(str, "GPO_INFO_FLAG_SLOWLINK ");
+ if (flags & GPO_INFO_FLAG_VERBOSE)
+ str = talloc_strdup_append(str, "GPO_INFO_FLAG_VERBOSE ");
+ if (flags & GPO_INFO_FLAG_SAFEMODE_BOOT)
+ str = talloc_strdup_append(str, "GPO_INFO_FLAG_SAFEMODE_BOOT ");
+ if (flags & GPO_INFO_FLAG_NOCHANGES)
+ str = talloc_strdup_append(str, "GPO_INFO_FLAG_NOCHANGES ");
+ if (flags & GPO_INFO_FLAG_MACHINE)
+ str = talloc_strdup_append(str, "GPO_INFO_FLAG_MACHINE ");
+ if (flags & GPO_INFO_FLAG_LOGRSOP_TRANSITION)
+ str = talloc_strdup_append(str, "GPO_INFO_FLAG_LOGRSOP_TRANSITION ");
+ if (flags & GPO_INFO_FLAG_LINKTRANSITION)
+ str = talloc_strdup_append(str, "GPO_INFO_FLAG_LINKTRANSITION ");
+ if (flags & GPO_INFO_FLAG_FORCED_REFRESH)
+ str = talloc_strdup_append(str, "GPO_INFO_FLAG_FORCED_REFRESH ");
+ if (flags & GPO_INFO_FLAG_BACKGROUND)
+ str = talloc_strdup_append(str, "GPO_INFO_FLAG_BACKGROUND ");
+
+ return str;
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gp_find_file(TALLOC_CTX *mem_ctx,
+ uint32_t flags,
+ const char *filename,
+ const char *suffix,
+ const char **filename_out)
+{
+ const char *tmp = NULL;
+ struct stat sbuf;
+ const char *path = NULL;
+
+ if (flags & GPO_LIST_FLAG_MACHINE) {
+ path = "Machine";
+ } else {
+ path = "User";
+ }
+
+ tmp = talloc_asprintf(mem_ctx, "%s/%s/%s", filename,
+ path, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(tmp);
+
+ if (stat(tmp, &sbuf) == 0) {
+ *filename_out = tmp;
+ return NT_STATUS_OK;
+ }
+
+ path = talloc_strdup_upper(mem_ctx, path);
+ NT_STATUS_HAVE_NO_MEMORY(path);
+
+ tmp = talloc_asprintf(mem_ctx, "%s/%s/%s", filename,
+ path, suffix);
+ NT_STATUS_HAVE_NO_MEMORY(tmp);
+
+ if (stat(tmp, &sbuf) == 0) {
+ *filename_out = tmp;
+ return NT_STATUS_OK;
+ }
+
+ return NT_STATUS_NO_SUCH_FILE;
+}
+
+/****************************************************************
+****************************************************************/
+
+ADS_STATUS gp_get_machine_token(ADS_STRUCT *ads,
+ TALLOC_CTX *mem_ctx,
+ const char *dn,
+ struct security_token **token)
+{
+#ifdef HAVE_ADS
+ struct security_token *ad_token = NULL;
+ ADS_STATUS status;
+ NTSTATUS ntstatus;
+
+ status = ads_get_sid_token(ads, mem_ctx, dn, &ad_token);
+ if (!ADS_ERR_OK(status)) {
+ return status;
+ }
+ ntstatus = merge_with_system_token(mem_ctx, ad_token,
+ token);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ return ADS_ERROR_NT(ntstatus);
+ }
+ return ADS_SUCCESS;
+#else
+ return ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+#endif
+}
+
+/****************************************************************
+****************************************************************/
+
+NTSTATUS gpo_copy(TALLOC_CTX *mem_ctx,
+ const struct GROUP_POLICY_OBJECT *gpo_src,
+ struct GROUP_POLICY_OBJECT **gpo_dst)
+{
+ struct GROUP_POLICY_OBJECT *gpo;
+
+ gpo = talloc_zero(mem_ctx, struct GROUP_POLICY_OBJECT);
+ NT_STATUS_HAVE_NO_MEMORY(gpo);
+
+ gpo->options = gpo_src->options;
+ gpo->version = gpo_src->version;
+
+ gpo->ds_path = talloc_strdup(gpo, gpo_src->ds_path);
+ if (gpo->ds_path == NULL) {
+ TALLOC_FREE(gpo);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gpo->file_sys_path = talloc_strdup(gpo, gpo_src->file_sys_path);
+ if (gpo->file_sys_path == NULL) {
+ TALLOC_FREE(gpo);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gpo->display_name = talloc_strdup(gpo, gpo_src->display_name);
+ if (gpo->display_name == NULL) {
+ TALLOC_FREE(gpo);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gpo->name = talloc_strdup(gpo, gpo_src->name);
+ if (gpo->name == NULL) {
+ TALLOC_FREE(gpo);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gpo->link = talloc_strdup(gpo, gpo_src->link);
+ if (gpo->link == NULL) {
+ TALLOC_FREE(gpo);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gpo->link_type = gpo_src->link_type;
+
+ if (gpo_src->user_extensions) {
+ gpo->user_extensions = talloc_strdup(gpo, gpo_src->user_extensions);
+ if (gpo->user_extensions == NULL) {
+ TALLOC_FREE(gpo);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (gpo_src->machine_extensions) {
+ gpo->machine_extensions = talloc_strdup(gpo, gpo_src->machine_extensions);
+ if (gpo->machine_extensions == NULL) {
+ TALLOC_FREE(gpo);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (gpo_src->security_descriptor == NULL) {
+ /* existing SD assumed */
+ TALLOC_FREE(gpo);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ gpo->security_descriptor = security_descriptor_copy(gpo,
+ gpo_src->security_descriptor);
+ if (gpo->security_descriptor == NULL) {
+ TALLOC_FREE(gpo);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gpo->next = gpo->prev = NULL;
+
+ *gpo_dst = gpo;
+
+ return NT_STATUS_OK;
+}
diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c
new file mode 100644
index 0000000..0f71163
--- /dev/null
+++ b/libgpo/pygpo.c
@@ -0,0 +1,767 @@
+/*
+ Unix SMB/CIFS implementation.
+ Copyright (C) Luke Morrison <luc785@hotmail.com> 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 "version.h"
+#include "param/pyparam.h"
+#include "gpo.h"
+#include "ads.h"
+#include "secrets.h"
+#include "../libds/common/flags.h"
+#include "librpc/rpc/pyrpc_util.h"
+#include "auth/credentials/pycredentials.h"
+#include "libcli/util/pyerrors.h"
+#include "python/py3compat.h"
+#include "python/modules.h"
+#include <pytalloc.h>
+#include "../libcli/security/security.h"
+
+/* A Python C API module to use LIBGPO */
+
+#define GPO_getter(ATTR) \
+static PyObject* GPO_get_##ATTR(PyObject *self, void *closure) \
+{ \
+ struct GROUP_POLICY_OBJECT *gpo_ptr \
+ = pytalloc_get_ptr(self); \
+ \
+ if (gpo_ptr->ATTR) \
+ return PyUnicode_FromString(gpo_ptr->ATTR); \
+ else \
+ Py_RETURN_NONE; \
+}
+GPO_getter(ds_path)
+GPO_getter(file_sys_path)
+GPO_getter(display_name)
+GPO_getter(name)
+GPO_getter(link)
+GPO_getter(user_extensions)
+GPO_getter(machine_extensions)
+#define GPO_setter(ATTR) \
+static int GPO_set_##ATTR(PyObject *self, PyObject *val, void *closure) \
+{ \
+ struct GROUP_POLICY_OBJECT *gpo_ptr \
+ = pytalloc_get_ptr(self); \
+ \
+ if (!PyUnicode_Check(val)) { \
+ PyErr_Format(PyExc_TypeError, \
+ "Cannot convert input to string"); \
+ return -1; \
+ } \
+ if (val != Py_None) { \
+ gpo_ptr->ATTR = talloc_strdup(gpo_ptr, \
+ _PyUnicode_AsString(val)); \
+ } else { \
+ gpo_ptr->ATTR = NULL; \
+ } \
+ return 0; \
+}
+GPO_setter(ds_path)
+GPO_setter(file_sys_path)
+GPO_setter(display_name)
+GPO_setter(name)
+GPO_setter(link)
+GPO_setter(user_extensions)
+GPO_setter(machine_extensions)
+#define GPO_int_getter(ATTR) \
+static PyObject* GPO_get_##ATTR(PyObject *self, void *closure) \
+{ \
+ struct GROUP_POLICY_OBJECT *gpo_ptr \
+ = pytalloc_get_ptr(self); \
+ \
+ return PyLong_FromLong(gpo_ptr->ATTR); \
+}
+GPO_int_getter(options)
+GPO_int_getter(version)
+GPO_int_getter(link_type)
+#define GPO_int_setter(ATTR) \
+static int GPO_set_##ATTR(PyObject *self, PyObject *val, void *closure) \
+{ \
+ struct GROUP_POLICY_OBJECT *gpo_ptr \
+ = pytalloc_get_ptr(self); \
+ \
+ if (!PyLong_Check(val)) { \
+ PyErr_Format(PyExc_TypeError, \
+ "Cannot convert input to int"); \
+ return -1; \
+ } else { \
+ gpo_ptr->ATTR = PyLong_AsLong(val); \
+ } \
+ return 0; \
+}
+GPO_int_setter(options)
+GPO_int_setter(version)
+GPO_int_setter(link_type)
+
+static PyObject *GPO_marshall_get_sec_desc_buf(PyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ struct GROUP_POLICY_OBJECT *gpo_ptr = pytalloc_get_ptr(self);
+ NTSTATUS status;
+ uint8_t *data = NULL;
+ size_t len = 0;
+
+ if (gpo_ptr->security_descriptor == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "Uninitialized");
+ return NULL;
+ }
+
+ status = marshall_sec_desc(gpo_ptr, gpo_ptr->security_descriptor,
+ &data, &len);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(PyExc_BufferError,
+ "marshall_sec_desc_buf failed: %s",
+ nt_errstr(status));
+ return NULL;
+ }
+
+ return PyBytes_FromStringAndSize((char *)data, len);
+}
+
+static PyObject *GPO_unmarshall_set_sec_desc(PyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ struct GROUP_POLICY_OBJECT *gpo_ptr = pytalloc_get_ptr(self);
+ char *bytes = NULL;
+ size_t length = 0;
+ NTSTATUS status;
+
+ if (!PyArg_ParseTuple(args, "s#", &bytes, &length)) {
+ PyErr_Format(PyExc_TypeError,
+ "Cannot convert input to bytes");
+ return NULL;
+ }
+
+ gpo_ptr->security_descriptor = talloc_zero(gpo_ptr,
+ struct security_descriptor);
+ status = unmarshall_sec_desc(gpo_ptr, (uint8_t *)bytes, length,
+ &gpo_ptr->security_descriptor);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(PyExc_BufferError,
+ "unmarshall_sec_desc failed: %s",
+ nt_errstr(status));
+ return NULL;
+ }
+
+ return Py_None;
+}
+
+static PyGetSetDef GPO_setters[] = {
+ {discard_const_p(char, "options"), (getter)GPO_get_options,
+ (setter)GPO_set_options, NULL, NULL},
+ {discard_const_p(char, "version"), (getter)GPO_get_version,
+ (setter)GPO_set_version, NULL, NULL},
+ {discard_const_p(char, "ds_path"), (getter)GPO_get_ds_path,
+ (setter)GPO_set_ds_path, NULL, NULL},
+ {discard_const_p(char, "file_sys_path"), (getter)GPO_get_file_sys_path,
+ (setter)GPO_set_file_sys_path, NULL, NULL},
+ {discard_const_p(char, "display_name"), (getter)GPO_get_display_name,
+ (setter)GPO_set_display_name, NULL, NULL},
+ {discard_const_p(char, "name"), (getter)GPO_get_name,
+ (setter)GPO_set_name, NULL, NULL},
+ {discard_const_p(char, "link"), (getter)GPO_get_link,
+ (setter)GPO_set_link, NULL, NULL},
+ {discard_const_p(char, "link_type"), (getter)GPO_get_link_type,
+ (setter)GPO_set_link_type, NULL, NULL},
+ {discard_const_p(char, "user_extensions"),
+ (getter)GPO_get_user_extensions,
+ (setter)GPO_set_user_extensions, NULL, NULL},
+ {discard_const_p(char, "machine_extensions"),
+ (getter)GPO_get_machine_extensions,
+ (setter)GPO_set_machine_extensions, NULL, NULL},
+ {0}
+};
+
+static PyObject *py_gpo_get_unix_path(PyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ NTSTATUS status;
+ const char *cache_dir = NULL;
+ PyObject *ret = NULL;
+ char *unix_path = NULL;
+ TALLOC_CTX *frame = NULL;
+ static const char *kwlist[] = {"cache_dir", NULL};
+ struct GROUP_POLICY_OBJECT *gpo_ptr \
+ = (struct GROUP_POLICY_OBJECT *)pytalloc_get_ptr(self);
+
+ frame = talloc_stackframe();
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s",
+ discard_const_p(char *, kwlist),
+ &cache_dir)) {
+ goto out;
+ }
+
+ if (!cache_dir) {
+ cache_dir = cache_path(talloc_tos(), GPO_CACHE_DIR);
+ if (!cache_dir) {
+ PyErr_SetString(PyExc_MemoryError,
+ "Failed to determine gpo cache dir");
+ goto out;
+ }
+ }
+
+ status = gpo_get_unix_path(frame, cache_dir, gpo_ptr, &unix_path);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Failed to determine gpo unix path: %s",
+ get_friendly_nt_error_msg(status));
+ goto out;
+ }
+
+ ret = PyUnicode_FromString(unix_path);
+
+out:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+static PyMethodDef GPO_methods[] = {
+ {"get_unix_path", PY_DISCARD_FUNC_SIG(PyCFunction,
+ py_gpo_get_unix_path),
+ METH_VARARGS | METH_KEYWORDS,
+ NULL },
+ {"set_sec_desc", PY_DISCARD_FUNC_SIG(PyCFunction,
+ GPO_unmarshall_set_sec_desc),
+ METH_VARARGS, NULL },
+ {"get_sec_desc_buf", PY_DISCARD_FUNC_SIG(PyCFunction,
+ GPO_marshall_get_sec_desc_buf),
+ METH_NOARGS, NULL },
+ {0}
+};
+
+static int py_gpo_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ struct GROUP_POLICY_OBJECT *gpo_ptr = pytalloc_get_ptr(self);
+ const char *name = NULL;
+ const char *display_name = NULL;
+ enum GPO_LINK_TYPE link_type = GP_LINK_UNKOWN;
+ const char *file_sys_path = NULL;
+
+ static const char *kwlist[] = {
+ "name", "display_name", "link_type", "file_sys_path", NULL
+ };
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssIs",
+ discard_const_p(char *, kwlist),
+ &name, &display_name, &link_type,
+ &file_sys_path)) {
+ return -1;
+ }
+
+ if (name) {
+ gpo_ptr->name = talloc_strdup(gpo_ptr, name);
+ }
+ if (display_name) {
+ gpo_ptr->display_name = talloc_strdup(gpo_ptr, display_name);
+ }
+ gpo_ptr->link_type = link_type;
+ if (file_sys_path) {
+ gpo_ptr->file_sys_path = talloc_strdup(gpo_ptr, file_sys_path);
+ }
+
+ return 0;
+}
+
+static PyObject *py_gpo_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ return pytalloc_new(struct GROUP_POLICY_OBJECT, type);
+}
+
+static PyTypeObject GPOType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "gpo.GROUP_POLICY_OBJECT",
+ .tp_doc = "GROUP_POLICY_OBJECT",
+ .tp_getset = GPO_setters,
+ .tp_methods = GPO_methods,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ .tp_new = py_gpo_new,
+ .tp_init = (initproc)py_gpo_init,
+};
+
+typedef struct {
+ PyObject_HEAD
+ ADS_STRUCT *ads_ptr;
+ PyObject *py_creds;
+ struct cli_credentials *cli_creds;
+} ADS;
+
+static void py_ads_dealloc(ADS* self)
+{
+ TALLOC_FREE(self->ads_ptr);
+ Py_CLEAR(self->py_creds);
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject* py_ads_connect(ADS *self, PyObject *Py_UNUSED(ignored));
+static int py_ads_init(ADS *self, PyObject *args, PyObject *kwds)
+{
+ const char *realm = NULL;
+ const char *workgroup = NULL;
+ const char *ldap_server = NULL;
+ PyObject *lp_obj = NULL;
+ PyObject *py_creds = NULL;
+ struct loadparm_context *lp_ctx = NULL;
+ bool ok = false;
+
+ static const char *kwlist[] = {
+ "ldap_server", "loadparm_context", "credentials", NULL
+ };
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|O",
+ discard_const_p(char *, kwlist),
+ &ldap_server, &lp_obj, &py_creds)) {
+ return -1;
+ }
+ /* keep reference to the credentials. Clear any earlier ones */
+ Py_CLEAR(self->py_creds);
+ self->cli_creds = NULL;
+ self->py_creds = py_creds;
+ Py_XINCREF(self->py_creds);
+
+ if (self->py_creds) {
+ ok = py_check_dcerpc_type(self->py_creds, "samba.credentials",
+ "Credentials");
+ if (!ok) {
+ return -1;
+ }
+ self->cli_creds
+ = PyCredentials_AsCliCredentials(self->py_creds);
+ }
+
+ ok = py_check_dcerpc_type(lp_obj, "samba.param", "LoadParm");
+ if (!ok) {
+ return -1;
+ }
+ lp_ctx = pytalloc_get_type(lp_obj, struct loadparm_context);
+ if (lp_ctx == NULL) {
+ return -1;
+ }
+ ok = lp_load_initial_only(lp_ctx->szConfigFile);
+ if (!ok) {
+ PyErr_Format(PyExc_RuntimeError, "Could not load config file '%s'",
+ lp_ctx->szConfigFile);
+ return -1;
+ }
+
+ if (self->cli_creds) {
+ realm = cli_credentials_get_realm(self->cli_creds);
+ workgroup = cli_credentials_get_domain(self->cli_creds);
+ } else {
+ realm = lp_realm();
+ workgroup = lp_workgroup();
+ }
+
+ /* in case __init__ is called more than once */
+ if (self->ads_ptr) {
+ TALLOC_FREE(self->ads_ptr);
+ }
+ /* always succeeds or crashes */
+ self->ads_ptr = ads_init(pytalloc_get_mem_ctx(args),
+ realm,
+ workgroup,
+ ldap_server,
+ ADS_SASL_PLAIN);
+
+ return 0;
+}
+
+/* connect. Failure to connect results in an Exception */
+static PyObject* py_ads_connect(ADS *self,
+ PyObject *Py_UNUSED(ignored))
+{
+ ADS_STATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ if (!self->ads_ptr) {
+ PyErr_SetString(PyExc_RuntimeError, "Uninitialized");
+ return NULL;
+ }
+ ADS_TALLOC_CONST_FREE(self->ads_ptr->auth.user_name);
+ ADS_TALLOC_CONST_FREE(self->ads_ptr->auth.password);
+ ADS_TALLOC_CONST_FREE(self->ads_ptr->auth.realm);
+ if (self->cli_creds) {
+ self->ads_ptr->auth.user_name = talloc_strdup(self->ads_ptr,
+ cli_credentials_get_username(self->cli_creds));
+ if (self->ads_ptr->auth.user_name == NULL) {
+ PyErr_NoMemory();
+ goto err;
+ }
+ self->ads_ptr->auth.password = talloc_strdup(self->ads_ptr,
+ cli_credentials_get_password(self->cli_creds));
+ if (self->ads_ptr->auth.password == NULL) {
+ PyErr_NoMemory();
+ goto err;
+ }
+ self->ads_ptr->auth.realm = talloc_strdup(self->ads_ptr,
+ cli_credentials_get_realm(self->cli_creds));
+ if (self->ads_ptr->auth.realm == NULL) {
+ PyErr_NoMemory();
+ goto err;
+ }
+ self->ads_ptr->auth.flags |= ADS_AUTH_USER_CREDS;
+ status = ads_connect_user_creds(self->ads_ptr);
+ } else {
+ char *passwd = NULL;
+
+ if (!secrets_init()) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "secrets_init() failed");
+ goto err;
+ }
+
+ self->ads_ptr->auth.user_name = talloc_asprintf(self->ads_ptr,
+ "%s$",
+ lp_netbios_name());
+ if (self->ads_ptr->auth.user_name == NULL) {
+ PyErr_NoMemory();
+ goto err;
+ }
+
+ passwd = secrets_fetch_machine_password(
+ self->ads_ptr->server.workgroup, NULL, NULL);
+ if (passwd == NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Failed to fetch the machine account "
+ "password");
+ goto err;
+ }
+
+ self->ads_ptr->auth.password = talloc_strdup(self->ads_ptr,
+ passwd);
+ SAFE_FREE(passwd);
+ if (self->ads_ptr->auth.password == NULL) {
+ PyErr_NoMemory();
+ goto err;
+ }
+ self->ads_ptr->auth.realm = talloc_asprintf_strupper_m(
+ self->ads_ptr, "%s", self->ads_ptr->server.realm);
+ if (self->ads_ptr->auth.realm == NULL) {
+ PyErr_NoMemory();
+ goto err;
+ }
+ self->ads_ptr->auth.flags |= ADS_AUTH_USER_CREDS;
+ status = ads_connect(self->ads_ptr);
+ }
+ if (!ADS_ERR_OK(status)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "ads_connect() failed: %s",
+ ads_errstr(status));
+ goto err;
+ }
+
+ TALLOC_FREE(frame);
+ Py_RETURN_TRUE;
+
+err:
+ TALLOC_FREE(frame);
+ return NULL;
+}
+
+/* Parameter mapping and functions for the GP_EXT struct */
+void initgpo(void);
+
+/* Global methods aka do not need a special pyobject type */
+static PyObject *py_gpo_get_sysvol_gpt_version(PyObject * self,
+ PyObject * args)
+{
+ TALLOC_CTX *tmp_ctx = NULL;
+ char *unix_path;
+ char *display_name = NULL;
+ uint32_t sysvol_version = 0;
+ PyObject *result;
+ NTSTATUS status;
+
+ if (!PyArg_ParseTuple(args, "s", &unix_path)) {
+ return NULL;
+ }
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return PyErr_NoMemory();
+ }
+ status = gpo_get_sysvol_gpt_version(tmp_ctx, unix_path,
+ &sysvol_version,
+ &display_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetNTSTATUS(status);
+ TALLOC_FREE(tmp_ctx);
+ return NULL;
+ }
+
+ result = Py_BuildValue("[s,i]", display_name, sysvol_version);
+ talloc_free(tmp_ctx);
+ return result;
+}
+
+#ifdef HAVE_ADS
+static ADS_STATUS find_samaccount(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
+ const char *samaccountname,
+ uint32_t *uac_ret, const char **dn_ret)
+{
+ ADS_STATUS status;
+ const char *attrs[] = { "userAccountControl", NULL };
+ const char *filter;
+ LDAPMessage *res = NULL;
+ char *dn = NULL;
+ uint32_t uac = 0;
+
+ filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
+ samaccountname);
+ if (filter == NULL) {
+ status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
+ goto out;
+ }
+
+ status = ads_do_search_all(ads, ads->config.bind_path,
+ LDAP_SCOPE_SUBTREE, filter, attrs, &res);
+
+ if (!ADS_ERR_OK(status)) {
+ goto out;
+ }
+
+ if (ads_count_replies(ads, res) != 1) {
+ status = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
+ goto out;
+ }
+
+ dn = ads_get_dn(ads, talloc_tos(), res);
+ if (dn == NULL) {
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+
+ if (!ads_pull_uint32(ads, res, "userAccountControl", &uac)) {
+ status = ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE);
+ goto out;
+ }
+
+ if (uac_ret) {
+ *uac_ret = uac;
+ }
+
+ if (dn_ret) {
+ *dn_ret = talloc_strdup(mem_ctx, dn);
+ if (*dn_ret == NULL) {
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
+ }
+ }
+out:
+ TALLOC_FREE(dn);
+ ads_msgfree(ads, res);
+
+ return status;
+}
+
+static PyObject *py_ads_get_gpo_list(ADS *self, PyObject *args, PyObject *kwds)
+{
+ TALLOC_CTX *frame = NULL;
+ struct GROUP_POLICY_OBJECT *gpo = NULL, *gpo_list = NULL;
+ ADS_STATUS status;
+ const char *samaccountname = NULL;
+ const char *dn = NULL;
+ uint32_t uac = 0;
+ uint32_t flags = 0;
+ struct security_token *token = NULL;
+ PyObject *ret = NULL;
+ TALLOC_CTX *gpo_ctx = NULL;
+ size_t list_size;
+ size_t i;
+
+ static const char *kwlist[] = {"samaccountname", NULL};
+
+ PyErr_WarnEx(PyExc_DeprecationWarning, "The get_gpo_list function"
+ " is deprecated as of Samba 4.19. Please use "
+ "the samba.gp module instead.", 2);
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s",
+ discard_const_p(char *, kwlist),
+ &samaccountname)) {
+ return NULL;
+ }
+ if (!self->ads_ptr) {
+ PyErr_SetString(PyExc_RuntimeError, "Uninitialized");
+ return NULL;
+ }
+
+ frame = talloc_stackframe();
+
+ status = find_samaccount(self->ads_ptr, frame,
+ samaccountname, &uac, &dn);
+ if (!ADS_ERR_OK(status)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Failed to find samAccountName '%s': %s",
+ samaccountname, ads_errstr(status));
+ goto out;
+ }
+
+ if (uac & UF_WORKSTATION_TRUST_ACCOUNT ||
+ uac & UF_SERVER_TRUST_ACCOUNT) {
+ flags |= GPO_LIST_FLAG_MACHINE;
+ status = gp_get_machine_token(self->ads_ptr, frame, dn,
+ &token);
+ if (!ADS_ERR_OK(status)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Failed to get machine token for '%s'(%s): %s",
+ samaccountname, dn, ads_errstr(status));
+ goto out;
+ }
+ } else {
+ status = ads_get_sid_token(self->ads_ptr, frame, dn, &token);
+ if (!ADS_ERR_OK(status)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Failed to get sid token for '%s'(%s): %s",
+ samaccountname, dn, ads_errstr(status));
+ goto out;
+ }
+ }
+
+ gpo_ctx = talloc_new(frame);
+ if (!gpo_ctx) {
+ PyErr_NoMemory();
+ goto out;
+ }
+ status = ads_get_gpo_list(self->ads_ptr, gpo_ctx, dn, flags, token,
+ &gpo_list);
+ if (!ADS_ERR_OK(status)) {
+ PyErr_Format(PyExc_RuntimeError,
+ "Failed to fetch GPO list: %s",
+ ads_errstr(status));
+ goto out;
+ }
+
+ /* Convert the C linked list into a python list */
+ list_size = 0;
+ for (gpo = gpo_list; gpo != NULL; gpo = gpo->next) {
+ list_size++;
+ }
+
+ i = 0;
+ ret = PyList_New(list_size);
+ if (ret == NULL) {
+ goto out;
+ }
+
+ for (gpo = gpo_list; gpo != NULL; gpo = gpo->next) {
+ PyObject *obj = pytalloc_reference_ex(&GPOType,
+ gpo_ctx, gpo);
+ if (obj == NULL) {
+ Py_CLEAR(ret);
+ goto out;
+ }
+
+ PyList_SetItem(ret, i, obj);
+ i++;
+ }
+
+out:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+#endif
+
+static PyMethodDef ADS_methods[] = {
+ { "connect", (PyCFunction)py_ads_connect, METH_NOARGS,
+ "Connect to the LDAP server" },
+#ifdef HAVE_ADS
+ { "get_gpo_list", PY_DISCARD_FUNC_SIG(PyCFunction, py_ads_get_gpo_list),
+ METH_VARARGS | METH_KEYWORDS,
+ NULL },
+#endif
+ {0}
+};
+
+static PyTypeObject ads_ADSType = {
+ .tp_name = "gpo.ADS_STRUCT",
+ .tp_basicsize = sizeof(ADS),
+ .tp_new = PyType_GenericNew,
+ .tp_dealloc = (destructor)py_ads_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+ .tp_doc = "ADS struct",
+ .tp_methods = ADS_methods,
+ .tp_init = (initproc)py_ads_init,
+};
+
+static PyMethodDef py_gpo_methods[] = {
+ {"gpo_get_sysvol_gpt_version",
+ (PyCFunction)py_gpo_get_sysvol_gpt_version,
+ METH_VARARGS, NULL},
+ {0}
+};
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "gpo",
+ .m_doc = "libgpo python bindings",
+ .m_size = -1,
+ .m_methods = py_gpo_methods,
+};
+
+/* Will be called by python when loading this module */
+void initgpo(void);
+
+MODULE_INIT_FUNC(gpo)
+{
+ PyObject *m;
+
+ debug_setup_talloc_log();
+
+ /* Instantiate the types */
+ m = PyModule_Create(&moduledef);
+ if (m == NULL) {
+ goto err;
+ }
+
+ if (PyModule_AddObject(m, "version",
+ PyUnicode_FromString(SAMBA_VERSION_STRING)) ) {
+ goto err;
+ }
+
+ if (pytalloc_BaseObject_PyType_Ready(&ads_ADSType) < 0) {
+ goto err;
+ }
+
+ Py_INCREF(&ads_ADSType);
+ if (PyModule_AddObject(m, "ADS_STRUCT", (PyObject *)&ads_ADSType)) {
+ goto err;
+ }
+
+ if (pytalloc_BaseObject_PyType_Ready(&GPOType) < 0) {
+ goto err;
+ }
+
+ Py_INCREF((PyObject *)(void *)&GPOType);
+ if (PyModule_AddObject(m, "GROUP_POLICY_OBJECT",
+ (PyObject *)&GPOType)) {
+ goto err;
+ }
+
+#define ADD_FLAGS(val) PyModule_AddObject(m, #val, PyLong_FromLong(val))
+
+ ADD_FLAGS(GP_LINK_UNKOWN);
+ ADD_FLAGS(GP_LINK_MACHINE);
+ ADD_FLAGS(GP_LINK_SITE);
+ ADD_FLAGS(GP_LINK_DOMAIN);
+ ADD_FLAGS(GP_LINK_OU);
+ ADD_FLAGS(GP_LINK_LOCAL);
+
+ return m;
+
+err:
+ Py_CLEAR(m);
+ return NULL;
+}
diff --git a/libgpo/wscript_build b/libgpo/wscript_build
new file mode 100644
index 0000000..cb0a40a
--- /dev/null
+++ b/libgpo/wscript_build
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+LIBGPO_SRC = '''gpo_ldap.c gpo_ini.c gpo_util.c gpo_fetch.c gpo_filesync.c
+ gpo_sec.c gpo_reg.c gpext/gpext.c'''
+
+bld.SAMBA3_LIBRARY('gpo',
+ source='${LIBGPO_SRC}',
+ deps='talloc ads TOKEN_UTIL auth',
+ vars=locals(),
+ private_library=True)
+
+bld.SAMBA3_LIBRARY('gpext',
+ source='''gpext/gpext.c''',
+ deps='talloc ads TOKEN_UTIL auth gpo',
+ private_library=True)
+
+pyparam_util = bld.pyembed_libname('pyparam_util')
+pyrpc_util = bld.pyembed_libname('pyrpc_util')
+bld.SAMBA3_PYTHON('python_samba_libgpo', 'pygpo.c',
+ deps='%s gpext talloc ads TOKEN_UTIL auth %s' % (pyparam_util, pyrpc_util),
+ realname='samba/gpo.so')
+
+if bld.AD_DC_BUILD_IS_ENABLED():
+ bld.RECURSE('admx')
diff --git a/librpc/ABI/ndr-0.0.1.sigs b/librpc/ABI/ndr-0.0.1.sigs
new file mode 100644
index 0000000..904be70
--- /dev/null
+++ b/librpc/ABI/ndr-0.0.1.sigs
@@ -0,0 +1,245 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.0.2.sigs b/librpc/ABI/ndr-0.0.2.sigs
new file mode 100644
index 0000000..66be5ba
--- /dev/null
+++ b/librpc/ABI/ndr-0.0.2.sigs
@@ -0,0 +1,247 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.0.3.sigs b/librpc/ABI/ndr-0.0.3.sigs
new file mode 100644
index 0000000..d9c76f0
--- /dev/null
+++ b/librpc/ABI/ndr-0.0.3.sigs
@@ -0,0 +1,251 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.0.4.sigs b/librpc/ABI/ndr-0.0.4.sigs
new file mode 100644
index 0000000..c1b880f
--- /dev/null
+++ b/librpc/ABI/ndr-0.0.4.sigs
@@ -0,0 +1,252 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.0.5.sigs b/librpc/ABI/ndr-0.0.5.sigs
new file mode 100644
index 0000000..36a4e30
--- /dev/null
+++ b/librpc/ABI/ndr-0.0.5.sigs
@@ -0,0 +1,255 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.0.6.sigs b/librpc/ABI/ndr-0.0.6.sigs
new file mode 100644
index 0000000..a9b27a3
--- /dev/null
+++ b/librpc/ABI/ndr-0.0.6.sigs
@@ -0,0 +1,256 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.0.7.sigs b/librpc/ABI/ndr-0.0.7.sigs
new file mode 100644
index 0000000..c88a56e
--- /dev/null
+++ b/librpc/ABI/ndr-0.0.7.sigs
@@ -0,0 +1,257 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.0.8.sigs b/librpc/ABI/ndr-0.0.8.sigs
new file mode 100644
index 0000000..6bf637c
--- /dev/null
+++ b/librpc/ABI/ndr-0.0.8.sigs
@@ -0,0 +1,258 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.0.9.sigs b/librpc/ABI/ndr-0.0.9.sigs
new file mode 100644
index 0000000..b363b96
--- /dev/null
+++ b/librpc/ABI/ndr-0.0.9.sigs
@@ -0,0 +1,259 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list **, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list **, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list **, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.1.0.sigs b/librpc/ABI/ndr-0.1.0.sigs
new file mode 100644
index 0000000..80a3faf
--- /dev/null
+++ b/librpc/ABI/ndr-0.1.0.sigs
@@ -0,0 +1,259 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list *, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.1.1.sigs b/librpc/ABI/ndr-0.1.1.sigs
new file mode 100644
index 0000000..434e110
--- /dev/null
+++ b/librpc/ABI/ndr-0.1.1.sigs
@@ -0,0 +1,262 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list *, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.1.2.sigs b/librpc/ABI/ndr-0.1.2.sigs
new file mode 100644
index 0000000..bf9fdfc
--- /dev/null
+++ b/librpc/ABI/ndr-0.1.2.sigs
@@ -0,0 +1,263 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list *, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
diff --git a/librpc/ABI/ndr-0.2.0.sigs b/librpc/ABI/ndr-0.2.0.sigs
new file mode 100644
index 0000000..6346f2f
--- /dev/null
+++ b/librpc/ABI/ndr-0.2.0.sigs
@@ -0,0 +1,264 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list *, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/ABI/ndr-0.2.1.sigs b/librpc/ABI/ndr-0.2.1.sigs
new file mode 100644
index 0000000..b73a463
--- /dev/null
+++ b/librpc/ABI/ndr-0.2.1.sigs
@@ -0,0 +1,265 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_get_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, ...)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_get_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: uint32_t (struct ndr_pull *, const void *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, ...)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_get_switch_value: uint32_t (struct ndr_push *, const void *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_table_misc: name = 0xXXXX "misc", syntax_id = {uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0}, helpstring = 0xXXXX, num_calls = 0, calls = 0xXXXX <misc_calls>, num_public_structs = 10, public_structs = 0xXXXX <misc_public_structs>, endpoints = 0xXXXX <misc_endpoints>, authservices = 0xXXXX <misc_authservices>
+ndr_token_peek: uint32_t (struct ndr_token_list *, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/ABI/ndr-1.0.0.sigs b/librpc/ABI/ndr-1.0.0.sigs
new file mode 100644
index 0000000..bc7c3e8
--- /dev/null
+++ b/librpc/ABI/ndr-1.0.0.sigs
@@ -0,0 +1,263 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_zero: struct GUID (void)
+_ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, const char *, const char *, ...)
+_ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_steal_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_steal_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list *, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/ABI/ndr-1.0.1.sigs b/librpc/ABI/ndr-1.0.1.sigs
new file mode 100644
index 0000000..8415085
--- /dev/null
+++ b/librpc/ABI/ndr-1.0.1.sigs
@@ -0,0 +1,264 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_to_ndr_buf: NTSTATUS (const struct GUID *, struct GUID_ndr_buf *)
+GUID_zero: struct GUID (void)
+_ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, const char *, const char *, ...)
+_ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_steal_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_steal_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list *, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/ABI/ndr-1.0.2.sigs b/librpc/ABI/ndr-1.0.2.sigs
new file mode 100644
index 0000000..0ec8575
--- /dev/null
+++ b/librpc/ABI/ndr-1.0.2.sigs
@@ -0,0 +1,265 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_to_ndr_buf: NTSTATUS (const struct GUID *, struct GUID_ndr_buf *)
+GUID_zero: struct GUID (void)
+_ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, const char *, const char *, ...)
+_ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: uint32_t (struct ndr_pull *, const void *)
+ndr_get_array_size: uint32_t (struct ndr_pull *, const void *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_steal_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_steal_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_buf_string: char *(const struct ndr_syntax_id *, struct ndr_syntax_id_buf *)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_peek: uint32_t (struct ndr_token_list *, const void *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/ABI/ndr-2.0.0.sigs b/librpc/ABI/ndr-2.0.0.sigs
new file mode 100644
index 0000000..aefe5aa
--- /dev/null
+++ b/librpc/ABI/ndr-2.0.0.sigs
@@ -0,0 +1,269 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_to_ndr_buf: NTSTATUS (const struct GUID *, struct GUID_ndr_buf *)
+GUID_zero: struct GUID (void)
+_ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, const char *, const char *, ...)
+_ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_get_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: void (ndr_print_fn_t, const char *, void *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_steal_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_steal_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_buf_string: char *(const struct ndr_syntax_id *, struct ndr_syntax_id_buf *)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_max_list_size: size_t (void)
+ndr_token_peek: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/ABI/ndr-3.0.0.sigs b/librpc/ABI/ndr-3.0.0.sigs
new file mode 100644
index 0000000..d3f3eca
--- /dev/null
+++ b/librpc/ABI/ndr-3.0.0.sigs
@@ -0,0 +1,269 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_to_ndr_buf: NTSTATUS (const struct GUID *, struct GUID_ndr_buf *)
+GUID_zero: struct GUID (void)
+_ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, const char *, const char *, ...)
+_ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_get_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: bool (int, ndr_print_fn_t, const char *, void *, const char *, const char *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_steal_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_steal_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_buf_string: char *(const struct ndr_syntax_id *, struct ndr_syntax_id_buf *)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_max_list_size: size_t (void)
+ndr_token_peek: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/ABI/ndr-3.0.1.sigs b/librpc/ABI/ndr-3.0.1.sigs
new file mode 100644
index 0000000..54aab1d
--- /dev/null
+++ b/librpc/ABI/ndr-3.0.1.sigs
@@ -0,0 +1,272 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_to_ndr_buf: NTSTATUS (const struct GUID *, struct GUID_ndr_buf *)
+GUID_zero: struct GUID (void)
+_ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, const char *, const char *, ...)
+_ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_get_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: bool (int, ndr_print_fn_t, const char *, void *, const char *, const char *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int64: void (struct ndr_print *, const char *, int64_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_steal_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int64: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int64: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_steal_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_buf_string: char *(const struct ndr_syntax_id *, struct ndr_syntax_id_buf *)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_max_list_size: size_t (void)
+ndr_token_peek: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/ABI/ndr-3.0.2.sigs b/librpc/ABI/ndr-3.0.2.sigs
new file mode 100644
index 0000000..2f9b4b8
--- /dev/null
+++ b/librpc/ABI/ndr-3.0.2.sigs
@@ -0,0 +1,273 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_to_ndr_buf: NTSTATUS (const struct GUID *, struct GUID_ndr_buf *)
+GUID_zero: struct GUID (void)
+_ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, const char *, const char *, ...)
+_ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_get_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: bool (int, ndr_print_fn_t, const char *, void *, const char *, const char *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, int, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, int, void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int64: void (struct ndr_print *, const char *, int64_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_steal_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, int, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, int, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, int, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, int, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, int, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, int, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, int, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, int, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, int, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, int, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, int, int32_t *)
+ndr_pull_int64: enum ndr_err_code (struct ndr_pull *, int, int64_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, int, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, int, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, int, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, int, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, int, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, int, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, int, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, int, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_noalloc: enum ndr_err_code (const uint8_t *, size_t, void *, ndr_pull_flags_fn_t, size_t *)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, int, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, int, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, int, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, int, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, int, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, int, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, int, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, int, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, int, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, int, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, int, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, int, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, int, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, int, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, int, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, int, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, int, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, int, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, int, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, int, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, int, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, int, int32_t)
+ndr_push_int64: enum ndr_err_code (struct ndr_push *, int, int64_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, int, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, int, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, int, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, int, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, int, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, int, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_steal_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, int, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, int, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, int, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, int, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, int, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, int, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, int, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, int, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, int, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, int, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, int, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, int, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (uint32_t *, uint32_t)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, int)
+ndr_size_GUID: size_t (const struct GUID *, int)
+ndr_size_string: uint32_t (int, const char * const *, int)
+ndr_size_string_array: size_t (const char **, uint32_t, int)
+ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_buf_string: char *(const struct ndr_syntax_id *, struct ndr_syntax_id_buf *)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_max_list_size: size_t (void)
+ndr_token_peek: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/ABI/ndr-4.0.0.sigs b/librpc/ABI/ndr-4.0.0.sigs
new file mode 100644
index 0000000..5474a51
--- /dev/null
+++ b/librpc/ABI/ndr-4.0.0.sigs
@@ -0,0 +1,277 @@
+GUID_all_zero: bool (const struct GUID *)
+GUID_buf_string: char *(const struct GUID *, struct GUID_txt_buf *)
+GUID_compare: int (const struct GUID *, const struct GUID *)
+GUID_equal: bool (const struct GUID *, const struct GUID *)
+GUID_from_data_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_ndr_blob: NTSTATUS (const DATA_BLOB *, struct GUID *)
+GUID_from_string: NTSTATUS (const char *, struct GUID *)
+GUID_hexstring: char *(TALLOC_CTX *, const struct GUID *)
+GUID_random: struct GUID (void)
+GUID_string: char *(TALLOC_CTX *, const struct GUID *)
+GUID_string2: char *(TALLOC_CTX *, const struct GUID *)
+GUID_to_ndr_blob: NTSTATUS (const struct GUID *, TALLOC_CTX *, DATA_BLOB *)
+GUID_to_ndr_buf: NTSTATUS (const struct GUID *, struct GUID_ndr_buf *)
+GUID_zero: struct GUID (void)
+_ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const char *, const char *, const char *, ...)
+_ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...)
+ndr_align_size: size_t (uint32_t, size_t)
+ndr_charset_length: uint32_t (const void *, charset_t)
+ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_padding: void (struct ndr_pull *, size_t)
+ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint32_t)
+ndr_check_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
+ndr_get_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_get_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_map_error2errno: int (enum ndr_err_code)
+ndr_map_error2ntstatus: NTSTATUS (enum ndr_err_code)
+ndr_map_error2string: const char *(enum ndr_err_code)
+ndr_policy_handle_empty: bool (const struct policy_handle *)
+ndr_policy_handle_equal: bool (const struct policy_handle *, const struct policy_handle *)
+ndr_print_DATA_BLOB: void (struct ndr_print *, const char *, DATA_BLOB)
+ndr_print_GUID: void (struct ndr_print *, const char *, const struct GUID *)
+ndr_print_HRESULT: void (struct ndr_print *, const char *, HRESULT)
+ndr_print_KRB5_EDATA_NTSTATUS: void (struct ndr_print *, const char *, const struct KRB5_EDATA_NTSTATUS *)
+ndr_print_NTSTATUS: void (struct ndr_print *, const char *, NTSTATUS)
+ndr_print_NTTIME: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_1sec: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_NTTIME_hyper: void (struct ndr_print *, const char *, NTTIME)
+ndr_print_WERROR: void (struct ndr_print *, const char *, WERROR)
+ndr_print_array_uint8: void (struct ndr_print *, const char *, const uint8_t *, uint32_t)
+ndr_print_bad_level: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_bitmap_flag: void (struct ndr_print *, size_t, const char *, uint32_t, uint32_t)
+ndr_print_bool: void (struct ndr_print *, const char *, const bool)
+ndr_print_debug: bool (int, ndr_print_fn_t, const char *, void *, const char *, const char *)
+ndr_print_debug_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_debugc: void (int, ndr_print_fn_t, const char *, void *)
+ndr_print_debugc_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_dlong: void (struct ndr_print *, const char *, int64_t)
+ndr_print_double: void (struct ndr_print *, const char *, double)
+ndr_print_enum: void (struct ndr_print *, const char *, const char *, const char *, uint32_t)
+ndr_print_function_debug: void (ndr_print_function_t, const char *, ndr_flags_type, void *)
+ndr_print_function_string: char *(TALLOC_CTX *, ndr_print_function_t, const char *, ndr_flags_type, void *)
+ndr_print_gid_t: void (struct ndr_print *, const char *, gid_t)
+ndr_print_hyper: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_int16: void (struct ndr_print *, const char *, int16_t)
+ndr_print_int32: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int3264: void (struct ndr_print *, const char *, int32_t)
+ndr_print_int64: void (struct ndr_print *, const char *, int64_t)
+ndr_print_int8: void (struct ndr_print *, const char *, int8_t)
+ndr_print_ipv4address: void (struct ndr_print *, const char *, const char *)
+ndr_print_ipv6address: void (struct ndr_print *, const char *, const char *)
+ndr_print_libndr_flags: void (struct ndr_print *, const char *, libndr_flags)
+ndr_print_ndr_syntax_id: void (struct ndr_print *, const char *, const struct ndr_syntax_id *)
+ndr_print_netr_SamDatabaseID: void (struct ndr_print *, const char *, enum netr_SamDatabaseID)
+ndr_print_netr_SchannelType: void (struct ndr_print *, const char *, enum netr_SchannelType)
+ndr_print_null: void (struct ndr_print *)
+ndr_print_pointer: void (struct ndr_print *, const char *, void *)
+ndr_print_policy_handle: void (struct ndr_print *, const char *, const struct policy_handle *)
+ndr_print_printf_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_ptr: void (struct ndr_print *, const char *, const void *)
+ndr_print_set_switch_value: enum ndr_err_code (struct ndr_print *, const void *, uint32_t)
+ndr_print_sockaddr_storage: void (struct ndr_print *, const char *, const struct sockaddr_storage *)
+ndr_print_steal_switch_value: uint32_t (struct ndr_print *, const void *)
+ndr_print_string: void (struct ndr_print *, const char *, const char *)
+ndr_print_string_array: void (struct ndr_print *, const char *, const char **)
+ndr_print_string_helper: void (struct ndr_print *, const char *, ...)
+ndr_print_struct: void (struct ndr_print *, const char *, const char *)
+ndr_print_struct_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, void *)
+ndr_print_svcctl_ServerType: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_time_t: void (struct ndr_print *, const char *, time_t)
+ndr_print_timespec: void (struct ndr_print *, const char *, const struct timespec *)
+ndr_print_timeval: void (struct ndr_print *, const char *, const struct timeval *)
+ndr_print_u16string: void (struct ndr_print *, const char *, const unsigned char *)
+ndr_print_udlong: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_udlongr: void (struct ndr_print *, const char *, uint64_t)
+ndr_print_uid_t: void (struct ndr_print *, const char *, uid_t)
+ndr_print_uint16: void (struct ndr_print *, const char *, uint16_t)
+ndr_print_uint32: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint3264: void (struct ndr_print *, const char *, uint32_t)
+ndr_print_uint8: void (struct ndr_print *, const char *, uint8_t)
+ndr_print_union: void (struct ndr_print *, const char *, int, const char *)
+ndr_print_union_debug: void (ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_union_string: char *(TALLOC_CTX *, ndr_print_fn_t, const char *, uint32_t, void *)
+ndr_print_winreg_Data: void (struct ndr_print *, const char *, const union winreg_Data *)
+ndr_print_winreg_Data_GPO: void (struct ndr_print *, const char *, const union winreg_Data_GPO *)
+ndr_print_winreg_Type: void (struct ndr_print *, const char *, enum winreg_Type)
+ndr_pull_DATA_BLOB: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, DATA_BLOB *)
+ndr_pull_GUID: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, struct GUID *)
+ndr_pull_HRESULT: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, HRESULT *)
+ndr_pull_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, struct KRB5_EDATA_NTSTATUS *)
+ndr_pull_NTSTATUS: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, NTSTATUS *)
+ndr_pull_NTTIME: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, NTTIME *)
+ndr_pull_NTTIME_1sec: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, NTTIME *)
+ndr_pull_NTTIME_hyper: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, NTTIME *)
+ndr_pull_WERROR: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, WERROR *)
+ndr_pull_advance: enum ndr_err_code (struct ndr_pull *, uint32_t)
+ndr_pull_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_append: enum ndr_err_code (struct ndr_pull *, DATA_BLOB *)
+ndr_pull_array_length: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_size: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_array_uint8: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint8_t *, uint32_t)
+ndr_pull_bytes: enum ndr_err_code (struct ndr_pull *, uint8_t *, uint32_t)
+ndr_pull_charset: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_charset_to_null: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, const char **, uint32_t, uint8_t, charset_t)
+ndr_pull_dlong: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, int64_t *)
+ndr_pull_double: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, double *)
+ndr_pull_enum_uint16: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint16_t *)
+ndr_pull_enum_uint1632: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint16_t *)
+ndr_pull_enum_uint32: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint32_t *)
+ndr_pull_enum_uint8: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint8_t *)
+ndr_pull_generic_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_get_relative_base_offset: uint32_t (struct ndr_pull *)
+ndr_pull_gid_t: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, gid_t *)
+ndr_pull_hyper: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint64_t *)
+ndr_pull_init_blob: struct ndr_pull *(const DATA_BLOB *, TALLOC_CTX *)
+ndr_pull_int16: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, int16_t *)
+ndr_pull_int32: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, int32_t *)
+ndr_pull_int64: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, int64_t *)
+ndr_pull_int8: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, int8_t *)
+ndr_pull_ipv4address: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, const char **)
+ndr_pull_ipv6address: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, const char **)
+ndr_pull_ndr_syntax_id: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, struct ndr_syntax_id *)
+ndr_pull_netr_SamDatabaseID: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, enum netr_SamDatabaseID *)
+ndr_pull_netr_SchannelType: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, enum netr_SchannelType *)
+ndr_pull_pointer: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, void **)
+ndr_pull_policy_handle: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, struct policy_handle *)
+ndr_pull_pop: enum ndr_err_code (struct ndr_pull *)
+ndr_pull_ref_ptr: enum ndr_err_code (struct ndr_pull *, uint32_t *)
+ndr_pull_relative_ptr1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_relative_ptr2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_relative_ptr_short: enum ndr_err_code (struct ndr_pull *, uint16_t *)
+ndr_pull_restore_relative_base_offset: void (struct ndr_pull *, uint32_t)
+ndr_pull_set_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset1: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
+ndr_pull_setup_relative_base_offset2: enum ndr_err_code (struct ndr_pull *, const void *)
+ndr_pull_steal_switch_value: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_pull_string: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, const char **)
+ndr_pull_string_array: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, const char ***)
+ndr_pull_struct_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_all_noalloc: enum ndr_err_code (const DATA_BLOB *, void *, ndr_pull_flags_fn_t)
+ndr_pull_struct_blob_noalloc: enum ndr_err_code (const uint8_t *, size_t, void *, ndr_pull_flags_fn_t, size_t *)
+ndr_pull_subcontext_end: enum ndr_err_code (struct ndr_pull *, struct ndr_pull *, size_t, ssize_t)
+ndr_pull_subcontext_start: enum ndr_err_code (struct ndr_pull *, struct ndr_pull **, size_t, ssize_t)
+ndr_pull_svcctl_ServerType: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint32_t *)
+ndr_pull_time_t: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, time_t *)
+ndr_pull_timespec: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, struct timespec *)
+ndr_pull_timeval: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, struct timeval *)
+ndr_pull_trailer_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_u16string: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, const unsigned char **)
+ndr_pull_udlong: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint64_t *)
+ndr_pull_udlongr: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint64_t *)
+ndr_pull_uid_t: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uid_t *)
+ndr_pull_uint16: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint16_t *)
+ndr_pull_uint1632: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint16_t *)
+ndr_pull_uint32: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint32_t *)
+ndr_pull_uint3264: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint32_t *)
+ndr_pull_uint8: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, uint8_t *)
+ndr_pull_union_align: enum ndr_err_code (struct ndr_pull *, size_t)
+ndr_pull_union_blob: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_union_blob_all: enum ndr_err_code (const DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_pull_flags_fn_t)
+ndr_pull_winreg_Data: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, union winreg_Data *)
+ndr_pull_winreg_Data_GPO: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, union winreg_Data_GPO *)
+ndr_pull_winreg_Type: enum ndr_err_code (struct ndr_pull *, ndr_flags_type, enum winreg_Type *)
+ndr_push_DATA_BLOB: enum ndr_err_code (struct ndr_push *, ndr_flags_type, DATA_BLOB)
+ndr_push_GUID: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const struct GUID *)
+ndr_push_HRESULT: enum ndr_err_code (struct ndr_push *, ndr_flags_type, HRESULT)
+ndr_push_KRB5_EDATA_NTSTATUS: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const struct KRB5_EDATA_NTSTATUS *)
+ndr_push_NTSTATUS: enum ndr_err_code (struct ndr_push *, ndr_flags_type, NTSTATUS)
+ndr_push_NTTIME: enum ndr_err_code (struct ndr_push *, ndr_flags_type, NTTIME)
+ndr_push_NTTIME_1sec: enum ndr_err_code (struct ndr_push *, ndr_flags_type, NTTIME)
+ndr_push_NTTIME_hyper: enum ndr_err_code (struct ndr_push *, ndr_flags_type, NTTIME)
+ndr_push_WERROR: enum ndr_err_code (struct ndr_push *, ndr_flags_type, WERROR)
+ndr_push_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_array_uint8: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const uint8_t *, uint32_t)
+ndr_push_blob: DATA_BLOB (struct ndr_push *)
+ndr_push_bytes: enum ndr_err_code (struct ndr_push *, const uint8_t *, uint32_t)
+ndr_push_charset: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_charset_to_null: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const char *, uint32_t, uint8_t, charset_t)
+ndr_push_dlong: enum ndr_err_code (struct ndr_push *, ndr_flags_type, int64_t)
+ndr_push_double: enum ndr_err_code (struct ndr_push *, ndr_flags_type, double)
+ndr_push_enum_uint16: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint16_t)
+ndr_push_enum_uint1632: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint16_t)
+ndr_push_enum_uint32: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint32_t)
+ndr_push_enum_uint8: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint8_t)
+ndr_push_expand: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_push_full_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_get_relative_base_offset: uint32_t (struct ndr_push *)
+ndr_push_gid_t: enum ndr_err_code (struct ndr_push *, ndr_flags_type, gid_t)
+ndr_push_hyper: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint64_t)
+ndr_push_init_ctx: struct ndr_push *(TALLOC_CTX *)
+ndr_push_int16: enum ndr_err_code (struct ndr_push *, ndr_flags_type, int16_t)
+ndr_push_int32: enum ndr_err_code (struct ndr_push *, ndr_flags_type, int32_t)
+ndr_push_int64: enum ndr_err_code (struct ndr_push *, ndr_flags_type, int64_t)
+ndr_push_int8: enum ndr_err_code (struct ndr_push *, ndr_flags_type, int8_t)
+ndr_push_ipv4address: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const char *)
+ndr_push_ipv6address: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const char *)
+ndr_push_ndr_syntax_id: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const struct ndr_syntax_id *)
+ndr_push_netr_SamDatabaseID: enum ndr_err_code (struct ndr_push *, ndr_flags_type, enum netr_SamDatabaseID)
+ndr_push_netr_SchannelType: enum ndr_err_code (struct ndr_push *, ndr_flags_type, enum netr_SchannelType)
+ndr_push_pipe_chunk_trailer: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint32_t)
+ndr_push_pointer: enum ndr_err_code (struct ndr_push *, ndr_flags_type, void *)
+ndr_push_policy_handle: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const struct policy_handle *)
+ndr_push_ref_ptr: enum ndr_err_code (struct ndr_push *)
+ndr_push_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_end: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_relative_ptr2_start: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_restore_relative_base_offset: void (struct ndr_push *, uint32_t)
+ndr_push_set_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset1: enum ndr_err_code (struct ndr_push *, const void *, uint32_t)
+ndr_push_setup_relative_base_offset2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr1: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_short_relative_ptr2: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_steal_switch_value: enum ndr_err_code (struct ndr_push *, const void *, uint32_t *)
+ndr_push_string: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const char *)
+ndr_push_string_array: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const char **)
+ndr_push_struct_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, const void *, ndr_push_flags_fn_t)
+ndr_push_struct_into_fixed_blob: enum ndr_err_code (DATA_BLOB *, const void *, ndr_push_flags_fn_t)
+ndr_push_subcontext_end: enum ndr_err_code (struct ndr_push *, struct ndr_push *, size_t, ssize_t)
+ndr_push_subcontext_start: enum ndr_err_code (struct ndr_push *, struct ndr_push **, size_t, ssize_t)
+ndr_push_svcctl_ServerType: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint32_t)
+ndr_push_time_t: enum ndr_err_code (struct ndr_push *, ndr_flags_type, time_t)
+ndr_push_timespec: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const struct timespec *)
+ndr_push_timeval: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const struct timeval *)
+ndr_push_trailer_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_u16string: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const unsigned char *)
+ndr_push_udlong: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint64_t)
+ndr_push_udlongr: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint64_t)
+ndr_push_uid_t: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uid_t)
+ndr_push_uint16: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint16_t)
+ndr_push_uint1632: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint16_t)
+ndr_push_uint32: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint32_t)
+ndr_push_uint3264: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint32_t)
+ndr_push_uint8: enum ndr_err_code (struct ndr_push *, ndr_flags_type, uint8_t)
+ndr_push_union_align: enum ndr_err_code (struct ndr_push *, size_t)
+ndr_push_union_blob: enum ndr_err_code (DATA_BLOB *, TALLOC_CTX *, void *, uint32_t, ndr_push_flags_fn_t)
+ndr_push_unique_ptr: enum ndr_err_code (struct ndr_push *, const void *)
+ndr_push_winreg_Data: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const union winreg_Data *)
+ndr_push_winreg_Data_GPO: enum ndr_err_code (struct ndr_push *, ndr_flags_type, const union winreg_Data_GPO *)
+ndr_push_winreg_Type: enum ndr_err_code (struct ndr_push *, ndr_flags_type, enum winreg_Type)
+ndr_push_zero: enum ndr_err_code (struct ndr_push *, uint32_t)
+ndr_set_flags: void (libndr_flags *, libndr_flags)
+ndr_size_DATA_BLOB: uint32_t (int, const DATA_BLOB *, ndr_flags_type)
+ndr_size_GUID: size_t (const struct GUID *, libndr_flags)
+ndr_size_string: uint32_t (int, const char * const *, ndr_flags_type)
+ndr_size_string_array: size_t (const char **, uint32_t, libndr_flags)
+ndr_size_struct: size_t (const void *, libndr_flags, ndr_push_flags_fn_t)
+ndr_size_union: size_t (const void *, libndr_flags, uint32_t, ndr_push_flags_fn_t)
+ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, libndr_flags)
+ndr_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_steal_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
+ndr_string_array_size: size_t (struct ndr_push *, const char *)
+ndr_string_length: uint32_t (const void *, uint32_t)
+ndr_syntax_id_buf_string: char *(const struct ndr_syntax_id *, struct ndr_syntax_id_buf *)
+ndr_syntax_id_equal: bool (const struct ndr_syntax_id *, const struct ndr_syntax_id *)
+ndr_syntax_id_from_string: bool (const char *, struct ndr_syntax_id *)
+ndr_syntax_id_null: uuid = {time_low = 0, time_mid = 0, time_hi_and_version = 0, clock_seq = "\000", node = "\000\000\000\000\000"}, if_version = 0
+ndr_syntax_id_to_string: char *(TALLOC_CTX *, const struct ndr_syntax_id *)
+ndr_token_max_list_size: size_t (void)
+ndr_token_peek: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *)
+ndr_token_retrieve_cmp_fn: enum ndr_err_code (struct ndr_token_list *, const void *, uint32_t *, comparison_fn_t, bool)
+ndr_token_store: enum ndr_err_code (TALLOC_CTX *, struct ndr_token_list *, const void *, uint32_t)
+ndr_transfer_syntax_ndr: uuid = {time_low = 2324192516, time_mid = 7403, time_hi_and_version = 4553, clock_seq = "\237\350", node = "\b\000+\020H`"}, if_version = 2
+ndr_transfer_syntax_ndr64: uuid = {time_low = 1903232307, time_mid = 48826, time_hi_and_version = 18743, clock_seq = "\203\031", node = "\265\333\357\234\314\066"}, if_version = 1
+ndr_zero_memory: void (void *, size_t)
diff --git a/librpc/binding-strings.txt b/librpc/binding-strings.txt
new file mode 100644
index 0000000..ca3d1b6
--- /dev/null
+++ b/librpc/binding-strings.txt
@@ -0,0 +1,4 @@
+DCERPC binding strings
+----------------------
+
+Please consult the rpcclient(1) manpage for binding string details.
diff --git a/librpc/gen_ndr/README b/librpc/gen_ndr/README
new file mode 100644
index 0000000..5ccb89d
--- /dev/null
+++ b/librpc/gen_ndr/README
@@ -0,0 +1,4 @@
+This contains the generated files from PIDL for the IDL files in ../idl/*.idl
+
+DO NOT REMOVE THIS FILE. The waf 1.5 build relies on this directory
+existing in the source tree.
diff --git a/librpc/idl/IDL_LICENSE.txt b/librpc/idl/IDL_LICENSE.txt
new file mode 100644
index 0000000..a2d87ec
--- /dev/null
+++ b/librpc/idl/IDL_LICENSE.txt
@@ -0,0 +1,85 @@
+The IDL files in this directory are made available by the Samba Team
+under the following license:
+
+ Permission to use, copy, modify, and distribute these interface
+ definitions 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.
+
+
+The following relates to IDL obtained from Open Specifications Documentation
+
+ Intellectual Property Rights Notice for Open Specifications Documentation
+
+ * Technical Documentation. Microsoft publishes Open Specifications
+ documentation (“this documentation”) for protocols, file formats,
+ data portability, computer languages, and standards
+ support. Additionally, overview documents cover inter-protocol
+ relationships and interactions.
+
+ * Copyrights. This documentation is covered by Microsoft
+ copyrights. Regardless of any other terms that are contained in
+ the terms of use for the Microsoft website that hosts this
+ documentation, you can make copies of it in order to develop
+ implementations of the technologies that are described in this
+ documentation and can distribute portions of it in your
+ implementations that use these technologies or in your
+ documentation as necessary to properly document the
+ implementation. You can also distribute in your implementation,
+ with or without modification, any schemas, IDLs, or code samples
+ that are included in the documentation. This permission also
+ applies to any documents that are referenced in the Open
+ Specifications documentation.
+
+ * No Trade Secrets. Microsoft does not claim any trade secret rights
+ in this documentation.
+
+ * Patents. Microsoft has patents that might cover your
+ implementations of the technologies described in the Open
+ Specifications documentation. Neither this notice nor Microsoft's
+ delivery of this documentation grants any licenses under those
+ patents or any other Microsoft patents. However, a given Open
+ Specifications document might be covered by the Microsoft Open
+ Specifications Promise or the Microsoft Community Promise. If you
+ would prefer a written license, or if the technologies described
+ in this documentation are not covered by the Open Specifications
+ Promise or Community Promise, as applicable, patent licenses are
+ available by contacting iplg@microsoft.com.
+
+ * License Programs. To see all of the protocols in scope under a
+ specific license program and the associated patents, visit the
+ Patent Map.
+
+ * Trademarks. The names of companies and products contained in this
+ documentation might be covered by trademarks or similar
+ intellectual property rights. This notice does not grant any
+ licenses under those rights. For a list of Microsoft trademarks,
+ visit www.microsoft.com/trademarks.
+
+ * Fictitious Names. The example companies, organizations, products,
+ domain names, email addresses, logos, people, places, and events
+ that are depicted in this documentation are fictitious. No
+ association with any real company, organization, product, domain
+ name, email address, logo, person, place, or event is intended or
+ should be inferred.
+
+ Reservation of Rights. All other rights are reserved, and this notice
+ does not grant any rights other than as specifically described above,
+ whether by implication, estoppel, or otherwise.
+
+ Tools. The Open Specifications documentation does not require the use
+ of Microsoft programming tools or programming environments in order
+ for you to develop an implementation. If you have access to Microsoft
+ programming tools and environments, you are free to take advantage of
+ them. Certain Open Specifications documents are intended for use in
+ conjunction with publicly available standards specifications and
+ network programming art and, as such, assume that the reader either
+ is familiar with the aforementioned material or has immediate access
+ to it.
+
+ Support. For questions and support, please contact dochelp@microsoft.com
+
+
+ The above is the IPR notice from MS-KILE
diff --git a/librpc/idl/ODJ.idl b/librpc/idl/ODJ.idl
new file mode 100644
index 0000000..00c731b
--- /dev/null
+++ b/librpc/idl/ODJ.idl
@@ -0,0 +1,268 @@
+/*
+ The MIT License (MIT)
+ Copyright (c) Microsoft Corporation
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+ associated documentation files (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or substantial
+ portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ The Offline Domain Join IDL has been derived from :
+
+ https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/NetMgmt/odj-idl.md
+*/
+
+import "misc.idl", "lsa.idl", "netlogon.idl", "security.idl";
+
+#include "idl_types.h"
+
+cpp_quote("#define OP_JP2_FLAG_PERSISTENTSITE 0x00000001")
+
+[
+ uuid("11111111-3333-5555-7777-99999999"),
+ version(0.0),
+ pointer_default(unique),
+ helpstring("Offline Domain Join IDL"),
+ helper("../librpc/ndr/ndr_ODJ.h")
+]
+interface ODJ
+{
+ typedef struct {
+ uint32 cbBlob;
+ [size_is(cbBlob),flag(LIBNDR_PRINT_ARRAY_HEX)] uint8 *pBlob;
+ } OP_BLOB;
+
+ /* Contains a serialized ODJ_WIN7_BLOB structure. */
+ const string ODJ_GUID_JOIN_PROVIDER = "{631c7621-5289-4321-bc9e-80f843f868c3}";
+
+ /* Contains a serialized OP_JOIN_PROV2_PART structure. */
+ const string ODJ_GUID_JOIN_PROVIDER2 = "{57BFC56B-52F9-480C-ADCB-91B3F8A82317}";
+
+ /* Contains a serialized OP_JOIN_PROV3_PART structure. */
+ const string ODJ_GUID_JOIN_PROVIDER3 = "{FC0CCF25-7FFA-474A-8611-69FFE269645F}";
+
+ /* Contains a serialized OP_CERT_PART structure. */
+ const string ODJ_GUID_CERT_PROVIDER = "{9c0971e9-832f-4873-8e87-ef1419d4781e}";
+
+ /* Contains a serialized OP_POLICY_PART structure. */
+ const string ODJ_GUID_POLICY_PROVIDER = "{68fb602a-0c09-48ce-b75f-07b7bd58f7ec}";
+
+#if 0
+ typedef struct {
+ char Value[6];
+ } SID_IDENTIFIER_AUTHORITY;
+
+ typedef struct {
+ char Revision;
+ char SubAuthorityCount;
+ SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
+ [size_is(SubAuthorityCount)] uint32 SubAuthority[*];
+ } ODJ_SID;
+
+ typedef struct {
+ USHORT Length;
+ USHORT MaximumLength;
+ [size_is(MaximumLength/2), length_is(Length/2)] PWSTR Buffer;
+ } ODJ_UNICODE_STRING;
+#endif
+#define ODJ_SID dom_sid2
+#define ODJ_UNICODE_STRING lsa_StringLarge
+
+#define ODJ_DECLARE_SERIALIZED_PTR(el_name) \
+ typedef [public] struct { \
+ el_name *p; \
+ } el_name ##_ctr; \
+ \
+ typedef [public,gensize] struct { \
+ [subcontext(0xFFFFFC01)] el_name ## _ctr s; \
+ } el_name ## _serialized_ptr;
+
+ typedef struct {
+ ODJ_UNICODE_STRING Name;
+ ODJ_UNICODE_STRING DnsDomainName;
+ ODJ_UNICODE_STRING DnsForestName;
+ GUID DomainGuid;
+ ODJ_SID *Sid;
+ } ODJ_POLICY_DNS_DOMAIN_INFO;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *lpDomain;
+ [string,charset(UTF16)] uint16 *lpMachineName;
+ [string,charset(UTF16)] [flag(NDR_SECRET)] uint16 *lpMachinePassword;
+ /*
+ * Not sure whether the following 4 bytes are padding or a
+ * pointer, at least it's value may not be 0 for Windows to accept our
+ * generated win7blobs - gd
+ */
+#if 0
+ [flag(NDR_ALIGN8)] DATA_BLOB _pad;
+#else
+ [value(0xffffffff)] uint32 _pad;
+#endif
+ ODJ_POLICY_DNS_DOMAIN_INFO DnsDomainInfo;
+ netr_DsRGetDCNameInfo DcInfo;
+ DWORD Options;
+ } ODJ_WIN7BLOB;
+
+ typedef ODJ_WIN7BLOB *PODJ_WIN7BLOB;
+
+ typedef struct {
+ DWORD dwFlags;
+ [string,charset(UTF16)] uint16 *lpNetbiosName;
+ [string,charset(UTF16)] uint16 *lpSiteName;
+ [string,charset(UTF16)] uint16 *lpPrimaryDNSDomain;
+ DWORD dwReserved;
+ [string,charset(UTF16)] uint16 *lpReserved;
+ } OP_JOINPROV2_PART;
+
+ typedef struct {
+ DWORD Rid;
+ [string,charset(UTF16)] uint16 *lpSid;
+ } OP_JOINPROV3_PART;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *pKeyPath;
+ [string,charset(UTF16)] uint16 *pValueName;
+ winreg_Type ulValueType;
+ uint32 cbValueData;
+ [size_is(cbValueData),flag(LIBNDR_PRINT_ARRAY_HEX)] uint8 *pValueData;
+ } OP_POLICY_ELEMENT;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *pSource;
+ uint32 ulRootKeyId;
+ uint32 cElements;
+ [size_is(cElements)] OP_POLICY_ELEMENT *pElements;
+ } OP_POLICY_ELEMENT_LIST;
+
+ typedef struct {
+ uint32 cElementLists;
+ [size_is(cElementLists)]
+ OP_POLICY_ELEMENT_LIST *pElementLists;
+ OP_BLOB Extension;
+ } OP_POLICY_PART;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *pTemplateName;
+ uint32 ulPrivateKeyExportPolicy;
+ [string,charset(UTF16)] uint16 *pPolicyServerUrl;
+ uint32 ulPolicyServerUrlFlags;
+ [string,charset(UTF16)] uint16 *pPolicyServerId;
+ uint32 cbPfx;
+ [size_is(cbPfx)] uint8 *pPfx;
+ } OP_CERT_PFX_STORE;
+
+ typedef struct {
+ uint32 StoreLocation;
+ [string,charset(UTF16)] uint16 *pStoreName;
+ uint32 cbSst;
+ [size_is(cbSst)] uint8 *pSst;
+ } OP_CERT_SST_STORE;
+
+ typedef struct {
+ uint32 cPfxStores;
+ [size_is(cPfxStores)] OP_CERT_PFX_STORE *pPfxStores;
+ uint32 cSstStores;
+ [size_is(cSstStores)] OP_CERT_SST_STORE *pSstStores;
+ OP_BLOB Extension;
+ } OP_CERT_PART;
+
+ ODJ_DECLARE_SERIALIZED_PTR(ODJ_WIN7BLOB)
+ ODJ_DECLARE_SERIALIZED_PTR(OP_JOINPROV2_PART)
+ ODJ_DECLARE_SERIALIZED_PTR(OP_JOINPROV3_PART)
+ ODJ_DECLARE_SERIALIZED_PTR(OP_POLICY_PART)
+ ODJ_DECLARE_SERIALIZED_PTR(OP_CERT_PART)
+
+ typedef [public,nodiscriminant,gensize] union {
+ [case(1)] [subcontext(0xFFFFFC01)] ODJ_WIN7BLOB win7blob;
+ [case(2)] [subcontext(0xFFFFFC01)] OP_JOINPROV2_PART_ctr join_prov2;
+ [case(3)] [subcontext(0xFFFFFC01)] OP_JOINPROV3_PART_ctr join_prov3;
+ [case(4)] [subcontext(0xFFFFFC01)] OP_CERT_PART_ctr cert_part;
+ [case(5)] [subcontext(0xFFFFFC01)] OP_POLICY_PART_ctr policy_part;
+ [default];
+ } OP_PACKAGE_PART_u;
+
+ typedef [public,bitmap32bit] bitmap {
+ OPSPI_PACKAGE_PART_ESSENTIAL = 0x00000001
+ } ODJ_PackageFlags;
+
+ typedef struct {
+ GUID PartType;
+ uint32 ulFlags;
+#if 1
+ [value(ndr_size_OP_PACKAGE_PART_u(Part, odj_switch_level_from_guid(&PartType), 0))] uint32 part_len;
+ [subcontext(4),subcontext_size(part_len),switch_is(odj_switch_level_from_guid(&PartType))] OP_PACKAGE_PART_u *Part;
+#else
+ OP_BLOB Part;
+#endif
+ OP_BLOB Extension;
+ } OP_PACKAGE_PART;
+
+ ODJ_DECLARE_SERIALIZED_PTR(OP_PACKAGE_PART)
+
+ typedef struct {
+ uint32 cParts;
+ [size_is(cParts)] OP_PACKAGE_PART *pParts;
+ OP_BLOB Extension;
+ } OP_PACKAGE_PART_COLLECTION;
+
+ ODJ_DECLARE_SERIALIZED_PTR(OP_PACKAGE_PART_COLLECTION)
+
+ typedef struct {
+ [value(ndr_size_OP_PACKAGE_PART_COLLECTION_serialized_ptr(w, 0))] uint32 cbBlob;
+ [subcontext(4), subcontext_size(cbBlob)] OP_PACKAGE_PART_COLLECTION_serialized_ptr *w;
+ } OP_PACKAGE_PART_COLLECTION_blob;
+
+ typedef struct {
+ GUID EncryptionType;
+ OP_BLOB EncryptionContext;
+#if 1
+ OP_PACKAGE_PART_COLLECTION_blob WrappedPartCollection;
+#else
+ OP_BLOB WrappedPartCollection;
+#endif
+ uint32 cbDecryptedPartCollection;
+ OP_BLOB Extension;
+ } OP_PACKAGE;
+
+ ODJ_DECLARE_SERIALIZED_PTR(OP_PACKAGE)
+
+ typedef [v1_enum,public] enum {
+ ODJ_WIN7_FORMAT = 0x00000001, /* blob is ODJ_WIN7BLOB */
+ ODJ_WIN8_FORMAT = 0x00000002 /* blob is OP_PACKAGE */
+ } ODJFormat;
+
+ typedef [public,nodiscriminant,gensize] union {
+ [case(ODJ_WIN7_FORMAT)] [subcontext(0xFFFFFC01)] ODJ_WIN7BLOB odj_win7blob;
+ [case(ODJ_WIN8_FORMAT)] [subcontext(0xFFFFFC01)] OP_PACKAGE_ctr op_package;
+ [default] [subcontext(0xFFFFFC01)] [flag(LIBNDR_FLAG_REMAINING)] DATA_BLOB blob;
+ } ODJ_BLOB_u;
+
+ typedef struct {
+ ODJFormat ulODJFormat;
+ [value(ndr_size_ODJ_BLOB_u(pBlob, ulODJFormat, 0))] uint32 cbBlob;
+#if 1
+ [switch_is(ulODJFormat), subcontext(4), subcontext_size(cbBlob)] ODJ_BLOB_u *pBlob;
+#else
+ [size_is(cbBlob),flag(LIBNDR_PRINT_ARRAY_HEX)] uint8 *pBlob;
+#endif
+ } ODJ_BLOB;
+
+ typedef [public] struct {
+ [value(1)] uint32 ulVersion;
+ uint32 ulcBlobs;
+ [size_is(ulcBlobs)] ODJ_BLOB *pBlobs;
+ } ODJ_PROVISION_DATA;
+
+ ODJ_DECLARE_SERIALIZED_PTR(ODJ_PROVISION_DATA)
+}
diff --git a/librpc/idl/atsvc.idl b/librpc/idl/atsvc.idl
new file mode 100644
index 0000000..e72c211
--- /dev/null
+++ b/librpc/idl/atsvc.idl
@@ -0,0 +1,119 @@
+/*
+ atsvc interface definition
+*/
+
+[ uuid("1ff70682-0a51-30e8-076d-740be8cee98b"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Microsoft AT-Scheduler Service"),
+ endpoint("ncacn_np:[\\pipe\\atsvc]", "ncalrpc:")
+] interface atsvc
+{
+ typedef [bitmap32bit] bitmap {
+ First = 0x00000001,
+ Second = 0x00000002,
+ Third = 0x00000004,
+ Fourth = 0x00000008,
+ Fifth = 0x00000010,
+ Sixth = 0x00000020,
+ Seventh = 0x00000040,
+ Eight = 0x00000080,
+ Ninth = 0x00000100,
+ Tenth = 0x00000200,
+ Eleventh = 0x00000400,
+ Twelfth = 0x00000800,
+ Thitteenth = 0x00001000,
+ Fourteenth = 0x00002000,
+ Fifteenth = 0x00004000,
+ Sixteenth = 0x00008000,
+ Seventeenth = 0x00010000,
+ Eighteenth = 0x00020000,
+ Nineteenth = 0x00040000,
+ Twentyth = 0x00080000,
+ Twentyfirst = 0x00100000,
+ Twentysecond = 0x00200000,
+ Twentythird = 0x00400000,
+ Twentyfourth = 0x00800000,
+ Twentyfifth = 0x01000000,
+ Twentysixth = 0x02000000,
+ Twentyseventh = 0x04000000,
+ Twentyeighth = 0x08000000,
+ Twentyninth = 0x10000000,
+ Thirtieth = 0x20000000,
+ Thirtyfirst = 0x40000000
+ } atsvc_DaysOfMonth;
+
+ typedef [bitmap8bit] bitmap {
+ JOB_RUN_PERIODICALLY = 0x01,
+ JOB_EXEC_ERROR = 0x02,
+ JOB_RUNS_TODAY = 0x04,
+ JOB_ADD_CURRENT_DATE = 0x08,
+ JOB_NONINTERACTIVE = 0x10
+ } atsvc_Flags;
+
+ typedef [bitmap8bit] bitmap {
+ DAYSOFWEEK_MONDAY = 0x01,
+ DAYSOFWEEK_TUESDAY = 0x02,
+ DAYSOFWEEK_WEDNESDAY = 0x04,
+ DAYSOFWEEK_THURSDAY = 0x08,
+ DAYSOFWEEK_FRIDAY = 0x10,
+ DAYSOFWEEK_SATURDAY = 0x20,
+ DAYSOFWEEK_SUNDAY = 0x40
+ } atsvc_DaysOfWeek;
+
+ typedef struct {
+ uint32 job_time;
+ atsvc_DaysOfMonth days_of_month;
+ atsvc_DaysOfWeek days_of_week;
+ atsvc_Flags flags;
+ [string,charset(UTF16)] uint16 *command;
+ } atsvc_JobInfo;
+
+ /******************/
+ /* Function: 0x00 */
+ [public] NTSTATUS atsvc_JobAdd(
+ [in,unique,string,charset(UTF16)] uint16 *servername,
+ [in] atsvc_JobInfo *job_info,
+ [out,ref] uint32 *job_id
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ [public] NTSTATUS atsvc_JobDel(
+ [in,unique,string,charset(UTF16)] uint16 *servername,
+ [in] uint32 min_job_id,
+ [in] uint32 max_job_id
+ );
+
+ typedef struct {
+ uint32 job_id;
+ uint32 job_time;
+ atsvc_DaysOfMonth days_of_month;
+ atsvc_DaysOfWeek days_of_week;
+ atsvc_Flags flags;
+ [string,charset(UTF16)] uint16 *command;
+ } atsvc_JobEnumInfo;
+
+ typedef struct {
+ uint32 entries_read;
+ [size_is(entries_read)] atsvc_JobEnumInfo *first_entry;
+ } atsvc_enum_ctr;
+
+ /******************/
+ /* Function: 0x02 */
+ [public] NTSTATUS atsvc_JobEnum(
+ [in,unique,string,charset(UTF16)] uint16 *servername,
+ [in,out] atsvc_enum_ctr *ctr,
+ [in] uint32 preferred_max_len,
+ [out,ref] uint32 *total_entries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x03 */
+ [public] NTSTATUS atsvc_JobGetInfo(
+ [in,unique,string,charset(UTF16)] uint16 *servername,
+ [in] uint32 job_id,
+ [out] atsvc_JobInfo **job_info
+ );
+}
diff --git a/librpc/idl/audiosrv.idl b/librpc/idl/audiosrv.idl
new file mode 100644
index 0000000..1b05986
--- /dev/null
+++ b/librpc/idl/audiosrv.idl
@@ -0,0 +1,23 @@
+[
+ uuid("0a74ef1c-41a4-4e06-83ae-dc74fb1cdd53"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Audio Server")
+] interface audiosrv
+{
+ [todo] void audiosrv_CreatezoneFactoriesList();
+ [todo] void audiosrv_CreateGfxFactoriesList();
+ [todo] void audiosrv_CreateGfxList();
+ [todo] void audiosrv_RemoveGfx();
+ [todo] void audiosrv_AddGfx();
+ [todo] void audiosrv_ModifyGfx();
+ [todo] void audiosrv_OpenGfx();
+ [todo] void audiosrv_Logon();
+ [todo] void audiosrv_Logoff();
+ [todo] void audiosrv_RegisterSessionNotificationEvent();
+ [todo] void audiosrv_UnregisterSessionNotificationEvent();
+ [todo] void audiosrv_SessionConnectState();
+ [todo] void audiosrv_DriverOpenDrvRegKey();
+ [todo] void audiosrv_AdvisePreferredDeviceChange();
+ [todo] void audiosrv_GetPnpInfo();
+}
diff --git a/librpc/idl/auth.idl b/librpc/idl/auth.idl
new file mode 100644
index 0000000..ab5675e
--- /dev/null
+++ b/librpc/idl/auth.idl
@@ -0,0 +1,170 @@
+#include "idl_types.h"
+
+/*
+ Authentication IDL structures
+
+ These are NOT public network structures, but it is helpful to define
+ these things in IDL. They may change without ABI breakage or
+ warning.
+
+*/
+
+import "misc.idl", "security.idl", "lsa.idl", "krb5pac.idl";
+[
+ pyhelper("librpc/ndr/py_auth.c"),
+ helper("../librpc/ndr/ndr_auth.h"),
+ helpstring("internal Samba authentication structures")
+]
+
+interface auth
+{
+ typedef [public] enum {
+ SEC_AUTH_METHOD_UNAUTHENTICATED = 0,
+ SEC_AUTH_METHOD_NTLM = 1,
+ SEC_AUTH_METHOD_KERBEROS = 2
+ } auth_method;
+
+ /* This is the parts of the session_info that don't change
+ * during local privilege and group manipulations */
+ typedef [public] struct {
+ [unique,charset(UTF8),string] char *account_name;
+ [unique,charset(UTF8),string] char *user_principal_name;
+ boolean8 user_principal_constructed;
+ [unique,charset(UTF8),string] char *domain_name;
+ [unique,charset(UTF8),string] char *dns_domain_name;
+
+ [unique,charset(UTF8),string] char *full_name;
+ [unique,charset(UTF8),string] char *logon_script;
+ [unique,charset(UTF8),string] char *profile_path;
+ [unique,charset(UTF8),string] char *home_directory;
+ [unique,charset(UTF8),string] char *home_drive;
+ [unique,charset(UTF8),string] char *logon_server;
+
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ NTTIME acct_expiry;
+ NTTIME last_password_change;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+
+ uint16 logon_count;
+ uint16 bad_password_count;
+
+ uint32 acct_flags;
+
+ /*
+ * The NETLOGON_GUEST flag being set indicates the user is not
+ * authenticated.
+ */
+ uint32 user_flags;
+ } auth_user_info;
+
+ /* This information is preserved only to assist torture tests */
+ typedef [public] struct {
+ /* Number SIDs from the DC netlogon validation info */
+ uint32 num_dc_sids;
+ [size_is(num_dc_sids)] auth_SidAttr dc_sids[*];
+ } auth_user_info_torture;
+
+ typedef [public] struct {
+ [unique,charset(UTF8),string] char *unix_name;
+
+ /*
+ * For performance reasons we keep an alpha_strcpy-sanitized version
+ * of the username around as long as the global variable current_user
+ * still exists. If we did not do keep this, we'd have to call
+ * alpha_strcpy whenever we do a become_user(), potentially on every
+ * smb request. See set_current_user_info in source3.
+ */
+ [unique,charset(UTF8),string] char *sanitized_username;
+ } auth_user_info_unix;
+
+ /*
+ * If the user was authenticated with a Kerberos ticket, this indicates
+ * the type of the ticket; TGT, or non-TGT (i.e. service ticket). If
+ * unset, the type is unknown. This indicator is useful for the KDC and
+ * the kpasswd service, which share the same account and keys. By
+ * ensuring it is provided with the appropriate ticket type, each service
+ * avoids accepting a ticket meant for the other.
+ *
+ * The heuristic used to determine the type is the presence or absence
+ * of a REQUESTER_SID buffer in the PAC; we use its presence to assume
+ * we have a TGT. This heuristic will fail for older Samba versions and
+ * Windows prior to Nov. 2021 updates, which lack support for this
+ * buffer.
+ */
+ typedef enum {
+ TICKET_TYPE_UNKNOWN = 0,
+ TICKET_TYPE_TGT = 1,
+ TICKET_TYPE_NON_TGT = 2
+ } ticket_type;
+
+ /*
+ * Used to indicate whether or not to include or disregard resource
+ * groups when forming a SamInfo structure, user_info_dc structure, or
+ * PAC, and whether or not to compress them when forming a PAC.
+ *
+ * When producing a TGT, existing resource groups are always copied
+ * unmodified into the PAC. When producing a service ticket, existing
+ * resource groups and resource groups in other domains are always
+ * discarded.
+ */
+ typedef enum {
+ AUTH_GROUP_INCLUSION_INVALID = 0, /* require invalid values to be handled. */
+ AUTH_INCLUDE_RESOURCE_GROUPS = 2,
+ AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED = 3,
+ AUTH_EXCLUDE_RESOURCE_GROUPS = 4
+ } auth_group_inclusion;
+
+ typedef [public] struct {
+ dom_sid sid;
+ security_GroupAttrs attrs;
+ } auth_SidAttr;
+
+ /* This is the interim product of the auth subsystem, before
+ * privileges and local groups are handled */
+ typedef [public] struct {
+ uint32 num_sids;
+ [size_is(num_sids)] auth_SidAttr sids[*];
+ auth_user_info *info;
+ [noprint] DATA_BLOB user_session_key;
+ [noprint] DATA_BLOB lm_session_key;
+ ticket_type ticket_type;
+ } auth_user_info_dc;
+
+ typedef [public] struct {
+ security_token *security_token;
+ security_unix_token *unix_token;
+ auth_user_info *info;
+ auth_user_info_unix *unix_info;
+ [value(NULL), ignore] auth_user_info_torture *torture;
+
+ /* This is the final session key, as used by SMB signing, and
+ * (truncated to 16 bytes) encryption on the SAMR and LSA pipes
+ * when over ncacn_np.
+ * It is calculated by NTLMSSP from the session key in the info3,
+ * and is set from the Kerberos session key using
+ * krb5_auth_con_getremotesubkey().
+ *
+ * Bottom line, it is not the same as the session keys in info3.
+ */
+
+ [noprint] DATA_BLOB session_key;
+
+ [value(NULL), ignore] cli_credentials *credentials;
+
+ /*
+ * It is really handy to have our authorization code log a
+ * token that can be used to tie later requests together.
+ * We generate this in auth_generate_session_info()
+ */
+ GUID unique_session_token;
+
+ ticket_type ticket_type;
+ } auth_session_info;
+
+ typedef [public] struct {
+ auth_session_info *session_info;
+ [noprint] DATA_BLOB exported_gssapi_credentials;
+ } auth_session_info_transport;
+}
diff --git a/librpc/idl/backupkey.idl b/librpc/idl/backupkey.idl
new file mode 100644
index 0000000..d235951
--- /dev/null
+++ b/librpc/idl/backupkey.idl
@@ -0,0 +1,153 @@
+#include "idl_types.h"
+
+import "misc.idl", "security.idl";
+[
+ uuid("3dde7c30-165d-11d1-ab8f-00805f14db40"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\protected_storage]", "ncacn_ip_tcp:"),
+ helpstring("Remote Backup Key Storage"),
+ helper("../librpc/ndr/ndr_backupkey.h"),
+ pointer_default(unique)
+]
+interface backupkey
+{
+ const string BACKUPKEY_RESTORE_GUID = "47270C64-2FC7-499B-AC5B-0E37CDCE899A";
+ const string BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID = "018FF48A-EABA-40C6-8F6D-72370240E967";
+
+ const string BACKUPKEY_RESTORE_GUID_WIN2K = "7FE94D50-178E-11D1-AB8F-00805F14DB40";
+ const string BACKUPKEY_BACKUP_GUID = "7F752B10-178E-11D1-AB8F-00805F14DB40";
+
+ /*
+ * The magic values are really what they are there is no name it's just remarkable values
+ * that are here to check that what is transmitted or decoded is really what the client or
+ * the server expect.
+ */
+ [public] typedef struct {
+ [value(0x00000002)] uint32 header1;
+ [value(0x00000494)] uint32 header2;
+ uint32 certificate_len;
+ [value(0x00000207)] uint32 magic1;
+ [value(0x0000A400)] uint32 magic2;
+ [value(0x32415352)] uint32 magic3;
+ [value(0x00000800)] uint32 magic4;
+ [subcontext(0),subcontext_size(4),flag(NDR_REMAINING)] DATA_BLOB public_exponent;
+
+ [subcontext(0),subcontext_size(256),flag(NDR_REMAINING)] DATA_BLOB modulus;
+ [subcontext(0),subcontext_size(128),flag(NDR_REMAINING)] DATA_BLOB prime1;
+ [subcontext(0),subcontext_size(128),flag(NDR_REMAINING)] DATA_BLOB prime2;
+ [subcontext(0),subcontext_size(128),flag(NDR_REMAINING)] DATA_BLOB exponent1;
+ [subcontext(0),subcontext_size(128),flag(NDR_REMAINING)] DATA_BLOB exponent2;
+ [subcontext(0),subcontext_size(128),flag(NDR_REMAINING)] DATA_BLOB coefficient;
+ [subcontext(0),subcontext_size(256),flag(NDR_REMAINING)] DATA_BLOB private_exponent;
+ [subcontext(0),subcontext_size(certificate_len),flag(NDR_REMAINING)] DATA_BLOB cert;
+ } bkrp_exported_RSA_key_pair;
+
+ [public] typedef struct {
+ [value(0x00000001)] uint32 magic;
+ uint8 key[256];
+ } bkrp_dc_serverwrap_key;
+
+ [public] typedef struct {
+ } bkrp_empty;
+
+ [public,gensize] typedef struct {
+ uint32 version;
+ uint32 encrypted_secret_len;
+ uint32 access_check_len;
+ GUID guid;
+ uint8 encrypted_secret[encrypted_secret_len];
+ uint8 access_check[access_check_len];
+ } bkrp_client_side_wrapped;
+
+ [public] typedef struct {
+ [value(0x00000000)] uint32 magic;
+ [subcontext(0),flag(NDR_REMAINING)] DATA_BLOB secret;
+ } bkrp_client_side_unwrapped;
+
+ [public] typedef struct {
+ uint32 secret_len;
+ [value(0x00000020)] uint32 magic;
+ uint8 secret[secret_len];
+ uint8 payload_key[32];
+ } bkrp_encrypted_secret_v2;
+
+ [public] typedef struct {
+ uint32 secret_len;
+ [value(0x00000030)] uint32 magic1;
+ [value(0x00006610)] uint32 magic2;
+ [value(0x0000800e)] uint32 magic3;
+ uint8 secret[secret_len];
+ uint8 payload_key[48];
+ } bkrp_encrypted_secret_v3;
+
+ /* Due to alignment constraint we can generate the structure only via pidl*/
+ [public, nopush, nopull] typedef struct {
+ [value(0x00000001)] uint32 magic;
+ uint32 nonce_len;
+ uint8 nonce[nonce_len];
+ dom_sid sid;
+ uint8 hash[20];
+ } bkrp_access_check_v2;
+
+ /* Due to alignment constraint we can generate the structure only via pidl*/
+ [public,nopush,nopull] typedef struct {
+ [value(0x00000001)] uint32 magic;
+ uint32 nonce_len;
+ uint8 nonce[nonce_len];
+ dom_sid sid;
+ uint8 hash[64];
+ } bkrp_access_check_v3;
+
+ [public] typedef struct {
+ uint8 r3[32];
+ uint8 mac[20];
+ dom_sid sid;
+ [subcontext(0),flag(NDR_REMAINING)] DATA_BLOB secret_data;
+ } bkrp_rc4encryptedpayload;
+
+ [public] typedef struct {
+ [value(0x00000001)] uint32 magic;
+ uint32 payload_length;
+ uint32 ciphertext_length;
+ GUID guid;
+ uint8 r2[68];
+ uint8 rc4encryptedpayload[ciphertext_length];
+ } bkrp_server_side_wrapped;
+
+ [public] typedef struct {
+ [flag(NDR_REMAINING)] DATA_BLOB opaque;
+ } bkrp_opaque_blob;
+
+ typedef enum {
+ BACKUPKEY_SERVER_WRAP_VERSION = 1,
+ BACKUPKEY_CLIENT_WRAP_VERSION2 = 2,
+ BACKUPKEY_CLIENT_WRAP_VERSION3 = 3
+ } bkrp_versions;
+
+ typedef enum {
+ BACKUPKEY_INVALID_GUID_INTEGER = 0xFFFF,
+ BACKUPKEY_RESTORE_GUID_INTEGER = 0x0000,
+ BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER = 0x0001,
+ BACKUPKEY_RESTORE_GUID_WIN2K_INTEGER = 0x0002,
+ BACKUPKEY_BACKUP_GUID_INTEGER = 0x0003
+ } bkrp_guid_to_integer;
+
+ [public] typedef [nodiscriminant] union {
+ [case(BACKUPKEY_RESTORE_GUID_INTEGER)] bkrp_client_side_wrapped restore_req;
+ [case(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER)] bkrp_empty empty;
+ [case(BACKUPKEY_RESTORE_GUID_WIN2K_INTEGER)] bkrp_server_side_wrapped unsign_req;
+ [case(BACKUPKEY_BACKUP_GUID_INTEGER)] bkrp_opaque_blob sign_req;
+ } bkrp_data_in_blob;
+
+ /******************/
+ /* Function: 0x00 */
+
+ [public, noprint] WERROR bkrp_BackupKey (
+ [in,ref] GUID *guidActionAgent,
+ [in,ref] [size_is(data_in_len)] uint8 *data_in,
+ [in] uint32 data_in_len,
+ [out,ref] [size_is(,*data_out_len)] uint8 **data_out,
+ [out,ref] uint32 *data_out_len,
+ [in] uint32 param
+ );
+}
diff --git a/librpc/idl/bkupblobs.idl b/librpc/idl/bkupblobs.idl
new file mode 100644
index 0000000..6e4dd98
--- /dev/null
+++ b/librpc/idl/bkupblobs.idl
@@ -0,0 +1,54 @@
+#include "idl_types.h"
+
+import "misc.idl";
+import "security.idl";
+import "fscc.idl";
+/* bkup blobs interface definition */
+
+
+[
+ pointer_default(unique),
+ helpstring("bkup blobs")
+]
+
+
+interface bkupblobs
+{
+ typedef [v1_enum] enum {
+ STREAM_ID_DATA = 1,
+ STREAM_ID_EX_DATA = 2,
+ STREAM_ID_SECURITY_DATA = 3,
+ STREAM_ID_ALTERNATE_DATA = 4,
+ STREAM_ID_LINK = 5,
+ STREAM_ID_OBJECTID = 7,
+ STREAM_ID_REPARSE_DATA = 8,
+ STREAM_ID_SPARSE_BLOCK = 9,
+ STREAM_ID_TXFS_DATA = 10
+ } bkup_StreamId;
+
+ typedef [v1_enum] enum {
+ STREAM_ATTRIBUTE_NORMAL = 0,
+ STREAM_ATTRIBUTE_SECURITY = 2,
+ STREAM_ATTRIBUTE_SPARSE = 8
+ } bkup_StreamAttribute;
+
+ typedef [nodiscriminant] union {
+ [default] DATA_BLOB blob;
+ [flag(NDR_ALIGN2),case(STREAM_ID_SECURITY_DATA)] security_descriptor sd;
+ [case(STREAM_ID_OBJECTID)] fscc_FileObjectIdBuffer_2 object;
+ } bkup_StreamData;
+
+ typedef [public] struct {
+ bkup_StreamId id;
+ bkup_StreamAttribute attribute;
+ hyper size;
+ uint32 stream_name_size;
+ [charset(UTF16),flag(STR_NOTERM)] uint16 stream_name[stream_name_size];
+ [subcontext(0), subcontext_size(size), switch_is(id)] [flag(NDR_REMAINING)] bkup_StreamData data;
+ } bkup_Win32StreamId;
+
+ typedef [nopush, nopull, flag(NDR_NOALIGN), public] struct {
+ uint32 num_stream;
+ bkup_Win32StreamId streams[num_stream];
+ } bkup_NTBackupFile;
+}
diff --git a/librpc/idl/browser.idl b/librpc/idl/browser.idl
new file mode 100644
index 0000000..94d4ce6
--- /dev/null
+++ b/librpc/idl/browser.idl
@@ -0,0 +1,86 @@
+import "srvsvc.idl";
+
+[
+ uuid("6bffd098-a112-3610-9833-012892020162"),
+ version(0.0),
+ helpstring("Browsing"),
+ pointer_default(unique),
+ endpoint("ncacn_np:[\\pipe\\browser]", "ncacn_ip_tcp:", "ncalrpc:")
+]
+interface browser
+{
+ /******************/
+ /* Function 0x00 */
+ [todo] void BrowserrServerEnum();
+
+ /******************/
+ /* Function 0x01 */
+ [todo] void BrowserrDebugCall();
+
+ /******************/
+ /* Function 0x02 */
+
+ typedef struct {
+ uint32 entries_read;
+ [size_is(entries_read)] srvsvc_NetSrvInfo100 *entries;
+ } BrowserrSrvInfo100Ctr;
+
+ typedef struct {
+ uint32 entries_read;
+ [size_is(entries_read)] srvsvc_NetSrvInfo101 *entries;
+ } BrowserrSrvInfo101Ctr;
+
+ typedef [switch_type(uint32)] union {
+ [case(100)] BrowserrSrvInfo100Ctr *info100;
+ [case(101)] BrowserrSrvInfo101Ctr *info101;
+ [default] ;
+ } BrowserrSrvInfoUnion;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] BrowserrSrvInfoUnion info;
+ } BrowserrSrvInfo;
+
+ WERROR BrowserrQueryOtherDomains(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,out,ref] BrowserrSrvInfo *info,
+ [out,ref] uint32 *total_entries
+ );
+
+ /******************/
+ /* Function 0x03 */
+ [todo] void BrowserrResetNetlogonState();
+
+ /******************/
+ /* Function 0x04 */
+ [todo] void BrowserrDebugTrace();
+
+ /******************/
+ /* Function 0x05 */
+ [todo] void BrowserrQueryStatistics();
+
+ /******************/
+ /* Function 0x06 */
+ [todo] void BrowserResetStatistics();
+
+ /******************/
+ /* Function 0x07 */
+ [todo] void NetrBrowserStatisticsClear();
+
+ /******************/
+ /* Function 0x08 */
+ [todo] void NetrBrowserStatisticsGet();
+
+ /******************/
+ /* Function 0x09 */
+ [todo] void BrowserrSetNetlogonState();
+
+ /******************/
+ /* Function 0x0a */
+ [todo] void BrowserrQueryEmulatedDomains();
+
+ /******************/
+ /* Function 0x0b */
+ [todo] void BrowserrServerEnumEx();
+
+}
diff --git a/librpc/idl/cab.idl b/librpc/idl/cab.idl
new file mode 100644
index 0000000..d08b535
--- /dev/null
+++ b/librpc/idl/cab.idl
@@ -0,0 +1,130 @@
+#include "idl_types.h"
+
+import "misc.idl";
+
+/*
+ IDL structures defining Cabinet files
+
+ more info can be found at:
+ https://msdn.microsoft.com/en-us/library/bb267310.aspx#cabinet_format
+*/
+
+[
+ pointer_default(unique),
+ helper("../librpc/ndr/ndr_cab.h"),
+ helpstring("Cabinet structure"),
+ uuid("12345678-0000-0000-0000-00000000")
+]
+ interface cab
+{
+
+ /*
+ * flags.cfhdrPREV_CABINET is set if this cabinet file is not the first in
+ * a set of cabinet files. When this bit is set, the szCabinetPrev and
+ * szDiskPrev fields are present in this CFHEADER.
+ *
+ * flags.cfhdrNEXT_CABINET is set if this cabinet file is not the last in a
+ * set of cabinet files. When this bit is set, the szCabinetNext and
+ * szDiskNext fields are present in this CFHEADER.
+ *
+ * flags.cfhdrRESERVE_PRESENT is set if this cabinet file contains any
+ * reserved fields. When this bit is set, the cbCFHeader, cbCFFolder, and
+ * cbCFData fields are present in this CFHEADER.
+ */
+
+ typedef [bitmap16bit] bitmap {
+ cfhdrPREV_CABINET = 0x0001,
+ cfhdrNEXT_CABINET = 0x0002,
+ cfhdrRESERVE_PRESENT = 0x0004
+ } cf_flags;
+
+ typedef [public,flag(NDR_PAHEX|NDR_LITTLE_ENDIAN|NDR_NOALIGN)] struct {
+ [charset(DOS),value("MSCF")] uint8 signature[4];
+ [value(0)] uint32 reserved1; /* reserved */
+ uint32 cbCabinet; /* size of this cabinet file in bytes */
+ [value(0)] uint32 reserved2; /* reserved */
+ [value(cFolders*8+36)] uint32 coffFiles; /* offset of the first CFFILE entry */
+ [value(0)] uint32 reserved3; /* reserved */
+ [value(3)] uint8 versionMinor; /* cabinet file format version, minor */
+ [value(1)] uint8 versionMajor; /* cabinet file format version, major */
+ uint16 cFolders; /* number of CFFOLDER entries in this cabinet */
+ uint16 cFiles; /* number of CFFILE entries in this cabinet */
+ cf_flags flags; /* cabinet file option indicators */
+ uint16 setID; /* must be the same for all cabinets in a set */
+ uint16 iCabinet; /* number of this cabinet file in a set */
+#if 0
+ [range(0,60000)] uint16 cbCFHeader; /* (optional) size of per-cabinet reserved area */
+ [range(0,255)] uint8 cbCFFolder; /* (optional) size of per-folder reserved area */
+ [range(0,255)] uint8 cbCFData; /* (optional) size of per-datablock reserved area */
+ uint8 abReserve[]; /* (optional) per-cabinet reserved area */
+ uint8 szCabinetPrev[]; /* (optional) name of previous cabinet file */
+ uint8 szDiskPrev[]; /* (optional) name of previous disk */
+ uint8 szCabinetNext[]; /* (optional) name of next cabinet file */
+ uint8 szDiskNext[]; /* (optional) name of next disk */
+#endif
+ } CFHEADER;
+
+ typedef enum {
+ CF_COMPRESS_NONE = 0,
+ CF_COMPRESS_MSZIP = 1,
+ CF_COMPRESS_LZX = 4611
+ } cf_compress_type;
+
+ typedef [public,flag(NDR_PAHEX|NDR_LITTLE_ENDIAN|NDR_NOALIGN)] struct {
+ uint32 coffCabStart; /* offset of the first CFDATA block in this folder */
+ uint16 cCFData; /* number of CFDATA blocks in this folder */
+ cf_compress_type typeCompress; /* compression type indicator */
+#if 0
+ uint8 abReserve[]; /* (optional) per-folder reserved area */
+#endif
+ } CFFOLDER;
+
+ const int ifoldCONTINUED_FROM_PREV = 0xFFFD;
+ const int ifoldCONTINUED_TO_NEXT = 0xFFFE;
+ const int ifoldCONTINUED_PREV_AND_NEXT = 0xFFFF;
+
+ typedef [bitmap16bit] bitmap {
+ _A_RDONLY = 0x01, /* file is read-only */
+ _A_HIDDEN = 0x02, /* file is hidden */
+ _A_SYSTEM = 0x04, /* file is a system file */
+ _A_ARCH = 0x20, /* file modified since last backup */
+ _A_EXEC = 0x40, /* run after extraction */
+ _A_NAME_IS_UTF = 0x80 /* szName[] contains UTF */
+ } cf_attributes;
+
+ typedef [noprint,flag(NDR_NOALIGN)] struct {
+ uint16 date;
+ } cf_date;
+
+ typedef [noprint,flag(NDR_NOALIGN)] struct {
+ uint16 time;
+ } cf_time;
+
+ typedef [public,flag(NDR_PAHEX|NDR_LITTLE_ENDIAN|NDR_NOALIGN),gensize] struct {
+ uint32 cbFile; /* uncompressed size of this file in bytes */
+ uint32 uoffFolderStart; /* uncompressed offset of this file in the folder */
+ uint16 iFolder; /* index into the CFFOLDER area */
+ cf_date date; /* date stamp for this file */
+ cf_time time; /* time stamp for this file */
+ cf_attributes attribs; /* attribute flags for this file */
+ [flag(r->attribs & _A_NAME_IS_UTF ? STR_UTF8|STR_NULLTERM : STR_ASCII|STR_NULLTERM)] string szName;
+ } CFFILE;
+
+ typedef [flag(NDR_PAHEX|NDR_LITTLE_ENDIAN|NDR_NOALIGN),nopull,nopush] struct {
+ uint32 csum; /* checksum of this CFDATA entry */
+ uint16 cbData; /* number of compressed bytes in this block */
+ uint16 cbUncomp; /* number of uncompressed bytes in this block */
+#if 0
+ uint8 abReserve[]; /* (optional) per-datablock reserved area */
+#endif
+ DATA_BLOB ab; /* compressed data bytes */
+ } CFDATA;
+
+ typedef [nopush,nopull,public,flag(NDR_PAHEX|NDR_LITTLE_ENDIAN|NDR_NOALIGN)] struct {
+ CFHEADER cfheader;
+ CFFOLDER cffolders[cfheader.cFolders];
+ CFFILE cffiles[cfheader.cFiles];
+ [noprint,value(ndr_count_cfdata(r))] uint32 cfdata_count;
+ CFDATA cfdata[cfdata_count];
+ } cab_file;
+}
diff --git a/librpc/idl/claims.idl b/librpc/idl/claims.idl
new file mode 100644
index 0000000..618a620
--- /dev/null
+++ b/librpc/idl/claims.idl
@@ -0,0 +1,149 @@
+/*
+ claims
+
+ claim: An assertion about a security principal
+
+ From MS-ADTS:
+
+ For ease of implementation, the full IDL for the data types used for
+ claims is provided
+
+ The below was initially obtained from MS-ADTS which is
+ Copyright © 2022 Microsoft Corporation as permitted
+ by the Open Specifications terms reproduced in IDL_LICENCE.txt
+*/
+
+#include "idl_types.h"
+
+[
+ uuid("bba9cb76-eb0c-462c-aa1b-5d8c34415701"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Active Directory Claims"),
+ helper("../librpc/ndr/ndr_claims.h")
+]
+interface claims
+{
+#define wchar_t uint16
+#define CLAIM_ID [string, charset(UTF16)] wchar_t *
+
+ const int CLAIM_LOWER_COMPRESSION_THRESHOLD = 368;
+ const int CLAIM_UPPER_COMPRESSION_THRESHOLD = 384;
+
+ typedef enum {
+ CLAIM_TYPE_INT64 = 1,
+ CLAIM_TYPE_UINT64 = 2,
+ CLAIM_TYPE_STRING = 3,
+ CLAIM_TYPE_BOOLEAN = 6
+ } CLAIM_TYPE;
+
+ typedef enum {
+ CLAIMS_SOURCE_TYPE_AD = 1,
+ CLAIMS_SOURCE_TYPE_CERTIFICATE = 2
+ } CLAIMS_SOURCE_TYPE;
+
+ typedef enum {
+ CLAIMS_COMPRESSION_FORMAT_NONE = 0,
+ CLAIMS_COMPRESSION_FORMAT_LZNT1 = 2,
+ CLAIMS_COMPRESSION_FORMAT_XPRESS = 3,
+ CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF = 4
+ } CLAIMS_COMPRESSION_FORMAT;
+
+ typedef struct {
+ [range(0, 10*1024*1024)] uint32 value_count;
+ [size_is(value_count)] int64 *values;
+ } CLAIM_INT64;
+
+ typedef struct {
+ [range(0, 10*1024*1024)] uint32 value_count;
+ [size_is(value_count)] hyper *values;
+ } CLAIM_UINT64;
+
+ typedef struct {
+ [range(0, 10*1024*1024)] uint32 value_count;
+ [size_is(value_count), string, charset(UTF16)] wchar_t **values;
+ } CLAIM_STRING;
+
+ typedef [switch_type(CLAIM_TYPE),flag(NDR_ALIGN8)] union {
+ [case(CLAIM_TYPE_INT64)] CLAIM_INT64 claim_int64;
+ [case(CLAIM_TYPE_UINT64)] CLAIM_UINT64 claim_uint64;
+ [case(CLAIM_TYPE_STRING)] CLAIM_STRING claim_string;
+ [case(CLAIM_TYPE_BOOLEAN)] CLAIM_UINT64 claim_boolean;
+ [default];
+ } CLAIM_ENTRY_VALUES;
+
+ typedef struct {
+ CLAIM_ID id;
+ CLAIM_TYPE type;
+ [switch_is(type)] CLAIM_ENTRY_VALUES values;
+ } CLAIM_ENTRY;
+
+ typedef struct {
+ CLAIMS_SOURCE_TYPE claims_source_type;
+ uint32 claims_count;
+ [size_is(claims_count)] CLAIM_ENTRY *claim_entries;
+ } CLAIMS_ARRAY;
+
+ typedef struct {
+ CLAIMS_SET_METADATA *metadata;
+ } CLAIMS_SET_METADATA_CTR;
+
+ typedef struct {
+ CLAIMS_SET *claims;
+ } CLAIMS_SET_CTR;
+
+ /* Public structures. */
+
+ typedef [public] struct {
+ uint32 claims_array_count;
+ [size_is(claims_array_count)] CLAIMS_ARRAY *claims_arrays;
+ uint16 reserved_type;
+ uint32 reserved_field_size;
+ [size_is(reserved_field_size)] uint8 *reserved_field;
+ } CLAIMS_SET;
+
+ typedef [public, gensize] struct {
+ [subcontext(0xFFFFFC01)] CLAIMS_SET_CTR claims;
+ } CLAIMS_SET_NDR;
+
+ typedef [public] struct {
+ [subcontext(0xFFFFFC01)] CLAIMS_SET_METADATA_CTR claims;
+ } CLAIMS_SET_METADATA_NDR;
+
+ typedef [public] struct {
+ [value(ndr_claims_compressed_size(claims_set,
+ r->compression_format,
+ ndr->flags))] uint32 claims_set_size;
+ [subcontext(4),
+ compression(ndr_claims_compression_alg(compression_format),
+ claims_set_size,
+ uncompressed_claims_set_size)
+ ] CLAIMS_SET_NDR *claims_set;
+ /*
+ * The second argument to
+ * ndr_claims_actual_wire_compression_alg() in the
+ * value() below should be
+ * uncompressed_claims_set_size but the value()
+ * handling isn't recursive (enough) so we have to
+ * specify that manually otherwise the
+ * compression_format in the above includes the struct
+ * member, not the value()
+ *
+ * The caller should set compression_format to
+ * CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF and this will
+ * be reset to CLAIMS_COMPRESSION_FORMAT_NONE if the
+ * buffer is not large enough to compress.
+ *
+ * Otherwise setting CLAIMS_COMPRESSION_FORMAT_NONE
+ * disabled compression entirely.
+ */
+ [value(ndr_claims_actual_wire_compression_alg(r->compression_format,
+ ndr_size_CLAIMS_SET_NDR(claims_set,
+ ndr->flags)))] CLAIMS_COMPRESSION_FORMAT compression_format;
+ [value(ndr_size_CLAIMS_SET_NDR(claims_set,
+ ndr->flags))] uint32 uncompressed_claims_set_size;
+ uint16 reserved_type;
+ uint32 reserved_field_size;
+ [size_is(reserved_field_size)] uint8 *reserved_field;
+ } CLAIMS_SET_METADATA;
+}
diff --git a/librpc/idl/clusapi.idl b/librpc/idl/clusapi.idl
new file mode 100644
index 0000000..7cc3f5f
--- /dev/null
+++ b/librpc/idl/clusapi.idl
@@ -0,0 +1,2962 @@
+import "winreg.idl", "misc.idl";
+
+#include "idl_types.h"
+
+[
+ uuid("b97db8b2-4c63-11cf-bff6-08002be23f2f"),
+ version(3.0),
+ pointer_default(unique),
+ endpoint("ncacn_ip_tcp:"),
+ authservice("MSServerClusterMgmtAPI"),
+ helpstring("Failover Cluster Management API (clusapi)")
+]
+#define MAX_CLUSTER_CONTROL_CODE_BUFFER_SIZE 0x7FFFFFFF
+ interface clusapi
+{
+#if 0
+ /*
+ * pidl does not yet have a real [context_handle] implementation, so we
+ * just use some defines here.
+ */
+
+ typedef [context_handle] void *HCLUSTER_RPC;
+ typedef [context_handle] void *HNODE_RPC;
+ typedef [context_handle] void *HGROUP_RPC;
+ typedef [context_handle] void *HRES_RPC;
+ typedef [context_handle] void *HKEY_RPC;
+ typedef [context_handle] void *HNOTIFY_RPC;
+ typedef [context_handle] void *HNETWORK_RPC;
+ typedef [context_handle] void *HNETINTERFACE_RPC;
+ typedef [context_handle] void *HBATCH_PORT_RPC;
+#else
+#define HCLUSTER_RPC policy_handle
+#define HNODE_RPC policy_handle
+#define HGROUP_RPC policy_handle
+#define HRES_RPC policy_handle
+#define HKEY_RPC policy_handle
+#define HNOTIFY_RPC policy_handle
+#define HNETWORK_RPC policy_handle
+#define HNETINTERFACE_RPC policy_handle
+#define HBATCH_PORT_RPC policy_handle
+#endif
+
+ typedef struct {
+ [ size_is( cbInSecurityDescriptor ), length_is( cbOutSecurityDescriptor ) ] uint8 *lpSecurityDescriptor;
+ uint32 cbInSecurityDescriptor;
+ uint32 cbOutSecurityDescriptor;
+ } RPC_SECURITY_DESCRIPTOR;
+
+ typedef struct {
+ uint32 nLength;
+ RPC_SECURITY_DESCRIPTOR RpcSecurityDescriptor;
+ long bInheritHandle;
+ } RPC_SECURITY_ATTRIBUTES;
+
+ typedef struct {
+ [value(20)] uint32 dwSize;
+ uint32 dwClusterHighestVersion;
+ uint32 dwClusterLowestVersion;
+ uint32 dwFlags;
+ uint32 dwReserved;
+ } CLUSTER_OPERATIONAL_VERSION_INFO;
+
+ typedef struct {
+ uint32 NodeId;
+ boolean8 SetAttempted;
+ uint32 ReturnStatus;
+ } IDL_CLUSTER_SET_PASSWORD_STATUS;
+
+ typedef enum {
+ IDL_CLUSTER_SET_PASSWORD_IGNORE_DOWN_NODES = 1
+ } IDL_CLUSTER_SET_PASSWORD_FLAGS;
+
+ typedef struct {
+ uint32 dwVersion;
+ uint32 dwGroupType;
+ } CLUSTER_CREATE_GROUP_INFO_RPC;
+
+ /*****************/
+ /* Function 0x00 */
+
+#if 0
+ /*
+ * pidl cannot generate code for functions that return structures in
+ * IDL, therefore pretend the function is void and add the returned
+ * structure as an out parameter. This is what we do with pretty much
+ * all the Open calls right now in this interface - gd
+ */
+
+ HCLUSTER_RPC
+ clusapi_OpenCluster(
+ [ out ] WERROR *Status
+ );
+#else
+ void
+ clusapi_OpenCluster(
+ [ out ] WERROR *Status,
+ [ out ] HCLUSTER_RPC *Cluster
+ );
+#endif
+
+ /*****************/
+ /* Function 0x01 */
+
+ WERROR
+ clusapi_CloseCluster(
+ [ in, out ] HCLUSTER_RPC *Cluster
+ );
+
+ /*****************/
+ /* Function 0x02 */
+
+ WERROR
+ clusapi_SetClusterName(
+ [ in, string ] [charset(UTF16)] uint16 *NewClusterName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x03 */
+
+ WERROR
+ clusapi_GetClusterName(
+ [ out, string ] [charset(UTF16)] uint16 **ClusterName,
+ [ out, string ] [charset(UTF16)] uint16 **NodeName
+ );
+
+ /*****************/
+ /* Function 0x04 */
+
+ WERROR
+ clusapi_GetClusterVersion(
+ [ out ] uint16 *lpwMajorVersion,
+ [ out ] uint16 *lpwMinorVersion,
+ [ out ] uint16 *lpwBuildNumber,
+ [ out, string ] [charset(UTF16)] uint16 **lpszVendorId,
+ [ out, string ] [charset(UTF16)] uint16 **lpszCSDVersion
+ );
+
+ /*****************/
+ /* Function 0x05 */
+
+ WERROR
+ clusapi_GetQuorumResource(
+ [ out, string ] [charset(UTF16)] uint16 **lpszResourceName,
+ [ out, string ] [charset(UTF16)] uint16 **lpszDeviceName,
+ [ out ] uint32 *pdwMaxQuorumLogSize,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x06 */
+
+ WERROR
+ clusapi_SetQuorumResource(
+ [ in ] HRES_RPC hResource,
+ [ in, string ] [charset(UTF16)] uint16 *lpszDeviceName,
+ [ in ] uint32 dwMaxQuorumLogSize,
+ [ out ] WERROR *rpc_status
+ );
+
+ typedef [bitmap32bit] bitmap {
+ CLUSTER_ENUM_NODE = 0x00000001,
+ CLUSTER_ENUM_RESTYPE = 0x00000002,
+ CLUSTER_ENUM_RESOURCE = 0x00000004,
+ CLUSTER_ENUM_GROUP = 0x00000008,
+ CLUSTER_ENUM_NETWORK = 0x00000010,
+ CLUSTER_ENUM_NETINTERFACE = 0x00000020,
+ CLUSTER_ENUM_INTERNAL_NETWORK = 0x80000000,
+ CLUSTER_ENUM_SHARED_VOLUME_RESOURCE = 0x40000000
+ } ClusterEnumType;
+
+ typedef struct {
+ ClusterEnumType Type;
+ [string] [charset(UTF16)] uint16 *Name;
+ } ENUM_ENTRY;
+
+ typedef struct {
+ uint32 EntryCount;
+ [size_is(EntryCount)] ENUM_ENTRY Entry[*];
+ } ENUM_LIST;
+
+ typedef struct {
+ [string] [charset(UTF16)] uint16 *Name;
+ [string] [charset(UTF16)] uint16 *Id;
+ uint32 dwState;
+ [string] [charset(UTF16)] uint16 *Owner;
+ uint32 dwFlags;
+ uint32 cbProperties;
+ [size_is(cbProperties)] uint8* Properties;
+ uint32 cbRoProperties;
+ [size_is(cbRoProperties)] uint8* RoProperties;
+ } GROUP_ENUM_ENTRY;
+
+ typedef struct {
+ [string] [charset(UTF16)] uint16 *Name;
+ [string] [charset(UTF16)] uint16 *Id;
+ [string] [charset(UTF16)] uint16 *OwnerName;
+ [string] [charset(UTF16)] uint16 *OwnerId;
+ uint32 cbProperties;
+ [size_is(cbProperties)] uint8* Properties;
+ uint32 cbRoProperties;
+ [size_is(cbRoProperties)] uint8* RoProperties;
+ } RESOURCE_ENUM_ENTRY;
+
+ typedef struct {
+ uint32 EntryCount;
+ [size_is(EntryCount)] GROUP_ENUM_ENTRY Entry[*];
+ } GROUP_ENUM_LIST;
+
+ typedef struct {
+ uint32 EntryCount;
+ [size_is(EntryCount)] RESOURCE_ENUM_ENTRY Entry[*];
+ } RESOURCE_ENUM_LIST;
+
+ /*****************/
+ /* Function 0x07 */
+
+ WERROR
+ clusapi_CreateEnum(
+ [ in ] ClusterEnumType dwType,
+ [ out ] ENUM_LIST **ReturnEnum,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x08 */
+
+#if 0
+ HRES_RPC
+ clusapi_OpenResource(
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenResource(
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HRES_RPC *hResource
+ );
+#endif
+ /*****************/
+ /* Function 0x09 */
+
+ typedef [v1_enum] enum {
+ CLUSTER_RESOURCE_DEFAULT_MONITOR = 0x00000000,
+ CLUSTER_RESOURCE_SEPARATE_MONITOR = 0x00000001
+ } clusapi_CreateResourceFlags;
+
+#if 0
+ HRES_RPC
+ clusapi_CreateResource(
+ [ in ] HGROUP_RPC hGroup,
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceName,
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceType,
+ [ in ] clusapi_CreateResourceFlags dwFlags,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_CreateResource(
+ [ in ] HGROUP_RPC hGroup,
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceName,
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceType,
+ [ in ] clusapi_CreateResourceFlags dwFlags,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HRES_RPC *hResource
+ );
+#endif
+ /*****************/
+ /* Function 0x0A */
+
+ WERROR
+ clusapi_DeleteResource(
+ [ in ] HRES_RPC hResource,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x0B */
+
+ WERROR
+ clusapi_CloseResource(
+ [ in, out ] HRES_RPC *Resource
+ );
+
+ /*****************/
+ /* Function 0x0C */
+
+ typedef [v1_enum] enum {
+ ClusterResourceInitializing = 0x00000001,
+ ClusterResourceOnline = 0x00000002,
+ ClusterResourceOffline = 0x00000003,
+ ClusterResourceFailed = 0x00000004,
+ ClusterResourceOnlinePending = 0x00000081,
+ ClusterResourceOfflinePending = 0x00000082,
+ ClusterResourceStateUnknown = 0xFFFFFFFF
+ } clusapi_ClusterResourceState;
+
+ WERROR
+ clusapi_GetResourceState(
+ [ in ] HRES_RPC hResource,
+ [ out ] clusapi_ClusterResourceState *State,
+ [ out, string ] [charset(UTF16)] uint16 **NodeName,
+ [ out, string ] [charset(UTF16)] uint16 **GroupName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x0D */
+
+ WERROR
+ clusapi_SetResourceName(
+ [ in ] HRES_RPC hResource,
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x0E */
+
+ WERROR
+ clusapi_GetResourceId(
+ [ in ] HRES_RPC hResource,
+ [ out, string ] [charset(UTF16)] uint16 **pGuid,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x0F */
+
+ WERROR
+ clusapi_GetResourceType(
+ [ in ] HRES_RPC hResource,
+ [ out, string ] [charset(UTF16)] uint16 **lpszResourceType,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x10 */
+
+ WERROR
+ clusapi_FailResource(
+ [ in ] HRES_RPC hResource,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x11 */
+
+ WERROR
+ clusapi_OnlineResource(
+ [ in ] HRES_RPC hResource,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x12 */
+
+ WERROR
+ clusapi_OfflineResource(
+ [ in ] HRES_RPC hResource,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x13 */
+
+ WERROR
+ clusapi_AddResourceDependency(
+ [ in ] HRES_RPC hResource,
+ [ in ] HRES_RPC hDependsOn,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x14 */
+
+ WERROR
+ clusapi_RemoveResourceDependency(
+ [ in ] HRES_RPC hResource,
+ [ in ] HRES_RPC hDependsOn,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x15 */
+
+ WERROR
+ clusapi_CanResourceBeDependent(
+ [ in ] HRES_RPC hResource,
+ [ in ] HRES_RPC hResourceDependent,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x16 */
+
+ WERROR
+ clusapi_CreateResEnum(
+ [ in ] HRES_RPC hResource,
+ [ in ] uint32 dwType,
+ [ out ] ENUM_LIST **ReturnEnum,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x17 */
+
+ WERROR
+ clusapi_AddResourceNode(
+ [ in ] HRES_RPC hResource,
+ [ in ] HNODE_RPC hNode,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x18 */
+
+ WERROR
+ clusapi_RemoveResourceNode(
+ [ in ] HRES_RPC hResource,
+ [ in ] HNODE_RPC hNode,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x19 */
+
+ WERROR
+ clusapi_ChangeResourceGroup(
+ [ in ] HRES_RPC hResource,
+ [ in ] HGROUP_RPC hGroup,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x1A */
+
+ WERROR
+ clusapi_CreateResourceType(
+ [ in, string ] [charset(UTF16)] uint16 *lpszTypeName,
+ [ in, string ] [charset(UTF16)] uint16 *lpszDisplayName,
+ [ in, string ] [charset(UTF16)] uint16 *lpszDllName,
+ [ in ] uint32 dwLooksAlive,
+ [ in ] uint32 dwIsAlive,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x1B */
+
+ WERROR
+ clusapi_DeleteResourceType(
+ [ in, string ] [charset(UTF16)] uint16 *lpszTypeName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x1C */
+#if 0
+ HKEY_RPC
+ clusapi_GetRootKey(
+ [ in ] winreg_AccessMask samDesired,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_GetRootKey(
+ [ in ] winreg_AccessMask samDesired,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HKEY_RPC *phKey
+ );
+#endif
+ /*****************/
+ /* Function 0x1D */
+#if 0
+ HKEY_RPC
+ clusapi_CreateKey(
+ [ in ] HKEY_RPC hKey,
+ [ in, string ] [charset(UTF16)] uint16 *lpSubKey,
+ [ in ] uint32 dwOptions,
+ [ in ] winreg_AccessMask samDesired,
+ [ in, unique ] RPC_SECURITY_ATTRIBUTES *lpSecurityAttributes,
+ [ out ] uint32 *lpdwDisposition,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_CreateKey(
+ [ in ] HKEY_RPC hKey,
+ [ in, string ] [charset(UTF16)] uint16 *lpSubKey,
+ [ in ] uint32 dwOptions,
+ [ in ] winreg_AccessMask samDesired,
+ [ in, unique ] RPC_SECURITY_ATTRIBUTES *lpSecurityAttributes,
+ [ out ] uint32 *lpdwDisposition,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HKEY_RPC *phKey
+ );
+#endif
+ /*****************/
+ /* Function 0x1E */
+#if 0
+ HKEY_RPC
+ clusapi_OpenKey(
+ [ in ] HKEY_RPC hKey,
+ [ in, string ] [charset(UTF16)] uint16 *lpSubKey,
+ [ in ] winreg_AccessMask samDesired,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenKey(
+ [ in ] HKEY_RPC hKey,
+ [ in, string ] [charset(UTF16)] uint16 *lpSubKey,
+ [ in ] winreg_AccessMask samDesired,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HKEY_RPC *phKey
+ );
+#endif
+ /*****************/
+ /* Function 0x1F */
+
+ WERROR
+ clusapi_EnumKey(
+ [ in ] HKEY_RPC hKey,
+ [ in ] uint32 dwIndex,
+ [ out, string ] [charset(UTF16)] uint16 **KeyName,
+ [ out ] NTTIME *lpftLastWriteTime,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x20 */
+
+ WERROR
+ clusapi_SetValue(
+ [ in ] HKEY_RPC hKey,
+ [ in, string ] [charset(UTF16)] uint16 *lpValueName,
+ [ in ] winreg_Type dwType,
+ [ in, size_is(cbData) ] uint8 *lpData,
+ [ in ] uint32 cbData,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x21 */
+
+ WERROR
+ clusapi_DeleteValue(
+ [ in ] HKEY_RPC hKey,
+ [ in, string ] [charset(UTF16)] uint16 *lpValueName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x22 */
+
+ WERROR
+ clusapi_QueryValue(
+ [ in ] HKEY_RPC hKey,
+ [ in, string ] [charset(UTF16)] uint16 *lpValueName,
+ [ out ] winreg_Type *lpValueType,
+ [ out, size_is(cbData) ] uint8 *lpData,
+ [ in ] uint32 cbData,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x23 */
+
+ WERROR
+ clusapi_DeleteKey(
+ [ in ] HKEY_RPC hKey,
+ [ in, string ] [charset(UTF16)] uint16 *lpSubKey,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x24 */
+
+ WERROR
+ clusapi_EnumValue(
+ [ in ] HKEY_RPC hKey,
+ [ in ] uint32 dwIndex,
+ [ out, string ] [charset(UTF16)] uint16 **lpValueName,
+ [ out ] winreg_Type *lpType,
+ [ out, size_is(*lpcbData) ] uint8 *lpData,
+ [ in, out ] uint32 *lpcbData,
+ [ out ] uint32 *TotalSize,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x25 */
+
+ WERROR
+ clusapi_CloseKey(
+ [ in, out ] HKEY_RPC *pKey
+ );
+
+ /*****************/
+ /* Function 0x26 */
+
+ WERROR
+ clusapi_QueryInfoKey(
+ [ in ] HKEY_RPC hKey,
+ [ out ] uint32 *lpcSubKeys,
+ [ out ] uint32 *lpcbMaxSubKeyLen,
+ [ out ] uint32 *lpcValues,
+ [ out ] uint32 *lpcbMaxValueNameLen,
+ [ out ] uint32 *lpcbMaxValueLen,
+ [ out ] uint32 *lpcbSecurityDescriptor,
+ [ out ] NTTIME *lpftLastWriteTime,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x27 */
+
+ WERROR
+ clusapi_SetKeySecurity(
+ [ in ] HKEY_RPC hKey,
+ [ in ] uint32 SecurityInformation,
+ [ in ] RPC_SECURITY_DESCRIPTOR *pRpcSecurityDescriptor,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x28 */
+
+ WERROR
+ clusapi_GetKeySecurity(
+ [ in ] HKEY_RPC hKey,
+ [ in ] uint32 SecurityInformation,
+ [ in, out ] RPC_SECURITY_DESCRIPTOR *pRpcSecurityDescriptor,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x29 */
+#if 0
+ HGROUP_RPC
+ clusapi_OpenGroup(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenGroup(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HGROUP_RPC *hGroup
+ );
+#endif
+ /*****************/
+ /* Function 0x2A */
+#if 0
+ HGROUP_RPC
+ clusapi_CreateGroup(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_CreateGroup(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HGROUP_RPC *hGroup
+ );
+#endif
+ /*****************/
+ /* Function 0x2B */
+
+ WERROR
+ clusapi_DeleteGroup(
+ [ in ] HGROUP_RPC Group,
+ [ in ] boolean8 force,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x2C */
+
+ WERROR
+ clusapi_CloseGroup(
+ [ in, out ] HGROUP_RPC *Group
+ );
+
+ /*****************/
+ /* Function 0x2D */
+
+ typedef [v1_enum] enum {
+ ClusterGroupOnline = 0x00000000,
+ ClusterGroupOffline = 0x00000001,
+ ClusterGroupFailed = 0x00000002,
+ ClusterGroupPartialOnline = 0x00000003,
+ ClusterGroupPending = 0x00000004,
+ ClusterGroupStateUnknown = 0xFFFFFFFF
+ } clusapi_ClusterGroupState;
+
+ WERROR
+ clusapi_GetGroupState(
+ [ in ] HGROUP_RPC hGroup,
+ [ out ] clusapi_ClusterGroupState *State,
+ [ out, string ] [charset(UTF16)] uint16 **NodeName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x2E */
+
+ WERROR
+ clusapi_SetGroupName(
+ [ in ] HGROUP_RPC hGroup,
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x2F */
+
+ WERROR
+ clusapi_GetGroupId(
+ [ in ] HGROUP_RPC hGroup,
+ [ out, string ] [charset(UTF16)] uint16 **pGuid,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x30 */
+
+ WERROR
+ clusapi_GetNodeId(
+ [ in ] HNODE_RPC hNode,
+ [ out, string ] [charset(UTF16)] uint16 **pGuid,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x31 */
+
+ WERROR
+ clusapi_OnlineGroup(
+ [ in ] HGROUP_RPC hGroup,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x32 */
+
+ WERROR
+ clusapi_OfflineGroup(
+ [ in ] HGROUP_RPC hGroup,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x33 */
+
+ WERROR
+ clusapi_MoveGroup(
+ [ in ] HGROUP_RPC hGroup,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x34 */
+
+ WERROR
+ clusapi_MoveGroupToNode(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] HNODE_RPC hNode,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x35 */
+
+ typedef [bitmap32bit] bitmap {
+ CLUSTER_GROUP_ENUM_CONTAINS = 0x00000001,
+ CLUSTER_GROUP_ENUM_NODES = 0x00000002
+ } ClusterGroupEnumType;
+
+ WERROR
+ clusapi_CreateGroupResourceEnum(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] ClusterGroupEnumType dwType,
+ [ out ] ENUM_LIST **ReturnEnum,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x36 */
+
+ WERROR
+ clusapi_SetGroupNodeList(
+ [ in ] HGROUP_RPC hGroup,
+ [ in, unique, size_is(cchListSize) ] uint16 *multiSzNodeList,
+ [ in ] uint32 cchListSize,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x37 */
+#if 0
+ HNOTIFY_RPC
+ clusapi_CreateNotify(
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_CreateNotify(
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HNOTIFY_RPC *hNotify
+ );
+#endif
+ /*****************/
+ /* Function 0x38 */
+
+ WERROR
+ clusapi_CloseNotify(
+ [ in, out ] HNOTIFY_RPC *Notify
+ );
+
+ /*****************/
+ /* Function 0x39 */
+
+ WERROR
+ clusapi_AddNotifyCluster(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HCLUSTER_RPC hCluster,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x3A */
+
+ WERROR
+ clusapi_AddNotifyNode(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ out ] uint32 *dwStateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x3B */
+
+ WERROR
+ clusapi_AddNotifyGroup(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ out ] uint32 *dwStateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x3C */
+
+ WERROR
+ clusapi_AddNotifyResource(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HRES_RPC hResource,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ out ] uint32 *dwStateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x3D */
+
+ WERROR
+ clusapi_AddNotifyKey(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HKEY_RPC hKey,
+ [ in ] uint32 dwNotifyKey,
+ [ in ] uint32 Filter,
+ [ in ] boolean8 WatchSubTree,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x3E */
+
+ WERROR
+ clusapi_ReAddNotifyNode(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ in ] uint32 StateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x3F */
+
+ WERROR
+ clusapi_ReAddNotifyGroup(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ in ] uint32 StateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x40 */
+
+ WERROR
+ clusapi_ReAddNotifyResource(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HRES_RPC hResource,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ in ] uint32 StateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x41 */
+
+ WERROR
+ clusapi_GetNotify(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ out ] uint32 *dwNotifyKey,
+ [ out ] uint32 *dwFilter,
+ [ out ] uint32 *dwStateSequence,
+ [ out, string ] [charset(UTF16)] uint16 **Name,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x42 */
+#if 0
+ HNODE_RPC
+ clusapi_OpenNode(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNodeName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenNode(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNodeName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HNODE_RPC *hNode
+ );
+#endif
+ /*****************/
+ /* Function 0x43 */
+
+ WERROR
+ clusapi_CloseNode(
+ [ in, out ] HNODE_RPC *Node
+ );
+
+ /*****************/
+ /* Function 0x44 */
+
+ typedef [v1_enum] enum {
+ ClusterNodeUp = 0x00000000,
+ ClusterNodeDown = 0x00000001,
+ ClusterNodePaused = 0x00000002,
+ ClusterNodeJoining = 0x00000003,
+ ClusterNodeStateUnknown = 0xFFFFFFFF
+ } clusapi_ClusterNodeState;
+
+ WERROR
+ clusapi_GetNodeState(
+ [ in ] HNODE_RPC hNode,
+ [ out ] clusapi_ClusterNodeState *State,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x45 */
+
+ WERROR
+ clusapi_PauseNode(
+ [ in ] HNODE_RPC hNode,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x46 */
+
+ WERROR
+ clusapi_ResumeNode(
+ [ in ] HNODE_RPC hNode,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x47 */
+
+ WERROR
+ clusapi_EvictNode(
+ [ in ] HNODE_RPC hNode,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x48 */
+
+ WERROR
+ clusapi_NodeResourceControl(
+ [ in ] HRES_RPC hResource,
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x49 */
+
+ typedef [v1_enum] enum {
+ CLUS_RESCLASS_UNKNOWN = 0x00000000,
+ CLUS_RESCLASS_STORAGE = 0x00000001,
+ CLUS_RESCLASS_NETWORK = 0x00000002
+ } clusapi_ResourceClass;
+
+ typedef [public] struct {
+ clusapi_ResourceClass Class;
+ uint32 SubClass;
+ } CLUS_RESOURCE_CLASS_INFO;
+
+ typedef [v1_enum] enum {
+ CLUSCTL_RESOURCE_UNKNOWN = 0x01000000,
+ CLUSCTL_RESOURCE_GET_CHARACTERISTICS = 0x01000005,
+ CLUSCTL_RESOURCE_GET_FLAGS = 0x01000009,
+ CLUSCTL_RESOURCE_GET_CLASS_INFO = 0x0100000D,
+ CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES = 0x01000011,
+ CLUSCTL_RESOURCE_GET_NAME = 0x01000029,
+ CLUSCTL_RESOURCE_GET_RESOURCE_TYPE = 0x0100002D,
+ CLUSCTL_RESOURCE_GET_ID = 0x01000039,
+ CLUSCTL_RESOURCE_ENUM_COMMON_PROPERTIES = 0x01000051,
+ CLUSCTL_RESOURCE_GET_RO_COMMON_PROPERTIES = 0x01000055,
+ CLUSCTL_RESOURCE_GET_COMMON_PROPERTIES = 0x01000059,
+ CLUSCTL_RESOURCE_SET_COMMON_PROPERTIES = 0x0140005E,
+ CLUSCTL_RESOURCE_VALIDATE_COMMON_PROPERTIES = 0x01000061,
+ CLUSCTL_RESOURCE_GET_COMMON_PROPERTY_FMTS = 0x01000065,
+ CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES = 0x01000079,
+ CLUSCTL_RESOURCE_GET_RO_PRIVATE_PROPERTIES = 0x0100007D,
+ CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES = 0x01000081,
+ CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES = 0x01400086,
+ CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES = 0x01000089,
+ CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS = 0x0100008D,
+ CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT = 0x014000A2,
+ CLUSCTL_RESOURCE_DELETE_REGISTRY_CHECKPOINT = 0x014000A6,
+ CLUSCTL_RESOURCE_GET_REGISTRY_CHECKPOINTS = 0x010000A9,
+ CLUSCTL_RESOURCE_ADD_CRYPTO_CHECKPOINT = 0x014000AE,
+ CLUSCTL_RESOURCE_DELETE_CRYPTO_CHECKPOINT = 0x014000B2,
+ CLUSCTL_RESOURCE_GET_CRYPTO_CHECKPOINTS = 0x010000B5,
+ CLUSCTL_RESOURCE_UPGRADE_DLL = 0x014000BA,
+ CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT_64BIT = 0x014000BE,
+ CLUSCTL_RESOURCE_ADD_REGISTRY_CHECKPOINT_32BIT = 0x014000C2,
+ CLUSCTL_RESOURCE_GET_NETWORK_NAME = 0x01000169,
+ CLUSCTL_RESOURCE_NETNAME_REGISTER_DNS_RECORDS = 0x01000172,
+ CLUSCTL_RESOURCE_GET_DNS_NAME = 0x01000175,
+ CLUSCTL_RESOURCE_NETNAME_SET_PWD_INFO = 0x0100017A,
+ CLUSCTL_RESOURCE_NETNAME_DELETE_CO = 0x0100017E,
+ CLUSCTL_RESOURCE_NETNAME_VALIDATE_VCO = 0x01000181,
+ CLUSCTL_RESOURCE_NETNAME_RESET_VCO = 0x01000185,
+ CLUSCTL_RESOURCE_NETNAME_CREDS_UPDATED = 0x01c0018a,
+ CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO = 0x01000191,
+ CLUSCTL_RESOURCE_STORAGE_IS_PATH_VALID = 0x01000199,
+ CLUSCTL_RESOURCE_IPADDRESS_RENEW_LEASE = 0x014001BE,
+ CLUSCTL_RESOURCE_IPADDRESS_RELEASE_LEASE = 0x014001C2,
+ CLUSCTL_RESOURCE_QUERY_MAINTENANCE_MODE = 0x010001E1,
+ CLUSCTL_RESOURCE_SET_MAINTENANCE_MODE = 0x014001E6,
+ CLUSCTL_RESOURCE_STORAGE_SET_DRIVELETTER = 0x014001EA,
+ CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO_EX = 0x010001F1,
+ CLUSCTL_RESOURCE_STORAGE_GET_DIRTY = 0x01000219,
+ CLUSCTL_RESOURCE_STORAGE_GET_MOUNTPOINTS = 0x01000211,
+ CLUSCTL_RESOURCE_STORAGE_GET_SHARED_VOLUME_INFO = 0x01000225,
+ CLUSCTL_RESOURCE_VM_START_MIGRATION = 0x01600004,
+ CLUSCTL_RESOURCE_VM_CANCEL_MIGRATION = 0x01600008,
+ CLUSCTL_RESOURCE_SET_CSV_MAINTENANCE_MODE = 0x01400296,
+ CLUSCTL_RESOURCE_ENABLE_SHARED_VOLUME_DIRECTIO = 0x0140028a,
+ CLUSCTL_RESOURCE_DISABLE_SHARED_VOLUME_DIRECTIO = 0x0140028e,
+ CLUSCTL_RESOURCE_SET_SHARED_VOLUME_BACKUP_MODE = 0x0140029a,
+ CLUSCTL_RESOURCE_GET_RELATED_RESOURCE_NAMES = 0x01001fad,
+ CLUSCTL_RESOURCE_POOL_GET_DRIVE_INFO = 0x010002b5,
+ CLUSCTL_RESOURCE_CLOUD_WITNESS_UPDATE_TOKEN = 0x014020e6,
+ CLUSCTL_RESOURCE_NETNAME_CHECK_OU_PERMISSIONS = 0x07002121,
+ CLUSCTL_RESOURCE_NETNAME_CHECK_AD_STATE = 0x07002125
+ } clusapi_ResourceControlCode;
+
+ WERROR
+ clusapi_ResourceControl(
+ [ in ] HRES_RPC hResource,
+ [ in ] clusapi_ResourceControlCode dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x4A */
+
+ WERROR
+ clusapi_NodeResourceTypeControl(
+ [ in ] HCLUSTER_RPC hCluster,
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceTypeName,
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x4B */
+
+ typedef [v1_enum] enum {
+ CLUSCTL_RESOURCE_TYPE_UNKNOWN = 0x02000000,
+ CLUSCTL_RESOURCE_TYPE_GET_CHARACTERISTICS = 0x02000005,
+ CLUSCTL_RESOURCE_TYPE_GET_FLAGS = 0x02000009,
+ CLUSCTL_RESOURCE_TYPE_GET_CLASS_INFO = 0x0200000D,
+ CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES = 0x02000011,
+ CLUSCTL_RESOURCE_TYPE_GET_ARB_TIMEOUT = 0x02000015,
+ CLUSCTL_RESOURCE_TYPE_ENUM_COMMON_PROPERTIES = 0x02000051,
+ CLUSCTL_RESOURCE_TYPE_GET_RO_COMMON_PROPERTIES = 0x02000055,
+ CLUSCTL_RESOURCE_TYPE_GET_COMMON_PROPERTIES = 0x02000059,
+ CLUSCTL_RESOURCE_TYPE_SET_COMMON_PROPERTIES = 0x0240005E,
+ CLUSCTL_RESOURCE_TYPE_VALIDATE_COMMON_PROPERTIES = 0x02000061,
+ CLUSCTL_RESOURCE_TYPE_GET_COMMON_PROPERTY_FMTS = 0x02000065,
+ CLUSCTL_RESOURCE_TYPE_GET_COMMON_RESOURCE_PROPERTY_FMTS = 0x02000069,
+ CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES = 0x02000079,
+ CLUSCTL_RESOURCE_TYPE_GET_RO_PRIVATE_PROPERTIES = 0x0200007D,
+ CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_PROPERTIES = 0x02000081,
+ CLUSCTL_RESOURCE_TYPE_SET_PRIVATE_PROPERTIES = 0x02400086,
+ CLUSCTL_RESOURCE_TYPE_VALIDATE_PRIVATE_PROPERTIES = 0x02000089,
+ CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_PROPERTY_FMTS = 0x0200008D,
+ CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS= 0x02000091,
+ CLUSCTL_RESOURCE_TYPE_STORAGE_GET_AVAILABLE_DISKS = 0x02000195,
+ CLUSCTL_RESOURCE_TYPE_NETNAME_VALIDATE_NETNAME = 0x02000235,
+ CLUSCTL_RESOURCE_TYPE_VALIDATE_PATH = 0x02000231,
+ CLUSCTL_RESOURCE_TYPE_GEN_APP_VALIDATE_DIRECTORY = 0x02000239,
+ CLUSCTL_RESOURCE_TYPE_STORAGE_GET_DRIVELETTERS = 0x020001ED,
+ CLUSCTL_RESOURCE_TYPE_STORAGE_GET_AVAILABLE_DISKS_EX = 0x020001F5,
+ CLUSCTL_RESOURCE_TYPE_STORAGE_REMAP_DRIVELETTER = 0x02000201,
+ CLUSCTL_RESOURCE_TYPE_STORAGE_GET_DISKID = 0x02000205,
+ CLUSCTL_RESOURCE_TYPE_STORAGE_IS_CLUSTERABLE = 0x02000209,
+ CLUSCTL_RESOURCE_TYPE_STORAGE_RELEASE_OWNERSHIP = 0x0240020E,
+ CLUSCTL_RESOURCE_TYPE_STORAGE_IS_CSV_FILE = 0x1000229,
+ CLUSCTL_RESOURCE_TYPE_CLOUD_WITNESS_VALIDATE_CREDENTIALS= 0x020020e1,
+ CLUSCTL_RESOURCE_TYPE_REPLICATION_GET_ELIGIBLE_LOGDISKS = 0x02002149,
+ CLUSCTL_RESOURCE_TYPE_REPLICATION_GET_ELIGIBLE_TARGET_DATADISKS = 0x0200214D,
+ CLUSCTL_RESOURCE_TYPE_REPLICATION_GET_ELIGIBLE_SOURCE_DATADISKS = 0x02002151,
+ CLUSCTL_RESOURCE_TYPE_REPLICATION_GET_REPLICA_VOLUMES = 0x02002159,
+ CLUSCTL_RESOURCE_TYPE_REPLICATION_GET_LOG_VOLUME = 0x0200215D,
+ CLUSCTL_RESOURCE_TYPE_REPLICATION_GET_REPLICATED_DISKS = 0x02002155,
+ CLUSCTL_RESOURCE_TYPE_REPLICATION_GET_RESOURCE_GROUP = 0x02002161
+ } clusapi_ResourceTypeControlCode;
+
+ WERROR
+ clusapi_ResourceTypeControl(
+ [ in ] HCLUSTER_RPC hCluster,
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceTypeName,
+ [ in ] clusapi_ResourceTypeControlCode dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x4C */
+
+ WERROR
+ clusapi_NodeGroupControl(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x4D */
+
+ typedef [v1_enum] enum {
+ CLUSCTL_GROUP_UNKNOWN = 0x03000000,
+ CLUSCTL_GROUP_GET_CHARACTERISTICS = 0x03000005,
+ CLUSCTL_GROUP_GET_FLAGS = 0x03000009,
+ CLUSCTL_GROUP_GET_NAME = 0x03000029,
+ CLUSCTL_GROUP_GET_ID = 0x03000039,
+ CLUSCTL_GROUP_ENUM_COMMON_PROPERTIES = 0x03000051,
+ CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES = 0x03000055,
+ CLUSCTL_GROUP_GET_COMMON_PROPERTIES = 0x03000059,
+ CLUSCTL_GROUP_SET_COMMON_PROPERTIES = 0x0340005E,
+ CLUSCTL_GROUP_VALIDATE_COMMON_PROPERTIES = 0x03000061,
+ CLUSCTL_GROUP_GET_COMMON_PROPERTY_FMTS = 0x03000065,
+ CLUSCTL_GROUP_ENUM_PRIVATE_PROPERTIES = 0x03000079,
+ CLUSCTL_GROUP_GET_RO_PRIVATE_PROPERTIES = 0x0300007D,
+ CLUSCTL_GROUP_GET_PRIVATE_PROPERTIES = 0x03000081,
+ CLUSCTL_GROUP_SET_PRIVATE_PROPERTIES = 0x03400086,
+ CLUSCTL_GROUP_VALIDATE_PRIVATE_PROPERTIES = 0x03000089
+ } clusapi_GroupControlCode;
+
+ WERROR
+ clusapi_GroupControl(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] clusapi_GroupControlCode dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x4E */
+
+ WERROR
+ clusapi_NodeNodeControl(
+ [ in ] HNODE_RPC hNode,
+ [ in ] HNODE_RPC hHostNode,
+ [ in ] uint32 dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x4F */
+
+ typedef [v1_enum] enum {
+ CLUSCTL_NODE_UNKNOWN = 0x04000000,
+ CLUSCTL_NODE_GET_CHARACTERISTICS = 0x04000005,
+ CLUSCTL_NODE_GET_FLAGS = 0x04000009,
+ CLUSCTL_NODE_GET_NAME = 0x04000029,
+ CLUSCTL_NODE_GET_ID = 0x04000039,
+ CLUSCTL_NODE_GET_CLUSTER_SERVICE_ACCOUNT_NAME = 0x04000041,
+ CLUSCTL_NODE_ENUM_COMMON_PROPERTIES = 0x04000051,
+ CLUSCTL_NODE_GET_RO_COMMON_PROPERTIES = 0x04000055,
+ CLUSCTL_NODE_GET_COMMON_PROPERTIES = 0x04000059,
+ CLUSCTL_NODE_SET_COMMON_PROPERTIES = 0x0440005E,
+ CLUSCTL_NODE_VALIDATE_COMMON_PROPERTIES = 0x04000061,
+ CLUSCTL_NODE_ENUM_PRIVATE_PROPERTIES = 0x04000079,
+ CLUSCTL_NODE_GET_RO_PRIVATE_PROPERTIES = 0x0400007D,
+ CLUSCTL_NODE_GET_PRIVATE_PROPERTIES = 0x04000081,
+ CLUSCTL_NODE_SET_PRIVATE_PROPERTIES = 0x04400086,
+ CLUSCTL_NODE_VALIDATE_PRIVATE_PROPERTIES = 0x04000089
+ } clusapi_NodeControlCode;
+
+ WERROR
+ clusapi_NodeControl(
+ [ in ] HNODE_RPC hNode,
+ [ in ] clusapi_NodeControlCode dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x50 */
+
+ WERROR
+ Opnum80NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x51 */
+#if 0
+ HNETWORK_RPC
+ clusapi_OpenNetwork(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetworkName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenNetwork(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetworkName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HNETWORK_RPC *hNetwork
+ );
+#endif
+ /*****************/
+ /* Function 0x52 */
+
+ WERROR
+ clusapi_CloseNetwork(
+ [ in, out ] HNETWORK_RPC *Network
+ );
+
+ /*****************/
+ /* Function 0x53 */
+
+ typedef [v1_enum] enum {
+ ClusterNetworkUnavailable = 0x00000000,
+ ClusterNetworkDown = 0x00000001,
+ ClusterNetworkPartitioned = 0x00000002,
+ ClusterNetworkUp = 0x00000003,
+ ClusterNetworkStateUnknown = 0xFFFFFFFF
+ } clusapi_ClusterNetworkState;
+
+ WERROR
+ clusapi_GetNetworkState(
+ [ in ] HNETWORK_RPC hNetwork,
+ [ out ] clusapi_ClusterNetworkState *State,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x54 */
+
+ WERROR
+ clusapi_SetNetworkName(
+ [ in ] HNETWORK_RPC hNetwork,
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetworkName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x55 */
+
+ WERROR
+ clusapi_CreateNetworkEnum(
+ [ in ] HNETWORK_RPC hNetwork,
+ [ in ] uint32 dwType,
+ [ out ] ENUM_LIST **ReturnEnum,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x56 */
+
+ WERROR
+ clusapi_GetNetworkId(
+ [ in ] HNETWORK_RPC hNetwork,
+ [ out, string ] [charset(UTF16)] uint16 **pGuid,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x57 */
+
+ WERROR
+ clusapi_SetNetworkPriorityOrder(
+ [ in, range(0, 1000)] uint32 NetworkCount,
+ [ in, string, size_is(NetworkCount) ] [charset(UTF16)] uint16 NetworkIdList[*],
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x58 */
+
+ WERROR
+ clusapi_NodeNetworkControl(
+ [ in ] HNETWORK_RPC hNetwork,
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x59 */
+
+ WERROR
+ clusapi_NetworkControl(
+ [ in ] HNETWORK_RPC hNetwork,
+ [ in ] uint32 dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x5A */
+
+ WERROR
+ clusapi_AddNotifyNetwork(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HNETWORK_RPC hNetwork,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ out ] uint32 *dwStateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x5B */
+
+ WERROR
+ clusapi_ReAddNotifyNetwork(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HNETWORK_RPC hNetwork,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ in ] uint32 StateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x5C */
+#if 0
+ HNETINTERFACE_RPC
+ clusapi_OpenNetInterface(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetInterfaceName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenNetInterface(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetInterfaceName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HNETINTERFACE_RPC *hNetInterface
+ );
+#endif
+ /*****************/
+ /* Function 0x5D */
+
+ WERROR
+ clusapi_CloseNetInterface(
+ [ in, out ] HNETINTERFACE_RPC *NetInterface
+ );
+
+ /*****************/
+ /* Function 0x5E */
+
+ typedef [v1_enum] enum {
+ ClusterNetInterfaceFailed = 0x00000000,
+ ClusterNetInterfaceUnreachable = 0x00000001,
+ ClusterNetInterfaceUnavailable = 0x00000002,
+ ClusterNetInterfaceUp = 0x00000003,
+ ClusterNetInterfaceStateUnknown = 0xFFFFFFFF
+ } clusapi_ClusterNetInterfaceState;
+
+ WERROR
+ clusapi_GetNetInterfaceState(
+ [ in ] HNETINTERFACE_RPC hNetInterface,
+ [ out ] clusapi_ClusterNetInterfaceState *State,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x5F */
+
+ WERROR
+ clusapi_GetNetInterface(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNodeName,
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetworkName,
+ [ out, string ] [charset(UTF16)] uint16 **lppszInterfaceName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x60 */
+
+ WERROR
+ clusapi_GetNetInterfaceId(
+ [ in ] HNETINTERFACE_RPC hNetInterface,
+ [ out, string ] [charset(UTF16)] uint16 **pGuid,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x61 */
+
+ WERROR
+ clusapi_NodeNetInterfaceControl(
+ [ in ] HNETINTERFACE_RPC hNetInterface,
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x62 */
+
+ WERROR
+ clusapi_NetInterfaceControl(
+ [ in ] HNETINTERFACE_RPC hNetInterface,
+ [ in ] uint32 dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x63 */
+
+ WERROR
+ clusapi_AddNotifyNetInterface(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HNETINTERFACE_RPC hNetInterface,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ out ] uint32 *dwStateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x64 */
+
+ WERROR
+ clusapi_ReAddNotifyNetInterface(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HNETINTERFACE_RPC hNetInterface,
+ [ in ] uint32 dwFilter,
+ [ in ] uint32 dwNotifyKey,
+ [ in ] uint32 StateSequence,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x65 */
+
+ WERROR
+ clusapi_CreateNodeEnum(
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwType,
+ [ out ] ENUM_LIST **ReturnEnum,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x66 */
+
+ WERROR
+ clusapi_GetClusterVersion2(
+ [ out ] uint16 *lpwMajorVersion,
+ [ out ] uint16 *lpwMinorVersion,
+ [ out ] uint16 *lpwBuildNumber,
+ [ out, string ] [charset(UTF16)] uint16 **lpszVendorId,
+ [ out, string ] [charset(UTF16)] uint16 **lpszCSDVersion,
+ [ out ] CLUSTER_OPERATIONAL_VERSION_INFO **ppClusterOpVerInfo,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x67 */
+
+ typedef [bitmap32bit] bitmap {
+ CLUSTER_RESOURCE_TYPE_ENUM_NODES = 0x00000001,
+ CLUSTER_RESOURCE_TYPE_ENUM_RESOURCES = 0x00000002
+ } ClusterResTypeEnumType;
+
+ WERROR
+ clusapi_CreateResTypeEnum(
+ [ in, string ] [charset(UTF16)] uint16 *lpszTypeName,
+ [ in ] ClusterResTypeEnumType dwType,
+ [ out ] ENUM_LIST **ReturnEnum,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x68 */
+
+ WERROR
+ clusapi_BackupClusterDatabase(
+ [ in, string ] [charset(UTF16)] uint16 *lpszPathName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x69 */
+
+ WERROR
+ clusapi_NodeClusterControl(
+ [ in ] HCLUSTER_RPC hCluster,
+ [ in ] HNODE_RPC hHostNode,
+ [ in ] uint32 dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x6A */
+
+ typedef [v1_enum] enum {
+ CLUSCTL_CLUSTER_UNKNOWN = 0x07000000,
+ CLUSCTL_CLUSTER_GET_FQDN = 0x0700003D,
+ CLUSCTL_CLUSTER_CHECK_VOTER_EVICT = 0x07000045,
+ CLUSCTL_CLUSTER_CHECK_VOTER_DOWN = 0x07000049,
+ CLUSCTL_CLUSTER_SHUTDOWN = 0x0700004D,
+ CLUSCTL_CLUSTER_ENUM_COMMON_PROPERTIES = 0x07000051,
+ CLUSCTL_CLUSTER_GET_RO_COMMON_PROPERTIES = 0x07000055,
+ CLUSCTL_CLUSTER_GET_COMMON_PROPERTIES = 0x07000059,
+ CLUSCTL_CLUSTER_SET_COMMON_PROPERTIES = 0x0740005E,
+ CLUSCTL_CLUSTER_VALIDATE_COMMON_PROPERTIES = 0x07000061,
+ CLUSCTL_CLUSTER_GET_COMMON_PROPERTY_FMTS = 0x07000065,
+ CLUSCTL_CLUSTER_ENUM_PRIVATE_PROPERTIES = 0x07000079,
+ CLUSCTL_CLUSTER_GET_RO_PRIVATE_PROPERTIES = 0x0700007D,
+ CLUSCTL_CLUSTER_GET_PRIVATE_PROPERTIES = 0x07000081,
+ CLUSCTL_CLUSTER_SET_PRIVATE_PROPERTIES = 0x07400086,
+ CLUSCTL_CLUSTER_VALIDATE_PRIVATE_PROPERTIES = 0x07000089,
+ CLUSCTL_CLUSTER_GET_SHARED_VOLUME_ID = 0x07000291,
+ CLUSCTL_CLUSTER_UPGRADE_CLUSTER_VERSION = 0x074000ce,
+ CLUSCTL_CLUSTER_CLEAR_UPGRADE_IN_PROGRESS = 0x074000d2,
+ CLUSCTL_CLUSTER_IS_READY_FOR_UPGRADE = 0x070000d5
+ } clusapi_ClusterControlCode;
+
+ typedef [v1_enum] enum {
+ CLUSPROP_SYNTAX_ENDMARK = 0x00000000,
+ CLUSPROP_SYNTAX_NAME = 0x00040003,
+ CLUSPROP_SYNTAX_RESCLASS = 0x00020002,
+ CLUSPROP_SYNTAX_LIST_VALUE_SZ = 0x00010003,
+ CLUSPROP_SYNTAX_LIST_VALUE_EXPAND_SZ = 0x00010004,
+ CLUSPROP_SYNTAX_LIST_VALUE_DWORD = 0x00010002,
+ CLUSPROP_SYNTAX_LIST_VALUE_BINARY = 0x00010001,
+ CLUSPROP_SYNTAX_LIST_VALUE_MULTI_SZ = 0x00010005,
+ CLUSPROP_SYNTAX_LIST_VALUE_LONG = 0x00010007,
+ CLUSPROP_SYNTAX_LIST_VALUE_EXPANDED_SZ = 0x00010008,
+ CLUSPROP_SYNTAX_LIST_VALUE_SECURITY_DESCRIPTOR = 0x00010009,
+ CLUSPROP_SYNTAX_LIST_VALUE_LARGE_INTEGER = 0x0001000a,
+ CLUSPROP_SYNTAX_LIST_VALUE_ULARGE_INTEGER = 0x00010006,
+ CLUSPROP_SYNTAX_LIST_VALUE_WORD = 0x0001000b,
+ CLUSPROP_SYNTAX_LIST_VALUE_FILETIME = 0x0001000c,
+ CLUSPROP_SYNTAX_DISK_SIGNATURE = 0x00050002,
+ CLUSPROP_SYNTAX_SCSI_ADDRESS = 0x00060002,
+ CLUSPROP_SYNTAX_DISK_NUMBER = 0x00070002,
+ CLUSPROP_SYNTAX_PARTITION_INFO = 0x00080001,
+ CLUSPROP_SYNTAX_DISK_SERIALNUMBER = 0x000a0003,
+ CLUSPROP_SYNTAX_DISK_GUID = 0x000b0003,
+ CLUSPROP_SYNTAX_DISK_SIZE = 0x000c0006,
+ CLUSPROP_SYNTAX_PARTITION_INFO_EX = 0x000d0001
+ } CLUSTER_PROPERTY_SYNTAX;
+
+ typedef struct {
+ CLUSTER_PROPERTY_SYNTAX Syntax;
+ uint32 Size;
+ [subcontext(0),subcontext_size(Size)] [flag(NDR_REMAINING)] DATA_BLOB Buffer;
+ [flag(NDR_ALIGN4)] DATA_BLOB Padding;
+ } clusapi_propertyValues;
+
+ typedef struct {
+ [value(CLUSPROP_SYNTAX_NAME)] CLUSTER_PROPERTY_SYNTAX syntax_name;
+ [value(strlen_m_term(buffer)*2)] uint32 size;
+ nstring buffer;
+ [flag(NDR_ALIGN2)] DATA_BLOB padding;
+ clusapi_propertyValues PropertyValues;
+ [value(CLUSPROP_SYNTAX_ENDMARK)] CLUSTER_PROPERTY_SYNTAX end_mark;
+ } clusapi_propertyValue;
+
+ typedef [public] struct {
+ uint32 propertyCount;
+ clusapi_propertyValue propertyValues[propertyCount];
+ [value(CLUSPROP_SYNTAX_ENDMARK)] CLUSTER_PROPERTY_SYNTAX end_mark;
+ } clusapi_PROPERTY_LIST;
+
+ WERROR
+ clusapi_ClusterControl(
+ [ in ] HCLUSTER_RPC hCluster,
+ [ in ] clusapi_ClusterControlCode dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize),
+ length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in ] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x6B */
+
+ WERROR
+ clusapi_UnblockGetNotifyCall(
+ [ in ] HNOTIFY_RPC hNotify
+ );
+
+ /*****************/
+ /* Function 0x6C */
+
+ WERROR
+ clusapi_SetServiceAccountPassword(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNewPassword,
+ [ in ] IDL_CLUSTER_SET_PASSWORD_FLAGS dwFlags,
+ [ out, size_is(ReturnStatusBufferSize), length_is(*SizeReturned) ]
+ IDL_CLUSTER_SET_PASSWORD_STATUS ReturnStatusBufferPtr[*],
+ [ in, range(0, (64 * 1024)) ] uint32 ReturnStatusBufferSize,
+ [ out ] uint32 *SizeReturned,
+ [ out ] uint32 *ExpectedBufferSize
+ );
+
+ /*****************/
+ /* Function 0x6D */
+
+ WERROR
+ clusapi_SetResourceDependencyExpression(
+ [ in ] HRES_RPC hResource,
+ [ in, string, unique ] [charset(UTF16)] uint16 *lpszDependencyExpression,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x6E */
+
+ WERROR
+ clusapi_GetResourceDependencyExpression(
+ [ in ] HRES_RPC hResource,
+ [ out, string ] [charset(UTF16)] uint16 **lpszDependencyExpression,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x6F */
+
+ WERROR
+ Opnum111NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x70 */
+
+ WERROR
+ clusapi_GetResourceNetworkName(
+ [ in ] HRES_RPC hResource,
+ [ out, string ] [charset(UTF16)] uint16 **lpszName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x71 */
+
+ WERROR
+ clusapi_ExecuteBatch(
+ [ in ] HKEY_RPC hKey,
+ [ in ] uint32 cbData,
+ [ in, size_is(cbData)] uint8 *lpData,
+ [ out ] int *pdwFailedCommand,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x72 */
+
+ WERROR
+ clusapi_CreateBatchPort(
+ [ in ] HKEY_RPC hKey,
+ [ out ] HBATCH_PORT_RPC *phBatchPort,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x73 */
+
+ WERROR
+ clusapi_GetBatchNotification(
+ [ in ] HBATCH_PORT_RPC hBatchNotify,
+ [ out ] uint32 *cbData,
+ [ out, size_is(,*cbData) ] uint8 ** lpData
+ );
+
+ /*****************/
+ /* Function 0x74 */
+
+ WERROR
+ clusapi_CloseBatchPort(
+ [ in, out ] HBATCH_PORT_RPC *phBatchPort
+ );
+
+ /*****************/
+ /* Function 0x75 */
+
+ typedef [bitmap32bit] bitmap {
+ CLUSAPI_READ_ACCESS = 0x00000001,
+ CLUSAPI_CHANGE_ACCESS = 0x00000002,
+ CLUSAPI_GENERIC_READ = 0x80000000,
+ CLUSAPI_GENERIC_WRITE = 0x40000000,
+ CLUSAPI_GENERIC_EXECUTE = 0x20000000,
+ CLUSAPI_GENERIC_ALL = 0x10000000,
+ CLUSAPI_MAXIMUM_ALLOWED = 0x02000000
+ } clusapi_DesiredAccessMask;
+
+#if 0
+ HCLUSTER_RPC
+ clusapi_OpenClusterEx(
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status
+ );
+#else
+ void
+ clusapi_OpenClusterEx(
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] HCLUSTER_RPC *hCluster
+ );
+#endif
+
+ /*****************/
+ /* Function 0x76 */
+#if 0
+ HNODE_RPC
+ clusapi_OpenNodeEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNodeName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenNodeEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNodeName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HNODE_RPC *hNode
+ );
+#endif
+ /*****************/
+ /* Function 0x77 */
+#if 0
+ HGROUP_RPC
+ clusapi_OpenGroupEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenGroupEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HGROUP_RPC *hGroup
+ );
+#endif
+ /*****************/
+ /* Function 0x78 */
+#if 0
+ HRES_RPC
+ clusapi_OpenResourceEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenResourceEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszResourceName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HRES_RPC *hResource
+ );
+#endif
+ /*****************/
+ /* Function 0x79 */
+#if 0
+ HNETWORK_RPC
+ clusapi_OpenNetworkEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetworkName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenNetworkEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetworkName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HNETWORK_RPC *hNetwork
+ );
+#endif
+ /*****************/
+ /* Function 0x7A */
+#if 0
+ HNETINTERFACE_RPC
+ clusapi_OpenNetInterfaceEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetInterfaceName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenNetInterfaceEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszNetInterfaceName,
+ [ in ] clusapi_DesiredAccessMask dwDesiredAccess,
+ [ out ] uint32 *lpdwGrantedAccess,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HNETINTERFACE_RPC *hNetInterface
+ );
+#endif
+ /*****************/
+ /* Function 0x7B */
+
+ WERROR
+ clusapi_ChangeCsvState(
+ [ in ] HRES_RPC hResource,
+ [ in ] uint32 dwState,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x7C */
+
+ WERROR
+ clusapi_CreateNodeEnumEx(
+ [in] HNODE_RPC hNode,
+ [in] uint32 dwType,
+ [in] uint32 dwOptions,
+ [out] ENUM_LIST **ReturnIdEnum,
+ [out] ENUM_LIST **ReturnNameEnum,
+ [out] WERROR* rpc_status
+ );
+
+ /*****************/
+ /* Function 0x7D */
+
+ WERROR
+ clusapi_CreateEnumEx(
+ [in] HCLUSTER_RPC hCluster,
+ [in] ClusterEnumType dwType,
+ [in] uint32 dwOptions,
+ [out] ENUM_LIST **ReturnIdEnum,
+ [out] ENUM_LIST **ReturnNameEnum,
+ [out] WERROR* rpc_status
+ );
+
+ /*****************/
+ /* Function 0x7E */
+
+ WERROR
+ clusapi_PauseNodeEx(
+ [ in ] HNODE_RPC hNode,
+ [ in ] boolean8 bDrainNode,
+ [ in ] uint32 dwPauseFlags,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x7F */
+
+ WERROR
+ clusapi_PauseNodeWithDrainTarget(
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwPauseFlags,
+ [ in ] HNODE_RPC hNodeDrainTarget,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x80 */
+
+ WERROR
+ clusapi_ResumeNodeEx(
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwResumeFailbackType,
+ [ in ] uint32 dwResumeFlagsReserved,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x81 */
+#if 0
+ HGROUP_RPC
+ clusapi_CreateGroupEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupName,
+ [ in, unique ] CLUSTER_CREATE_GROUP_INFO_RPC *pGroupInfo,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_CreateGroupEx(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupName,
+ [ in, unique ] CLUSTER_CREATE_GROUP_INFO_RPC *pGroupInfo,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HGROUP_RPC *hGroup
+ );
+#endif
+ /*****************/
+ /* Function 0x82 */
+
+ WERROR
+ clusapi_OnlineGroupEx(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] uint32 dwOnlineFlags,
+ [ in, size_is(cbInBufferSize) ] uint8* lpInBuffer,
+ [ in ] uint32 cbInBufferSize,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x83 */
+
+ WERROR
+ clusapi_OfflineGroupEx(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] uint32 dwOfflineFlags,
+ [ in, size_is(cbInBufferSize) ] uint8* lpInBuffer,
+ [ in ] uint32 cbInBufferSize,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x84 */
+
+ WERROR
+ clusapi_MoveGroupEx(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] uint32 dwMoveFlags,
+ [ in, size_is(cbInBufferSize) ] uint8* lpInBuffer,
+ [ in ] uint32 cbInBufferSize,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x85 */
+
+ WERROR
+ clusapi_MoveGroupToNodeEx(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] HNODE_RPC hNode,
+ [ in ] uint32 dwMoveFlags,
+ [ in, size_is(cbInBufferSize) ] uint8* lpInBuffer,
+ [ in ] uint32 cbInBufferSize,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x86 */
+
+ WERROR
+ clusapi_CancelClusterGroupOperation(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] uint32 dwCancelFlags,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x87 */
+
+ WERROR
+ clusapi_OnlineResourceEx(
+ [ in ] HRES_RPC hResource,
+ [ in ] uint32 dwOnlineFlags,
+ [ in, size_is(cbInBufferSize) ] uint8* lpInBuffer,
+ [ in ] uint32 cbInBufferSize,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x88 */
+
+ WERROR
+ clusapi_OfflineResourceEx(
+ [ in ] HRES_RPC hResource,
+ [ in ] uint32 dwOfflineFlags,
+ [ in, size_is(cbInBufferSize) ] uint8* lpInBuffer,
+ [ in ] uint32 cbInBufferSize,
+ [ out ] WERROR *rpc_status
+ );
+
+#define HGENERIC_RPC policy_handle
+#if 0
+ typedef [context_handle] void *HGENERIC_RPC;
+#endif
+
+ typedef struct {
+ uint32 dwObjectType; /* really of type CLUSTER_OBJECT_TYPE_RPC */
+ hyper FilterFlags;
+ } NOTIFY_FILTER_AND_TYPE_RPC;
+
+ typedef struct {
+ NOTIFY_FILTER_AND_TYPE_RPC FilterAndType;
+ [ size_is(dwBufferSize ) ] uint8* buffer;
+ uint32 dwBufferSize;
+ [string] [charset(UTF16)] uint16 *ObjectId;
+ [string] [charset(UTF16)] uint16 *ParentId;
+ [string] [charset(UTF16)] uint16 *Name;
+ [string] [charset(UTF16)] uint16 *Type;
+ } NOTIFICATION_DATA_RPC;
+
+ typedef struct {
+ uint32 *dwNotifyKey;
+ NOTIFICATION_DATA_RPC NotificationData;
+ } NOTIFICATION_RPC;
+
+ /*****************/
+ /* Function 0x89 */
+
+ /*
+ * Notify interface V2 functions
+ */
+#if 0
+ HNOTIFY_RPC
+ clusapi_CreateNotifyV2(
+ [ out ] WERROR *rpc_error,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_CreateNotifyV2(
+ [ out ] WERROR *rpc_error,
+ [ out ] WERROR *rpc_status,
+ [ out ] HNOTIFY_RPC *hNotify
+ );
+
+#endif
+ /*****************/
+ /* Function 0x8A */
+
+ WERROR
+ clusapi_AddNotifyV2(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] HGENERIC_RPC hObject,
+ [ in ] NOTIFY_FILTER_AND_TYPE_RPC filter,
+ [ in ] uint32 dwNotifyKey,
+ [ in ] uint32 dwVersion,
+ [ in ] boolean8 isTargetedAtObject,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x8B */
+
+ WERROR
+ clusapi_GetNotifyV2(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ out, size_is(,*dwNumNotifications) ] NOTIFICATION_RPC **Notifications,
+ [ out ] uint32 *dwNumNotifications
+ );
+
+ /*****************/
+ /* Function 0x8C */
+
+ WERROR
+ clusapi_QueryAllValues(
+ [ in ] HKEY_RPC hKey,
+ [ out ] uint32 *pcbData,
+ [ out, size_is(1, *pcbData) ] uint8 ** ppData,
+ [ out ] WERROR *rpc_status
+ );
+
+ typedef struct {
+ uint32 DiskIdType;
+ uint8 DiskIdBlob[16];
+ } CLUSTER_DISKID;
+
+ /*****************/
+ /* Function 0x8D */
+
+ WERROR
+ clusapi_StmFindDisk(
+ [ in ] HCLUSTER_RPC hCluster,
+ [ in ] uint32 dwFlags,
+ [ in, out, unique ] CLUSTER_DISKID *pDiskId,
+ [ in, size_is(uniqueIdSize), unique ] uint8 *pUniqueId,
+ [ in ] uint32 uniqueIdSize,
+ [ out, ref, string ] [charset(UTF16)] uint16 **ppszDeviceName,
+ [ out ] WERROR *rpc_status
+ );
+
+ typedef struct{
+ [string] [charset(UTF16)] uint16 *pszNodeName;
+ HRESULT ResultCode;
+ uint32 ResultSize;
+ [unique, size_is(ResultSize)] uint8 *pResultData;
+ } CLUSTER_MRR_NODE_RESPONSE;
+
+ typedef struct {
+ uint32 NodeCount;
+ [size_is(NodeCount)] CLUSTER_MRR_NODE_RESPONSE *pNodes;
+ } CLUSTER_MRR_RESPONSE;
+
+ /*****************/
+ /* Function 0x8E */
+
+ WERROR
+ clusapi_ClusterMrr(
+ [ in ] HCLUSTER_RPC hCluster,
+ [ in ] boolean8 fExcludeSelf,
+ [ in ] hyper nodeSet,
+ [ in ] uint32 dwTimeout,
+ [ in ] uint32 dwComponent,
+ [ in ] uint32 dwControlCode,
+ [ in ] uint32 inSize,
+ [ in, unique, size_is(inSize) ] uint8 *pInData,
+ [ out, ref, size_is(1, 1) ] CLUSTER_MRR_RESPONSE **ppInfo,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x8F */
+
+ WERROR
+ clusapi_CreateGroupEnum(
+ [ in ] HCLUSTER_RPC hCluster,
+ [ in, unique, size_is(cbProperties)] uint8* pProperties,
+ [ in ] uint32 cbProperties,
+ [ in, unique, size_is(cbRoProperties)] uint8* pRoProperties,
+ [ in ] uint32 cbRoProperties,
+ [ out ] GROUP_ENUM_LIST **ppResultList,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x90 */
+
+ WERROR
+ clusapi_CreateResourceEnum(
+ [ in ] HCLUSTER_RPC hCluster,
+ [ in, unique, size_is(cbProperties)] uint8* pProperties,
+ [ in ] uint32 cbProperties,
+ [ in, unique, size_is(cbRoProperties)] uint8* pRoProperties,
+ [ in ] uint32 cbRoProperties,
+ [ out ] RESOURCE_ENUM_LIST **ppResultList,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x91 */
+
+ WERROR
+ clusapi_ExecuteReadBatch(
+ [ in ] HKEY_RPC hKey,
+ [ in ] uint32 cbInData,
+ [ in, size_is(cbInData)] uint8 *lpInData,
+ [ out ] uint32 *cbOutData,
+ [ out, size_is(,*cbOutData) ] uint8 ** lpOutData,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x92 */
+
+ WERROR
+ clusapi_RestartResource(
+ [ in ] HRES_RPC hResource,
+ [ in ] uint32 dwFlags,
+ [ out ] WERROR *rpc_status
+ );
+
+ typedef struct {
+ uint32 dwNotifyKey;
+ uint32 dwFilter;
+ [string] [charset(UTF16)] uint16 *Name;
+ } NOTIFICATION_DATA_ASYNC_RPC;
+
+ /*****************/
+ /* Function 0x93 */
+
+ WERROR
+ clusapi_GetNotifyAsync(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ out, size_is(,*dwNumNotifications) ] NOTIFICATION_DATA_ASYNC_RPC **Notifications,
+ [ out ] uint32 *dwNumNotifications
+ );
+
+ typedef enum {
+ DiskIdSignature = 0x00000001,
+ DiskIdGuid = 0x00000002,
+ DiskIdUnKnown = 0x00001388
+ } CLUSDSK_DISKID_ENUM;
+
+#if 0
+ typedef struct {
+ CLUSDSK_DISKID_ENUM DiskIdType;
+ [switch_is(DiskIdType)] union {
+ [case(DiskIdSignature)] uint32 DiskSignature;
+ [case(DiskIdGuid)] GUID DiskGuid;
+ };
+ } CLUSDSK_DISKID;
+#endif
+ typedef enum {
+ CLUSPROP_TYPE_ENDMARK = 0x0000,
+ CLUSPROP_TYPE_LIST_VALUE = 0x0001,
+ CLUSPROP_TYPE_RESCLASS = 0x0002,
+ CLUSPROP_TYPE_NAME = 0x0004,
+ CLUSPROP_TYPE_SIGNATURE = 0x0005,
+ CLUSPROP_TYPE_SCSIADDRESS = 0x0006,
+ CLUSPROP_TYPE_DISK_NUMBER = 0x0007,
+ CLUSPROP_TYPE_PARTITION_INFO = 0x0008,
+ CLUSPROP_TYPE_DISK_SERIALNUMBER = 0x000a,
+ CLUSPROP_TYPE_DISK_GUID = 0x000b,
+ CLUSPROP_TYPE_DISK_SIZE = 0x000c,
+ CLUSPROP_TYPE_PARTITION_INFO_EX = 0x000d
+ } CLUSTER_PROPERTY_TYPE;
+
+ typedef enum {
+ CLUSPROP_FORMAT_UNKNOWN = 0x0000,
+ CLUSPROP_FORMAT_BINARY = 0x0001,
+ CLUSPROP_FORMAT_DWORD = 0x0002,
+ CLUSPROP_FORMAT_SZ = 0x0003,
+ CLUSPROP_FORMAT_EXPAND_SZ = 0x0004,
+ CLUSPROP_FORMAT_MULTI_SZ = 0x0005,
+ CLUSPROP_FORMAT_ULARGE_INTEGER = 0x0006,
+ CLUSPROP_FORMAT_LONG = 0x0007,
+ CLUSPROP_FORMAT_EXPANDED_SZ = 0x0008,
+ CLUSPROP_FORMAT_SECURITY_DESCRIPTOR = 0x0009,
+ CLUSPROP_FORMAT_LARGE_INTEGER = 0x000a,
+ CLUSPROP_FORMAT_WORD = 0x000b,
+ CLUSPROP_FORMAT_FILETIME = 0x000c
+ } CLUSTER_PROPERTY_FORMAT;
+
+ typedef enum {
+ CLUS_CHAR_UNKNOWN = 0x00000000,
+ CLUS_CHAR_QUORUM = 0x00000001,
+ CLUS_CHAR_DELETE_REQUIRES_ALL_NODES = 0x00000002,
+ CLUS_CHAR_LOCAL_QUORUM = 0x00000004,
+ CLUS_CHAR_BROADCAST_DELETE = 0x00000020,
+ CLUS_CHAR_SINGLE_CLUSTER_INSTANCE = 0x00000040,
+ CLUS_CHAR_SINGLE_GROUP_INSTANCE = 0x00000080,
+ CLUS_CHAR_COEXIST_IN_SHARED_VOLUME_GROUP = 0x00000100,
+ CLUS_CHAR_RESERVED1 = 0x00000200,
+ CLUS_CHAR_MONITOR_DETACH = 0x00000400,
+ CLUS_CHAR_RESERVED2 = 0x00000800,
+ CLUS_CHAR_RESERVED3 = 0x00001000,
+ CLUS_CHAR_RESERVED4 = 0x00002000
+ } CLUS_CHARACTERISTICS;
+
+ typedef enum {
+ CLUS_FLAG_CORE = 0x00000001
+ } CLUS_FLAGS;
+
+ typedef enum {
+ MaintenanceModeTypeDisableIsAliveCheck = 1,
+ MaintenanceModeTypeOfflineResource = 2,
+ MaintenanceModeTypeUnclusterResource = 3
+ } MAINTENANCE_MODE_TYPE;
+
+ typedef enum {
+ CLUSTER_CHANGE_NODE_STATE = 0x00000001,
+ CLUSTER_CHANGE_NODE_DELETED = 0x00000002,
+ CLUSTER_CHANGE_NODE_ADDED = 0x00000004,
+ CLUSTER_CHANGE_NODE_PROPERTY = 0x00000008,
+ CLUSTER_CHANGE_REGISTRY_NAME = 0x00000010,
+ CLUSTER_CHANGE_REGISTRY_ATTRIBUTES = 0x00000020,
+ CLUSTER_CHANGE_REGISTRY_VALUE = 0x00000040,
+ CLUSTER_CHANGE_REGISTRY_SUBTREE = 0x00000080,
+ CLUSTER_CHANGE_RESOURCE_STATE = 0x00000100,
+ CLUSTER_CHANGE_RESOURCE_DELETED = 0x00000200,
+ CLUSTER_CHANGE_RESOURCE_ADDED = 0x00000400,
+ CLUSTER_CHANGE_RESOURCE_PROPERTY = 0x00000800,
+ CLUSTER_CHANGE_GROUP_STATE = 0x00001000,
+ CLUSTER_CHANGE_GROUP_DELETED = 0x00002000,
+ CLUSTER_CHANGE_GROUP_ADDED = 0x00004000,
+ CLUSTER_CHANGE_GROUP_PROPERTY = 0x00008000,
+ CLUSTER_CHANGE_RESOURCE_TYPE_DELETED = 0x00010000,
+ CLUSTER_CHANGE_RESOURCE_TYPE_ADDED = 0x00020000,
+ CLUSTER_CHANGE_RESOURCE_TYPE_PROPERTY = 0x00040000,
+ CLUSTER_CHANGE_CLUSTER_RECONNECT = 0x00080000,
+ CLUSTER_CHANGE_NETWORK_STATE = 0x00100000,
+ CLUSTER_CHANGE_NETWORK_DELETED = 0x00200000,
+ CLUSTER_CHANGE_NETWORK_ADDED = 0x00400000,
+ CLUSTER_CHANGE_NETWORK_PROPERTY = 0x00800000,
+ CLUSTER_CHANGE_NETINTERFACE_STATE = 0x01000000,
+ CLUSTER_CHANGE_NETINTERFACE_DELETED = 0x02000000,
+ CLUSTER_CHANGE_NETINTERFACE_ADDED = 0x04000000,
+ CLUSTER_CHANGE_NETINTERFACE_PROPERTY = 0x08000000,
+ CLUSTER_CHANGE_QUORUM_STATE = 0x10000000,
+ CLUSTER_CHANGE_CLUSTER_STATE = 0x20000000,
+ CLUSTER_CHANGE_CLUSTER_PROPERTY = 0x40000000,
+ CLUSTER_CHANGE_HANDLE_CLOSE = 0x80000000
+ } CLUSTER_CHANGE;
+
+ typedef enum {
+ CLUSREG_SET_VALUE = 1,
+ CLUSREG_CREATE_KEY = 2,
+ CLUSREG_DELETE_KEY = 3,
+ CLUSREG_DELETE_VALUE = 4,
+ CLUSREG_VALUE_DELETED = 6,
+ CLUSREG_READ_KEY = 7,
+ CLUSREG_READ_VALUE = 8,
+ CLUSREG_READ_ERROR = 9
+ } CLUSTER_REG_BATCH_COMMAND;
+#if 0
+ typedef enum {
+ IDL_CLUSTER_SET_PASSWORD_IGNORE_DOWN_NODES = 1
+ } IDL_CLUSTER_SET_PASSWORD_FLAGS;
+#endif
+ typedef enum {
+ CLUSTER_QUORUM_MAINTAINED = 0,
+ CLUSTER_QUORUM_LOST = 1
+ } CLUSTER_QUORUM_VALUE;
+
+ typedef enum {
+ CLUSTER_OBJECT_TYPE_CLUSTER = 0x00000001,
+ CLUSTER_OBJECT_TYPE_GROUP = 0x00000002,
+ CLUSTER_OBJECT_TYPE_RESOURCE = 0x00000003,
+ CLUSTER_OBJECT_TYPE_RESOURCE_TYPE = 0x00000004,
+ CLUSTER_OBJECT_TYPE_NETWORK_INTERFACE = 0x00000005,
+ CLUSTER_OBJECT_TYPE_NETWORK = 0x00000006,
+ CLUSTER_OBJECT_TYPE_NODE = 0x00000007,
+ CLUSTER_OBJECT_TYPE_REGISTRY = 0x00000008,
+ CLUSTER_OBJECT_TYPE_QUORUM = 0x00000009,
+ CLUSTER_OBJECT_TYPE_SHARED_VOLUME = 0x0000000a
+ } CLUSTER_OBJECT_TYPE;
+
+ typedef enum {
+ CLUSTER_CHANGE_CLUSTER_RECONNECT_V2 = 0x00000001,
+ CLUSTER_CHANGE_CLUSTER_STATE_V2 = 0x00000002,
+ CLUSTER_CHANGE_CLUSTER_GROUP_ADDED_V2 = 0x00000004,
+ CLUSTER_CHANGE_CLUSTER_HANDLE_CLOSE_V2 = 0x00000008,
+ CLUSTER_CHANGE_CLUSTER_NETWORK_ADDED_V2 = 0x00000010,
+ CLUSTER_CHANGE_CLUSTER_NODE_ADDED_V2 = 0x00000020,
+ CLUSTER_CHANGE_CLUSTER_RESOURCE_TYPE_ADDED_V2 = 0x00000040,
+ CLUSTER_CHANGE_CLUSTER_COMMON_PROPERTY_V2 = 0x00000080,
+ CLUSTER_CHANGE_CLUSTER_PRIVATE_PROPERTY_V2 = 0x00000100,
+ CLUSTER_CHANGE_CLUSTER_LOST_NOTIFICATIONS_V2 = 0x00000200,
+ CLUSTER_CHANGE_CLUSTER_RENAME_V2 = 0x00000400
+ } CLUSTER_CHANGE_CLUSTER_V2;
+
+ typedef enum {
+ CLUSTER_CHANGE_GROUP_DELETED_V2 = 0x00000001,
+ CLUSTER_CHANGE_GROUP_COMMON_PROPERTY_V2 = 0x00000002,
+ CLUSTER_CHANGE_GROUP_PRIVATE_PROPERTY_V2 = 0x00000004,
+ CLUSTER_CHANGE_GROUP_STATE_V2 = 0x00000008,
+ CLUSTER_CHANGE_GROUP_OWNER_NODE_V2 = 0x00000010,
+ CLUSTER_CHANGE_GROUP_PREFERRED_OWNERS_V2 = 0x00000020,
+ CLUSTER_CHANGE_GROUP_RESOURCE_ADDED_V2 = 0x00000040,
+ CLUSTER_CHANGE_GROUP_RESOURCE_GAINED_V2 = 0x00000080,
+ CLUSTER_CHANGE_GROUP_RESOURCE_LOST_V2 = 0x00000100,
+ CLUSTER_CHANGE_GROUP_HANDLE_CLOSE_V2 = 0x00000200
+ } CLUSTER_CHANGE_GROUP_V2;
+
+ typedef enum {
+ CLUSTER_CHANGE_RESOURCE_COMMON_PROPERTY_V2 = 0x00000001,
+ CLUSTER_CHANGE_RESOURCE_PRIVATE_PROPERTY_V2 = 0x00000002,
+ CLUSTER_CHANGE_RESOURCE_STATE_V2 = 0x00000004,
+ CLUSTER_CHANGE_RESOURCE_OWNER_GROUP_V2 = 0x00000008,
+ CLUSTER_CHANGE_RESOURCE_DEPENDENCIES_V2 = 0x00000010,
+ CLUSTER_CHANGE_RESOURCE_DEPENDENTS_V2 = 0x00000020,
+ CLUSTER_CHANGE_RESOURCE_POSSIBLE_OWNERS_V2 = 0x00000040,
+ CLUSTER_CHANGE_RESOURCE_DELETED_V2 = 0x00000080,
+ CLUSTER_CHANGE_RESOURCE_DLL_UPGRADED_V2 = 0x00000100,
+ CLUSTER_CHANGE_RESOURCE_HANDLE_CLOSE_V2 = 0x00000200
+ } CLUSTER_CHANGE_RESOURCE_V2;
+
+ typedef enum {
+ CLUSTER_CHANGE_RESOURCE_TYPE_DELETED_V2 = 0x00000001,
+ CLUSTER_CHANGE_RESOURCE_TYPE_COMMON_PROPERTY_V2 = 0x00000002,
+ CLUSTER_CHANGE_RESOURCE_TYPE_PRIVATE_PROPERTY_V2 = 0x00000004,
+ CLUSTER_CHANGE_RESOURCE_TYPE_POSSIBLE_OWNERS_V2 = 0x00000008,
+ CLUSTER_CHANGE_RESOURCE_TYPE_DLL_UPGRADED_V2 = 0x00000010
+ } CHANGE_RESOURCE_TYPE_V2;
+
+ typedef enum {
+ CLUSTER_CHANGE_NETINTERFACE_DELETED_V2 = 0x00000001,
+ CLUSTER_CHANGE_NETINTERFACE_COMMON_PROPERTY_V2 = 0x00000002,
+ CLUSTER_CHANGE_NETINTERFACE_PRIVATE_PROPERTY_V2 = 0x00000004,
+ CLUSTER_CHANGE_NETINTERFACE_STATE_V2 = 0x00000008,
+ CLUSTER_CHANGE_NETINTERFACE_HANDLE_CLOSE_V2 = 0x00000010
+ } CLUSTER_CHANGE_NETINTERFACE_V2;
+
+ typedef enum {
+ CLUSTER_CHANGE_NETWORK_DELETED_V2 = 0x00000001,
+ CLUSTER_CHANGE_NETWORK_COMMON_PROPERTY_V2 = 0x00000002,
+ CLUSTER_CHANGE_NETWORK_PRIVATE_PROPERTY_V2 = 0x00000004,
+ CLUSTER_CHANGE_NETWORK_STATE_V2 = 0x00000008,
+ CLUSTER_CHANGE_NETWORK_HANDLE_CLOSE_V2 = 0x00000010
+ } CLUSTER_CHANGE_NETWORK_V2;
+
+ typedef enum {
+ CLUSTER_CHANGE_NODE_NETINTERFACE_ADDED_V2 = 0x00000001,
+ CLUSTER_CHANGE_NODE_DELETED_V2 = 0x00000002,
+ CLUSTER_CHANGE_NODE_COMMON_PROPERTY_V2 = 0x00000004,
+ CLUSTER_CHANGE_NODE_PRIVATE_PROPERTY_V2 = 0x00000008,
+ CLUSTER_CHANGE_NODE_STATE_V2 = 0x00000010,
+ CLUSTER_CHANGE_NODE_GROUP_GAINED_V2 = 0x00000020,
+ CLUSTER_CHANGE_NODE_GROUP_LOST_V2 = 0x00000040,
+ CLUSTER_CHANGE_NODE_HANDLE_CLOSE_V2 = 0x00000080
+ } CLUSTER_CHANGE_NODE_V2;
+
+ typedef enum {
+ CLUSTER_CHANGE_REGISTRY_ATTRIBUTES_V2 = 0x00000001,
+ CLUSTER_CHANGE_REGISTRY_NAME_V2 = 0x00000002,
+ CLUSTER_CHANGE_REGISTRY_SUBTREE_V2 = 0x00000004,
+ CLUSTER_CHANGE_REGISTRY_VALUE_V2 = 0x00000008,
+ CLUSTER_CHANGE_REGISTRY_HANDLE_CLOSE_V2 = 0x00000010
+ } CLUSTER_CHANGE_REGISTRY_V2;
+
+ typedef enum {
+ CLUSTER_CHANGE_QUORUM_STATE_V2 = 0x00000001
+ } CLUSTER_CHANGE_QUORUM_V2;
+
+ typedef enum {
+ CLUSTER_CHANGE_SHARED_VOLUME_STATE_V2 = 0x00000001
+ } CLUSTER_CHANGE_SHARED_VOLUME_V2;
+#if 0
+ typedef enum {
+ DiskIdSignature = 0x00000001,
+ DiskIdGuid = 0x00000002,
+ DiskIdUnKnown = 0x00001388
+ } CLUSDSK_DISKID_ENUM;
+#endif
+
+ /*****************/
+ /* Function 0x94 */
+
+ WERROR
+ Opnum148NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x95 */
+
+ WERROR
+ Opnum149otUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x96 */
+
+ WERROR
+ Opnum150NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x97 */
+
+ WERROR
+ Opnum151NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x98 */
+
+ WERROR
+ Opnum152NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x99 */
+
+ WERROR
+ Opnum153NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x9A */
+
+ WERROR
+ Opnum154NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x9B */
+
+ WERROR
+ clusapi_AddNotifyResourceTypeV2(
+ [ in ] HNOTIFY_RPC hNotify,
+ [ in ] hyper filter,
+ [ in ] uint32 dwNotifyKey,
+ [ in, string ] [charset(UTF16)] uint16 *resTypeName,
+ [ in ] uint32 dwVersion,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x9C */
+
+ WERROR
+ Opnum156NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x9D */
+
+ WERROR
+ clusapi_ExecuteReadBatchEx(
+ [in] HKEY_RPC hKey,
+ [in] uint32 cbInData,
+ [in, size_is(cbInData)] uint8* lpInData,
+ [in] uint32 flags,
+ [out] uint32* cbOutData,
+ [out, size_is(,*cbOutData)] uint8** lpOutData,
+ [out] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0x9E */
+
+ WERROR
+ Opnum158NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x9F */
+
+ WERROR
+ Opnum159NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0xA0 */
+
+ WERROR
+ Opnum160NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0xA1 */
+
+ WERROR
+ Opnum161NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0xA2 */
+
+ WERROR
+ Opnum162NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0xA3 */
+
+#define HGROUPSET_RPC policy_handle
+#if 0
+ typedef [context_handle] void *HGROUPSET_RPC;
+#endif
+#if 0
+ HGROUPSET_RPC
+ clusapi_CreateGroupSet (
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupSetName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_CreateGroupSet (
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupSetName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HGROUPSET_RPC *hGroupSet
+ );
+#endif
+
+ /*****************/
+ /* Function 0xA4 */
+#if 0
+ HGROUPSET_RPC
+ clusapi_OpenGroupSet(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupSetName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status
+ );
+#else
+ void
+ clusapi_OpenGroupSet(
+ [ in, string ] [charset(UTF16)] uint16 *lpszGroupSetName,
+ [ out ] WERROR *Status,
+ [ out ] WERROR *rpc_status,
+ [ out ] HGROUPSET_RPC *hGroupSet
+ );
+#endif
+
+ /*****************/
+ /* Function 0xA5 */
+
+ WERROR
+ clusapi_CloseGroupSet(
+ [ in, out ] HGROUPSET_RPC *GroupSet
+ );
+
+ /*****************/
+ /* Function 0xA6 */
+
+ WERROR
+ clusapi_DeleteGroupSet(
+ [ in ] HGROUPSET_RPC GroupSet,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xA7 */
+
+ WERROR
+ clusapi_AddGroupToGroupSet(
+ [ in ] HGROUPSET_RPC GroupSet,
+ [ in ] HGROUP_RPC Group,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xA8 */
+
+ WERROR
+ clusapi_RemoveGroupFromGroupSet(
+ [ in ] HGROUP_RPC Group,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xA9 */
+
+ WERROR
+ clusapi_MoveGroupToGroupSet(
+ [ in ] HGROUPSET_RPC GroupSet,
+ [ in ] HGROUP_RPC Group,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xAA */
+
+ WERROR
+ Opnum170NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0xAB */
+
+ WERROR
+ clusapi_AddGroupSetDependency(
+ [ in ] HGROUPSET_RPC DependentGroupSet,
+ [ in ] HGROUPSET_RPC ProviderGroupSet,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xAC */
+
+ WERROR
+ clusapi_AddGroupToGroupSetDependency(
+ [ in ] HGROUP_RPC DependentGroup,
+ [ in ] HGROUPSET_RPC ProviderGroupSet,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xAD */
+
+ typedef [v1_enum] enum {
+ CLUSCTL_GROUPSET_GET_ID = 0x08000039,
+ CLUSCTL_GROUPSET_GET_RO_COMMON_PROPERTIES = 0x08000055,
+ CLUSCTL_GROUPSET_GET_COMMON_PROPERTIES = 0x08000059,
+ CLUSCTL_GROUPSET_GET_GROUPS = 0x08002D71,
+ CLUSCTL_GROUPSET_GET_PROVIDER_GROUPS = 0x08002D75,
+ CLUSCTL_GROUPSET_GET_PROVIDER_GROUPSETS = 0x08002D79,
+ CLUSCTL_GROUPSET_SET_COMMON_PROPERTIES = 0x0840005E
+ } clusapi_GroupSetControlCode;
+
+ WERROR
+ clusapi_NodeGroupSetControl(
+ [ in ] HGROUPSET_RPC hGroupSet,
+ [ in ] HNODE_RPC hNode,
+ [ in ] clusapi_GroupSetControlCode dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize), length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in, range(0, MAX_CLUSTER_CONTROL_CODE_BUFFER_SIZE)] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xAE */
+
+ WERROR
+ clusapi_GroupSetControl(
+ [ in ] HGROUPSET_RPC hGroupSet,
+ [ in ] clusapi_GroupSetControlCode dwControlCode,
+ [ in, unique, size_is(nInBufferSize) ] uint8 *lpInBuffer,
+ [ in ] uint32 nInBufferSize,
+ [ out, size_is(nOutBufferSize), length_is (*lpBytesReturned)] uint8 *lpOutBuffer,
+ [ in, range(0, 0x7FFFFFFF)] uint32 nOutBufferSize,
+ [ out ] uint32 *lpBytesReturned,
+ [ out ] uint32 *lpcbRequired,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xAF */
+
+ WERROR
+ clusapi_SetGroupDependencyExpression(
+ [ in ] HGROUP_RPC hGroup,
+ [ in, string ] [charset(UTF16)] uint16 *lpszDependencyExpression,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xB0 */
+
+ WERROR
+ clusapi_RemoveClusterGroupDependency(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] HGROUP_RPC hDependsOn,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xB1 */
+
+ WERROR
+ clusapi_SetGroupSetDependencyExpression(
+ [ in ] HGROUPSET_RPC hGroupSet,
+ [ in, string ] [charset(UTF16)] uint16 *lpszDependencyExpression,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xB2 */
+
+ WERROR
+ clusapi_RemoveGroupSetDependency(
+ [ in ] HGROUPSET_RPC hGroupSet,
+ [ in ] HGROUPSET_RPC hDependsOn,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xB3 */
+
+ WERROR
+ clusapi_RemoveClusterGroupToGroupSetDependency(
+ [ in ] HGROUP_RPC hGroup,
+ [ in ] HGROUPSET_RPC hDependsOn,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xB4 */
+
+ WERROR
+ clusapi_CreateGroupSetEnum(
+ [ in ] HCLUSTER_RPC hCluster,
+ [ out ] ENUM_LIST **ReturnEnum,
+ [ out ] WERROR * rpc_status
+ );
+
+ /*****************/
+ /* Function 0xB5 */
+
+ WERROR
+ clusapi_CreateNetInterfaceEnum(
+ [in] HCLUSTER_RPC hCluster,
+ [in, string] [charset(UTF16)] uint16 *lpszNodeName,
+ [in, string] [charset(UTF16)] uint16 *lpszNetworkName,
+ [out] ENUM_LIST **ReturnEnum,
+ [out] WERROR * rpc_status
+ );
+
+ /*****************/
+ /* Function 0xB6 */
+
+ WERROR
+ clusapi_ChangeCsvStateEx(
+ [ in ] HRES_RPC hResource,
+ [ in ] uint32 dwState,
+ [ in, string ] [charset(UTF16)] uint16 *lpszVolumeName,
+ [ out ] WERROR *rpc_status
+ );
+
+ /*****************/
+ /* Function 0xB7 */
+
+ WERROR
+ clusapi_AddGroupToGroupSetEx(
+ [ in ] HGROUPSET_RPC GroupSet,
+ [ in ] HGROUP_RPC Group,
+ [ in ] uint32 FaultDomain,
+ [ in ] uint32 UpdateDomain,
+ [ in ] boolean8 UseDomains,
+ [ in ] uint32 *Reserved,
+ [ out ] WERROR *rpc_status
+ );
+}
diff --git a/librpc/idl/conditional_ace.idl b/librpc/idl/conditional_ace.idl
new file mode 100644
index 0000000..8db0ed6
--- /dev/null
+++ b/librpc/idl/conditional_ace.idl
@@ -0,0 +1,458 @@
+#include "idl_types.h"
+
+/*
+ IDL structures and constants for conditional aces.
+*/
+
+import "security.idl";
+
+interface conditional_ace
+{
+ /*
+ * Conditional ACEs have an expression at the end of the ACE.
+ * We know it is there because the ACE type has CALLBACK in
+ * its name, and we know how long it is because the size field
+ * in the ACE points somewhere beyond the otherwise accounted
+ * for objects:
+ *
+ * | type | flags | size | access_mask | trustee | |
+ * `---------------------------------->|
+ *
+ * If the first 4 bytes of the extra bit (called "coda" in our
+ * structs) are {'a', 'r', 't', 'x'}, the callback ACE is a
+ * conditional ACE. On Windows it is possible to register
+ * other kinds of callback ACEs with different magic strings
+ * that get handled by callback functions. There is little
+ * evidence of this ever happening, but that explains the
+ * name.
+ *
+ * After the "artx", a conditional ACE consists of a series of
+ * tokens that describe an expression tree in reverse Polish
+ * order. The expression can work with claim and SID values
+ * from the security token, comparing them to each other and
+ * to literal values. [MS-DTYP] is reasonably clear about how
+ * they work.
+ */
+
+ /*
+ * Token types from [MS-DTYP] 2.4.4.17 "Conditional ACEs".
+ */
+ typedef [enum8bit] enum {
+ /*
+ * Microsoft counts padding zeroes as a kind of token.
+ * There should be up to three of these at the end, to
+ * round out the size to a multiple of four.
+ */
+ CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING = 0x00,
+
+ /* Literal tokens
+ * ==============
+ *
+ * Literal integers. These are *all* stored using 10
+ * bytes:
+ *
+ * - 8 bytes for the value, limited to the correct range
+ * (e.g. -128 to 127 for INT8)
+ * - 1 byte for sign, probably just used for display
+ * - 1 byte for base, just used for display
+ *
+ * SDDL integers are all stored using 64 bits, but
+ * different token types can be used to pretend they
+ * have smaller width. In comparisons (which is all
+ * they can be used for) the type does not matter. The
+ * only special thing a non-64 bit literal can do is
+ * to cause a parsing error by being out of range (it
+ * is an open question as to how you would end up with
+ * short integers, let alone invalid ones, as the SDDL
+ * syntax does not have a way of specifying them).
+ */
+ CONDITIONAL_ACE_TOKEN_INT8 = 0x01,
+ CONDITIONAL_ACE_TOKEN_INT16 = 0x02,
+ CONDITIONAL_ACE_TOKEN_INT32 = 0x03,
+ CONDITIONAL_ACE_TOKEN_INT64 = 0x04,
+
+ /*
+ * Literal strings and structured types.
+ *
+ * These have an unsigned 32 bit byte length, followed
+ * by data.
+ *
+ * for unicode the data is UTF-16.
+ * octet strings are bytes.
+ * the composite type is a list type.
+ * the sid type has an ordinary binary sid after the length.
+ */
+ CONDITIONAL_ACE_TOKEN_UNICODE = 0x10,
+ CONDITIONAL_ACE_TOKEN_OCTET_STRING = 0x18,
+ CONDITIONAL_ACE_TOKEN_COMPOSITE = 0x50,
+ CONDITIONAL_ACE_TOKEN_SID = 0x51,
+
+ CONDITIONAL_ACE_LOCAL_ATTRIBUTE = 0xf8,
+ CONDITIONAL_ACE_USER_ATTRIBUTE = 0xf9,
+ CONDITIONAL_ACE_RESOURCE_ATTRIBUTE = 0xfa,
+ CONDITIONAL_ACE_DEVICE_ATTRIBUTE = 0xfb,
+
+ /*
+ * Unary relational operator tokens
+ * ================================
+ *
+ * For the membership ops, the operand can be a single
+ * SID or a composite list of SIDs.
+ *
+ * Member_Of: true if the security token user SIDs
+ * array contains all of the SIDs in the operand.
+ */
+ CONDITIONAL_ACE_TOKEN_MEMBER_OF = 0x89,
+ /*
+ * Device_Member_Of: true if the security token device
+ * SIDs array contains all of the SIDs in the operand.
+ */
+ CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF = 0x8a,
+ /*
+ * Member_Of_Any: true if the user SIDs array contains any of
+ * the SIDs in the operand.
+ */
+ CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY = 0x8b,
+ /*
+ * Device_Member_Of_Any: true if the device SIDs array
+ * contains any of the SIDs in the operand.
+ */
+ CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY = 0x8c,
+
+ /*
+ * Logical inverses of the member-of crew.
+ */
+ CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF = 0x90,
+ CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF = 0x91,
+ CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY = 0x92,
+ CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY = 0x93,
+
+ /*
+ * Binary relational operators
+ * ===========================
+ *
+ * The left hand side argument (LHS) is an attribute.
+ * The RHS is an attribute or a value or composite
+ * list of values (depending on the operation).
+ *
+ * If the types mismatch, the result is UNKNOWN.
+ */
+ CONDITIONAL_ACE_TOKEN_EQUAL = 0x80, /* == */
+ CONDITIONAL_ACE_TOKEN_NOT_EQUAL = 0x81, /* != */
+ CONDITIONAL_ACE_TOKEN_LESS_THAN = 0x82, /* < */
+ CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL = 0x83, /* <= */
+ CONDITIONAL_ACE_TOKEN_GREATER_THAN = 0x84, /* > */
+ CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL = 0x85, /* >= */
+
+ /*
+ * "contains" implies "all of", in contrast to the "any of"
+ * operators.
+ */
+ CONDITIONAL_ACE_TOKEN_CONTAINS = 0x86,
+ CONDITIONAL_ACE_TOKEN_ANY_OF = 0x88,
+ CONDITIONAL_ACE_TOKEN_NOT_CONTAINS = 0x8e,
+ CONDITIONAL_ACE_TOKEN_NOT_ANY_OF = 0x8f,
+
+ /*
+ * Unary logical operators
+ * =======================
+ *
+ * The operand for the existence operators must be a
+ * local attribute or a resource attribute.
+ */
+ CONDITIONAL_ACE_TOKEN_EXISTS = 0x87, /* Exists */
+ CONDITIONAL_ACE_TOKEN_NOT_EXISTS = 0x8d, /* Not_Exists */
+ /* NOT operator */
+ CONDITIONAL_ACE_TOKEN_NOT = 0xa2, /* ! */
+
+ /*
+ * Binary logical operators
+ * ========================
+ */
+ CONDITIONAL_ACE_TOKEN_AND = 0xa0, /* && */
+ CONDITIONAL_ACE_TOKEN_OR = 0xa1, /* || */
+
+ /*
+ * Samba specific pseudo-tokens
+ * ============================
+ *
+ * In running the conditional ace we maintain a stack
+ * that is used as operands to the operators. Some of
+ * the values on the stack are literals found inline
+ * in the data, some are primitives resulting from
+ * attribute look-up operations, and some are logical
+ * results from comparison operations, which are in
+ * the ternary form just mentioned. [MS-DTYP]
+ * describes no token form for these ternary values,
+ * as they are not used on the wire (that is, you
+ * can't have a literal 'true' in a conditional ace).
+ * So we add a token representation for Boolean result
+ * types to use on the stack, using an available
+ * opcode. The result of a lookup can also be 'NULL',
+ * or an error, and we have opcodes for those too.
+ *
+ * These token types raise an error if they show up in
+ * a conditional ACE, just like any other unknown
+ * token type. They are for internal use only.
+ *
+ * In [MS-DTYP] these are called "Result Value".
+ */
+
+ CONDITIONAL_ACE_SAMBA_RESULT_BOOL = 0x0f,
+ CONDITIONAL_ACE_SAMBA_RESULT_NULL = 0x0e,
+ CONDITIONAL_ACE_SAMBA_RESULT_ERROR = 0x0d,
+
+ /*
+ * Samba specific parentheses pseudo-tokens
+ * ========================================
+ *
+ * These are useful for compiling SDDL, but will never show
+ * up in the compiled ACE or during evaluation.
+ */
+ CONDITIONAL_ACE_SAMBA_SDDL_PAREN = 0x09,
+ CONDITIONAL_ACE_SAMBA_SDDL_PAREN_END = 0x08
+ } token_type;
+
+ /*
+ * Integer attributes.
+ * ==================
+ *
+ * Integers are stored with a base indicator and a sign
+ * indicator.
+ *
+ * Integer base is stored for display purposes. For example,
+ * the number 17 will be shown as "021" with option 1, "17"
+ * with 2, and "0x11" with 3. Comparisons are not affected.
+ */
+ typedef [enum8bit] enum {
+ CONDITIONAL_ACE_INT_BASE_8 = 0x01,
+ CONDITIONAL_ACE_INT_BASE_10 = 0x02,
+ CONDITIONAL_ACE_INT_BASE_16 = 0x03
+ } int_base;
+
+ /*
+ * Integer sign, mostly for display purposes[1]. It seems
+ * negative numbers should be flagged here as negative (i.e.
+ * with 2), while positive numbers should be flagged with
+ * "none" (3), unless you want them to show up with a plus
+ * sign in SDDL.
+ *
+ * [1] it is possible this has some real significance, perhaps
+ * acting as an unsigned flag. TO BE DETERMINED.
+ */
+ typedef [enum8bit] enum {
+ CONDITIONAL_ACE_INT_SIGN_POSITIVE = 0x01,
+ CONDITIONAL_ACE_INT_SIGN_NEGATIVE = 0x02,
+ CONDITIONAL_ACE_INT_SIGN_NONE = 0x03
+ } int_sign;
+
+ /*
+ * Ternary logical values
+ *
+ * Conditional ACEs use a ternary logic where values can be
+ * unknown as well as true or false.
+ *
+ * The "Bool" result token can take any of these three values.
+ * There is no literal Boolean value, but an integer of value
+ * 0 or 1 can be compared with a Boolean result.
+ */
+ typedef enum {
+ ACE_CONDITION_FALSE = 0,
+ ACE_CONDITION_TRUE = 1,
+ ACE_CONDITION_UNKNOWN = -1
+ } ternary_logic_value;
+ /*
+ * Sub-structures for struct ace_condition_token -> data,
+ * which vary according to the token->type.
+ */
+ typedef [flag(NDR_NOALIGN)] struct {
+ int64 value;
+ } ace_condition_result;
+
+ typedef [public] struct {
+ int64 value;
+ uint8 sign;
+ uint8 base;
+ } ace_condition_int;
+
+ typedef [public] struct {
+ /*
+ * Zeroes are not allowed in the binary format (which
+ * is otherwise UTF-16), and if we did let them
+ * through we would end up with a truncated string.
+ */
+ [flag(STR_SIZE4|STR_NOTERM|STR_BYTESIZE|STR_NO_EMBEDDED_NUL)] string value;
+ } ace_condition_unicode;
+
+ typedef [public] struct {
+ [subcontext(4)] dom_sid sid;
+ } ace_condition_sid;
+
+ /*
+ * The composite type has an array of sub-tokens, which can
+ * themselves be composites containing composites, though this
+ * is unlikely to be useful when dealing with claims.
+ *
+ * This structure is not representative of the wire format.
+ */
+ typedef struct {
+ ace_condition_token *tokens;
+ uint32 n_members;
+ } ace_condition_composite;
+
+ /*
+ * Operators have no data, but it is sometimes helpful for
+ * SDDL compilation messages to record the position in the
+ * string.
+ */
+ typedef struct {
+ uint32 sddl_position;
+ } ace_condition_op;
+
+ /*
+ * struct ace_condition_sddl_op is not as real token, but is
+ * used in compiling sddl. The idea is, for example, that if
+ * popping with a ')' doesn't match the right '(', the details
+ * of the '(' are there for the error message.
+ */
+ typedef struct {
+ uint32 start;
+ uint32 position;
+ } ace_condition_sddl_op;
+
+
+ typedef [nodiscriminant] union {
+ [case(CONDITIONAL_ACE_TOKEN_SID)] ace_condition_sid sid;
+ [case(CONDITIONAL_ACE_TOKEN_COMPOSITE)]ace_condition_composite composite;
+ [case(CONDITIONAL_ACE_TOKEN_OCTET_STRING)] DATA_BLOB bytes;
+ [case(CONDITIONAL_ACE_TOKEN_UNICODE)]ace_condition_unicode unicode;
+
+ [case(CONDITIONAL_ACE_LOCAL_ATTRIBUTE)]ace_condition_unicode local_attr;
+ [case(CONDITIONAL_ACE_USER_ATTRIBUTE)]ace_condition_unicode user_attr;
+ [case(CONDITIONAL_ACE_DEVICE_ATTRIBUTE)]ace_condition_unicode device_attr;
+ [case(CONDITIONAL_ACE_RESOURCE_ATTRIBUTE)]ace_condition_unicode resource_attr;
+
+ [case(CONDITIONAL_ACE_TOKEN_INT64)]ace_condition_int int64;
+ [case(CONDITIONAL_ACE_TOKEN_INT32)]ace_condition_int int32;
+ [case(CONDITIONAL_ACE_TOKEN_INT16)]ace_condition_int int16;
+ [case(CONDITIONAL_ACE_TOKEN_INT8)]ace_condition_int int8;
+ [case(CONDITIONAL_ACE_SAMBA_SDDL_PAREN)]ace_condition_sddl_op sddl_op;
+
+ [case(CONDITIONAL_ACE_SAMBA_RESULT_BOOL)]ace_condition_result result;
+ /* NULL and Error results are empty */
+ [case(CONDITIONAL_ACE_SAMBA_RESULT_NULL)]ace_condition_result result_null;
+ [case(CONDITIONAL_ACE_SAMBA_RESULT_ERROR)]ace_condition_result result_error;
+
+ /* operations */
+ [case(CONDITIONAL_ACE_TOKEN_MEMBER_OF)]ace_condition_op member_of;
+ [case(CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF)]ace_condition_op device_member_of;
+ [case(CONDITIONAL_ACE_TOKEN_MEMBER_OF_ANY)]ace_condition_op member_of_any;
+ [case(CONDITIONAL_ACE_TOKEN_DEVICE_MEMBER_OF_ANY)]ace_condition_op device_member_of_any;
+ [case(CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF)]ace_condition_op not_member_of;
+ [case(CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF)]ace_condition_op not_device_member_of;
+ [case(CONDITIONAL_ACE_TOKEN_NOT_MEMBER_OF_ANY)]ace_condition_op not_member_of_any;
+ [case(CONDITIONAL_ACE_TOKEN_NOT_DEVICE_MEMBER_OF_ANY)]ace_condition_op not_device_member_of_any;
+ [case(CONDITIONAL_ACE_TOKEN_EQUAL)]ace_condition_op equal;
+ [case(CONDITIONAL_ACE_TOKEN_NOT_EQUAL)]ace_condition_op not_equal;
+ [case(CONDITIONAL_ACE_TOKEN_LESS_THAN)]ace_condition_op less_than;
+ [case(CONDITIONAL_ACE_TOKEN_LESS_OR_EQUAL)]ace_condition_op less_or_equal;
+ [case(CONDITIONAL_ACE_TOKEN_GREATER_THAN)]ace_condition_op greater_than;
+ [case(CONDITIONAL_ACE_TOKEN_GREATER_OR_EQUAL)]ace_condition_op greater_or_equal;
+ [case(CONDITIONAL_ACE_TOKEN_CONTAINS)]ace_condition_op contains;
+ [case(CONDITIONAL_ACE_TOKEN_ANY_OF)]ace_condition_op any_of;
+ [case(CONDITIONAL_ACE_TOKEN_NOT_CONTAINS)]ace_condition_op not_contains;
+ [case(CONDITIONAL_ACE_TOKEN_NOT_ANY_OF)]ace_condition_op not_any_of;
+ [case(CONDITIONAL_ACE_TOKEN_AND)]ace_condition_op and;
+ [case(CONDITIONAL_ACE_TOKEN_OR)]ace_condition_op or;
+ [case(CONDITIONAL_ACE_TOKEN_NOT)]ace_condition_op not;
+ [case(CONDITIONAL_ACE_TOKEN_EXISTS)]ace_condition_op exists;
+ [case(CONDITIONAL_ACE_TOKEN_NOT_EXISTS)]ace_condition_op not_exists;
+
+ [default] ace_condition_op op;
+ } ace_condition_token_data;
+
+ /*
+ * struct ace_condition_token is the fundamental building
+ * block of a conditional ACE expression.
+ */
+ typedef [public] struct {
+ [switch_is(type)] ace_condition_token_data data;
+ uint32 flags;
+ token_type type;
+ } ace_condition_token;
+
+ /*
+ * The expression as a whole is an just an array of tokens.
+ *
+ * But because we are always going to need a stack for
+ * evaluating the expression, we allocate that and keep it
+ * handy.
+ */
+ typedef [public] struct {
+ ace_condition_token *tokens;
+ ace_condition_token *stack;
+ uint32 length;
+ } ace_condition_script;
+
+ typedef enum {
+ ACE_CONDITION_FLAG_ALLOW_DEVICE = 0x01
+ } ace_condition_flags;
+
+ /*
+ * Flags for ace_condition_token.flags field.
+ *
+ * The following flags from security claims are used:
+ *
+ * CLAIM_SECURITY_ATTRIBUTE_NON_INHERITABLE = 1
+ * CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE = 2
+ *
+ * CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED = 1 << 30
+ *
+ * The first two of these are used on the wire in
+ * CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 structures, while the
+ * latter is in an application specific range that is not
+ * seen on the wire. It is used to indicate that a composite
+ * token contains no duplicate values, which is supposed to
+ * be true for composite values from claims (including from
+ * resource attribute ACEs), but not literal composites. It's
+ * expensive to check, so this flag helps us avoid extra work
+ * can avoid doing it over and over if we remember.
+ *
+ *
+ * CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR is set when a token
+ * value on the stack is set from an attribute lookup.
+ *
+ * This is necessary because for binary relational operators
+ * (MS-DTYP 2.4.4.17.6), the left-hand argument must be an
+ * attribute lookup, but by the time we have come to the
+ * operator that argument has been resolved into an ordinary
+ * token. So we set the flag so the operator can know.
+ */
+ const uint32 CONDITIONAL_ACE_FLAG_TOKEN_FROM_ATTR = UINT32_C(1) << 31;
+
+ /*
+ * The maximum size of the conditional ACE conditions in the
+ * binary form. There is an absolute limit of slightly less
+ * than 64k, as the security descriptor, the ACL, and the ace
+ * all have 16 bit length fields, and each adds some overhead.
+ *
+ * In practice, a couple of hundred bytes would do, and people
+ * making extremely large conditional expressions probably
+ * don't have good intentions.
+ */
+ const int CONDITIONAL_ACE_MAX_LENGTH = 10000;
+ /*
+ * CONDITIONAL_ACE_MAX_TOKENS is another arbitrarily chosen
+ * number used to allocate token arrays and stacks.
+ *
+ * The relationship between the number of tokens and the byte
+ * length is variable, depending on the nature of the
+ * conditions. An operator token takes up one byte in the
+ * binary format (which CONDITIONAL_ACE_MAX_LENGTH above
+ * measures), an integer 10 bytes, and attributes and strings
+ * at least two bytes per character plus four for the length.
+ * SIDs are stored as struct dom_sid, around sixty-eight
+ * bytes, plus a four byte length field.
+ */
+ const int CONDITIONAL_ACE_MAX_TOKENS = 2000;
+}
diff --git a/librpc/idl/dbgidl.idl b/librpc/idl/dbgidl.idl
new file mode 100644
index 0000000..0712392
--- /dev/null
+++ b/librpc/idl/dbgidl.idl
@@ -0,0 +1,9 @@
+[
+ uuid("1d55b526-c137-46c5-ab79-638f2a68e869"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Remote IDL debugger")
+] interface dbgidl
+{
+ void dummy_dbgidl();
+}
diff --git a/librpc/idl/dcerpc.idl b/librpc/idl/dcerpc.idl
new file mode 100644
index 0000000..414b896
--- /dev/null
+++ b/librpc/idl/dcerpc.idl
@@ -0,0 +1,662 @@
+#include "idl_types.h"
+
+/*
+ the base dcerpc packet definitions - not traditionally coded as IDL,
+ but given that pidl can handle it nicely it simplifies things a lot
+ to do it this way
+
+ See [C706 - DCE 1.1: Remote Procedure Call] for the OpenGroup
+ DCERPC specification:
+ http://pubs.opengroup.org/onlinepubs/9629399/toc.htm
+
+ See C706 - Chapter 12: RPC PDU Encodings for packet layouts:
+ http://www.opengroup.org/onlinepubs/9629399/chap12.htm
+
+ See also [MS-RPCE] for the Microsoft
+ "Remote Procedure Call Protocol Extensions".
+ http://msdn.microsoft.com/en-us/library/cc243560.aspx
+
+*/
+import "misc.idl";
+
+cpp_quote("extern const uint8_t DCERPC_SEC_VT_MAGIC[8];")
+
+[
+ helper("../librpc/ndr/ndr_dcerpc.h")
+]
+interface dcerpc
+{
+ typedef struct {
+ uint16 context_id;
+ uint8 num_transfer_syntaxes;
+ ndr_syntax_id abstract_syntax;
+ ndr_syntax_id transfer_syntaxes[num_transfer_syntaxes];
+ } dcerpc_ctx_list;
+
+ typedef [public] struct {
+ uint16 max_xmit_frag;
+ uint16 max_recv_frag;
+ uint32 assoc_group_id;
+ uint8 num_contexts;
+ dcerpc_ctx_list ctx_list[num_contexts];
+ [flag(NDR_REMAINING)] DATA_BLOB auth_info;
+ } dcerpc_bind;
+
+ const uint8 DCERPC_REQUEST_LENGTH = 24;
+
+ typedef struct {
+ } dcerpc_empty;
+
+ typedef [nodiscriminant] union {
+ [default] GUID object;
+ [case(false)] dcerpc_empty empty;
+ } dcerpc_object;
+
+ typedef struct {
+ uint32 alloc_hint;
+ uint16 context_id;
+ uint16 opnum;
+ /*
+ * NDR_DCERPC_REQUEST_OBJECT_PRESENT
+ * is defined differently for ndr_dcerpc.c and py_dcerpc.c
+ */
+ [switch_is(NDR_DCERPC_REQUEST_OBJECT_PRESENT)] dcerpc_object object;
+ [flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier;
+ } dcerpc_request;
+
+ typedef [enum16bit] enum {
+ DCERPC_BIND_ACK_RESULT_ACCEPTANCE = 0,
+ DCERPC_BIND_ACK_RESULT_USER_REJECTION = 1,
+ DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION = 2,
+ DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK = 3
+ } dcerpc_bind_ack_result;
+
+ const int DCERPC_BIND_PROVIDER_REJECT =
+ DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION;
+
+ typedef [enum16bit] enum {
+ DCERPC_BIND_ACK_REASON_NOT_SPECIFIED = 0,
+ DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED = 1,
+ DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED = 2,
+ DCERPC_BIND_ACK_REASON_LOCAL_LIMIT_EXCEEDED = 3
+ } dcerpc_bind_ack_reason_values;
+
+ const int DCERPC_BIND_REASON_ASYNTAX =
+ DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
+
+ typedef [bitmap16bit] bitmap {
+ DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING = 0x0001,
+ DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN = 0x0002
+ } dcerpc_bind_time_features;
+
+ typedef [nodiscriminant] union {
+ [case(DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK)]
+ dcerpc_bind_time_features negotiate;
+ [default] dcerpc_bind_ack_reason_values value;
+ } dcerpc_bind_ack_reason;
+
+ typedef struct {
+ dcerpc_bind_ack_result result;
+ [switch_is(result)] dcerpc_bind_ack_reason reason;
+ ndr_syntax_id syntax;
+ } dcerpc_ack_ctx;
+
+ typedef struct {
+ uint16 max_xmit_frag;
+ uint16 max_recv_frag;
+ uint32 assoc_group_id;
+ [value(strlen_m_term_null(secondary_address))] uint16 secondary_address_size;
+ [charset(DOS)] uint8 secondary_address[secondary_address_size];
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad1;
+ uint8 num_results;
+ dcerpc_ack_ctx ctx_list[num_results];
+ [flag(NDR_REMAINING)] DATA_BLOB auth_info;
+ } dcerpc_bind_ack;
+
+ typedef [public,enum16bit] enum {
+ DCERPC_BIND_NAK_REASON_NOT_SPECIFIED = 0,
+ DCERPC_BIND_NAK_REASON_TEMPORARY_CONGESTION = 1,
+ DCERPC_BIND_NAK_REASON_LOCAL_LIMIT_EXCEEDED = 2,
+ DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED = 4,
+ DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE = 8,
+ DCERPC_BIND_NAK_REASON_INVALID_CHECKSUM = 9
+ } dcerpc_bind_nak_reason;
+
+ const int DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED =
+ DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED;
+ const int DCERPC_BIND_REASON_INVALID_AUTH_TYPE =
+ DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE;
+
+ typedef [public] struct {
+ uint8 rpc_vers; /* RPC version */
+ uint8 rpc_vers_minor; /* Minor version */
+ } dcerpc_bind_nak_version;
+
+ typedef [public,nopull] struct {
+ dcerpc_bind_nak_reason reject_reason;
+ uint8 num_versions;
+ dcerpc_bind_nak_version versions[num_versions];
+ [flag(NDR_REMAINING)] DATA_BLOB _pad;
+ } dcerpc_bind_nak;
+
+ const uint8 DCERPC_RESPONSE_LENGTH = 24;
+
+ typedef struct {
+ uint32 alloc_hint;
+ uint16 context_id;
+ uint8 cancel_count;
+ [value(0)] uint8 reserved;
+ [flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier;
+ } dcerpc_response;
+
+ typedef [v1_enum] enum {
+ DCERPC_NCA_S_COMM_FAILURE = 0x1C010001,
+ DCERPC_NCA_S_OP_RNG_ERROR = 0x1C010002,
+ DCERPC_NCA_S_UNKNOWN_IF = 0x1C010003,
+ DCERPC_NCA_S_WRONG_BOOT_TIME = 0x1C010006,
+ DCERPC_NCA_S_YOU_CRASHED = 0x1C010009,
+ DCERPC_NCA_S_PROTO_ERROR = 0x1C01000B,
+ DCERPC_NCA_S_OUT_ARGS_TOO_BIG = 0x1C010013,
+ DCERPC_NCA_S_SERVER_TOO_BUSY = 0x1C010014,
+ DCERPC_NCA_S_FAULT_STRING_TOO_LARGE = 0x1C010015,
+ DCERPC_NCA_S_UNSUPPORTED_TYPE = 0x1C010017,
+ DCERPC_NCA_S_FAULT_INT_DIV_BY_ZERO = 0x1C000001,
+ DCERPC_NCA_S_FAULT_ADDR_ERROR = 0x1C000002,
+ DCERPC_NCA_S_FAULT_FP_DIV_BY_ZERO = 0x1C000003,
+ DCERPC_NCA_S_FAULT_FP_UNDERFLOW = 0x1C000004,
+ DCERPC_NCA_S_FAULT_FP_OVERRFLOW = 0x1C000005,
+ DCERPC_NCA_S_FAULT_INVALID_TAG = 0x1C000006,
+ DCERPC_NCA_S_FAULT_INVALID_BOUND = 0x1C000007,
+ DCERPC_NCA_S_FAULT_RPC_VERSION_MISMATCH = 0x1C000008,
+ DCERPC_NCA_S_FAULT_UNSPEC_REJECT = 0x1C000009,
+ DCERPC_NCA_S_FAULT_BAD_ACTID = 0x1C00000A,
+ DCERPC_NCA_S_FAULT_WHO_ARE_YOU_FAILED = 0x1C00000B,
+ DCERPC_NCA_S_FAULT_MANAGER_NOT_ENTERED = 0x1C00000C,
+ DCERPC_NCA_S_FAULT_CANCEL = 0x1C00000D,
+ DCERPC_NCA_S_FAULT_ILL_INST = 0x1C00000E,
+ DCERPC_NCA_S_FAULT_FP_ERROR = 0x1C00000F,
+ DCERPC_NCA_S_FAULT_INT_OVERFLOW = 0x1C000010,
+ DCERPC_NCA_S_UNUSED_1C000011 = 0x1C000011,
+ DCERPC_NCA_S_FAULT_UNSPEC = 0x1C000012,
+ DCERPC_NCA_S_FAULT_REMOTE_COMM_FAILURE = 0x1C000013,
+ DCERPC_NCA_S_FAULT_PIPE_EMPTY = 0x1C000014,
+ DCERPC_NCA_S_FAULT_PIPE_CLOSED = 0x1C000015,
+ DCERPC_NCA_S_FAULT_PIPE_ORDER = 0x1C000016,
+ DCERPC_NCA_S_FAULT_PIPE_DISCIPLINE = 0x1C000017,
+ DCERPC_NCA_S_FAULT_PIPE_COMM_ERROR = 0x1C000018,
+ DCERPC_NCA_S_FAULT_PIPE_MEMORY = 0x1C000019,
+ DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH = 0x1C00001A,
+ DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY = 0x1C00001B,
+ DCERPC_NCA_S_INVALID_PRES_CONTEXT_ID = 0x1C00001C,
+ DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL = 0x1C00001D,
+ DCERPC_NCA_S_UNUSED_1C00001E = 0x1C00001E,
+ DCERPC_NCA_S_INVALID_CHECKSUM = 0x1C00001F,
+ DCERPC_NCA_S_INVALID_CRC = 0x1C000020,
+ DCERPC_NCA_S_FAULT_USER_DEFINED = 0x1C000021,
+ DCERPC_NCA_S_FAULT_TX_OPEN_FAILED = 0x1C000022,
+ DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR = 0x1C000023,
+ DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND = 0x1C000024,
+ DCERPC_NCA_S_FAULT_NO_CLIENT_STUB = 0x1C000025,
+ DCERPC_FAULT_ACCESS_DENIED = 0x00000005,
+ DCERPC_FAULT_SERVER_UNAVAILABLE = 0x000006ba,
+ DCERPC_FAULT_NO_CALL_ACTIVE = 0x000006bd,
+ DCERPC_FAULT_CANT_PERFORM = 0x000006d8,
+ DCERPC_FAULT_OUT_OF_RESOURCES = 0x000006d9,
+ DCERPC_FAULT_BAD_STUB_DATA = 0x000006f7,
+ DCERPC_FAULT_SEC_PKG_ERROR = 0x00000721
+ } dcerpc_nca_status;
+
+ const int DCERPC_FAULT_OP_RNG_ERROR = DCERPC_NCA_S_OP_RNG_ERROR;
+ const int DCERPC_FAULT_NDR = DCERPC_FAULT_BAD_STUB_DATA;
+ const int DCERPC_FAULT_INVALID_TAG = DCERPC_NCA_S_FAULT_INVALID_TAG;
+ const int DCERPC_FAULT_CONTEXT_MISMATCH = DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH;
+ const int DCERPC_FAULT_OTHER = 0x00000001;
+
+ /* we return this fault when we haven't yet run the test
+ to see what fault w2k3 returns in this case */
+ const int DCERPC_FAULT_TODO = 0x00000042;
+
+ typedef [bitmap8bit] bitmap {
+ DCERPC_FAULT_FLAG_EXTENDED_ERROR_INFORMATION = 0x01
+ } dcerpc_fault_flags;
+
+ typedef struct {
+ uint32 alloc_hint;
+ uint16 context_id;
+ uint8 cancel_count;
+ dcerpc_fault_flags flags;
+ dcerpc_nca_status status;
+ [value(0)] uint32 reserved;
+ [flag(NDR_REMAINING)] DATA_BLOB error_and_verifier;
+ } dcerpc_fault;
+
+ const uint8 DCERPC_FAULT_LENGTH = 32;
+
+ /* the auth types we know about */
+ typedef [enum8bit] enum {
+ DCERPC_AUTH_TYPE_NONE = 0,
+ /* this seems to be not krb5! */
+ DCERPC_AUTH_TYPE_KRB5_1 = 1,
+ DCERPC_AUTH_TYPE_SPNEGO = 9,
+ DCERPC_AUTH_TYPE_NTLMSSP = 10,
+ DCERPC_AUTH_TYPE_KRB5 = 16,
+ DCERPC_AUTH_TYPE_DPA = 17,
+ DCERPC_AUTH_TYPE_MSN = 18,
+ DCERPC_AUTH_TYPE_DIGEST = 21,
+ DCERPC_AUTH_TYPE_SCHANNEL = 68,
+ DCERPC_AUTH_TYPE_MSMQ = 100,
+ DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM = 200
+ } dcerpc_AuthType;
+ const char *AS_SYSTEM_MAGIC_PATH_TOKEN = "/root/ncalrpc_as_system";
+
+ typedef [enum8bit] enum {
+ DCERPC_AUTH_LEVEL_NONE = 1,
+ DCERPC_AUTH_LEVEL_CONNECT = 2,
+ DCERPC_AUTH_LEVEL_CALL = 3,
+ DCERPC_AUTH_LEVEL_PACKET = 4,
+ DCERPC_AUTH_LEVEL_INTEGRITY = 5,
+ DCERPC_AUTH_LEVEL_PRIVACY = 6
+ } dcerpc_AuthLevel;
+
+ typedef [public] struct {
+ dcerpc_AuthType auth_type;
+ dcerpc_AuthLevel auth_level;
+ uint8 auth_pad_length;
+ uint8 auth_reserved;
+ uint32 auth_context_id;
+ [flag(NDR_REMAINING)] DATA_BLOB credentials;
+ } dcerpc_auth;
+
+ const uint8 DCERPC_AUTH_TRAILER_LENGTH = 8;
+ const uint8 DCERPC_AUTH_PAD_ALIGNMENT = 16;
+
+ typedef [public] struct {
+ [value(0)] uint32 _pad;
+ [flag(NDR_REMAINING)] DATA_BLOB auth_info;
+ } dcerpc_auth3;
+
+ typedef [public] struct {
+ [flag(NDR_REMAINING)] DATA_BLOB auth_info;
+ } dcerpc_orphaned;
+
+ typedef [public] struct {
+ [flag(NDR_REMAINING)] DATA_BLOB auth_info;
+ } dcerpc_co_cancel;
+
+ typedef [public] struct {
+ uint32 version;
+ uint32 id;
+ } dcerpc_cl_cancel;
+
+ typedef [public] struct {
+ uint32 version;
+ uint32 id;
+ boolean32 server_is_accepting;
+ } dcerpc_cancel_ack;
+
+ typedef [public] struct {
+ uint32 version;
+ uint8 _pad1;
+ uint16 window_size;
+ uint32 max_tdsu;
+ uint32 max_frag_size;
+ uint16 serial_no;
+ uint16 selack_size;
+ uint32 selack[selack_size];
+ } dcerpc_fack;
+
+ typedef [public] struct {
+ } dcerpc_ack;
+
+ typedef [public] struct {
+ } dcerpc_ping;
+
+ typedef [public] struct {
+ } dcerpc_shutdown;
+
+ typedef [public] struct {
+ } dcerpc_working;
+
+ /* RTS data structures */
+ typedef [public] struct {
+ GUID Cookie;
+ } RTSCookie;
+
+ typedef [v1_enum,public] enum {
+ RTS_IPV4 = 0,
+ RTS_IPV6 = 1
+ } AddressType;
+
+ typedef [nodiscriminant] union {
+ [case(RTS_IPV4)] ipv4address ClientAddressIPV4;
+ [case(RTS_IPV6)] ipv6address ClientAddressIPV6;
+ } ClientAddressType;
+
+ typedef [public] struct {
+ AddressType AddressType;
+ [switch_is(AddressType)] ClientAddressType ClientAddress;
+ uint8 Padding[12];
+ } ClientAddress;
+
+ typedef [v1_enum, public] enum {
+ FDClient = 0,
+ FDInProxy = 1,
+ FDServer = 2,
+ FDOutProxy = 3
+ } ForwardDestination;
+
+ typedef [public] struct {
+ uint32 BytesReceived;
+ uint32 AvailableWindow;
+ RTSCookie ChannelCookie;
+ } FlowControlAcknowledgment;
+
+ /* RTS commands */
+
+ /* RTS command: 0x0 */
+ typedef [public] struct {
+ [range(0x2000,0x40000)] uint32 ReceiveWindowSize;
+ } dcerpc_rts_cmd_ReceiveWindowSize;
+
+ /* RTS command: 0x1 */
+ typedef [public] struct {
+ FlowControlAcknowledgment Ack;
+ } dcerpc_rts_cmd_FlowControlAck;
+
+ /* RTS command: 0x2 */
+ typedef [public] struct {
+ [range(0x1D4C0,0xDBBA00)] uint32 ConnectionTimeout;
+ } dcerpc_rts_cmd_ConnectionTimeout;
+
+ /* RTS command: 0x3 */
+ typedef [public] struct {
+ RTSCookie Cookie;
+ } dcerpc_rts_cmd_Cookie;
+
+ /* RTS command: 0x4 */
+ typedef [public] struct {
+ [range(0x20000,0x80000000)] uint32 ChannelLifetime;
+ } dcerpc_rts_cmd_ChannelLifetime;
+
+ /* RTS command: 0x5 */
+ typedef [public] struct {
+ uint32 ClientKeepalive;
+ } dcerpc_rts_cmd_ClientKeepalive;
+
+ /* RTS command: 0x6 */
+ typedef [public] struct {
+ uint32 Version;
+ } dcerpc_rts_cmd_Version;
+
+ /* RTS command: 0x7 */
+ typedef [public] struct {
+ } dcerpc_rts_cmd_Empty;
+
+ /* RTS command: 0x8 */
+ typedef [public] struct {
+ [range(0x0,0xFFFF)] uint32 ConformanceCount;
+ uint8 Padding[ConformanceCount];
+ } dcerpc_rts_cmd_Padding;
+
+ /* RTS command: 0x9 */
+ typedef [public] struct {
+ } dcerpc_rts_cmd_NegativeANCE;
+
+ /* RTS Command: 0xA */
+ typedef [public] struct {
+ } dcerpc_rts_cmd_ANCE;
+
+ /* RTS command: 0xB */
+ typedef [public] struct {
+ ClientAddress ClientAddress;
+ } dcerpc_rts_cmd_ClientAddress;
+
+ /* RTS command: 0xC */
+ typedef [public] struct {
+ RTSCookie AssociationGroupId;
+ } dcerpc_rts_cmd_AssociationGroupId;
+
+ /* RTS command: 0xD */
+ typedef [public] struct {
+ ForwardDestination ForwardDestination;
+ } dcerpc_rts_cmd_Destination;
+
+ /* RTS command: 0xE */
+ typedef [public] struct {
+ uint32 PingTrafficSent;
+ } dcerpc_rts_cmd_PingTrafficSentNotify;
+
+ typedef [nodiscriminant] union {
+ [case(0x0)] dcerpc_rts_cmd_ReceiveWindowSize ReceiveWindowSize;
+ [case(0x1)] dcerpc_rts_cmd_FlowControlAck FlowControlAck;
+ [case(0x2)] dcerpc_rts_cmd_ConnectionTimeout ConnectionTimeout;
+ [case(0x3)] dcerpc_rts_cmd_Cookie Cookie;
+ [case(0x4)] dcerpc_rts_cmd_ChannelLifetime ChannelLifetime;
+ [case(0x5)] dcerpc_rts_cmd_ClientKeepalive ClientKeepalive;
+ [case(0x6)] dcerpc_rts_cmd_Version Version;
+ [case(0x7)] dcerpc_rts_cmd_Empty Empty;
+ [case(0x8)] dcerpc_rts_cmd_Padding Padding;
+ [case(0x9)] dcerpc_rts_cmd_NegativeANCE NegativeANCE;
+ [case(0xA)] dcerpc_rts_cmd_ANCE ANCE;
+ [case(0xB)] dcerpc_rts_cmd_ClientAddress ClientAddress;
+ [case(0xC)] dcerpc_rts_cmd_AssociationGroupId AssociationGroupId;
+ [case(0xD)] dcerpc_rts_cmd_Destination Destination;
+ [case(0xE)] dcerpc_rts_cmd_PingTrafficSentNotify PingTrafficSentNotify;
+ } dcerpc_rts_cmds;
+
+ typedef [public] struct {
+ uint32 CommandType;
+ [switch_is(CommandType)] dcerpc_rts_cmds Command;
+ } dcerpc_rts_cmd;
+
+ /* The RTS flags */
+ typedef [public, bitmap16bit] bitmap {
+ RTS_FLAG_NONE = 0x0000,
+ RTS_FLAG_PING = 0x0001,
+ RTS_FLAG_OTHER_CMD = 0x0002,
+ RTS_FLAG_RECYCLE_CHANNEL = 0x0004,
+ RTS_FLAG_IN_CHANNEL = 0x0008,
+ RTS_FLAG_OUT_CHANNEL = 0x0010,
+ RTS_FLAG_EOF = 0x0020,
+ RTS_FLAG_ECHO = 0x0040
+ } dcerpc_rts_flags;
+
+ typedef [public] struct {
+ dcerpc_rts_flags Flags;
+ uint16 NumberOfCommands;
+ dcerpc_rts_cmd Commands[NumberOfCommands];
+ } dcerpc_rts;
+
+ typedef [public,enum8bit] enum {
+ DCERPC_PKT_REQUEST = 0, /* Ordinary request. */
+ DCERPC_PKT_PING = 1, /* Connectionless is server alive ? */
+ DCERPC_PKT_RESPONSE = 2, /* Ordinary reply. */
+ DCERPC_PKT_FAULT = 3, /* Fault in processing of call. */
+ DCERPC_PKT_WORKING = 4, /* Connectionless reply to a ping when server busy. */
+ DCERPC_PKT_NOCALL = 5, /* Connectionless reply to a ping when server has lost part of clients call. */
+ DCERPC_PKT_REJECT = 6, /* Refuse a request with a code. */
+ DCERPC_PKT_ACK = 7, /* Connectionless client to server code. */
+ DCERPC_PKT_CL_CANCEL = 8, /* Connectionless cancel. */
+ DCERPC_PKT_FACK = 9, /* Connectionless fragment ack. Both client and server send. */
+ DCERPC_PKT_CANCEL_ACK = 10, /* Server ACK to client cancel request. */
+ DCERPC_PKT_BIND = 11, /* Bind to interface. */
+ DCERPC_PKT_BIND_ACK = 12, /* Server ack of bind. */
+ DCERPC_PKT_BIND_NAK = 13, /* Server nack of bind. */
+ DCERPC_PKT_ALTER = 14, /* Alter auth. */
+ DCERPC_PKT_ALTER_RESP = 15, /* Reply to alter auth. */
+ DCERPC_PKT_AUTH3 = 16, /* not the real name! this is undocumented! */
+ DCERPC_PKT_SHUTDOWN = 17, /* Server to client request to shutdown. */
+ DCERPC_PKT_CO_CANCEL = 18, /* Connection-oriented cancel request. */
+ DCERPC_PKT_ORPHANED = 19, /* Client telling server it's aborting a partially sent request or telling server to stop sending replies. */
+ DCERPC_PKT_RTS = 20 /* RTS packets used in ncacn_http */
+ } dcerpc_pkt_type;
+
+ typedef [public,nodiscriminant] union {
+ [case(DCERPC_PKT_REQUEST)] dcerpc_request request;
+ [case(DCERPC_PKT_PING)] dcerpc_ping ping;
+ [case(DCERPC_PKT_RESPONSE)] dcerpc_response response;
+ [case(DCERPC_PKT_FAULT)] dcerpc_fault fault;
+ [case(DCERPC_PKT_WORKING)] dcerpc_working working;
+ [case(DCERPC_PKT_NOCALL)] dcerpc_fack nocall;
+ [case(DCERPC_PKT_REJECT)] dcerpc_fault reject;
+ [case(DCERPC_PKT_ACK)] dcerpc_ack ack;
+ [case(DCERPC_PKT_CL_CANCEL)] dcerpc_cl_cancel cl_cancel;
+ [case(DCERPC_PKT_FACK)] dcerpc_fack fack;
+ [case(DCERPC_PKT_CANCEL_ACK)] dcerpc_cancel_ack cancel_ack;
+ [case(DCERPC_PKT_BIND)] dcerpc_bind bind;
+ [case(DCERPC_PKT_BIND_ACK)] dcerpc_bind_ack bind_ack;
+ [case(DCERPC_PKT_BIND_NAK)] dcerpc_bind_nak bind_nak;
+ [case(DCERPC_PKT_ALTER)] dcerpc_bind alter;
+ [case(DCERPC_PKT_ALTER_RESP)] dcerpc_bind_ack alter_resp;
+ [case(DCERPC_PKT_SHUTDOWN)] dcerpc_shutdown shutdown;
+ [case(DCERPC_PKT_CO_CANCEL)] dcerpc_co_cancel co_cancel;
+ [case(DCERPC_PKT_ORPHANED)] dcerpc_orphaned orphaned;
+ [case(DCERPC_PKT_AUTH3)] dcerpc_auth3 auth3;
+ [case(DCERPC_PKT_RTS)] dcerpc_rts rts;
+ } dcerpc_payload;
+
+ /* pfc_flags values */
+ typedef [public,bitmap8bit] bitmap {
+ DCERPC_PFC_FLAG_FIRST = 0x01, /* First fragment */
+ DCERPC_PFC_FLAG_LAST = 0x02, /* Last fragment */
+ DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING = 0x04, /* depends on the pdu type */
+ DCERPC_PFC_FLAG_CONC_MPX = 0x10, /* supports concurrent multiplexing of a single connection. */
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE = 0x20, /* on a fault it means the server hasn't done anything */
+ DCERPC_PFC_FLAG_MAYBE = 0x40, /* `maybe' call semantics requested */
+ DCERPC_PFC_FLAG_OBJECT_UUID = 0x80 /* on valid guid is in the optional object field */
+ } dcerpc_pfc_flags;
+
+ /* Cancel was pending at sender */
+ const int DCERPC_PFC_FLAG_PENDING_CANCEL =
+ DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING;
+ const int DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN =
+ DCERPC_PFC_FLAG_PENDING_CANCEL_OR_HDR_SIGNING;
+
+ /* these offsets are needed by the signing code */
+ const uint8 DCERPC_PFC_OFFSET = 3;
+ const uint8 DCERPC_DREP_OFFSET = 4;
+ const uint8 DCERPC_FRAG_LEN_OFFSET = 8;
+ const uint32 DCERPC_FRAG_MAX_SIZE = 5840;
+ const uint8 DCERPC_AUTH_LEN_OFFSET = 10;
+ const uint8 DCERPC_NCACN_PAYLOAD_OFFSET = 16;
+
+ /*
+ * See [MS-RPCE] 3.3.3.5.4 Maximum Server Input Data Size
+ * 4 MByte is the default limit of reassembled request payload
+ */
+ const uint32 DCERPC_NCACN_REQUEST_DEFAULT_MAX_SIZE = 0x400000;
+
+ /*
+ * See [MS-RPCE] 3.3.2.5.2 Handling Responses
+ *
+ * Indicates that Windows accepts up to 0x7FFFFFFF ~2 GByte
+ *
+ * talloc has a limit of 256 MByte, so we need to use something smaller.
+ *
+ * For now we try our luck with 240 MByte.
+ */
+ const uint32 DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE = 0xf000000; /* 240 MByte */
+
+ /* little-endian flag */
+ const uint8 DCERPC_DREP_LE = 0x10;
+
+ typedef [public,nopush,nopull,noprint] struct {
+ uint8 rpc_vers; /* RPC version */
+ uint8 rpc_vers_minor; /* Minor version */
+ dcerpc_pkt_type ptype; /* Packet type */
+ dcerpc_pfc_flags pfc_flags; /* Fragmentation flags */
+ uint8 drep[4]; /* NDR data representation */
+ uint16 frag_length; /* Total length of fragment */
+ uint16 auth_length; /* authenticator length */
+ uint32 call_id; /* Call identifier */
+ [switch_is(ptype)] dcerpc_payload u;
+ } ncacn_packet;
+
+ typedef [public] struct {
+ uint8 rpc_vers; /* RPC version (4) */
+ uint8 ptype;
+ uint8 pfc_flags;
+ uint8 ncadg_flags;
+ uint8 drep[3];
+ uint8 serial_high;
+ GUID object;
+ GUID iface;
+ GUID activity;
+ uint32 server_boot; /* Server boot time */
+ uint32 iface_version;
+ uint32 seq_num;
+ uint16 opnum;
+ uint16 ihint;
+ uint16 ahint;
+ uint16 len;
+ uint16 fragnum;
+ uint8 auth_proto;
+ uint8 serial_low;
+ [switch_is(ptype)] dcerpc_payload u;
+ } ncadg_packet;
+
+ typedef [bitmap16bit] bitmap {
+ DCERPC_SEC_VT_COMMAND_ENUM = 0x3FFF,
+ DCERPC_SEC_VT_COMMAND_END = 0x4000,
+ DCERPC_SEC_VT_MUST_PROCESS = 0x8000
+ } dcerpc_sec_vt_command;
+
+ typedef [enum16bit] enum {
+ DCERPC_SEC_VT_COMMAND_BITMASK1 = 0x0001,
+ DCERPC_SEC_VT_COMMAND_PCONTEXT = 0x0002,
+ DCERPC_SEC_VT_COMMAND_HEADER2 = 0x0003
+ } dcerpc_sec_vt_command_enum;
+
+ typedef [bitmap32bit] bitmap {
+ DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING = 0x00000001
+ } dcerpc_sec_vt_bitmask1;
+
+ typedef struct {
+ ndr_syntax_id abstract_syntax;
+ ndr_syntax_id transfer_syntax;
+ } dcerpc_sec_vt_pcontext;
+
+ typedef struct {
+ dcerpc_pkt_type ptype; /* Packet type */
+ [value(0)] uint8 reserved1;
+ [value(0)] uint16 reserved2;
+ uint8 drep[4]; /* NDR data representation */
+ uint32 call_id; /* Call identifier */
+ uint16 context_id;
+ uint16 opnum;
+ } dcerpc_sec_vt_header2;
+
+ typedef [switch_type(dcerpc_sec_vt_command_enum),nodiscriminant] union {
+ [case(DCERPC_SEC_VT_COMMAND_BITMASK1)] dcerpc_sec_vt_bitmask1 bitmask1;
+ [case(DCERPC_SEC_VT_COMMAND_PCONTEXT)] dcerpc_sec_vt_pcontext pcontext;
+ [case(DCERPC_SEC_VT_COMMAND_HEADER2)] dcerpc_sec_vt_header2 header2;
+ [default,flag(NDR_REMAINING)] DATA_BLOB _unknown;
+ } dcerpc_sec_vt_union;
+
+ typedef struct {
+ dcerpc_sec_vt_command command;
+ [switch_is(command & DCERPC_SEC_VT_COMMAND_ENUM)]
+ [subcontext(2),flag(NDR_SUBCONTEXT_NO_UNREAD_BYTES)]
+ dcerpc_sec_vt_union u;
+ } dcerpc_sec_vt;
+
+ typedef [public,nopush,nopull] struct {
+ uint16 count;
+ } dcerpc_sec_vt_count;
+
+ /*
+ * We assume that the whole verification trailer fits into
+ * the last 1024 bytes after the stub data.
+ *
+ * There're currently only 3 commands defined and each should
+ * only be used once.
+ */
+ const uint16 DCERPC_SEC_VT_MAX_SIZE = 1024;
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad;
+ [value(DCERPC_SEC_VT_MAGIC)] uint8 magic[8];
+ dcerpc_sec_vt_count count;
+ dcerpc_sec_vt commands[count.count];
+ } dcerpc_sec_verification_trailer;
+}
diff --git a/librpc/idl/dcom.idl b/librpc/idl/dcom.idl
new file mode 100644
index 0000000..5559811
--- /dev/null
+++ b/librpc/idl/dcom.idl
@@ -0,0 +1,314 @@
+/**
+ DCOM interfaces
+ http://www.ietf.org/internet-drafts/draft-brown-dcom-v1-spec-04.txt
+ */
+
+import "misc.idl";
+
+[
+ uuid("18f70770-8e64-11cf-9af1-0020af6e72f4"),
+ pointer_default(unique),
+ version(0.0)
+] interface dcom_Unknown
+{
+ void UseProtSeq();
+ void GetCustomProtseqInfo();
+ void UpdateResolverBindings();
+}
+
+[
+ object,
+ uuid("00000000-0000-0000-C000-000000000046"),
+ pointer_default(unique),
+ helpstring("Base interface for all COM interfaces")
+]
+interface IUnknown
+{
+ /*****************/
+ /* Function 0x00 */
+ /* Returns the interface with the specified IID
+ if implemented by this object */
+ [local] WERROR QueryInterface(
+ [in,unique] GUID *iid,
+ [out,iid_is(riid)] IUnknown **data
+ );
+
+ /*****************/
+ /* Function 0x01 */
+ [local] uint32 AddRef();
+
+ /*****************/
+ /* Function 0x02 */
+ [local] uint32 Release();
+}
+
+
+[
+ object,
+ uuid("00000001-0000-0000-C000-000000000046"),
+ pointer_default(unique)
+] interface IClassFactory : IUnknown
+{
+ [local] WERROR CreateInstance(
+ [in,unique] MInterfacePointer *pUnknown,
+ [in,unique] GUID *iid,
+ [out, iid_is(riid),unique] MInterfacePointer **ppv
+ );
+
+ [call_as(CreateInstance)] WERROR RemoteCreateInstance();
+
+ /* Set lock to TRUE when you want to do a lock
+ and set it to FALSE when you want to unlock */
+ [local] WERROR LockServer(
+ [in] uint8 lock
+ );
+
+ [call_as(LockServer)] WERROR RemoteLockServer();
+}
+
+/* The remote version of IUnknown. This interface exists on every */
+/* OXID (whether an OXID represents either a thread or a process is */
+/* implementation specific). It is used by clients to query for new */
+/* interfaces, get additional references (for marshaling), and release */
+/* outstanding references. */
+/* This interface is passed along during OXID resolution. */
+/* */
+[
+ uuid("00000131-0000-0000-C000-000000000046"),
+ object,
+ pointer_default(unique),
+ helpstring("Remote version of IUnknown")
+]
+interface IRemUnknown : IUnknown
+{
+ typedef [public] struct
+ {
+ WERROR hResult; /* result of call */
+ STDOBJREF std; /* data for returned interface */
+ }
+ REMQIRESULT;
+
+ [call_as(QueryInterface)] WERROR RemQueryInterface (
+ [in,unique] GUID *ripid, /* interface to QI on */
+ [in] uint32 cRefs, /* count of AddRefs requested */
+ [in] uint16 cIids, /* count of IIDs that follow */
+ [in, unique, size_is(cIids)] GUID *iids, /* IIDs to QI for */
+ [out, size_is(cIids), unique] MInterfacePointer *ip
+ );
+
+ typedef struct
+ {
+ GUID ipid; /* ipid to AddRef/Release */
+ uint32 cPublicRefs;
+ uint32 cPrivateRefs;
+ } REMINTERFACEREF;
+
+ [call_as(AddRef)] WERROR RemAddRef (
+ [in] uint16 cInterfaceRefs,
+ [in, size_is(cInterfaceRefs)] REMINTERFACEREF InterfaceRefs[],
+ [out, size_is(cInterfaceRefs), unique] WERROR *pResults
+ );
+
+ [call_as(Release)] WERROR RemRelease (
+ [in] uint16 cInterfaceRefs,
+ [in, size_is(cInterfaceRefs)] REMINTERFACEREF InterfaceRefs[]
+ );
+}
+
+[
+ uuid("00000140-0000-0000-c000-000000000046"),
+ object
+] interface IClassActivator : IUnknown
+{
+ void GetClassObject(
+ [in] GUID clsid,
+ [in] uint32 context,
+ [in] uint32 locale,
+ [in] GUID iid,
+ [out, iid_is(iid)] MInterfacePointer *data
+ );
+}
+
+[
+ uuid("00000136-0000-0000-c000-000000000046"),
+ pointer_default(unique),
+ object
+] interface ISCMLocalActivator : IClassActivator
+{
+ WERROR ISCMLocalActivator_CreateInstance( );
+}
+
+[
+ pointer_default(unique),
+ uuid("c6f3ee72-ce7e-11d1-b71e-00c04fc3111a")
+] interface IMachineLocalActivator
+{
+ WERROR IMachineLocalActivator_foo();
+}
+
+[
+ pointer_default(unique),
+ uuid("e60c73e6-88f9-11cf-9af1-0020af6e72f4")
+] interface ILocalObjectExporter
+{
+ WERROR ILocalObjectExporter_Foo();
+}
+
+/* Looks like this is the equivalent of .NET's
+ System.Activator class */
+[
+ uuid("000001a0-0000-0000-c000-000000000046"),
+ object
+]
+ interface ISystemActivator : IClassActivator
+{
+ WERROR ISystemActivatorRemoteCreateInstance(
+ [in] hyper unknown1, /* OXID ? */
+ [in] MInterfacePointer iface1,
+ [in] hyper unknown2,
+ [out] uint32 *unknown3,
+ [out] MInterfacePointer *iface2
+ );
+}
+
+
+
+/* Derived from IRemUnknown, this interface supports Remote Query interface */
+/* for objects that supply additional data beyond the STDOBJREF in their */
+/* marshaled interface packets. */
+[
+ object,
+ pointer_default(unique),
+ uuid("00000143-0000-0000-C000-000000000046")
+]
+
+interface IRemUnknown2 : IRemUnknown
+{
+ [call_as(QueryInterface2)] WERROR RemQueryInterface2 (
+ [in, unique] GUID *ripid,
+ [in] uint16 cIids,
+ [in, size_is(cIids), unique] GUID *iids,
+ [out, size_is(cIids), unique] WERROR *phr,
+ [out, size_is(cIids), unique] MInterfacePointer *ppMIF
+ );
+}
+
+[
+ object,
+ pointer_default(unique),
+ uuid("00020400-0000-0000-C000-000000000046")
+] interface IDispatch : IUnknown
+{
+ /*****************/
+ /* Function 0x03 */
+ WERROR GetTypeInfoCount(
+ [out, unique] uint16 *pctinfo
+ );
+
+ typedef struct {
+ } REF_ITypeInfo;
+
+ /*****************/
+ /* Function 0x04 */
+ WERROR GetTypeInfo (
+ [in] uint16 iTInfo,
+ [in] uint32 lcid,
+ [out, unique] REF_ITypeInfo *ppTInfo
+ );
+
+ /*****************/
+ /* Function 0x05 */
+ WERROR GetIDsOfNames(
+ [in, unique] GUID *riid,
+ /*FIXME[in,size_is(cNames)] OLESTR *rgszNames[], */
+ [in] uint16 cNames,
+ [in] uint32 lcid,
+ [out,size_is(cNames), unique] uint32 *rgDispId
+ );
+
+ typedef struct {
+ uint16 vartype;
+ uint16 FIXME;
+ } VARIANT;
+
+ typedef struct {
+ uint16 FIXME;
+ } DISPPARAMS;
+
+ /* Exception ? */
+ typedef struct {
+ uint16 FIXME;
+ } EXCEPINFO;
+
+ /*****************/
+ /* Function 0x06 */
+ WERROR Invoke(
+ [in] uint32 dispIdMember,
+ [in, unique] GUID *riid,
+ [in] uint32 lcid,
+ [in] uint16 wFlags,
+ [out,in, unique] DISPPARAMS *pDispParams,
+ [out, unique] VARIANT *pVarResult,
+ [out, unique] EXCEPINFO *pExcepInfo,
+ [out, unique] uint16 *puArgErr
+ );
+}
+
+[
+ object,
+ local,
+ uuid("00000003-0000-0000-C000-000000000046")
+] interface IMarshal : IUnknown
+{
+ WERROR MarshalInterface();
+ WERROR UnMarshalInterface();
+}
+
+[
+ uuid("DA23F6DB-6F45-466C-9EED-0B65286F2D78"),
+ helpstring("ICoffeeMachine Interface"),
+ pointer_default(unique),
+ object
+] interface ICoffeeMachine : IUnknown
+{
+ WERROR MakeCoffee([in,string,charset(UTF16)] uint16 *flavor);
+}
+
+[
+ uuid("db7c21f8-fe33-4c11-aea5-ceb56f076fbb"),
+ helpstring("coffeemachine class")
+] coclass coffeemachine
+{
+ interface icoffeemachine;
+}
+
+[
+ object,
+ uuid("0000000C-0000-0000-C000-000000000046"),
+ helpstring("Stream")
+]
+interface IStream : IUnknown
+{
+ WERROR Read(
+ [out, size_is(num_requested), length_is(*num_read)] uint8 pv[],
+ [in] uint32 num_requested,
+ [in, unique] uint32 *num_readx,
+ [out] uint32 *num_read
+ );
+
+ WERROR Write(
+ [in,size_is(num_requested),unique] uint8 *data,
+ [in] uint32 num_requested,
+ [out] uint32 *num_written
+ );
+}
+
+[
+ uuid("5e9ddec7-5767-11cf-beab-00aa006c3606"),
+ progid("Samba.Simple"),
+ helpstring("simple class"),
+ internal
+] coclass simple
+{
+ interface IStream;
+}
diff --git a/librpc/idl/dfs.idl b/librpc/idl/dfs.idl
new file mode 100644
index 0000000..1b145f3
--- /dev/null
+++ b/librpc/idl/dfs.idl
@@ -0,0 +1,419 @@
+/*
+ dfs interface definition
+*/
+
+import "misc.idl";
+
+[ uuid("4fc742e0-4a10-11cf-8273-00aa004ae673"),
+ version(3.0),
+ pointer_default(unique),
+ helpstring("Settings for Microsoft Distributed File System"),
+ endpoint("ncacn_np:[\\pipe\\netdfs]", "ncacn_ip_tcp:", "ncalrpc:")
+] interface netdfs
+{
+ /******************/
+ /* Function: 0x00 */
+ typedef [v1_enum] enum {
+ DFS_MANAGER_VERSION_NT4 = 1,
+ DFS_MANAGER_VERSION_W2K = 2,
+ DFS_MANAGER_VERSION_W2K3 = 4,
+ DFS_MANAGER_VERSION_W2K8 = 6
+ } dfs_ManagerVersion;
+
+ [public] void dfs_GetManagerVersion(
+ [out] dfs_ManagerVersion *version
+ );
+
+
+ /******************/
+ /* Function: 0x01 */
+ WERROR dfs_Add (
+ [in] [string,charset(UTF16)] uint16 *path,
+ [in] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *share,
+ [in,unique] [string,charset(UTF16)] uint16 *comment,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x02 */
+ WERROR dfs_Remove (
+ [in] [string,charset(UTF16)] uint16 *dfs_entry_path,
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *sharename
+ );
+
+ /******************/
+ /* Function: 0x03 */
+
+ typedef struct {
+ } dfs_Info0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ } dfs_Info1;
+
+ typedef [public,bitmap32bit] bitmap {
+ DFS_VOLUME_STATE_OK = 0x1,
+ DFS_VOLUME_STATE_INCONSISTENT = 0x2,
+ DFS_VOLUME_STATE_OFFLINE = 0x3,
+ DFS_VOLUME_STATE_ONLINE = 0x4,
+ DFS_VOLUME_STATE_STANDALONE = DFS_VOLUME_FLAVOR_STANDALONE,
+ DFS_VOLUME_STATE_AD_BLOB = DFS_VOLUME_FLAVOR_AD_BLOB
+ } dfs_VolumeState;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 num_stores;
+ } dfs_Info2;
+
+ const int DFS_STORAGE_STATES = 0xf;
+
+ /* yes, this is a bitmap */
+ typedef [public,bitmap32bit] bitmap {
+ DFS_STORAGE_STATE_OFFLINE = 1,
+ DFS_STORAGE_STATE_ONLINE = 2,
+ DFS_STORAGE_STATE_ACTIVE = 4
+ } dfs_StorageState;
+
+ typedef struct {
+ dfs_StorageState state;
+ [string,charset(UTF16)] uint16 *server;
+ [string,charset(UTF16)] uint16 *share;
+ } dfs_StorageInfo;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 num_stores;
+ [size_is(num_stores)] dfs_StorageInfo *stores;
+ } dfs_Info3;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 timeout;
+ GUID guid;
+ uint32 num_stores;
+ [size_is(num_stores)] dfs_StorageInfo *stores;
+ } dfs_Info4;
+
+ /* verified with dfsutil */
+ typedef [public,bitmap32bit] bitmap {
+ DFS_PROPERTY_FLAG_INSITE_REFERRALS = 0x01,
+ DFS_PROPERTY_FLAG_ROOT_SCALABILITY = 0x02,
+ DFS_PROPERTY_FLAG_SITE_COSTING = 0x04,
+ DFS_PROPERTY_FLAG_TARGET_FAILBACK = 0x08,
+ DFS_PROPERTY_FLAG_CLUSTER_ENABLED = 0x10 /* untested */
+ } dfs_PropertyFlags;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 timeout;
+ GUID guid;
+ dfs_PropertyFlags flags;
+ uint32 pktsize;
+ uint32 num_stores;
+ } dfs_Info5;
+
+ typedef [v1_enum] enum {
+ DFS_INVALID_PRIORITY_CLASS = -1,
+ DFS_SITE_COST_NORMAL_PRIORITY_CLASS = 0,
+ DFS_GLOBAL_HIGH_PRIORITY_CLASS = 1,
+ DFS_SITE_COST_HIGH_PRIORITY_CLASS = 2,
+ DFS_SITE_COST_LOW_PRIORITY_CLASS = 3,
+ DFS_GLOBAL_LOW_PRIORITY_CLASS = 4
+ } dfs_Target_PriorityClass;
+
+ typedef struct {
+ dfs_Target_PriorityClass target_priority_class;
+ uint16 target_priority_rank;
+ uint16 reserved;
+ } dfs_Target_Priority;
+
+ typedef struct {
+ dfs_StorageInfo info;
+ dfs_Target_Priority target_priority;
+ } dfs_StorageInfo2;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *entry_path;
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 timeout;
+ GUID guid;
+ dfs_PropertyFlags flags;
+ uint32 pktsize;
+ uint16 num_stores;
+ [size_is(num_stores)] dfs_StorageInfo2 *stores;
+ } dfs_Info6;
+
+ typedef struct {
+ GUID generation_guid;
+ } dfs_Info7;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *comment;
+ } dfs_Info100;
+
+ typedef struct {
+ dfs_StorageState state;
+ } dfs_Info101;
+
+ typedef struct {
+ uint32 timeout;
+ } dfs_Info102;
+
+ typedef struct {
+ dfs_PropertyFlags flags;
+ } dfs_Info103;
+
+ typedef struct {
+ dfs_Target_Priority priority;
+ } dfs_Info104;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *comment;
+ dfs_VolumeState state;
+ uint32 timeout;
+ uint32 property_flag_mask;
+ uint32 property_flags;
+ } dfs_Info105;
+
+ typedef struct {
+ dfs_StorageState state;
+ dfs_Target_Priority priority;
+ } dfs_Info106;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *dom_root;
+ } dfs_Info200;
+
+ typedef enum {
+ DFS_VOLUME_FLAVOR_STANDALONE = 0x100,
+ DFS_VOLUME_FLAVOR_AD_BLOB = 0x200
+ } dfs_VolumeFlavor;
+
+ typedef struct {
+ dfs_VolumeFlavor flavor;
+ [string,charset(UTF16)] uint16 *dom_root;
+ } dfs_Info300;
+
+ typedef union {
+ [case(0)] dfs_Info0 *info0;
+ [case(1)] dfs_Info1 *info1;
+ [case(2)] dfs_Info2 *info2;
+ [case(3)] dfs_Info3 *info3;
+ [case(4)] dfs_Info4 *info4;
+ [case(5)] dfs_Info5 *info5;
+ [case(6)] dfs_Info6 *info6;
+ [case(7)] dfs_Info7 *info7;
+ [case(100)] dfs_Info100 *info100;
+ [case(101)] dfs_Info101 *info101;
+ [case(102)] dfs_Info102 *info102;
+ [case(103)] dfs_Info103 *info103;
+ [case(104)] dfs_Info104 *info104;
+ [case(105)] dfs_Info105 *info105;
+ [case(106)] dfs_Info106 *info106;
+ } dfs_Info;
+
+ WERROR dfs_SetInfo (
+ [in] [string,charset(UTF16)] uint16 dfs_entry_path[],
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *sharename,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] dfs_Info *info
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ WERROR dfs_GetInfo (
+ [in] [string,charset(UTF16)] uint16 dfs_entry_path[],
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *sharename,
+ [in] uint32 level,
+ [out,switch_is(level)] dfs_Info *info
+ );
+
+ /******************/
+ /* Function: 0x05 */
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info1 *s;
+ } dfs_EnumArray1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info2 *s;
+ } dfs_EnumArray2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info3 *s;
+ } dfs_EnumArray3;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info4 *s;
+ } dfs_EnumArray4;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info5 *s;
+ } dfs_EnumArray5;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info6 *s;
+ } dfs_EnumArray6;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info200 *s;
+ } dfs_EnumArray200;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] dfs_Info300 *s;
+ } dfs_EnumArray300;
+
+
+ typedef union {
+ [case(1)] dfs_EnumArray1 *info1;
+ [case(2)] dfs_EnumArray2 *info2;
+ [case(3)] dfs_EnumArray3 *info3;
+ [case(4)] dfs_EnumArray4 *info4;
+ [case(5)] dfs_EnumArray5 *info5;
+ [case(6)] dfs_EnumArray6 *info6;
+ [case(200)] dfs_EnumArray200 *info200;
+ [case(300)] dfs_EnumArray300 *info300;
+ } dfs_EnumInfo;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] dfs_EnumInfo e;
+ } dfs_EnumStruct;
+
+ WERROR dfs_Enum (
+ [in] uint32 level,
+ [in] uint32 bufsize,
+ [in,out,unique] dfs_EnumStruct *info,
+ [in,out,unique] uint32 *total
+ );
+
+ /* Function 0x06 */
+ [todo] WERROR dfs_Rename();
+
+ /* Function 0x07 */
+ [todo] WERROR dfs_Move();
+
+ /* Function 0x08 */
+ [todo] WERROR dfs_ManagerGetConfigInfo();
+
+ /* Function 0x09 */
+ [todo] WERROR dfs_ManagerSendSiteInfo();
+
+ /* Function 0x0a */
+ typedef struct {
+ uint32 unknown1;
+ [string,charset(UTF16)] uint16 *unknown2;
+ } dfs_UnknownStruct;
+
+ WERROR dfs_AddFtRoot(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 dns_servername[],
+ [in] [string,charset(UTF16)] uint16 dfsname[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] [string,charset(UTF16)] uint16 comment[],
+ [in] [string,charset(UTF16)] uint16 dfs_config_dn[],
+ [in] uint8 unknown1,
+ [in] uint32 flags,
+ [in,out,unique] dfs_UnknownStruct **unknown2
+ );
+
+ /* Function 0x0b */
+ WERROR dfs_RemoveFtRoot(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 dns_servername[],
+ [in] [string,charset(UTF16)] uint16 dfsname[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] uint32 flags,
+ [in,out,unique] dfs_UnknownStruct **unknown
+ );
+
+ /* Function 0x0c */
+ WERROR dfs_AddStdRoot(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] [string,charset(UTF16)] uint16 comment[],
+ [in] uint32 flags
+ );
+
+ /* Function 0x0d */
+ WERROR dfs_RemoveStdRoot(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] uint32 flags
+ );
+
+ /* Function 0x0e */
+ WERROR dfs_ManagerInitialize(
+ [in] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 flags
+ );
+
+ /* Function 0x0f */
+ WERROR dfs_AddStdRootForced(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 rootshare[],
+ [in] [string,charset(UTF16)] uint16 comment[],
+ [in] [string,charset(UTF16)] uint16 store[] /* C:\\whatever */
+ );
+
+ /* Function 0x10 */
+ WERROR dfs_GetDcAddress(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in,out,ref] [string,charset(UTF16)] uint16 **server_fullname,
+ [in,out,ref] boolean8 *is_root,
+ [in,out,ref] uint32 *ttl
+ );
+
+ /* Function 0x11 */
+ WERROR dfs_SetDcAddress(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 server_fullname[],
+ [in] uint32 flags,
+ [in] uint32 ttl
+ );
+
+ /* Function 0x12 */
+ WERROR dfs_FlushFtTable(
+ [in] [string,charset(UTF16)] uint16 servername[],
+ [in] [string,charset(UTF16)] uint16 rootshare[]
+ );
+
+ /* Function 0x13 */
+ [todo] WERROR dfs_Add2();
+
+ /* Function 0x14 */
+ [todo] WERROR dfs_Remove2();
+
+ /* Function 0x15 */
+ [public] WERROR dfs_EnumEx(
+ [in] [string,charset(UTF16)] uint16 dfs_name[],
+ [in] uint32 level,
+ [in] uint32 bufsize,
+ [in,out,unique] dfs_EnumStruct *info,
+ [in,out,unique] uint32 *total
+ );
+
+ /* Function 0x16 */
+ [todo] WERROR dfs_SetInfo2();
+}
diff --git a/librpc/idl/dfsblobs.idl b/librpc/idl/dfsblobs.idl
new file mode 100644
index 0000000..7b8795d
--- /dev/null
+++ b/librpc/idl/dfsblobs.idl
@@ -0,0 +1,115 @@
+#include "idl_types.h"
+
+import "misc.idl";
+/*
+dfs blobs interface definition
+*/
+
+
+[
+ pointer_default(unique),
+ helpstring("dfs referral blobs"),
+ uuid("12345778-1234-abcd-0001-00000003")
+]
+
+
+interface dfsblobs
+{
+ typedef [bitmap32bit] bitmap {
+ DFS_HEADER_FLAG_REFERAL_SVR = 0x00000001,
+ DFS_HEADER_FLAG_STORAGE_SVR = 0x00000002,
+ DFS_HEADER_FLAG_TARGET_BCK = 0x00000004
+ } DFS_HEADER_FLAG;
+
+ typedef [enum16bit] enum {
+ DFS_SERVER_NON_ROOT = 0x0000,
+ DFS_SERVER_ROOT = 0x0001
+ } DFS_SERVER_TYPE;
+
+ typedef [enum16bit] enum {
+ DFS_FLAG_REFERRAL_DOMAIN_RESP = 0x0002,
+ DFS_FLAG_REFERRAL_FIRST_TARGET_SET = 0x0004
+ } DFS_FLAGS_REFERRAL;
+
+ typedef struct {
+ uint16 size;
+ uint16 server_type;
+ uint16 entry_flags;
+ nstring *share_name;
+ } dfs_referral_v1;
+
+ typedef struct {
+ uint16 size;
+ DFS_SERVER_TYPE server_type;
+ DFS_FLAGS_REFERRAL entry_flags;
+ uint32 proximity;
+ uint32 ttl;
+ [relative_short] nstring *DFS_path;
+ [relative_short] nstring *DFS_alt_path;
+ [relative_short] nstring *netw_address;
+ } dfs_referral_v2;
+
+ typedef struct {
+ [relative_short] nstring *DFS_path;
+ [relative_short] nstring *DFS_alt_path;
+ [relative_short] nstring *netw_address;
+ } dfs_normal_referral;
+
+ typedef struct {
+ [relative_short] nstring *special_name;
+ uint16 nb_expanded_names;
+ [relative_short,subcontext(0),flag(NDR_REMAINING|STR_NULLTERM)] string_array *expanded_names;
+ } dfs_domain_referral;
+
+ typedef [nodiscriminant] union {
+ [case(0)] dfs_normal_referral r1;
+ [case(2)] dfs_domain_referral r2;
+ [default];
+ } dfs_referral;
+
+ typedef [nodiscriminant] union {
+ [case(16)] uint8 value[16];
+ [default];
+ } dfs_padding;
+
+ typedef [flag(NDR_NOALIGN)] struct {
+ uint16 size;
+ DFS_SERVER_TYPE server_type;
+ DFS_FLAGS_REFERRAL entry_flags;
+ uint32 ttl;
+ [switch_is(entry_flags & DFS_FLAG_REFERRAL_DOMAIN_RESP)] dfs_referral referrals;
+ /* this is either 0 or 16 bytes */
+ [switch_is(size - 18)] dfs_padding service_site_guid;
+ } dfs_referral_v3;
+
+ typedef [nodiscriminant] union {
+ [case(1)] dfs_referral_v1 v1;
+ [case(2)] dfs_referral_v2 v2;
+ [case(3)] dfs_referral_v3 v3;
+ [case(4)] dfs_referral_v3 v4;
+ [default];
+ } dfs_referral_version;
+
+ typedef [flag(NDR_NOALIGN)] [relative_base] struct {
+ uint16 version;
+ [switch_is(version)] dfs_referral_version referral;
+ } dfs_referral_type;
+
+ typedef [public] struct {
+ uint16 path_consumed;
+ uint16 nb_referrals;
+ DFS_HEADER_FLAG header_flags;
+ dfs_referral_type referral_entries[nb_referrals];
+ } dfs_referral_resp;
+
+ typedef [public] struct {
+ uint16 max_referral_level;
+ nstring servername;
+ } dfs_GetDFSReferral_in;
+
+ [public] void dfs_GetDFSReferral(
+ [in] dfs_GetDFSReferral_in req,
+ [out,ref] dfs_referral_resp *resp
+ );
+
+}
diff --git a/librpc/idl/dns.idl b/librpc/idl/dns.idl
new file mode 100644
index 0000000..ec8668a
--- /dev/null
+++ b/librpc/idl/dns.idl
@@ -0,0 +1,282 @@
+#include "idl_types.h"
+
+/*
+ IDL structures for DNS operations
+
+ DNS is not traditionally encoded using IDL/NDR. This is a bit of an
+ experiment, and I may well switch us back to a more traditional
+ encoding if it doesn't work out
+*/
+
+import "misc.idl", "dnsp.idl";
+[
+ helper("librpc/ndr/ndr_dns.h"),
+ helpstring("DNS records"),
+ version(0.0),
+ uuid("a047c001-5f22-40b0-9d52-7042c43f711a")
+]
+interface dns
+{
+ const int DNS_SERVICE_PORT = 53;
+ const int DNS_MAX_LABELS = 127;
+ const int DNS_MAX_DOMAIN_LENGTH = 253;
+ const int DNS_MAX_LABEL_LENGTH = 63;
+
+ typedef [public,bitmap16bit] bitmap {
+ DNS_RCODE = 0x001F,
+ DNS_FLAG_RECURSION_AVAIL = 0x0080,
+ DNS_FLAG_RECURSION_DESIRED = 0x0100,
+ DNS_FLAG_TRUNCATION = 0x0200,
+ DNS_FLAG_AUTHORITATIVE = 0x0400,
+ DNS_OPCODE = 0x7800,
+ DNS_FLAG_REPLY = 0x8000
+ } dns_operation;
+
+ /* the opcodes are in the operation field, masked with
+ DNS_OPCODE */
+ typedef [public] enum {
+ DNS_OPCODE_QUERY = (0x0<<11),
+ DNS_OPCODE_IQUERY = (0x1<<11),
+ DNS_OPCODE_STATUS = (0x2<<11),
+ DNS_OPCODE_UPDATE = (0x5<<11),
+ DNS_OPCODE_RELEASE = (0x6<<11),
+ DNS_OPCODE_WACK = (0x7<<11),
+ DNS_OPCODE_REFRESH = (0x8<<11),
+ DNS_OPCODE_REFRESH2 = (0x9<<11),
+ DNS_OPCODE_MULTI_HOME_REG = (0xf<<11)
+ } dns_opcode;
+
+ /* rcode values */
+ typedef [public] enum {
+ DNS_RCODE_OK = 0x00,
+ DNS_RCODE_FORMERR = 0x01,
+ DNS_RCODE_SERVFAIL = 0x02,
+ DNS_RCODE_NXDOMAIN = 0x03,
+ DNS_RCODE_NOTIMP = 0x04,
+ DNS_RCODE_REFUSED = 0x05,
+ DNS_RCODE_YXDOMAIN = 0x06,
+ DNS_RCODE_YXRRSET = 0x07,
+ DNS_RCODE_NXRRSET = 0x08,
+ DNS_RCODE_NOTAUTH = 0x09,
+ DNS_RCODE_NOTZONE = 0x0A,
+ DNS_RCODE_BADSIG = 0x10,
+ DNS_RCODE_BADKEY = 0x11,
+ DNS_RCODE_BADTIME = 0x12,
+ DNS_RCODE_BADMODE = 0x13,
+ DNS_RCODE_BADNAME = 0x14,
+ DNS_RCODE_BADALG = 0x15
+ } dns_rcode;
+
+ typedef [public,enum16bit] enum {
+ DNS_QCLASS_IN = 0x0001,
+ DNS_QCLASS_NONE = 0x00FE,
+ DNS_QCLASS_ANY = 0x00FF
+ } dns_qclass;
+
+ /* These vese values could have been merged with NBT_QTYPE values, but
+ DNS_QTYPE_SRV and NBT_QTYPE_STATUS have the same numeric value. */
+ typedef [public,enum16bit] enum {
+ DNS_QTYPE_ZERO = 0x0000,
+ DNS_QTYPE_A = 0x0001,
+ DNS_QTYPE_NS = 0x0002,
+ DNS_QTYPE_MD = 0x0003,
+ DNS_QTYPE_MF = 0x0004,
+ DNS_QTYPE_CNAME = 0x0005,
+ DNS_QTYPE_SOA = 0x0006,
+ DNS_QTYPE_MB = 0x0007,
+ DNS_QTYPE_MG = 0x0008,
+ DNS_QTYPE_MR = 0x0009,
+ DNS_QTYPE_NULL = 0x000A,
+ DNS_QTYPE_WKS = 0x000B,
+ DNS_QTYPE_PTR = 0x000C,
+ DNS_QTYPE_HINFO = 0x000D,
+ DNS_QTYPE_MINFO = 0x000E,
+ DNS_QTYPE_MX = 0x000F,
+ DNS_QTYPE_TXT = 0x0010,
+ DNS_QTYPE_RP = 0x0011,
+ DNS_QTYPE_AFSDB = 0x0012,
+ DNS_QTYPE_X25 = 0x0013,
+ DNS_QTYPE_ISDN = 0x0014,
+ DNS_QTYPE_RT = 0x0015,
+ DNS_QTYPE_SIG = 0x0018,
+ DNS_QTYPE_KEY = 0x0019,
+ DNS_QTYPE_AAAA = 0x001C,
+ DNS_QTYPE_LOC = 0x001D,
+ DNS_QTYPE_NXT = 0x001E,
+ DNS_QTYPE_NETBIOS= 0x0020,
+ DNS_QTYPE_SRV = 0x0021,
+ DNS_QTYPE_ATMA = 0x0022,
+ DNS_QTYPE_NAPTR = 0x0023,
+ DNS_QTYPE_CERT = 0x0025,
+ DNS_QTYPE_DNAME = 0x0027,
+ DNS_QTYPE_OPT = 0x0029,
+ DNS_QTYPE_DS = 0x002B,
+ DNS_QTYPE_SSHFP = 0x002C,
+ DNS_QTYPE_IPSECKEY = 0x002D,
+ DNS_QTYPE_RRSIG = 0x002E,
+ DNS_QTYPE_NSEC = 0x002F,
+ DNS_QTYPE_DNSKEY = 0x0030,
+ DNS_QTYPE_DHCID = 0x0031,
+ DNS_QTYPE_NSEC3 = 0x0032,
+ DNS_QTYPE_NSEC3PARAM = 0x0033,
+ DNS_QTYPE_TLSA = 0x0034,
+ DNS_QTYPE_CDS = 0x003B,
+ DNS_QTYPE_CDNSKEY = 0x003C,
+ DNS_QTYPE_SVCB = 0x0040,
+ DNS_QTYPE_HTTPS = 0x0041,
+ DNS_QTYPE_TKEY = 0x00F9,
+ DNS_QTYPE_TSIG = 0x00FA,
+ DNS_QTYPE_IXFR = 0x00FB,
+ DNS_QTYPE_AXFR = 0x00FC,
+ DNS_QTYPE_MAILB = 0x00FD,
+ DNS_QTYPE_MAILA = 0x00FE,
+ DNS_QTYPE_ALL = 0x00FF,
+ DNS_QTYPE_URI = 0x0100,
+ DNS_QTYPE_CAA = 0x0101
+ } dns_qtype;
+
+ typedef [public,enum16bit] enum {
+ DNS_TKEY_MODE_NULL = 0x0000,
+ DNS_TKEY_MODE_SERVER = 0x0001,
+ DNS_TKEY_MODE_DH = 0x0002,
+ DNS_TKEY_MODE_GSSAPI = 0x0003,
+ DNS_TKEY_MODE_CLIENT = 0x0004,
+ DNS_TKEY_MODE_DELETE = 0x0005,
+ DNS_TKEY_MODE_LAST = 0xFFFF
+ } dns_tkey_mode;
+
+ typedef [public] struct {
+ dns_string name;
+ dns_qtype question_type;
+ dns_qclass question_class;
+ } dns_name_question;
+
+ typedef [public] struct {
+ uint16 length;
+ uint8 data[length];
+ } dns_rdata_data;
+
+ typedef struct {
+ dns_string mname;
+ dns_string rname;
+ uint32 serial;
+ uint32 refresh;
+ uint32 retry;
+ uint32 expire;
+ uint32 minimum;
+ } dns_soa_record;
+
+ typedef [public] struct {
+ uint16 preference;
+ dns_string exchange;
+ } dns_mx_record;
+
+ typedef [public,nopull] struct {
+ dnsp_string_list txt;
+ } dns_txt_record;
+
+ typedef [public] struct {
+ dns_string mbox;
+ dns_string txt;
+
+ } dns_rp_record;
+
+ typedef [public] struct {
+ uint16 priority;
+ uint16 weight;
+ uint16 port;
+ dns_string target;
+ } dns_srv_record;
+
+ typedef [public] struct {
+ uint16 option_code;
+ uint16 option_length;
+ uint8 option_data[option_length];
+ } dns_opt_record;
+
+ typedef [flag(NDR_NO_COMP),public] struct {
+ dns_string algorithm;
+ uint32 inception;
+ uint32 expiration;
+ dns_tkey_mode mode;
+ uint16 error;
+ uint16 key_size;
+ uint8 key_data[key_size];
+ uint16 other_size;
+ uint8 other_data[other_size];
+ } dns_tkey_record;
+
+ typedef [flag(NDR_NO_COMP),public] struct {
+ dns_string algorithm_name;
+ uint16 time_prefix; /* 0 until February 2106*/
+ uint32 time;
+ uint16 fudge;
+ uint16 mac_size;
+ uint8 mac[mac_size];
+ uint16 original_id;
+ uint16 error;
+ uint16 other_size;
+ uint8 other_data[other_size];
+ } dns_tsig_record;
+
+ typedef [flag(NDR_NO_COMP|NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ dns_string name;
+ dns_qclass rr_class;
+ uint32 ttl;
+ dns_string algorithm_name;
+ uint16 time_prefix; /* 0 until February 2106*/
+ uint32 time;
+ uint16 fudge;
+ uint16 error;
+ uint16 other_size;
+ uint8 other_data[other_size];
+ } dns_fake_tsig_rec;
+
+ typedef [nodiscriminant,public,flag(NDR_NOALIGN)] union {
+ [case(DNS_QTYPE_A)] ipv4address ipv4_record;
+ [case(DNS_QTYPE_NS)] dns_string ns_record;
+ [case(DNS_QTYPE_CNAME)] dns_string cname_record;
+ [case(DNS_QTYPE_SOA)] dns_soa_record soa_record;
+ [case(DNS_QTYPE_PTR)] dns_string ptr_record;
+ [case(DNS_QTYPE_HINFO)] dnsp_hinfo hinfo_record;
+ [case(DNS_QTYPE_MX)] dns_mx_record mx_record;
+ [case(DNS_QTYPE_TXT)] dns_txt_record txt_record;
+ [case(DNS_QTYPE_RP)] dns_rp_record rp_record;
+ [case(DNS_QTYPE_AAAA)] ipv6address ipv6_record;
+ [case(DNS_QTYPE_SRV)] dns_srv_record srv_record;
+ [case(DNS_QTYPE_OPT)] dns_opt_record opt_record;
+ [case(DNS_QTYPE_TSIG)] dns_tsig_record tsig_record;
+ [case(DNS_QTYPE_TKEY)] dns_tkey_record tkey_record;
+ [default];
+ } dns_rdata;
+
+ typedef [flag(LIBNDR_PRINT_ARRAY_HEX|NDR_NOALIGN),nopush,nopull] struct {
+ dns_string name;
+ dns_qtype rr_type;
+ dns_qclass rr_class;
+ uint32 ttl;
+ uint16 length; /* Should be set to either UINT16_MAX or 0 */
+ [switch_is(rr_type)] dns_rdata rdata;
+ DATA_BLOB unexpected;
+ } dns_res_rec;
+
+ typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ uint16 id;
+ dns_operation operation;
+ uint16 qdcount;
+ uint16 ancount;
+ uint16 nscount;
+ uint16 arcount;
+ dns_name_question questions[qdcount];
+ dns_res_rec answers[ancount];
+ dns_res_rec nsrecs[nscount];
+ dns_res_rec additional[arcount];
+ } dns_name_packet;
+
+ /*
+ this is a convenience hook for ndrdump
+ */
+ [nopython] void decode_dns_name_packet(
+ [in] dns_name_packet packet
+ );
+}
diff --git a/librpc/idl/dnsp.idl b/librpc/idl/dnsp.idl
new file mode 100644
index 0000000..0cb18bf
--- /dev/null
+++ b/librpc/idl/dnsp.idl
@@ -0,0 +1,293 @@
+#include "idl_types.h"
+
+/*
+ IDL structures for DNSP structures
+
+ See [MS-DNSP].pdf in MCPP for details
+*/
+
+import "misc.idl";
+
+/*
+ note that this is not a real RPC interface. We are just using PIDL
+ to save us a lot of tedious hand parsing of the dnsRecord
+ attribute. The uuid is randomly generated.
+ */
+[
+ uuid("bdd66e9e-d45f-4202-85c0-6132edc4f30a"),
+ version(0.0),
+ pointer_default(unique),
+ helper("../librpc/ndr/ndr_dnsp.h"),
+ helpstring("DNSP interfaces")
+]
+
+interface dnsp
+{
+ typedef [enum16bit,public] enum {
+ DNS_TYPE_TOMBSTONE = 0x0,
+ DNS_TYPE_A = 0x1,
+ DNS_TYPE_NS = 0x2,
+ DNS_TYPE_MD = 0x3,
+ DNS_TYPE_MF = 0x4,
+ DNS_TYPE_CNAME = 0x5,
+ DNS_TYPE_SOA = 0x6,
+ DNS_TYPE_MB = 0x7,
+ DNS_TYPE_MG = 0x8,
+ DNS_TYPE_MR = 0x9,
+ DNS_TYPE_NULL = 0xA,
+ DNS_TYPE_WKS = 0xB,
+ DNS_TYPE_PTR = 0xC,
+ DNS_TYPE_HINFO = 0xD,
+ DNS_TYPE_MINFO = 0xE,
+ DNS_TYPE_MX = 0xF,
+ DNS_TYPE_TXT = 0x10,
+ DNS_TYPE_RP = 0x11,
+ DNS_TYPE_AFSDB = 0x12,
+ DNS_TYPE_X25 = 0x13,
+ DNS_TYPE_ISDN = 0x14,
+ DNS_TYPE_RT = 0x15,
+ DNS_TYPE_SIG = 0x18,
+ DNS_TYPE_KEY = 0x19,
+ DNS_TYPE_AAAA = 0x1C,
+ DNS_TYPE_LOC = 0x1D,
+ DNS_TYPE_NXT = 0x1E,
+ DNS_TYPE_SRV = 0x21,
+ DNS_TYPE_ATMA = 0x22,
+ DNS_TYPE_NAPTR = 0x23,
+ DNS_TYPE_CERT = 0x25,
+ DNS_TYPE_DNAME = 0x27,
+ DNS_TYPE_DS = 0x2B,
+ DNS_TYPE_SSHFP = 0x2C,
+ DNS_TYPE_IPSECKEY = 0x2D,
+ DNS_TYPE_RRSIG = 0x2E,
+ DNS_TYPE_NSEC = 0x2F,
+ DNS_TYPE_DNSKEY= 0x30,
+ DNS_TYPE_DHCID = 0x31,
+ DNS_TYPE_NSEC3 = 0x32,
+ DNS_TYPE_NSEC3PARAM = 0x33,
+ DNS_TYPE_TLSA = 0x34,
+ DNS_TYPE_CDS = 0x3B,
+ DNS_TYPE_CDNSKEY = 0x3C,
+ DNS_TYPE_SVCB = 0x40,
+ DNS_TYPE_HTTPS = 0x41,
+ DNS_TYPE_ALL = 0xFF,
+ DNS_TYPE_URI = 0x100,
+ DNS_TYPE_CAA = 0x101,
+ DNS_TYPE_WINS = 0xFF01,
+ DNS_TYPE_WINSR = 0xFF02
+ } dns_record_type;
+
+ typedef [bitmap32bit] bitmap {
+ DNS_RPC_FLAG_SUPPRESS_NOTIFY = 0x00010000,
+ DNS_RPC_FLAG_AGING_ON = 0x00020000,
+ DNS_RPC_FLAG_OPEN_ACL = 0x00040000,
+ DNS_RPC_FLAG_RECORD_WIRE_FORMAT = 0x00100000,
+ DNS_RPC_FLAG_SUPPRESS_RECORD_UPDATE_PTR = 0x00200000,
+ DNS_RPC_FLAG_NODE_COMPLETE = 0x00800000,
+ DNS_RPC_FLAG_NODE_STICKY = 0x01000000,
+ DNS_RPC_FLAG_RECORD_CREATE_PTR = 0x02000000,
+ DNS_RPC_FLAG_RECORD_TTL_CHANGE = 0x04000000,
+ DNS_RPC_FLAG_RECORD_DEFAULT_TTL = 0x08000000,
+ DNS_RPC_FLAG_ZONE_DELEGATION = 0x10000000,
+ DNS_RPC_FLAG_AUTH_ZONE_ROOT = 0x20000000,
+ DNS_RPC_FLAG_ZONE_ROOT = 0x40000000,
+ DNS_RPC_FLAG_CACHE_DATA = 0x80000000
+ }
+ dns_rpc_node_flags;
+
+
+ typedef [enum8bit] enum {
+ DNS_RANK_NONE = 0x00,
+ DNS_RANK_CACHE_BIT = 0x01,
+ DNS_RANK_ROOT_HINT = 0x08,
+ DNS_RANK_OUTSIDE_GLUE = 0x20,
+ DNS_RANK_CACHE_NA_ADDITIONAL = 0x31,
+ DNS_RANK_CACHE_NA_AUTHORITY = 0x41,
+ DNS_RANK_CACHE_A_ADDITIONAL = 0x51,
+ DNS_RANK_CACHE_NA_ANSWER = 0x61,
+ DNS_RANK_CACHE_A_AUTHORITY = 0x71,
+ DNS_RANK_GLUE = 0x80,
+ DNS_RANK_NS_GLUE = 0x82,
+ DNS_RANK_CACHE_A_ANSWER = 0xc1,
+ DNS_RANK_ZONE = 0xf0
+ } dns_record_rank;
+
+ typedef [v1_enum] enum {
+ DNS_ZONE_TYPE_CACHE = 0x00,
+ DNS_ZONE_TYPE_PRIMARY = 0x01,
+ DNS_ZONE_TYPE_SECONDARY = 0x02,
+ DNS_ZONE_TYPE_STUB = 0x03,
+ DNS_ZONE_TYPE_FORWARDER = 0x04,
+ DNS_ZONE_TYPE_SECONDARY_CACHE = 0x05
+ } dns_zone_type;
+
+ typedef [public,enum8bit] enum {
+ DNS_ZONE_UPDATE_OFF = 0x00,
+ DNS_ZONE_UPDATE_UNSECURE = 0x01,
+ DNS_ZONE_UPDATE_SECURE = 0x02
+ } dns_zone_update;
+
+ typedef [v1_enum] enum {
+ DSPROPERTY_ZONE_EMPTY = 0x00,
+ DSPROPERTY_ZONE_TYPE = 0x01,
+ DSPROPERTY_ZONE_ALLOW_UPDATE = 0x02,
+ DSPROPERTY_ZONE_SECURE_TIME = 0x08,
+ DSPROPERTY_ZONE_NOREFRESH_INTERVAL = 0x10,
+ DSPROPERTY_ZONE_SCAVENGING_SERVERS = 0x11,
+ DSPROPERTY_ZONE_AGING_ENABLED_TIME = 0x12,
+ DSPROPERTY_ZONE_REFRESH_INTERVAL = 0x20,
+ DSPROPERTY_ZONE_AGING_STATE = 0x40,
+ DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME = 0x80,
+ DSPROPERTY_ZONE_MASTER_SERVERS = 0x81,
+ DSPROPERTY_ZONE_AUTO_NS_SERVERS = 0x82,
+ DSPROPERTY_ZONE_DCPROMO_CONVERT = 0x83,
+ DSPROPERTY_ZONE_SCAVENGING_SERVERS_DA = 0x90,
+ DSPROPERTY_ZONE_MASTER_SERVERS_DA = 0x91,
+ DSPROPERTY_ZONE_NS_SERVERS_DA = 0x92,
+ DSPROPERTY_ZONE_NODE_DBFLAGS = 0x100
+
+ } dns_property_id;
+
+ typedef [enum8bit] enum {
+ DCPROMO_CONVERT_NONE = 0x00,
+ DCPROMO_CONVERT_DOMAIN = 0x01,
+ DCPROMO_CONVERT_FOREST = 0x02
+ } dns_dcpromo_flag;
+
+ typedef [public] struct {
+ uint32 serial;
+ uint32 refresh;
+ uint32 retry;
+ uint32 expire;
+ uint32 minimum;
+ dnsp_name mname;
+ dnsp_name rname;
+ } dnsp_soa;
+
+ typedef [public] struct {
+ uint16 wPriority;
+ dnsp_name nameTarget;
+ } dnsp_mx;
+
+ typedef [public] struct {
+ dnsp_string cpu;
+ dnsp_string os;
+ } dnsp_hinfo;
+
+ typedef [public] struct {
+ uint16 wPriority;
+ uint16 wWeight;
+ uint16 wPort;
+ dnsp_name nameTarget;
+ } dnsp_srv;
+
+ typedef struct {
+ uint32 addrCount;
+ uint32 addrArray[addrCount];
+ } dnsp_ip4_array;
+
+ typedef struct {
+ uint16 family;
+ [flag(NDR_BIG_ENDIAN)] uint16 port;
+ [flag(NDR_BIG_ENDIAN)] ipv4address ipv4;
+ ipv6address ipv6;
+ uint8 pad[8];
+ uint32 unused[8];
+ } dnsp_dns_addr;
+
+ typedef [public] struct {
+ uint32 MaxCount;
+ uint32 AddrCount;
+ uint32 Tag;
+ uint16 Family;
+ uint16 Reserved0;
+ uint32 Flags;
+ uint32 MatchFlag;
+ uint32 Reserved1;
+ uint32 Reserved2;
+ dnsp_dns_addr AddrArray[AddrCount];
+ } dnsp_dns_addr_array;
+
+ typedef [public,nopull,nopush,noprint,gensize] struct {
+ uint8 count;
+ dnsp_string str[count];
+ } dnsp_string_list;
+
+ typedef [nodiscriminant,gensize] union {
+ [case(DNS_TYPE_TOMBSTONE)] NTTIME EntombedTime;
+ [case(DNS_TYPE_A)] [flag(NDR_BIG_ENDIAN)] ipv4address ipv4;
+ [case(DNS_TYPE_NS)] dnsp_name ns;
+ [case(DNS_TYPE_CNAME)] dnsp_name cname;
+ [case(DNS_TYPE_SOA)] [flag(NDR_BIG_ENDIAN)] dnsp_soa soa;
+ [case(DNS_TYPE_MX)] [flag(NDR_BIG_ENDIAN)] dnsp_mx mx;
+ [case(DNS_TYPE_TXT)] dnsp_string_list txt;
+ [case(DNS_TYPE_PTR)] dnsp_name ptr;
+ [case(DNS_TYPE_HINFO)] dnsp_hinfo hinfo;
+ [case(DNS_TYPE_AAAA)] ipv6address ipv6;
+ [case(DNS_TYPE_SRV)] [flag(NDR_BIG_ENDIAN)] dnsp_srv srv;
+ [default] [flag(NDR_REMAINING)] DATA_BLOB data;
+ } dnsRecordData;
+
+ /* this is the format for the dnsRecord attribute in the DNS
+ partitions in AD */
+ typedef [public] struct {
+ [value(ndr_size_dnsRecordData(&data,wType,ndr->flags))] uint16 wDataLength;
+ dns_record_type wType;
+ [value(5)] uint8 version;
+ dns_record_rank rank;
+ uint16 flags;
+ uint32 dwSerial;
+ [flag(NDR_BIG_ENDIAN)] uint32 dwTtlSeconds;
+ uint32 dwReserved;
+ uint32 dwTimeStamp;
+ [switch_is(wType)] dnsRecordData data;
+ } dnsp_DnssrvRpcRecord;
+
+ typedef [nodiscriminant,gensize] union {
+ [case(DSPROPERTY_ZONE_EMPTY)] ;
+ [case(DSPROPERTY_ZONE_TYPE)] dns_zone_type zone_type;
+ [case(DSPROPERTY_ZONE_ALLOW_UPDATE)] dns_zone_update allow_update_flag;
+ [case(DSPROPERTY_ZONE_SECURE_TIME)] NTTIME zone_secure_time;
+ [case(DSPROPERTY_ZONE_NOREFRESH_INTERVAL)] uint32 norefresh_hours;
+ [case(DSPROPERTY_ZONE_REFRESH_INTERVAL)] uint32 refresh_hours;
+ [case(DSPROPERTY_ZONE_AGING_STATE)] uint32 aging_enabled;
+ [case(DSPROPERTY_ZONE_SCAVENGING_SERVERS)] dnsp_ip4_array servers;
+ [case(DSPROPERTY_ZONE_AGING_ENABLED_TIME)] uint32 next_scavenging_cycle_hours;
+ [case(DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME)] nstring deleted_by_hostname;
+ [case(DSPROPERTY_ZONE_MASTER_SERVERS)] dnsp_ip4_array master_servers;
+ [case(DSPROPERTY_ZONE_AUTO_NS_SERVERS)] dnsp_ip4_array ns_servers;
+ [case(DSPROPERTY_ZONE_DCPROMO_CONVERT)] dns_dcpromo_flag dcpromo_flag;
+ [case(DSPROPERTY_ZONE_SCAVENGING_SERVERS_DA)] dnsp_dns_addr_array s_ns_servers;
+ [case(DSPROPERTY_ZONE_MASTER_SERVERS_DA)] dnsp_dns_addr_array z_master_servers;
+ [case(DSPROPERTY_ZONE_NS_SERVERS_DA)] dnsp_dns_addr_array d_ns_servers;
+ [case(DSPROPERTY_ZONE_NODE_DBFLAGS)] dns_rpc_node_flags flags;
+ } dnsPropertyData;
+
+ /* this is the format for the dnsProperty attribute in the DNS
+ partitions in AD */
+ typedef [flag(NDR_NOALIGN),public] struct {
+ [value(ndr_size_dnsPropertyData(&data,id,ndr->flags))] uint32 wDataLength;
+ uint32 namelength;
+ [value(0)] uint32 flag;
+ [value(1)] uint32 version;
+ dns_property_id id;
+ [switch_is(id)] dnsPropertyData data;
+ uint32 name;
+ } dnsp_DnsProperty;
+
+ /*
+ * this is the format for the dnsProperty attribute in the DNS
+ * partitions in AD when the wDataLength is 0. This is an
+ * invalid format seen from some Windows servers in the same
+ * domain.
+ */
+ typedef [flag(NDR_NOALIGN),public] struct {
+ [range(0, 0), value(0)] uint32 wDataLength;
+ uint32 namelength;
+ [value(0)] uint32 flag;
+ [value(1)] uint32 version;
+ dns_property_id id;
+ [switch_is(DSPROPERTY_ZONE_EMPTY)] dnsPropertyData data;
+ uint32 name;
+ } dnsp_DnsProperty_short;
+}
diff --git a/librpc/idl/dnsserver.idl b/librpc/idl/dnsserver.idl
new file mode 100644
index 0000000..a6c413a
--- /dev/null
+++ b/librpc/idl/dnsserver.idl
@@ -0,0 +1,1529 @@
+#include "idl_types.h"
+/*
+ dnsserver interface definition
+ for a protocol description see [MS-DNSP].pdf
+*/
+
+import "misc.idl", "dnsp.idl";
+
+[ uuid("50abc2a4-574d-40b3-9d66-ee4fd5fba076"),
+ version(5.0),
+ pointer_default(unique),
+ endpoint("ncacn_ip_tcp:", "ncacn_np:[\\pipe\\dnsserver]"),
+ helper("../librpc/ndr/ndr_dnsserver.h"),
+ helpstring("DNS Management Server")
+] interface dnsserver
+{
+
+#define wchar_t uint16
+#define BOOLEAN boolean8
+#define BOOL boolean32
+#define BYTE uint8
+#define UCHAR uint8
+#define CHAR char
+#define PBYTE BYTE*
+#define DWORD uint32
+#define PDWORD uint32 *
+
+ /* */
+ /* DNS RPC data types */
+ /* */
+
+ typedef [v1_enum] enum {
+ DNS_RPC_USE_TCPIP = 0x00000001,
+ DNS_RPC_USE_NAMED_PIPE = 0x00000002,
+ DNS_RPC_USE_LPC = 0x00000004,
+ DNS_RPC_USE_ALL_PROTOCOLS = 0xFFFFFFFF
+ }
+ DNS_RPC_PROTOCOLS;
+
+ typedef [v1_enum] enum {
+ DNS_CLIENT_VERSION_W2K = 0x00000000,
+ DNS_CLIENT_VERSION_DOTNET = 0x00060000,
+ DNS_CLIENT_VERSION_LONGHORN = 0x00070000
+ }
+ DNS_RPC_CLIENT_VERSION;
+
+ /* Return buffer */
+ typedef struct {
+ DWORD dwLength;
+ [size_is(dwLength)] BYTE Buffer[];
+ } DNS_RPC_BUFFER;
+
+ /* String Array */
+ typedef struct {
+ [range(0,10000)] DWORD dwCount;
+ [size_is(dwCount),string,charset(UTF8)] char * pszStrings[];
+ } DNS_RPC_UTF8_STRING_LIST;
+
+ /* Name and parameter value */
+ typedef struct {
+ DWORD dwParam;
+ [string, charset(UTF8)] char * pszNodeName;
+ }
+ DNS_RPC_NAME_AND_PARAM;
+
+
+ /* */
+ /* DNS Resource Record data types */
+ /* */
+
+ /* DNS_RECORD_TYPE is defined in dnsp.idl as dns_record_type */
+ /* DNS_RPC_NODE_FLAGS is defined in dnsp.idl as dns_rpc_node_flags */
+
+ typedef [public,gensize] struct {
+ [value(strlen(str))] uint8 len;
+ [charset(UNIX)] uint8 str[len];
+ }
+ DNS_RPC_NAME;
+
+ typedef struct {
+ uint16 wLength;
+ uint16 wRecordCount;
+ uint32 dwFlags;
+ uint32 dwChildCount;
+ DNS_RPC_NAME dnsNodeName;
+ }
+ DNS_RPC_NODE;
+
+ typedef struct {
+ uint32 dwSerialNo;
+ uint32 dwRefresh;
+ uint32 dwRetry;
+ uint32 dwExpire;
+ uint32 dwMinimumTtl;
+ DNS_RPC_NAME NamePrimaryServer;
+ DNS_RPC_NAME ZoneAdministratorEmail;
+ }
+ DNS_RPC_RECORD_SOA;
+
+ typedef struct {
+ uint16 wPreference;
+ DNS_RPC_NAME nameExchange;
+ }
+ DNS_RPC_RECORD_NAME_PREFERENCE;
+
+ typedef [nopull,nopush] struct {
+ uint8 count;
+ DNS_RPC_NAME str[count];
+ }
+ DNS_RPC_RECORD_STRING;
+
+ typedef struct {
+ uint16 wPriority;
+ uint16 wWeight;
+ uint16 wPort;
+ DNS_RPC_NAME nameTarget;
+ }
+ DNS_RPC_RECORD_SRV;
+
+ typedef [nodiscriminant,gensize,flag(NDR_NOALIGN)] union {
+ [case(DNS_TYPE_TOMBSTONE)] NTTIME EntombedTime;
+ [case(DNS_TYPE_A)] [flag(NDR_BIG_ENDIAN)] ipv4address ipv4;
+ [case(DNS_TYPE_NS)] DNS_RPC_NAME name;
+ [case(DNS_TYPE_MD)] DNS_RPC_NAME name;
+ [case(DNS_TYPE_MF)] DNS_RPC_NAME name;
+ [case(DNS_TYPE_CNAME)] DNS_RPC_NAME name;
+ [case(DNS_TYPE_SOA)] DNS_RPC_RECORD_SOA soa;
+ [case(DNS_TYPE_MB)] DNS_RPC_NAME name;
+ [case(DNS_TYPE_MG)] DNS_RPC_NAME name;
+ [case(DNS_TYPE_MR)] DNS_RPC_NAME name;
+ [case(DNS_TYPE_PTR)] DNS_RPC_NAME ptr;
+ [case(DNS_TYPE_HINFO)] DNS_RPC_NAME hinfo;
+ [case(DNS_TYPE_MX)] DNS_RPC_RECORD_NAME_PREFERENCE mx;
+ [case(DNS_TYPE_TXT)] DNS_RPC_RECORD_STRING txt;
+ [case(DNS_TYPE_AAAA)] ipv6address ipv6;
+ [case(DNS_TYPE_SRV)] DNS_RPC_RECORD_SRV srv;
+ [case(DNS_TYPE_DNAME)] DNS_RPC_NAME name;
+ }
+ DNS_RPC_RECORD_DATA;
+
+ typedef [public] struct {
+ [value(ndr_size_DNS_RPC_RECORD_DATA(&data,wType,0))] uint16 wDataLength;
+ dns_record_type wType;
+ DWORD dwFlags;
+ DWORD dwSerial;
+ DWORD dwTtlSeconds;
+ DWORD dwTimeStamp;
+ DWORD dwReserved;
+ [subcontext(0),subcontext_size(wDataLength),switch_is(wType)] DNS_RPC_RECORD_DATA data;
+ }
+ DNS_RPC_RECORD;
+
+ typedef struct {
+ [value(ndr_size_DNS_RPC_RECORD_DATA(&rec.data,rec.wType,0))] uint3264 wContextLength;
+ DNS_RPC_RECORD rec;
+ }
+ DNS_RPC_RECORD_BUF;
+
+
+ /* */
+ /* DNS Address Information data types */
+ /* */
+
+ typedef [v1_enum] enum {
+ DNS_IPVAL_DNS_SERVERS = 0x00,
+ DNS_IPVAL_DNS_ROOTHINTS = 0x01,
+ DNS_IPVAL_DNS_FORWARDERS = 0x02,
+ DNS_IPVAL_DNS_ZONE_MASTERS = 0x03,
+ DNS_IPVAL_DNS_DELEGATIONS = 0x04
+ }
+ DNS_IPVAL_CONTEXT;
+
+ typedef [v1_enum] enum {
+ ERROR_SUCCESS = 0x00,
+ DNS_IPVAL_INVALID_ADDR = 0x01,
+ DNS_IPVAL_UNREACHABLE = 0x02,
+ DNS_IPVAL_NO_RESPONSE = 0x03,
+ DNS_IPVAL_NOT_AUTH_FOR_ZONE = 0x04,
+ DNS_IPVAL_UNKNOWN_ERROR = 0xFF,
+ DNS_IPVAL_NO_TCP = 0x80000000
+ }
+ DNS_IP_VALIDATE_RETURN_FLAGS;
+
+ typedef struct {
+ DWORD AddrCount;
+ [size_is( AddrCount )] DWORD AddrArray[];
+ } IP4_ARRAY;
+#define PIP4_ARRAY IP4_ARRAY*
+
+ typedef struct {
+ CHAR MaxSa[32];
+ DWORD DnsAddrUserDword[8];
+ } DNS_ADDR;
+
+ typedef struct {
+ DWORD MaxCount;
+ DWORD AddrCount;
+ DWORD Tag;
+ WORD Family;
+ WORD WordReserved;
+ DWORD Flags;
+ DWORD MatchFlag;
+ DWORD Reserved1;
+ DWORD Reserved2;
+ [size_is( AddrCount )] DNS_ADDR AddrArray[];
+ } DNS_ADDR_ARRAY;
+#define PDNS_ADDR_ARRAY DNS_ADDR_ARRAY*
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+ DWORD dwContext;
+ DWORD dwReserved1;
+ [string, charset(UTF8)] char * pszContextName;
+ PDNS_ADDR_ARRAY aipValidateAddrs;
+ }
+ DNS_RPC_IP_VALIDATE;
+
+
+ /* */
+ /* DNS Server data types */
+ /* */
+
+ typedef [enum8bit] enum {
+ DNS_BOOT_METHOD_UNINITIALIZED = 0x00,
+ DNS_BOOT_METHOD_FILE = 0x01,
+ DNS_BOOT_METHOD_REGISTRY = 0x02,
+ DNS_BOOT_METHOD_DIRECTORY = 0x03
+ }
+ DNS_BOOT_METHOD;
+
+ typedef [v1_enum] enum {
+ DNS_ALLOW_RFC_NAMES_ONLY = 0x00,
+ DNS_ALLOW_NONRFC_NAMES = 0x01,
+ DNS_ALLOW_MULTIBYTE_NAMES = 0x02,
+ DNS_ALLOW_ALL_NAMES = 0x03
+ }
+ DNS_NAME_CHECK_FLAG;
+
+ typedef struct {
+ /* version */
+ /* basic configuration flags */
+
+ DWORD dwVersion;
+ DNS_BOOT_METHOD fBootMethod;
+ BOOLEAN fAdminConfigured;
+ BOOLEAN fAllowUpdate;
+ BOOLEAN fDsAvailable;
+
+ /* pointer section */
+
+ [string, charset(UTF8)] char * pszServerName;
+
+ /* DS container */
+
+ [string, charset(UTF16)] wchar_t * pszDsContainer;
+
+ /* IP interfaces */
+
+ PIP4_ARRAY aipServerAddrs;
+ PIP4_ARRAY aipListenAddrs;
+
+ /* forwarders */
+
+ PIP4_ARRAY aipForwarders;
+
+ /* future extensions */
+
+ PDWORD pExtension1;
+ PDWORD pExtension2;
+ PDWORD pExtension3;
+ PDWORD pExtension4;
+ PDWORD pExtension5;
+
+ /* DWORD section */
+
+ /* logging */
+
+ DWORD dwLogLevel;
+ DWORD dwDebugLevel;
+
+ /* configuration DWORDs */
+
+ DWORD dwForwardTimeout;
+ DWORD dwRpcProtocol;
+ DNS_NAME_CHECK_FLAG dwNameCheckFlag;
+ DWORD cAddressAnswerLimit;
+ DWORD dwRecursionRetry;
+ DWORD dwRecursionTimeout;
+ DWORD dwMaxCacheTtl;
+ DWORD dwDsPollingInterval;
+
+ /* aging / scavenging */
+
+ DWORD dwScavengingInterval;
+ DWORD dwDefaultRefreshInterval;
+ DWORD dwDefaultNoRefreshInterval;
+
+ DWORD dwReserveArray[10];
+
+ /* BYTE section */
+
+ /* configuration flags */
+
+ BOOLEAN fAutoReverseZones;
+ BOOLEAN fAutoCacheUpdate;
+
+ /* recursion control */
+
+ BOOLEAN fRecurseAfterForwarding;
+ BOOLEAN fForwardDelegations;
+ BOOLEAN fNoRecursion;
+ BOOLEAN fSecureResponses;
+
+ /* lookup control */
+
+ BOOLEAN fRoundRobin;
+ BOOLEAN fLocalNetPriority;
+
+ /* BIND compatibility and mimicking */
+
+ BOOLEAN fBindSecondaries;
+ BOOLEAN fWriteAuthorityNs;
+
+ /* Bells and whistles */
+
+ BOOLEAN fStrictFileParsing;
+ BOOLEAN fLooseWildcarding;
+
+ /* aging / scavenging */
+
+ BOOLEAN fDefaultAgingState;
+ BOOLEAN fReserveArray[15];
+ }
+ DNS_RPC_SERVER_INFO_W2K;
+
+ typedef struct {
+ [string, charset(UTF8)] uint8 *extension;
+ } DNS_EXTENSION;
+
+ typedef [public] struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ /* basic configuration flags */
+
+ DWORD dwVersion;
+ DNS_BOOT_METHOD fBootMethod;
+ BOOLEAN fAdminConfigured;
+ BOOLEAN fAllowUpdate;
+ BOOLEAN fDsAvailable;
+
+ /* pointer section */
+
+ [string, charset(UTF8)] char * pszServerName;
+
+ /* DS container */
+
+ [string, charset(UTF16)] wchar_t * pszDsContainer;
+
+ /* IP interfaces */
+
+ PIP4_ARRAY aipServerAddrs;
+ PIP4_ARRAY aipListenAddrs;
+
+ /* forwarders */
+
+ PIP4_ARRAY aipForwarders;
+
+ /* logging */
+
+ PIP4_ARRAY aipLogFilter;
+ [string, charset(UTF16)] wchar_t * pwszLogFilePath;
+
+ /* Server domain/forest */
+
+ [string, charset(UTF8)] char * pszDomainName; /* UTF-8 FQDN */
+ [string, charset(UTF8)] char * pszForestName; /* UTF-8 FQDN */
+
+ /* Built-in directory partitions */
+
+ [string, charset(UTF8)] char * pszDomainDirectoryPartition; /* UTF-8 FQDN */
+ [string, charset(UTF8)] char * pszForestDirectoryPartition; /* UTF-8 FQDN */
+
+ /* future extensions */
+ DNS_EXTENSION pExtensions[6];
+
+ /* DWORD section */
+
+ /* logging */
+
+ DWORD dwLogLevel;
+ DWORD dwDebugLevel;
+
+ /* configuration DWORDs */
+
+ DWORD dwForwardTimeout;
+ DWORD dwRpcProtocol;
+ DNS_NAME_CHECK_FLAG dwNameCheckFlag;
+ DWORD cAddressAnswerLimit;
+ DWORD dwRecursionRetry;
+ DWORD dwRecursionTimeout;
+ DWORD dwMaxCacheTtl;
+ DWORD dwDsPollingInterval;
+ DWORD dwLocalNetPriorityNetMask;
+
+ /* aging and scavenging */
+
+ DWORD dwScavengingInterval;
+ DWORD dwDefaultRefreshInterval;
+ DWORD dwDefaultNoRefreshInterval;
+ DWORD dwLastScavengeTime;
+
+ /* more logging */
+
+ DWORD dwEventLogLevel;
+ DWORD dwLogFileMaxSize;
+
+ /* Active Directory information */
+
+ DWORD dwDsForestVersion;
+ DWORD dwDsDomainVersion;
+ DWORD dwDsDsaVersion;
+
+ DWORD dwReserveArray[ 4 ];
+
+ /* BYTE section */
+
+ /* configuration flags */
+
+ BOOLEAN fAutoReverseZones;
+ BOOLEAN fAutoCacheUpdate;
+
+ /* recursion control */
+
+ BOOLEAN fRecurseAfterForwarding;
+ BOOLEAN fForwardDelegations;
+ BOOLEAN fNoRecursion;
+ BOOLEAN fSecureResponses;
+
+ /* lookup control */
+
+ BOOLEAN fRoundRobin;
+ BOOLEAN fLocalNetPriority;
+
+ /* BIND compatibility and mimicking */
+
+ BOOLEAN fBindSecondaries;
+ BOOLEAN fWriteAuthorityNs;
+
+ /* Bells and whistles */
+
+ BOOLEAN fStrictFileParsing;
+ BOOLEAN fLooseWildcarding;
+
+ /* aging \ scavenging */
+
+ BOOLEAN fDefaultAgingState;
+
+ BOOLEAN fReserveArray[ 15 ];
+ }
+ DNS_RPC_SERVER_INFO_DOTNET;
+
+ typedef [public] struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ /* basic configuration flags */
+
+ DWORD dwVersion;
+ DNS_BOOT_METHOD fBootMethod;
+ BOOLEAN fAdminConfigured;
+ BOOLEAN fAllowUpdate;
+ BOOLEAN fDsAvailable;
+
+ /* pointer section */
+
+ [string, charset(UTF8)] char * pszServerName;
+
+ /* DS container */
+
+ [string, charset(UTF16)] wchar_t * pszDsContainer;
+
+ /* IP interfaces */
+
+ PDNS_ADDR_ARRAY aipServerAddrs;
+ PDNS_ADDR_ARRAY aipListenAddrs;
+
+ /* forwarders */
+
+ PDNS_ADDR_ARRAY aipForwarders;
+
+ /* logging */
+
+ PDNS_ADDR_ARRAY aipLogFilter;
+ [string, charset(UTF16)] wchar_t * pwszLogFilePath;
+
+ /* Server domain/forest */
+
+ [string, charset(UTF8)] char * pszDomainName; /* UTF-8 FQDN */
+ [string, charset(UTF8)] char * pszForestName; /* UTF-8 FQDN */
+
+ /* Built-in directory partitions */
+
+ [string, charset(UTF8)] char * pszDomainDirectoryPartition; /* UTF-8 FQDN */
+ [string, charset(UTF8)] char * pszForestDirectoryPartition; /* UTF-8 FQDN */
+
+ /* future extensions */
+ DNS_EXTENSION pExtensions[6];
+
+ /* DWORD section */
+
+ /* logging */
+
+ DWORD dwLogLevel;
+ DWORD dwDebugLevel;
+
+ /* configuration DWORDs */
+
+ DWORD dwForwardTimeout;
+ DWORD dwRpcProtocol;
+ DNS_NAME_CHECK_FLAG dwNameCheckFlag;
+ DWORD cAddressAnswerLimit;
+ DWORD dwRecursionRetry;
+ DWORD dwRecursionTimeout;
+ DWORD dwMaxCacheTtl;
+ DWORD dwDsPollingInterval;
+ DWORD dwLocalNetPriorityNetMask;
+
+ /* aging and scavenging */
+
+ DWORD dwScavengingInterval;
+ DWORD dwDefaultRefreshInterval;
+ DWORD dwDefaultNoRefreshInterval;
+ DWORD dwLastScavengeTime;
+
+ /* more logging */
+
+ DWORD dwEventLogLevel;
+ DWORD dwLogFileMaxSize;
+
+ /* Active Directory information */
+
+ DWORD dwDsForestVersion;
+ DWORD dwDsDomainVersion;
+ DWORD dwDsDsaVersion;
+ BOOLEAN fReadOnlyDC;
+
+ DWORD dwReserveArray[ 3 ];
+
+ /* BYTE section */
+
+ /* configuration flags */
+
+ BOOLEAN fAutoReverseZones;
+ BOOLEAN fAutoCacheUpdate;
+
+ /* recursion control */
+
+ BOOLEAN fRecurseAfterForwarding;
+ BOOLEAN fForwardDelegations;
+ BOOLEAN fNoRecursion;
+ BOOLEAN fSecureResponses;
+
+ /* lookup control */
+
+ BOOLEAN fRoundRobin;
+ BOOLEAN fLocalNetPriority;
+
+ /* BIND compatibility and mimicking */
+
+ BOOLEAN fBindSecondaries;
+ BOOLEAN fWriteAuthorityNs;
+
+ /* Bells and whistles */
+
+ BOOLEAN fStrictFileParsing;
+ BOOLEAN fLooseWildcarding;
+
+ /* aging \ scavenging */
+
+ BOOLEAN fDefaultAgingState;
+
+ BOOLEAN fReserveArray[ 15 ];
+ }
+ DNS_RPC_SERVER_INFO_LONGHORN;
+#define DNS_RPC_SERVER_INFO DNS_RPC_SERVER_INFO_LONGHORN
+
+
+ /* */
+ /* DNS Application directory partition data types */
+ /* */
+
+ typedef [bitmap32bit] bitmap {
+ DNS_DP_AUTOCREATED = 0x00000001,
+ DNS_DP_LEGACY = 0x00000002,
+ DNS_DP_DOMAIN_DEFAULT = 0x00000004,
+ DNS_DP_FOREST_DEFAULT = 0x00000008,
+ DNS_DP_ENLISTED = 0x00000010,
+ DNS_DP_DELETED = 0x00000020
+ }
+ DNS_RPC_DP_FLAGS;
+
+ typedef struct {
+ [string, charset(UTF16)] wchar_t * pszReplicaDn;
+ }
+ DNS_RPC_DP_REPLICA;
+#define PDNS_RPC_DP_REPLICA DNS_RPC_DP_REPLICA*
+
+ typedef [v1_enum] enum {
+ DNS_DP_OKAY = 0x00,
+ DNS_DP_STATE_REPL_INCOMING = 0x01,
+ DNS_DP_STATE_REPL_OUTGOING = 0x02,
+ DNS_DP_STATE_UNKNOWN = 0x03
+ } DNS_DP_STATE;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ [string, charset(UTF8)] char * pszDpFqdn;
+ [string, charset(UTF16)] wchar_t * pszDpDn;
+ [string, charset(UTF16)] wchar_t * pszCrDn;
+ DWORD dwFlags;
+ DWORD dwZoneCount;
+ DNS_DP_STATE dwState;
+
+ DWORD dwReserved[ 3 ];
+ DNS_EXTENSION pwszReserved[ 3 ];
+ [range(0,10000)] DWORD dwReplicaCount;
+ [size_is(dwReplicaCount)] PDNS_RPC_DP_REPLICA ReplicaArray[];
+ }
+ DNS_RPC_DP_INFO;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ [string, charset(UTF8)] char * pszDpFqdn;
+ DWORD dwFlags;
+ DWORD dwZoneCount;
+ }
+ DNS_RPC_DP_ENUM;
+#define PDNS_RPC_DP_ENUM DNS_RPC_DP_ENUM*
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+ [range(0,5000)] DWORD dwDpCount;
+ [size_is(dwDpCount)] PDNS_RPC_DP_ENUM DpArray[];
+ }
+ DNS_RPC_DP_LIST;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+ [string, charset(UTF8)] char * pszDpFqdn; /* UTF8 */
+ DWORD dwOperation;
+ }
+ DNS_RPC_ENLIST_DP;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+ [string, charset(UTF8)] char * pszDestPartition;
+ }
+ DNS_RPC_ZONE_CHANGE_DP;
+
+
+ /* */
+ /* DNS Zone data types */
+ /* */
+
+ /* DNS_ZONE_TYPE defined in dnsp as dns_zone_type */
+
+ typedef [v1_enum] enum {
+ DNS_ZONE_SECSECURE_NO_SECURITY = 0x00,
+ DNS_ZONE_SECSECURE_NS_ONLY = 0x01,
+ DNS_ZONE_SECSECURE_LIST_ONLY = 0x02,
+ DNS_ZONE_SECSECURE_NO_XFER = 0x03
+ }
+ DNS_ZONE_SECONDARY_SECURITY;
+
+ typedef [v1_enum] enum {
+ DNS_ZONE_NOTIFY_OFF = 0x00,
+ DNS_ZONE_NOTIFY_ALL_SECONDARIES = 0x01,
+ DNS_ZONE_NOTIFY_LIST_ONLY = 0x02
+ }
+ DNS_ZONE_NOTIFY_LEVEL;
+
+ typedef [v1_enum] enum {
+ DNS_ZONE_REQUEST_PRIMARY = 0x00000001,
+ DNS_ZONE_REQUEST_SECONDARY = 0x00000002,
+ DNS_ZONE_REQUEST_CACHE = 0x00000004,
+ DNS_ZONE_REQUEST_AUTO = 0x00000008,
+ DNS_ZONE_REQUEST_FORWARD = 0x00000010,
+ DNS_ZONE_REQUEST_REVERSE = 0x00000020,
+ DNS_ZONE_REQUEST_FORWARDER = 0x00000040,
+ DNS_ZONE_REQUEST_STUB = 0x00000080,
+ DNS_ZONE_REQUEST_DS = 0x00000100,
+ DNS_ZONE_REQUEST_NON_DS = 0x00000200,
+ DNS_ZONE_REQUEST_DOMAIN_DP = 0x00000400,
+ DNS_ZONE_REQUEST_FOREST_DP = 0x00000800,
+ DNS_ZONE_REQUEST_CUSTOM_DP = 0x00001000,
+ DNS_ZONE_REQUEST_LEGACY_DP = 0x00002000
+ }
+ DNS_ZONE_REQUEST_FILTERS;
+
+ typedef [bitmap32bit] bitmap {
+ DNS_RPC_ZONE_PAUSED = 0x0001,
+ DNS_RPC_ZONE_SHUTDOWN = 0x0002,
+ DNS_RPC_ZONE_REVERSE = 0x0004,
+ DNS_RPC_ZONE_AUTOCREATED = 0x0008,
+ DNS_RPC_ZONE_DSINTEGRATED = 0x0010,
+ DNS_RPC_ZONE_AGING = 0x0020,
+ DNS_RPC_ZONE_UPDATE_UNSECURE = 0x0040,
+ DNS_RPC_ZONE_UPDATE_SECURE = 0x0080,
+ DNS_RPC_ZONE_READONLY = 0x0100
+ } DNS_RPC_ZONE_FLAGS;
+
+ typedef struct {
+ [string, charset(UTF16)] uint16 * pszZoneName;
+ DNS_RPC_ZONE_FLAGS Flags;
+ UCHAR ZoneType;
+ UCHAR Version;
+ }
+ DNS_RPC_ZONE_W2K;
+#define PDNS_RPC_ZONE_W2K DNS_RPC_ZONE_W2K*
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+ [string, charset(UTF16)] wchar_t * pszZoneName;
+ DNS_RPC_ZONE_FLAGS Flags;
+ UCHAR ZoneType;
+ UCHAR Version;
+ DNS_RPC_DP_FLAGS dwDpFlags;
+ [string, charset(UTF8)] char * pszDpFqdn;
+ }
+ DNS_RPC_ZONE_DOTNET;
+#define DNS_RPC_ZONE DNS_RPC_ZONE_DOTNET
+#define PDNS_RPC_ZONE_DOTNET DNS_RPC_ZONE_DOTNET*
+
+ /* Zone enumeration */
+ typedef struct {
+ [range(0,500000)] DWORD dwZoneCount;
+ [size_is(dwZoneCount)] PDNS_RPC_ZONE_W2K ZoneArray[];
+ }
+ DNS_RPC_ZONE_LIST_W2K;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+ [range(0,500000)] DWORD dwZoneCount;
+ [size_is(dwZoneCount)] PDNS_RPC_ZONE_DOTNET ZoneArray[];
+ }
+ DNS_RPC_ZONE_LIST_DOTNET;
+#define DNS_RPC_ZONE_LIST DNS_RPC_ZONE_LIST_DOTNET
+
+ /* Zone information */
+ typedef struct {
+ [string, charset(UTF8)] char * pszZoneName;
+ DWORD dwZoneType;
+ BOOL fReverse;
+ dns_zone_update fAllowUpdate;
+ DWORD fPaused;
+ DWORD fShutdown;
+ DWORD fAutoCreated;
+
+ /* Database info */
+ DWORD fUseDatabase;
+ [string, charset(UTF8)] char * pszDataFile;
+
+ /* Masters */
+ PIP4_ARRAY aipMasters;
+
+ /* Secondaries */
+ DNS_ZONE_SECONDARY_SECURITY fSecureSecondaries;
+ DNS_ZONE_NOTIFY_LEVEL fNotifyLevel;
+ PIP4_ARRAY aipSecondaries;
+ PIP4_ARRAY aipNotify;
+
+ /* WINS or NetBIOS lookup */
+ BOOL fUseWins;
+ BOOL fUseNbstat;
+
+ /* Aging */
+ BOOL fAging;
+ DWORD dwNoRefreshInterval;
+ DWORD dwRefreshInterval;
+ DWORD dwAvailForScavengeTime;
+ PIP4_ARRAY aipScavengeServers;
+
+ /* save some space, just in case */
+ /* avoid versioning issues if possible */
+ DWORD pvReserved1;
+ DWORD pvReserved2;
+ DWORD pvReserved3;
+ DWORD pvReserved4;
+ }
+ DNS_RPC_ZONE_INFO_W2K;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ [string, charset(UTF8)] char * pszZoneName;
+ DWORD dwZoneType;
+ BOOL fReverse;
+ dns_zone_update fAllowUpdate;
+ DWORD fPaused;
+ DWORD fShutdown;
+ DWORD fAutoCreated;
+
+ /* Database info */
+ DWORD fUseDatabase;
+ [string, charset(UTF8)] char * pszDataFile;
+
+ /* Masters */
+ PIP4_ARRAY aipMasters;
+
+ /* Secondaries */
+ DNS_ZONE_SECONDARY_SECURITY fSecureSecondaries;
+ DNS_ZONE_NOTIFY_LEVEL fNotifyLevel;
+ PIP4_ARRAY aipSecondaries;
+ PIP4_ARRAY aipNotify;
+
+ /* WINS or NetBIOS lookup */
+ BOOL fUseWins;
+ BOOL fUseNbstat;
+
+ /* Aging */
+ BOOL fAging;
+ DWORD dwNoRefreshInterval;
+ DWORD dwRefreshInterval;
+ DWORD dwAvailForScavengeTime;
+ PIP4_ARRAY aipScavengeServers;
+
+ /* Forwarder zones */
+ DWORD dwForwarderTimeout;
+ DWORD fForwarderSlave;
+
+ /* Stub zones */
+ PIP4_ARRAY aipLocalMasters;
+
+ /* Directory partition */
+ DWORD dwDpFlags;
+ [string, charset(UTF8)] char * pszDpFqdn;
+ [string, charset(UTF16)] wchar_t * pwszZoneDn;
+
+ /* Xfr time information */
+ DWORD dwLastSuccessfulSoaCheck;
+ DWORD dwLastSuccessfulXfr;
+
+ /* save some space, just in case */
+ DWORD dwReserved1;
+ DWORD dwReserved2;
+ DWORD dwReserved3;
+ DWORD dwReserved4;
+ DWORD dwReserved5;
+ [string, charset(UTF8)] char * pReserved1;
+ [string, charset(UTF8)] char * pReserved2;
+ [string, charset(UTF8)] char * pReserved3;
+ [string, charset(UTF8)] char * pReserved4;
+ }
+ DNS_RPC_ZONE_INFO_DOTNET;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ [string, charset(UTF8)] char * pszZoneName;
+ DWORD dwZoneType;
+ BOOL fReverse;
+ dns_zone_update fAllowUpdate;
+ DWORD fPaused;
+ DWORD fShutdown;
+ DWORD fAutoCreated;
+
+ /* Database info */
+ DWORD fUseDatabase;
+ [string, charset(UTF8)] char * pszDataFile;
+
+ /* Masters */
+ PDNS_ADDR_ARRAY aipMasters;
+
+ /* Secondaries */
+ DNS_ZONE_SECONDARY_SECURITY fSecureSecondaries;
+ DNS_ZONE_NOTIFY_LEVEL fNotifyLevel;
+ PDNS_ADDR_ARRAY aipSecondaries;
+ PDNS_ADDR_ARRAY aipNotify;
+
+ /* WINS or NetBIOS lookup */
+ BOOL fUseWins;
+ BOOL fUseNbstat;
+
+ /* Aging */
+ BOOL fAging;
+ DWORD dwNoRefreshInterval;
+ DWORD dwRefreshInterval;
+ DWORD dwAvailForScavengeTime;
+ PDNS_ADDR_ARRAY aipScavengeServers;
+
+ /* Forwarder zones */
+ DWORD dwForwarderTimeout;
+ DWORD fForwarderSlave;
+
+ /* Stub zones */
+ PDNS_ADDR_ARRAY aipLocalMasters;
+
+ /* Directory partition */
+ DWORD dwDpFlags;
+ [string, charset(UTF8)] char * pszDpFqdn;
+ [string, charset(UTF16)] wchar_t * pwszZoneDn;
+ /* Xfr time information */
+ DWORD dwLastSuccessfulSoaCheck;
+ DWORD dwLastSuccessfulXfr;
+
+ DWORD fQueuedForBackgroundLoad;
+ DWORD fBackgroundLoadInProgress;
+ BOOL fReadOnlyZone;
+
+ /* Additional zone transfer information */
+ DWORD dwLastXfrAttempt;
+ DWORD dwLastXfrResult;
+ }
+ DNS_RPC_ZONE_INFO_LONGHORN;
+#define DNS_RPC_ZONE_INFO DNS_RPC_ZONE_INFO_LONGHORN
+
+ /* Zone property data */
+ typedef struct {
+ DNS_ZONE_SECONDARY_SECURITY fSecureSecondaries;
+ DNS_ZONE_NOTIFY_LEVEL fNotifyLevel;
+ PIP4_ARRAY aipSecondaries;
+ PIP4_ARRAY aipNotify;
+ }
+ DNS_RPC_ZONE_SECONDARIES_W2K;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ DNS_ZONE_SECONDARY_SECURITY fSecureSecondaries;
+ DNS_ZONE_NOTIFY_LEVEL fNotifyLevel;
+ PIP4_ARRAY aipSecondaries;
+ PIP4_ARRAY aipNotify;
+ }
+ DNS_RPC_ZONE_SECONDARIES_DOTNET;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ DNS_ZONE_SECONDARY_SECURITY fSecureSecondaries;
+ DNS_ZONE_NOTIFY_LEVEL fNotifyLevel;
+ PDNS_ADDR_ARRAY aipSecondaries;
+ PDNS_ADDR_ARRAY aipNotify;
+ }
+ DNS_RPC_ZONE_SECONDARIES_LONGHORN;
+#define DNS_RPC_ZONE_SECONDARIES DNS_RPC_ZONE_SECONDARIES_LONGHORN
+
+ /* Zone database */
+ typedef struct {
+ DWORD fDsIntegrated;
+ [string, charset(UTF8)] char * pszFileName;
+ }
+ DNS_RPC_ZONE_DATABASE_W2K;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ DWORD fDsIntegrated;
+ [string, charset(UTF8)] char * pszFileName;
+ }
+ DNS_RPC_ZONE_DATABASE_DOTNET;
+#define DNS_RPC_ZONE_DATABASE DNS_RPC_ZONE_DATABASE_DOTNET
+
+ /* Zone create data */
+ typedef struct {
+ [string, charset(UTF8)] char * pszZoneName;
+ DWORD dwZoneType;
+ dns_zone_update fAllowUpdate;
+ BOOL fAging;
+ DWORD dwFlags;
+
+ /* Database info */
+
+ [string, charset(UTF8)] char * pszDataFile;
+ DWORD fDsIntegrated;
+ DWORD fLoadExisting;
+
+ /* Admin name (if auto-create SOA) */
+
+ [string, charset(UTF8)] char * pszAdmin;
+
+ /* Masters (if secondary) */
+
+ PIP4_ARRAY aipMasters;
+
+ /* Secondaries */
+
+ PIP4_ARRAY aipSecondaries;
+ DNS_ZONE_SECONDARY_SECURITY fSecureSecondaries;
+ DNS_ZONE_NOTIFY_LEVEL fNotifyLevel;
+
+ /* Reserve some space to avoid versioning issues */
+
+ [string, charset(UTF8)] char * pvReserved1;
+ [string, charset(UTF8)] char * pvReserved2;
+ [string, charset(UTF8)] char * pvReserved3;
+ [string, charset(UTF8)] char * pvReserved4;
+ [string, charset(UTF8)] char * pvReserved5;
+ [string, charset(UTF8)] char * pvReserved6;
+ [string, charset(UTF8)] char * pvReserved7;
+ [string, charset(UTF8)] char * pvReserved8;
+ DWORD dwReserved1;
+ DWORD dwReserved2;
+ DWORD dwReserved3;
+ DWORD dwReserved4;
+ DWORD dwReserved5;
+ DWORD dwReserved6;
+ DWORD dwReserved7;
+ DWORD dwReserved8;
+ }
+ DNS_RPC_ZONE_CREATE_INFO_W2K;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ [string, charset(UTF8)] char * pszZoneName;
+ DWORD dwZoneType;
+ dns_zone_update fAllowUpdate;
+ BOOL fAging;
+ DWORD dwFlags;
+
+ /* Database info */
+
+ [string, charset(UTF8)] char * pszDataFile;
+ DWORD fDsIntegrated;
+ DWORD fLoadExisting;
+
+ /* Admin name (if auto-create SOA) */
+
+ [string, charset(UTF8)] char * pszAdmin;
+
+ /* Masters (if secondary) */
+
+ PIP4_ARRAY aipMasters;
+
+ /* Secondaries */
+
+ PIP4_ARRAY aipSecondaries;
+ DNS_ZONE_SECONDARY_SECURITY fSecureSecondaries;
+ DNS_ZONE_NOTIFY_LEVEL fNotifyLevel;
+
+ /* Forwarder zones */
+
+ DWORD dwTimeout;
+ DWORD fRecurseAfterForwarding;
+
+ /* Directory partition */
+
+ DWORD dwDpFlags; /* specify built-in DP or */
+ [string, charset(UTF8)] char * pszDpFqdn; /* UTF8 FQDN of partition */
+
+ DWORD dwReserved[ 32 ];
+ }
+ DNS_RPC_ZONE_CREATE_INFO_DOTNET;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ [string, charset(UTF8)] char * pszZoneName;
+ DWORD dwZoneType;
+ dns_zone_update fAllowUpdate;
+ BOOL fAging;
+ DWORD dwFlags;
+
+ /* Database info */
+
+ [string, charset(UTF8)] char * pszDataFile;
+ DWORD fDsIntegrated;
+ DWORD fLoadExisting;
+
+ /* Admin name (if auto-create SOA) */
+
+ [string, charset(UTF8)] char * pszAdmin;
+
+ /* Masters (if secondary) */
+
+ PDNS_ADDR_ARRAY aipMasters;
+
+ /* Secondaries */
+
+ PDNS_ADDR_ARRAY aipSecondaries;
+ DNS_ZONE_SECONDARY_SECURITY fSecureSecondaries;
+ DNS_ZONE_NOTIFY_LEVEL fNotifyLevel;
+
+ /* Forwarder zones */
+
+ DWORD dwTimeout;
+ DWORD fRecurseAfterForwarding;
+
+ /* Directory partition */
+
+ DWORD dwDpFlags; /* specify built-in DP or */
+ [string, charset(UTF8)] char * pszDpFqdn; /* UTF8 FQDN of partition */
+
+ DWORD dwReserved[ 32 ];
+ }
+ DNS_RPC_ZONE_CREATE_INFO_LONGHORN;
+#define DNS_RPC_ZONE_CREATE_INFO DNS_RPC_ZONE_CREATE_INFO_LONGHORN
+
+ /* Zone export */
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ [string, charset(UTF8)] char * pszZoneExportFile;
+ }
+ DNS_RPC_ZONE_EXPORT_INFO;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+
+ DWORD dwFilter;
+ [string, charset(UTF8)] char * pszPartitionFqdn;
+ [string, charset(UTF8)] char * pszQueryString;
+
+ DNS_EXTENSION pszReserved[ 6 ];
+ }
+ DNS_RPC_ENUM_ZONES_FILTER;
+
+ /* Forwarders information */
+ typedef struct {
+ DWORD fRecurseAfterForwarding;
+ DWORD dwForwardTimeout;
+ PIP4_ARRAY aipForwarders;
+ }
+ DNS_RPC_FORWARDERS_W2K;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+ DWORD fRecurseAfterForwarding;
+ DWORD dwForwardTimeout;
+ PIP4_ARRAY aipForwarders;
+ }
+ DNS_RPC_FORWARDERS_DOTNET;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+ DWORD fRecurseAfterForwarding;
+ DWORD dwForwardTimeout;
+ PDNS_ADDR_ARRAY aipForwarders;
+ }
+ DNS_RPC_FORWARDERS_LONGHORN;
+#define DNS_RPC_FORWARDERS DNS_RPC_FORWARDERS_LONGHORN
+
+
+ /* */
+ /* DNS autoconfig data types */
+ /* */
+
+ typedef [v1_enum] enum {
+ DNS_RPC_AUTOCONFIG_INTERNAL_ROOTHINTS = 0x00000001,
+ DNS_RPC_AUTOCONFIG_INTERNAL_FORWARDERS = 0x00000002,
+ DNS_RPC_AUTOCONFIG_INTERNAL_ZONES = 0x00000004,
+ DNS_RPC_AUTOCONFIG_INTERNAL_SELFPOINT = 0x00000010,
+ DNS_RPC_AUTOCONFIG_INTERNAL_SELFPOINT_PREPEND = 0x00000020,
+ DNS_RPC_AUTOCONFIG_INTERNAL_SELFPOINT_APPEND = 0x00000040,
+ DNS_RPC_AUTOCONFIG_INTERNAL_RETURN_ERROR = 0x00008000,
+ DNS_RPC_AUTOCONFIG_ALL = 0xFFFFFFFF
+ }
+ DNS_RPC_AUTOCONFIG;
+
+ typedef struct {
+ DWORD dwRpcStructureVersion;
+ DWORD dwReserved0;
+ DNS_RPC_AUTOCONFIG dwAutoConfigFlags;
+ DWORD dwReserved1;
+ [string, charset(UTF8)] char * pszNewDomainName;
+ }
+ DNS_RPC_AUTOCONFIGURE;
+
+
+ /* */
+ /* DNS logging data types */
+ /* */
+
+ typedef [bitmap32bit] bitmap {
+ DNS_EVENT_LOG_SUCCESS = 0x00000000,
+ DNS_EVENT_LOG_ERROR_TYPE = 0x00000001,
+ DNS_EVENT_LOG_WARNING_TYPE = 0x00000002,
+ DNS_EVENT_LOG_INFORMATION_TYPE = 0x00000004
+ }
+ DNS_EVENT_LOG_TYPES;
+
+ typedef [bitmap32bit] bitmap {
+ DNS_RPC_VIEW_AUTHORITY_DATA = 0x00000001,
+ DNS_RPC_VIEW_CACHE_DATA = 0x00000002,
+ DNS_RPC_VIEW_GLUE_DATA = 0x00000004,
+ DNS_RPC_VIEW_ROOT_HINT_DATA = 0x00000008,
+ DNS_RPC_VIEW_ADDITIONAL_DATA = 0x00000010,
+ DNS_RPC_VIEW_NO_CHILDREN = 0x00010000,
+ DNS_RPC_VIEW_ONLY_CHILDREN = 0x00020000
+ }
+ DNS_SELECT_FLAGS;
+
+
+ /* */
+ /* DNS statistics data types */
+ /* */
+
+ typedef struct {
+ DWORD StatId;
+ WORD wLength;
+ BOOLEAN fClear;
+ UCHAR fReserved;
+ }
+ DNSSRV_STAT_HEADER;
+
+ typedef struct {
+ DNSSRV_STAT_HEADER Header;
+ BYTE Buffer[1];
+ }
+ DNSSRV_STAT;
+
+
+ /* */
+ /* DNS Typid and Union of all RPC data types */
+ /* */
+
+ typedef [v1_enum] enum {
+ DNSSRV_TYPEID_NULL = 0,
+ DNSSRV_TYPEID_DWORD = 1,
+ DNSSRV_TYPEID_LPSTR = 2,
+ DNSSRV_TYPEID_LPWSTR = 3,
+ DNSSRV_TYPEID_IPARRAY = 4,
+ DNSSRV_TYPEID_BUFFER = 5,
+ DNSSRV_TYPEID_SERVER_INFO_W2K = 6,
+ DNSSRV_TYPEID_STATS = 7,
+ DNSSRV_TYPEID_FORWARDERS_W2K = 8,
+ DNSSRV_TYPEID_ZONE_W2K = 9,
+ DNSSRV_TYPEID_ZONE_INFO_W2K = 10,
+ DNSSRV_TYPEID_ZONE_SECONDARIES_W2K = 11,
+ DNSSRV_TYPEID_ZONE_DATABASE_W2K = 12,
+ DNSSRV_TYPEID_ZONE_TYPE_RESET_W2K = 13,
+ DNSSRV_TYPEID_ZONE_CREATE_W2K = 14,
+ DNSSRV_TYPEID_NAME_AND_PARAM = 15,
+ DNSSRV_TYPEID_ZONE_LIST_W2K = 16,
+ DNSSRV_TYPEID_ZONE_RENAME = 17,
+ DNSSRV_TYPEID_ZONE_EXPORT = 18,
+ DNSSRV_TYPEID_SERVER_INFO_DOTNET = 19,
+ DNSSRV_TYPEID_FORWARDERS_DOTNET = 20,
+ DNSSRV_TYPEID_ZONE = 21,
+ DNSSRV_TYPEID_ZONE_INFO_DOTNET = 22,
+ DNSSRV_TYPEID_ZONE_SECONDARIES_DOTNET = 23,
+ DNSSRV_TYPEID_ZONE_DATABASE = 24,
+ DNSSRV_TYPEID_ZONE_TYPE_RESET_DOTNET = 25,
+ DNSSRV_TYPEID_ZONE_CREATE_DOTNET = 26,
+ DNSSRV_TYPEID_ZONE_LIST = 27,
+ DNSSRV_TYPEID_DP_ENUM = 28,
+ DNSSRV_TYPEID_DP_INFO = 29,
+ DNSSRV_TYPEID_DP_LIST = 30,
+ DNSSRV_TYPEID_ENLIST_DP = 31,
+ DNSSRV_TYPEID_ZONE_CHANGE_DP = 32,
+ DNSSRV_TYPEID_ENUM_ZONES_FILTER = 33,
+ DNSSRV_TYPEID_ADDRARRAY = 34,
+ DNSSRV_TYPEID_SERVER_INFO = 35,
+ DNSSRV_TYPEID_ZONE_INFO = 36,
+ DNSSRV_TYPEID_FORWARDERS = 37,
+ DNSSRV_TYPEID_ZONE_SECONDARIES = 38,
+ DNSSRV_TYPEID_ZONE_TYPE_RESET = 39,
+ DNSSRV_TYPEID_ZONE_CREATE = 40,
+ DNSSRV_TYPEID_IP_VALIDATE = 41,
+ DNSSRV_TYPEID_AUTOCONFIGURE = 42,
+ DNSSRV_TYPEID_UTF8_STRING_LIST = 43,
+ DNSSRV_TYPEID_UNICODE_STRING_LIST = 44
+ }
+ DNS_RPC_TYPEID;
+
+ typedef [switch_type(uint3264)] union {
+ [case(DNSSRV_TYPEID_NULL)] PBYTE Null;
+
+ [case(DNSSRV_TYPEID_DWORD)] DWORD Dword;
+
+ [case(DNSSRV_TYPEID_LPSTR)] [string, charset(UTF8)] char * String;
+
+ [case(DNSSRV_TYPEID_LPWSTR)] [string, charset(UTF16)] wchar_t * WideString;
+
+ [case(DNSSRV_TYPEID_IPARRAY)] IP4_ARRAY *IpArray;
+
+ [case(DNSSRV_TYPEID_BUFFER)]
+ DNS_RPC_BUFFER *Buffer;
+
+ [case(DNSSRV_TYPEID_SERVER_INFO_W2K)]
+ DNS_RPC_SERVER_INFO_W2K *ServerInfoW2K;
+
+ [case(DNSSRV_TYPEID_STATS)]
+ DNSSRV_STAT *Stats;
+
+ [case(DNSSRV_TYPEID_FORWARDERS_W2K)]
+ DNS_RPC_FORWARDERS_W2K *ForwardersW2K;
+
+ [case(DNSSRV_TYPEID_ZONE_W2K)]
+ DNS_RPC_ZONE_W2K *ZoneW2K;
+
+ [case(DNSSRV_TYPEID_ZONE_INFO_W2K)]
+ DNS_RPC_ZONE_INFO_W2K *ZoneInfoW2K;
+
+ [case(DNSSRV_TYPEID_ZONE_SECONDARIES_W2K)]
+ DNS_RPC_ZONE_SECONDARIES_W2K *SecondariesW2K;
+
+ [case(DNSSRV_TYPEID_ZONE_DATABASE_W2K)]
+ DNS_RPC_ZONE_DATABASE_W2K *DatabaseW2K;
+
+ [case(DNSSRV_TYPEID_ZONE_CREATE_W2K)]
+ DNS_RPC_ZONE_CREATE_INFO_W2K *ZoneCreateW2K;
+
+ [case(DNSSRV_TYPEID_NAME_AND_PARAM)]
+ DNS_RPC_NAME_AND_PARAM *NameAndParam;
+
+ [case(DNSSRV_TYPEID_ZONE_LIST_W2K)]
+ DNS_RPC_ZONE_LIST_W2K *ZoneListW2K;
+
+ [case(DNSSRV_TYPEID_SERVER_INFO_DOTNET)]
+ DNS_RPC_SERVER_INFO_DOTNET *ServerInfoDotNet;
+
+ [case(DNSSRV_TYPEID_FORWARDERS_DOTNET)]
+ DNS_RPC_FORWARDERS_DOTNET *ForwardersDotNet;
+
+ [case(DNSSRV_TYPEID_ZONE)]
+ DNS_RPC_ZONE *Zone;
+
+ [case(DNSSRV_TYPEID_ZONE_INFO_DOTNET)]
+ DNS_RPC_ZONE_INFO_DOTNET *ZoneInfoDotNet;
+
+ [case(DNSSRV_TYPEID_ZONE_SECONDARIES_DOTNET)]
+ DNS_RPC_ZONE_SECONDARIES_DOTNET *SecondariesDotNet;
+
+ [case(DNSSRV_TYPEID_ZONE_DATABASE)]
+ DNS_RPC_ZONE_DATABASE *Database;
+
+ [case(DNSSRV_TYPEID_ZONE_CREATE_DOTNET)]
+ DNS_RPC_ZONE_CREATE_INFO_DOTNET *ZoneCreateDotNet;
+
+ [case(DNSSRV_TYPEID_ZONE_LIST)]
+ DNS_RPC_ZONE_LIST *ZoneList;
+
+ [case(DNSSRV_TYPEID_ZONE_EXPORT)]
+ DNS_RPC_ZONE_EXPORT_INFO *ZoneExport;
+
+ [case(DNSSRV_TYPEID_DP_INFO)]
+ DNS_RPC_DP_INFO *DirectoryPartition;
+
+ [case(DNSSRV_TYPEID_DP_ENUM)]
+ DNS_RPC_DP_ENUM *DirectoryPartitionEnum;
+
+ [case(DNSSRV_TYPEID_DP_LIST)]
+ DNS_RPC_DP_LIST *DirectoryPartitionList;
+
+ [case(DNSSRV_TYPEID_ENLIST_DP)]
+ DNS_RPC_ENLIST_DP *EnlistDirectoryPartition;
+
+ [case(DNSSRV_TYPEID_ZONE_CHANGE_DP)]
+ DNS_RPC_ZONE_CHANGE_DP *ZoneChangeDirectoryPartition;
+
+ [case(DNSSRV_TYPEID_ENUM_ZONES_FILTER)]
+ DNS_RPC_ENUM_ZONES_FILTER *EnumZonesFilter;
+
+ [case(DNSSRV_TYPEID_ADDRARRAY)]
+ DNS_ADDR_ARRAY *AddrArray;
+
+ [case(DNSSRV_TYPEID_SERVER_INFO)]
+ DNS_RPC_SERVER_INFO *ServerInfo;
+
+ [case(DNSSRV_TYPEID_ZONE_CREATE)]
+ DNS_RPC_ZONE_CREATE_INFO *ZoneCreate;
+
+ [case(DNSSRV_TYPEID_FORWARDERS)]
+ DNS_RPC_FORWARDERS *Forwarders;
+
+ [case(DNSSRV_TYPEID_ZONE_SECONDARIES)]
+ DNS_RPC_ZONE_SECONDARIES *Secondaries;
+
+ [case(DNSSRV_TYPEID_IP_VALIDATE)]
+ DNS_RPC_IP_VALIDATE *IpValidate;
+
+ [case(DNSSRV_TYPEID_ZONE_INFO)]
+ DNS_RPC_ZONE_INFO *ZoneInfo;
+
+ [case(DNSSRV_TYPEID_AUTOCONFIGURE)]
+ DNS_RPC_AUTOCONFIGURE *AutoConfigure;
+
+ [case(DNSSRV_TYPEID_UTF8_STRING_LIST)]
+ DNS_RPC_UTF8_STRING_LIST *Utf8StringList;
+ } DNSSRV_RPC_UNION;
+
+
+ /* */
+ /* DNS RPC interface */
+ /* */
+
+ typedef [public,gensize] struct {
+ [value((12+ndr_size_DNS_RPC_NAME(&dnsNodeName,0)+3) & ~3)] uint16 wLength;
+ uint16 wRecordCount;
+ uint32 dwFlags;
+ uint32 dwChildCount;
+ DNS_RPC_NAME dnsNodeName;
+ DNS_RPC_RECORD records[wRecordCount];
+ } DNS_RPC_RECORDS;
+
+ typedef [public,nopull,nopush,gensize] struct {
+ uint32 count;
+ DNS_RPC_RECORDS rec[count];
+ } DNS_RPC_RECORDS_ARRAY;
+
+ WERROR DnssrvOperation(
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in] DWORD dwContext,
+ [in,unique,string,charset(UTF8)] uint8 *pszOperation,
+ [in] DNS_RPC_TYPEID dwTypeId,
+ [in, switch_is(dwTypeId)] DNSSRV_RPC_UNION pData
+ );
+
+ WERROR DnssrvQuery(
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in,unique,string,charset(UTF8)] uint8 *pszOperation,
+ [out] DNS_RPC_TYPEID *pdwTypeId,
+ [out, switch_is(*pdwTypeId)] DNSSRV_RPC_UNION *ppData
+ );
+
+ WERROR DnssrvComplexOperation(
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in,unique,string,charset(UTF8)] uint8 *pszOperation,
+ [in] DNS_RPC_TYPEID dwTypeIn,
+ [in, switch_is(dwTypeIn)] DNSSRV_RPC_UNION pDataIn,
+ [out] DNS_RPC_TYPEID *pdwTypeOut,
+ [out, switch_is(*pdwTypeOut)] DNSSRV_RPC_UNION *ppDataOut
+ );
+
+ WERROR DnssrvEnumRecords(
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in,unique,string,charset(UTF8)] uint8 *pszNodeName,
+ [in,unique,string,charset(UTF8)] uint8 *pszStartChild,
+ [in] dns_record_type wRecordType,
+ [in] DNS_SELECT_FLAGS fSelectFlag,
+ [in,unique,string,charset(UTF8)] uint8 *pszFilterStart,
+ [in,unique,string,charset(UTF8)] uint8 *pszFilterStop,
+ [out] DWORD *pdwBufferLength,
+ [out,ref,subcontext(4),subcontext_size(*pdwBufferLength)] DNS_RPC_RECORDS_ARRAY **pBuffer
+ );
+
+ WERROR DnssrvUpdateRecord(
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in,unique,string,charset(UTF8)] uint8 *pszNodeName,
+ [in, unique] DNS_RPC_RECORD_BUF *pAddRecord,
+ [in, unique] DNS_RPC_RECORD_BUF *pDeleteRecord
+ );
+
+ WERROR DnssrvOperation2(
+ [in] DNS_RPC_CLIENT_VERSION dwClientVersion,
+ [in] uint32 dwSettingFlags,
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in] DWORD dwContext,
+ [in,unique,string,charset(UTF8)] uint8 *pszOperation,
+ [in] DNS_RPC_TYPEID dwTypeId,
+ [in, switch_is(dwTypeId)] DNSSRV_RPC_UNION pData
+ );
+
+ WERROR DnssrvQuery2(
+ [in] DNS_RPC_CLIENT_VERSION dwClientVersion,
+ [in] uint32 dwSettingFlags,
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in,unique,string,charset(UTF8)] uint8 *pszOperation,
+ [out] DNS_RPC_TYPEID *pdwTypeId,
+ [out, switch_is(*pdwTypeId)] DNSSRV_RPC_UNION *ppData
+ );
+
+ WERROR DnssrvComplexOperation2(
+ [in] DNS_RPC_CLIENT_VERSION dwClientVersion,
+ [in] uint32 dwSettingFlags,
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in,unique,string,charset(UTF8)] uint8 *pszOperation,
+ [in] DNS_RPC_TYPEID dwTypeIn,
+ [in, switch_is(dwTypeIn)] DNSSRV_RPC_UNION pDataIn,
+ [out] DNS_RPC_TYPEID *pdwTypeOut,
+ [out, switch_is(*pdwTypeOut)] DNSSRV_RPC_UNION *ppDataOut
+ );
+
+ WERROR DnssrvEnumRecords2(
+ [in] DNS_RPC_CLIENT_VERSION dwClientVersion,
+ [in] DWORD dwSettingFlags,
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in,unique,string,charset(UTF8)] uint8 *pszNodeName,
+ [in,unique,string,charset(UTF8)] uint8 *pszStartChild,
+ [in] dns_record_type wRecordType,
+ [in] DNS_SELECT_FLAGS fSelectFlag,
+ [in,unique,string,charset(UTF8)] uint8 *pszFilterStart,
+ [in,unique,string,charset(UTF8)] uint8 *pszFilterStop,
+ [out] uint32 *pdwBufferLength,
+ [out,ref,subcontext(4),subcontext_size(*pdwBufferLength)] DNS_RPC_RECORDS_ARRAY **pBuffer
+ );
+
+ WERROR DnssrvUpdateRecord2(
+ [in] DNS_RPC_CLIENT_VERSION dwClientVersion,
+ [in] uint32 dwSettingFlags,
+ [in,unique,string,charset(UTF16)] uint16 *pwszServerName,
+ [in,unique,string,charset(UTF8)] uint8 *pszZone,
+ [in,string,charset(UTF8)] uint8 *pszNodeName,
+ [in, unique] DNS_RPC_RECORD_BUF *pAddRecord,
+ [in, unique] DNS_RPC_RECORD_BUF *pDeleteRecord
+ );
+}
diff --git a/librpc/idl/drsblobs.idl b/librpc/idl/drsblobs.idl
new file mode 100644
index 0000000..9d49569
--- /dev/null
+++ b/librpc/idl/drsblobs.idl
@@ -0,0 +1,680 @@
+#include "idl_types.h"
+
+import "drsuapi.idl", "misc.idl", "samr.idl", "lsa.idl", "security.idl";
+
+[
+ uuid("12345778-1234-abcd-0001-00000001"),
+ version(0.0),
+ pointer_default(unique),
+ helper("../librpc/ndr/ndr_drsblobs.h"),
+ helpstring("Active Directory Replication LDAP Blobs")
+]
+interface drsblobs {
+ typedef bitmap drsuapi_DrsOptions drsuapi_DrsOptions;
+ typedef [v1_enum] enum drsuapi_DsAttributeId drsuapi_DsAttributeId;
+ typedef [v1_enum] enum lsa_TrustAuthType lsa_TrustAuthType;
+ /*
+ * replPropertyMetaData
+ * w2k uses version 1
+ * w2k3 uses version 1
+ *
+ * Also equivalent to
+ * MS-DRSR 4.1.10.2.22 PROPERTY_META_DATA
+ */
+ typedef [public] struct {
+ drsuapi_DsAttributeId attid;
+ uint32 version;
+ NTTIME_1sec originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ } replPropertyMetaData1;
+
+ typedef struct {
+ uint32 count;
+ [value(0)] uint32 reserved;
+ replPropertyMetaData1 array[count];
+ } replPropertyMetaDataCtr1;
+
+ typedef [nodiscriminant] union {
+ [case(1)] replPropertyMetaDataCtr1 ctr1;
+ } replPropertyMetaDataCtr;
+
+ typedef [public] struct {
+ uint32 version;
+ [value(0)] uint32 reserved;
+ [switch_is(version)] replPropertyMetaDataCtr ctr;
+ } replPropertyMetaDataBlob;
+
+ /*
+ * replUpToDateVector
+ * w2k uses version 1
+ * w2k3 uses version 2
+ */
+ typedef struct {
+ uint32 count;
+ [value(0)] uint32 reserved;
+ drsuapi_DsReplicaCursor cursors[count];
+ } replUpToDateVectorCtr1;
+
+ typedef struct {
+ uint32 count;
+ [value(0)] uint32 reserved;
+ drsuapi_DsReplicaCursor2 cursors[count];
+ } replUpToDateVectorCtr2;
+
+ typedef [nodiscriminant] union {
+ [case(1)] replUpToDateVectorCtr1 ctr1;
+ [case(2)] replUpToDateVectorCtr2 ctr2;
+ } replUpToDateVectorCtr;
+
+ typedef [public] struct {
+ uint32 version;
+ [value(0)] uint32 reserved;
+ [switch_is(version)] replUpToDateVectorCtr ctr;
+ } replUpToDateVectorBlob;
+
+ /*
+ * repsFrom/repsTo
+ * w2k uses version 1
+ * w2k3 uses version 1
+ * w2k8 uses version 2
+ */
+ typedef [public,gensize] struct {
+ [value(strlen(dns_name)+1)] uint32 __dns_name_size;
+ [charset(DOS)] uint8 dns_name[__dns_name_size];
+ } repsFromTo1OtherInfo;
+
+ typedef [public,gensize,flag(NDR_PAHEX)] struct {
+ /* this includes the 8 bytes of the repsFromToBlob header */
+ [value(ndr_size_repsFromTo1(this, ndr->flags)+8)] uint32 blobsize;
+ uint32 consecutive_sync_failures;
+ NTTIME_1sec last_success;
+ NTTIME_1sec last_attempt;
+ WERROR result_last_attempt;
+ [relative] repsFromTo1OtherInfo *other_info;
+ [value(ndr_size_repsFromTo1OtherInfo(other_info, ndr->flags))] uint32 other_info_length;
+ drsuapi_DrsOptions replica_flags;
+ uint8 schedule[84];
+ [value(0)] uint32 reserved;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ GUID source_dsa_obj_guid; /* the 'objectGuid' field of the CN=NTDS Settings object */
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ GUID transport_guid;
+ } repsFromTo1;
+
+ typedef [public,relative_base,gensize] struct {
+ [value(ndr_size_repsFromTo2OtherInfo(this,ndr->flags))]
+ uint32 __ndr_size;
+ [relative] nstring *dns_name1;
+ uint32 unknown1;
+ [relative] nstring *dns_name2;
+ hyper unknown2;
+ } repsFromTo2OtherInfo;
+
+ typedef [public,gensize,flag(NDR_PAHEX)] struct {
+ /* this includes the 8 bytes of the repsFromToBlob header */
+ [value(ndr_size_repsFromTo2(this, ndr->flags)+8)] uint32 blobsize;
+ uint32 consecutive_sync_failures;
+ NTTIME_1sec last_success;
+ NTTIME_1sec last_attempt;
+ WERROR result_last_attempt;
+ [relative] repsFromTo2OtherInfo *other_info;
+ [value(ndr_size_repsFromTo2OtherInfo(other_info, ndr->flags))] uint32 other_info_length;
+ drsuapi_DrsOptions replica_flags;
+ uint8 schedule[84];
+ [value(0)] uint32 reserved;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ GUID source_dsa_obj_guid; /* the 'objectGuid' field of the CN=NTDS Settings object */
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ GUID transport_guid;
+ hyper unknown1;
+ } repsFromTo2;
+
+ typedef [nodiscriminant] union {
+ [case(1)] repsFromTo1 ctr1;
+ [case(2)] repsFromTo2 ctr2;
+ } repsFromTo;
+
+ typedef [public] struct {
+ uint32 version;
+ [value(0)] uint32 reserved;
+ [switch_is(version)] repsFromTo ctr;
+ } repsFromToBlob;
+
+ /* Replication schedule structures as defined in MS-ADTS 7.1.4.5
+ * Appears as attribute of NTDSConnection object
+ */
+ typedef [public] struct {
+ [value(0)] uint32 type; /* always 0 */
+ uint32 offset;
+ } scheduleHeader;
+
+ typedef [public] struct {
+ uint8 slots[168];
+ } scheduleSlots;
+
+ typedef [public] struct {
+ uint32 size;
+ [value(0)] uint32 bandwidth; /* ignored */
+ uint32 numberOfSchedules; /* typically 1 */
+ scheduleHeader headerArray[numberOfSchedules];
+ scheduleSlots dataArray[numberOfSchedules];
+ } schedule;
+
+ /*
+ * partialAttributeSet
+ * w2k uses version 1
+ * w2k3 uses version 1
+ */
+ typedef struct {
+ uint32 count;
+ drsuapi_DsAttributeId array[count];
+ } partialAttributeSetCtr1;
+
+ typedef [nodiscriminant] union {
+ [case(1)] partialAttributeSetCtr1 ctr1;
+ } partialAttributeSetCtr;
+
+ typedef [public] struct {
+ uint32 version;
+ [value(0)] uint32 reserved;
+ [switch_is(version)] partialAttributeSetCtr ctr;
+ } partialAttributeSetBlob;
+
+ /*
+ * schemaInfo attribute
+ *
+ * Used as an attribute on Schema.
+ * Also during replication as part of
+ * prefixMap to identify what revision
+ * of Schema source DC has
+ */
+ typedef [public,flag(NDR_NOALIGN)] struct {
+ [value(0xFF)] uint8 marker;
+ [flag(NDR_BIG_ENDIAN)] uint32 revision;
+ GUID invocation_id;
+ } schemaInfoBlob;
+
+
+ /*
+ * MS w2k3 and w2k8 prefixMap format
+ * There is no version number. Format is:
+ * uint32 - number of entries in the map
+ * uint32 - total bytes that structure occupies
+ * ENTRIES:
+ * uint16 - prefix ID (OID's last sub-id encoded. see prefixMap)
+ * uint16 - number of bytes in prefix N
+ * uint8[N] - BER encoded prefix
+ */
+ typedef [noprint,flag(NDR_NOALIGN)] struct {
+ uint16 entryID;
+ uint16 length;
+ uint8 binary_oid[length];
+ } drsuapi_MSPrefixMap_Entry;
+
+ typedef [public,gensize] struct {
+ uint32 num_entries;
+ [value(ndr_size_drsuapi_MSPrefixMap_Ctr(r, ndr->flags))] uint32 __ndr_size;
+ drsuapi_MSPrefixMap_Entry entries[num_entries];
+ } drsuapi_MSPrefixMap_Ctr;
+
+ /*
+ * prefixMap
+ * w2k unknown
+ * w2k3 unknown
+ * samba4 uses 0x44534442 'DSDB'
+ *
+ * as we windows don't return the prefixMap attribute when you ask for
+ * we don't know the format, but the attribute is not replicated
+ * so that we can choose our own format...
+ */
+ typedef [v1_enum] enum {
+ PREFIX_MAP_VERSION_DSDB = 0x44534442
+ } prefixMapVersion;
+
+ typedef [nodiscriminant] union {
+ [case(PREFIX_MAP_VERSION_DSDB)] drsuapi_DsReplicaOIDMapping_Ctr dsdb;
+ } prefixMapCtr;
+
+ typedef [public] struct {
+ prefixMapVersion version;
+ [value(0)] uint32 reserved;
+ [switch_is(version)] prefixMapCtr ctr;
+ } prefixMapBlob;
+
+ /*
+ * the cookie for the LDAP dirsync control
+ */
+ typedef [nodiscriminant,gensize] union {
+ [case(0)];
+ [default] replUpToDateVectorBlob uptodateness_vector;
+ } ldapControlDirSyncExtra;
+
+ typedef struct {
+ [value(3)] uint32 u1;
+ NTTIME time;
+ uint32 u2;
+ uint32 u3;
+ [value(ndr_size_ldapControlDirSyncExtra(&extra, extra.uptodateness_vector.version, 0))]
+ uint32 extra_length;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ GUID guid1;
+ [switch_is(extra_length)] ldapControlDirSyncExtra extra;
+ } ldapControlDirSyncBlob;
+
+ typedef [public,relative_base] struct {
+ [charset(DOS),value("MSDS")] uint8 msds[4];
+ [subcontext(0)] ldapControlDirSyncBlob blob;
+ } ldapControlDirSyncCookie;
+
+ typedef [public] struct {
+ [value(2*strlen_m(name))] uint16 name_len;
+ [value(strlen(data))] uint16 data_len;
+ uint16 reserved; /* 2 for 'Packages', 1 for 'Primary:*', but should be ignored */
+ [charset(UTF16)] uint8 name[name_len];
+ /*
+ * the data field contains data as HEX strings
+ *
+ * 'Packages':
+ * data contains the list of packages
+ * as non termiated UTF16 strings with
+ * a UTF16 NULL byte as separator
+ *
+ * 'Primary:Kerberos-Newer-Keys':
+ * ...
+ *
+ * 'Primary:Kerberos':
+ * ...
+ *
+ * 'Primary:WDigest':
+ * ...
+ *
+ * 'Primary:CLEARTEXT':
+ * data contains the cleartext password
+ * as UTF16 string encoded as HEX string
+ *
+ * 'Primary:userPassword':
+ * ...
+ *
+ * 'Primary:SambaGPG':
+ * ...
+ *
+ * 'Primary:NTLM-Strong-NTOWF':
+ * ... Not yet implemented.
+ *
+ */
+ [charset(DOS)] uint8 data[data_len];
+ } supplementalCredentialsPackage;
+
+ /* this are 0x30 (48) whitespaces (0x20) */
+ const string SUPPLEMENTAL_CREDENTIALS_PREFIX = " ";
+
+ typedef [flag(NDR_PAHEX),public] enum {
+ SUPPLEMENTAL_CREDENTIALS_SIGNATURE = 0x0050
+ } supplementalCredentialsSignature;
+
+ typedef [gensize,nopush,nopull] struct {
+ [value(SUPPLEMENTAL_CREDENTIALS_PREFIX),charset(UTF16)] uint16 prefix[0x30];
+ [value(SUPPLEMENTAL_CREDENTIALS_SIGNATURE)] supplementalCredentialsSignature signature;
+ uint16 num_packages;
+ supplementalCredentialsPackage packages[num_packages];
+ } supplementalCredentialsSubBlob;
+
+ typedef [public] struct {
+ [value(0)] uint32 unknown1;
+ [value(ndr_size_supplementalCredentialsSubBlob(&sub, ndr->flags))] uint32 __ndr_size;
+ [value(0)] uint32 unknown2;
+ [subcontext(0),subcontext_size(__ndr_size)] supplementalCredentialsSubBlob sub;
+ [value(0)] uint8 unknown3;
+ } supplementalCredentialsBlob;
+
+ typedef [public] struct {
+ [flag(STR_NOTERM|NDR_REMAINING)] string_array names;
+ } package_PackagesBlob;
+
+ typedef struct {
+ [value(2*strlen_m(string))] uint16 length;
+ [value(2*strlen_m(string))] uint16 size;
+ [relative,subcontext(0),subcontext_size(size),flag(STR_NOTERM|NDR_REMAINING)] string *string;
+ } package_PrimaryKerberosString;
+
+ typedef struct {
+ [value(0)] uint16 reserved1;
+ [value(0)] uint16 reserved2;
+ [value(0)] uint32 reserved3;
+ uint32 keytype;
+ [value((value?value->length:0))] uint32 value_len;
+ [relative,subcontext(0),subcontext_size(value_len),flag(NDR_REMAINING)] DATA_BLOB *value;
+ } package_PrimaryKerberosKey3;
+
+ typedef struct {
+ uint16 num_keys;
+ uint16 num_old_keys;
+ package_PrimaryKerberosString salt;
+ package_PrimaryKerberosKey3 keys[num_keys];
+ package_PrimaryKerberosKey3 old_keys[num_old_keys];
+ [value(0)] uint32 padding1;
+ [value(0)] uint32 padding2;
+ [value(0)] uint32 padding3;
+ [value(0)] uint32 padding4;
+ [value(0)] uint32 padding5;
+ } package_PrimaryKerberosCtr3;
+
+ typedef struct {
+ [value(0)] uint16 reserved1;
+ [value(0)] uint16 reserved2;
+ [value(0)] uint32 reserved3;
+ uint32 iteration_count;
+ uint32 keytype;
+ [value((value?value->length:0))] uint32 value_len;
+ [relative,subcontext(0),subcontext_size(value_len),flag(NDR_REMAINING)] DATA_BLOB *value;
+ } package_PrimaryKerberosKey4;
+
+ typedef struct {
+ uint16 num_keys;
+ [value(0)] uint16 num_service_keys;
+ uint16 num_old_keys;
+ uint16 num_older_keys;
+ package_PrimaryKerberosString salt;
+ uint32 default_iteration_count;
+ package_PrimaryKerberosKey4 keys[num_keys];
+ package_PrimaryKerberosKey4 service_keys[num_service_keys];
+ package_PrimaryKerberosKey4 old_keys[num_old_keys];
+ package_PrimaryKerberosKey4 older_keys[num_older_keys];
+ } package_PrimaryKerberosCtr4;
+
+ typedef [nodiscriminant] union {
+ [case(3)] package_PrimaryKerberosCtr3 ctr3;
+ [case(4)] package_PrimaryKerberosCtr4 ctr4;
+ } package_PrimaryKerberosCtr;
+
+ typedef [public] struct {
+ uint16 version;
+ [value(0)] uint16 flags;
+ [switch_is(version)] package_PrimaryKerberosCtr ctr;
+ } package_PrimaryKerberosBlob;
+
+ typedef [public] struct {
+ [flag(NDR_REMAINING)] DATA_BLOB cleartext;
+ } package_PrimaryCLEARTEXTBlob;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 hash[16];
+ } package_PrimaryWDigestHash;
+
+ typedef [public] struct {
+ [value(0x31)] uint16 unknown1;
+ [value(0x01)] uint8 unknown2;
+ uint8 num_hashes;
+ [value(0)] uint32 unknown3;
+ [value(0)] udlong uuknown4;
+ package_PrimaryWDigestHash hashes[num_hashes];
+ } package_PrimaryWDigestBlob;
+
+ typedef [public] struct {
+ [flag(NDR_REMAINING)] DATA_BLOB gpg_blob;
+ } package_PrimarySambaGPGBlob;
+
+ /*
+ * Password hashes stored in a scheme compatible with
+ * OpenLDAP's userPassword attribute. The Package is named
+ * Primary:userPassword each calculated hash,
+ * which is typically calculated via crypt(), the scheme is stored.
+ * The scheme name and the {scheme} format is re-used from OpenLDAP's
+ * use for userPassword to aid interopability when exported.
+ *
+ * The currently supported scheme so far is {CRYPT}, which may
+ * be specified multiple times if both CryptSHA256 ($5$) and
+ * CryptSHA512 ($6$) are in use.
+ *
+ * current_nt_hash is either the unicodePwd or the
+ * NTLM-Strong-NTOWF, to allow us to prove this password is
+ * a valid element.
+ */
+ typedef struct {
+ [value(2*strlen_m(scheme))] uint16 scheme_len;
+ [charset(UTF16)] uint8 scheme[scheme_len];
+ [value((value?value->length:0))] uint32 value_len;
+ [relative,subcontext(0),subcontext_size(value_len),
+ flag(NDR_REMAINING)] DATA_BLOB *value;
+ } package_PrimaryUserPasswordValue;
+
+ typedef [public] struct {
+ samr_Password current_nt_hash;
+ uint16 num_hashes;
+ package_PrimaryUserPasswordValue hashes[num_hashes];
+ } package_PrimaryUserPasswordBlob;
+
+ typedef struct {
+ [value(0)] uint32 size;
+ } AuthInfoNone;
+
+ typedef struct {
+ [value(16)] uint32 size;
+ samr_Password password;
+ } AuthInfoNT4Owf;
+
+ /*
+ * the secret value is encoded as UTF16 if it's a string
+ * but depending the AuthType, it might also be krb5 trusts have random bytes here, so converting to UTF16
+ * mayfail...
+ *
+ * TODO: We should try handle the case of a random buffer in all places
+ * we deal with cleartext passwords from windows
+ *
+ * so we don't use this:
+ *
+ * uint32 value_len;
+ * [charset(UTF16)] uint8 value[value_len];
+ */
+
+ typedef struct {
+ uint32 size;
+ uint8 password[size];
+ } AuthInfoClear;
+
+ typedef struct {
+ [value(4)] uint32 size;
+ uint32 version;
+ } AuthInfoVersion;
+
+ typedef [nodiscriminant] union {
+ [case(TRUST_AUTH_TYPE_NONE)] AuthInfoNone none;
+ [case(TRUST_AUTH_TYPE_NT4OWF)] AuthInfoNT4Owf nt4owf;
+ [case(TRUST_AUTH_TYPE_CLEAR)] AuthInfoClear clear;
+ [case(TRUST_AUTH_TYPE_VERSION)] AuthInfoVersion version;
+ } AuthInfo;
+
+ typedef [public] struct {
+ NTTIME LastUpdateTime;
+ lsa_TrustAuthType AuthType;
+ [switch_is(AuthType)] AuthInfo AuthInfo;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad;
+ } AuthenticationInformation;
+
+ /* count is not on the wire */
+ typedef [public,nopull,nopush,gensize] struct {
+ uint32 count;
+ AuthenticationInformation array[count];
+ } AuthenticationInformationArray;
+
+ /* we cannot use [relative] pointers here because Windows expects the
+ * previous_offset to match the total size of the struct in case
+ * the previous array is empty, see MS-LSAD 2.2.7.16 - gd */
+ typedef [public,gensize,nopush] struct {
+ uint32 count;
+ [value((count > 0) ? 12 : 0)] uint32 current_offset;
+ [value((count > 0) ? 12 + ndr_size_AuthenticationInformationArray(&current, ndr->flags) : 0)] uint32 previous_offset;
+ [subcontext(0),subcontext_size((previous_offset)-(current_offset))] AuthenticationInformationArray current;
+ [subcontext(0)] [flag(NDR_REMAINING)] AuthenticationInformationArray previous;
+ } trustAuthInOutBlob;
+
+ typedef [public,nopull] struct {
+ uint8 confounder[512];
+ [subcontext(0),subcontext_size(outgoing_size)] trustAuthInOutBlob outgoing;
+ [subcontext(0),subcontext_size(incoming_size)] trustAuthInOutBlob incoming;
+ [value(ndr_size_trustAuthInOutBlob(&outgoing, ndr->flags))] uint32 outgoing_size;
+ [value(ndr_size_trustAuthInOutBlob(&incoming, ndr->flags))] uint32 incoming_size;
+ } trustDomainPasswords;
+
+ typedef [public] struct {
+ uint32 marker;
+ DATA_BLOB data;
+ } DsCompressedChunk;
+
+ typedef struct {
+ uint16 __size;
+ [size_is(__size),charset(DOS)] uint8 *string;
+ } ExtendedErrorAString;
+
+ typedef struct {
+ uint16 __size;
+ [size_is(__size),charset(UTF16)] uint16 *string;
+ } ExtendedErrorUString;
+
+ typedef struct {
+ uint16 length;
+ [size_is(length)] uint8 *data;
+ } ExtendedErrorBlob;
+
+ typedef enum {
+ EXTENDED_ERROR_COMPUTER_NAME_PRESENT = 1,
+ EXTENDED_ERROR_COMPUTER_NAME_NOT_PRESENT= 2
+ } ExtendedErrorComputerNamePresent;
+
+ typedef [switch_type(ExtendedErrorComputerNamePresent)] union {
+ [case(EXTENDED_ERROR_COMPUTER_NAME_PRESENT)] ExtendedErrorUString name;
+ [case(EXTENDED_ERROR_COMPUTER_NAME_NOT_PRESENT)];
+ } ExtendedErrorComputerNameU;
+
+ typedef struct {
+ ExtendedErrorComputerNamePresent present;
+ [switch_is(present)] ExtendedErrorComputerNameU n;
+ } ExtendedErrorComputerName;
+
+ typedef enum {
+ EXTENDED_ERROR_PARAM_TYPE_ASCII_STRING = 1,
+ EXTENDED_ERROR_PARAM_TYPE_UNICODE_STRING = 2,
+ EXTENDED_ERROR_PARAM_TYPE_UINT32 = 3,
+ EXTENDED_ERROR_PARAM_TYPE_UINT16 = 4,
+ EXTENDED_ERROR_PARAM_TYPE_UINT64 = 5,
+ EXTENDED_ERROR_PARAM_TYPE_NONE = 6,
+ EXTENDED_ERROR_PARAM_TYPE_BLOB = 7
+ } ExtendedErrorParamType;
+
+ typedef [switch_type(ExtendedErrorParamType)] union {
+ [case(EXTENDED_ERROR_PARAM_TYPE_ASCII_STRING)] ExtendedErrorAString a_string;
+ [case(EXTENDED_ERROR_PARAM_TYPE_UNICODE_STRING)] ExtendedErrorUString u_string;
+ [case(EXTENDED_ERROR_PARAM_TYPE_UINT32)] uint32 uint32;
+ [case(EXTENDED_ERROR_PARAM_TYPE_UINT16)] uint16 uint16;
+ [case(EXTENDED_ERROR_PARAM_TYPE_UINT64)] hyper uint64;
+ [case(EXTENDED_ERROR_PARAM_TYPE_NONE)];
+ [case(EXTENDED_ERROR_PARAM_TYPE_BLOB)] ExtendedErrorBlob blob;
+ } ExtendedErrorParamU;
+
+ typedef struct {
+ ExtendedErrorParamType type;
+ [switch_is(type)] ExtendedErrorParamU p;
+ } ExtendedErrorParam;
+
+ typedef [public] struct {
+ [max_recursion(20000)] ExtendedErrorInfo *next;
+ ExtendedErrorComputerName computer_name;
+ hyper pid;
+ NTTIME time;
+ uint32 generating_component;
+ WERROR status;
+ uint16 detection_location;
+ uint16 flags;
+ uint16 num_params;
+ [size_is(num_params)] ExtendedErrorParam params[];
+ } ExtendedErrorInfo;
+
+ typedef struct {
+ [unique] ExtendedErrorInfo *info;
+ } ExtendedErrorInfoPtr;
+
+ /* MS-ADTS 7.1.6.9.3 msDS-TrustForestTrustInfo Attribute */
+
+ typedef struct {
+ [value(strlen_m(string))] uint32 size;
+ [charset(UTF8)] uint8 string[size];
+ } ForestTrustString;
+
+ typedef [flag(NDR_NOALIGN)] struct {
+ [value(ndr_size_dom_sid0(&sid, ndr->flags))] uint32 sid_size;
+ [subcontext(0),subcontext_size(sid_size)] dom_sid sid;
+ ForestTrustString dns_name;
+ ForestTrustString netbios_name;
+ } ForestTrustDataDomainInfo;
+
+ typedef [flag(NDR_NOALIGN)] struct {
+ uint32 size;
+ uint8 data[size];
+ } ForestTrustDataBinaryData;
+
+ typedef [nodiscriminant] union {
+ [case(FOREST_TRUST_TOP_LEVEL_NAME)] ForestTrustString name;
+ [case(FOREST_TRUST_TOP_LEVEL_NAME_EX)] ForestTrustString name;
+ [case(FOREST_TRUST_DOMAIN_INFO)] ForestTrustDataDomainInfo info;
+ [default] ForestTrustDataBinaryData data;
+ } ForestTrustData;
+
+ /* same as lsa_ForestTrustRecordType, but only 8 bit */
+ typedef [enum8bit] enum {
+ FOREST_TRUST_TOP_LEVEL_NAME = LSA_FOREST_TRUST_TOP_LEVEL_NAME,
+ FOREST_TRUST_TOP_LEVEL_NAME_EX = LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX,
+ FOREST_TRUST_DOMAIN_INFO = LSA_FOREST_TRUST_DOMAIN_INFO
+ } ForestTrustInfoRecordType;
+
+ /* meaning of flags depends on record type and values are
+ the same as in lsa.idl, see collision record types */
+ typedef [public,gensize,flag(NDR_NOALIGN)] struct {
+ lsa_ForestTrustRecordFlags flags;
+ NTTIME timestamp;
+ ForestTrustInfoRecordType type;
+ [switch_is(type)] ForestTrustData data;
+ } ForestTrustInfoRecord;
+
+ typedef [flag(NDR_NOALIGN)] struct {
+ [value(ndr_size_ForestTrustInfoRecord(&record, ndr->flags))] uint32 record_size;
+ ForestTrustInfoRecord record;
+ } ForestTrustInfoRecordArmor;
+
+ typedef [public,flag(NDR_NOALIGN)] struct {
+ uint32 version;
+ uint32 count;
+ ForestTrustInfoRecordArmor records[count];
+ } ForestTrustInfo;
+
+ typedef enum {
+ ENC_SECRET_AES_128_AEAD = 1
+ } EncryptedSecretAlgorithm;
+
+ const uint32 ENCRYPTED_SECRET_MAGIC_VALUE = 0xCA5CADED;
+
+ typedef [public] struct {
+ DATA_BLOB cleartext;
+ } PlaintextSecret;
+
+ /* The AEAD routines uses this as the additional authenticated data */
+ typedef [public] struct {
+ uint32 magic;
+ uint32 version;
+ uint32 algorithm;
+ uint32 flags;
+ } EncryptedSecretHeader;
+
+ typedef [public] struct {
+ /*
+ * The iv is before the header to ensure that the first bytes of
+ * the encrypted values are not predictable.
+ * We do this so that if the decryption gets disabled, we don't
+ * end up with predictable unicodePasswords.
+ */
+ DATA_BLOB iv;
+ EncryptedSecretHeader header;
+ [flag(NDR_REMAINING)] DATA_BLOB encrypted;
+ } EncryptedSecret;
+}
diff --git a/librpc/idl/drsuapi.idl b/librpc/idl/drsuapi.idl
new file mode 100644
index 0000000..99fbca6
--- /dev/null
+++ b/librpc/idl/drsuapi.idl
@@ -0,0 +1,1915 @@
+#include "idl_types.h"
+
+import "security.idl", "misc.idl", "lsa.idl", "samr.idl";
+
+[
+ uuid("e3514235-4b06-11d1-ab04-00c04fc2dcd2"),
+ version(4.0),
+ endpoint("ncacn_np:[\\pipe\\lsass]","ncacn_np:[\\pipe\\protected_storage]", "ncacn_ip_tcp:", "ncalrpc:"),
+ authservice("ldap"),
+ helpstring("Active Directory Replication"),
+ helper("../librpc/ndr/ndr_drsuapi.h"),
+ pointer_default(unique)
+]
+interface drsuapi
+{
+ typedef bitmap security_GroupAttrs security_GroupAttrs;
+
+ /* see MS-DRSR section 5.39 */
+ typedef [public,bitmap32bit] bitmap {
+ DRSUAPI_DRS_ASYNC_OP = 0x00000001,
+ DRSUAPI_DRS_GETCHG_CHECK = 0x00000002,
+ DRSUAPI_DRS_UPDATE_NOTIFICATION = 0x00000002,
+ DRSUAPI_DRS_ADD_REF = 0x00000004,
+ DRSUAPI_DRS_SYNC_ALL = 0x00000008,
+ DRSUAPI_DRS_DEL_REF = 0x00000008,
+ DRSUAPI_DRS_WRIT_REP = 0x00000010,
+ DRSUAPI_DRS_INIT_SYNC = 0x00000020,
+ DRSUAPI_DRS_PER_SYNC = 0x00000040,
+ DRSUAPI_DRS_MAIL_REP = 0x00000080,
+ DRSUAPI_DRS_ASYNC_REP = 0x00000100,
+ DRSUAPI_DRS_IGNORE_ERROR = 0x00000100,
+ DRSUAPI_DRS_TWOWAY_SYNC = 0x00000200,
+ DRSUAPI_DRS_CRITICAL_ONLY = 0x00000400,
+ DRSUAPI_DRS_GET_ANC = 0x00000800,
+ DRSUAPI_DRS_GET_NC_SIZE = 0x00001000,
+ DRSUAPI_DRS_LOCAL_ONLY = 0x00001000,
+ DRSUAPI_DRS_NONGC_RO_REP = 0x00002000,
+ DRSUAPI_DRS_SYNC_BYNAME = 0x00004000,
+ DRSUAPI_DRS_REF_OK = 0x00004000,
+ DRSUAPI_DRS_FULL_SYNC_NOW = 0x00008000,
+ DRSUAPI_DRS_NO_SOURCE = 0x00008000,
+ DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS = 0x00010000,
+ DRSUAPI_DRS_FULL_SYNC_PACKET = 0x00020000,
+ DRSUAPI_DRS_SYNC_REQUEUE = 0x00040000,
+ DRSUAPI_DRS_SYNC_URGENT = 0x00080000,
+ DRSUAPI_DRS_REF_GCSPN = 0x00100000,
+ DRSUAPI_DRS_NO_DISCARD = 0x00100000,
+ DRSUAPI_DRS_NEVER_SYNCED = 0x00200000,
+ DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING = 0x00400000,
+ DRSUAPI_DRS_INIT_SYNC_NOW = 0x00800000,
+ DRSUAPI_DRS_PREEMPTED = 0x01000000,
+ DRSUAPI_DRS_SYNC_FORCED = 0x02000000,
+ DRSUAPI_DRS_DISABLE_AUTO_SYNC = 0x04000000,
+ DRSUAPI_DRS_DISABLE_PERIODIC_SYNC = 0x08000000,
+ DRSUAPI_DRS_USE_COMPRESSION = 0x10000000,
+ DRSUAPI_DRS_NEVER_NOTIFY = 0x20000000,
+ DRSUAPI_DRS_SYNC_PAS = 0x40000000,
+ DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP = 0x80000000
+ } drsuapi_DrsOptions;
+
+ typedef [public,bitmap32bit] bitmap {
+ DRSUAPI_DRS_GET_TGT = 0x00000001
+ } drsuapi_DrsMoreOptions;
+
+ /* see DRS_MSG_REPMOD_V1 */
+ typedef [public,bitmap32bit] bitmap {
+ DRSUAPI_DRS_UPDATE_FLAGS = 0x00000001,
+ DRSUAPI_DRS_UPDATE_ADDRESS = 0x00000002,
+ DRSUAPI_DRS_UPDATE_SCHEDULE = 0x00000004
+ } drsuapi_DrsUpdate;
+
+ /*****************/
+ /* Function 0x00 drsuapi_DsBind() */
+
+ /* MS-DRSR 5.39 DRS_EXTENSIONS_INT */
+ typedef [bitmap32bit] bitmap {
+ DRSUAPI_SUPPORTED_EXTENSION_BASE = 0x00000001,
+ DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION = 0x00000002,
+ DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI = 0x00000004,
+ DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2 = 0x00000008,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS = 0x00000010,
+ DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1 = 0x00000020,
+ DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION = 0x00000040,
+ DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY = 0x00000080,
+ DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE = 0x00000100,
+ DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2 = 0x00000200,
+ DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION = 0x00000400,
+ DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2 = 0x00000800,
+ DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD= 0x00001000,
+ DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND = 0x00002000,
+ DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO = 0x00004000,
+ DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION = 0x00008000,
+ DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01 = 0x00010000,
+ DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP = 0x00020000,
+ DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY = 0x00040000,
+ DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3 = 0x00080000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V5 = 0x00100000,
+ DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2 = 0x00200000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6 = 0x00400000,
+ DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS = 0x00800000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8 = 0x01000000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5 = 0x02000000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6 = 0x04000000,
+ /*
+ * the following 3 have the same value
+ * repadmin.exe /bind says that
+ */
+ DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3 = 0x08000000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7 = 0x08000000,
+ DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT = 0x08000000,
+ DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS = 0x10000000,
+ DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10 = 0x20000000,
+ DRSUAPI_SUPPORTED_EXTENSION_RESERVED_PART2 = 0x40000000,
+ DRSUAPI_SUPPORTED_EXTENSION_RESERVED_PART3 = 0x80000000
+ } drsuapi_SupportedExtensions;
+
+ typedef [bitmap32bit] bitmap {
+ DRSUAPI_SUPPORTED_EXTENSION_ADAM = 0x00000001,
+ DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2 = 0x00000002,
+ DRSUAPI_SUPPORTED_EXTENSION_RECYCLE_BIN = 0x00000004
+ } drsuapi_SupportedExtensionsExt;
+
+ /* this is used by w2k */
+ typedef [public] struct {
+ drsuapi_SupportedExtensions supported_extensions;
+ GUID site_guid;
+ uint32 pid;
+ } drsuapi_DsBindInfo24;
+
+ /* this is used by w2k3 */
+ typedef [public] struct {
+ drsuapi_SupportedExtensions supported_extensions;
+ GUID site_guid;
+ uint32 pid;
+ uint32 repl_epoch;
+ } drsuapi_DsBindInfo28;
+
+ typedef [public] struct {
+ drsuapi_SupportedExtensions supported_extensions;
+ GUID site_guid;
+ uint32 pid;
+ uint32 repl_epoch;
+ drsuapi_SupportedExtensionsExt supported_extensions_ext;
+ } drsuapi_DsBindInfo32;
+
+ /* this is used by w2k8 */
+ typedef [public] struct {
+ drsuapi_SupportedExtensions supported_extensions;
+ GUID site_guid;
+ uint32 pid;
+ uint32 repl_epoch;
+ drsuapi_SupportedExtensionsExt supported_extensions_ext;
+ GUID config_dn_guid;
+ } drsuapi_DsBindInfo48;
+
+ /* this is used by w2k12 R2 [MS-DRSR] Section 5.39 */
+ typedef [public] struct {
+ drsuapi_SupportedExtensions supported_extensions;
+ GUID site_guid;
+ uint32 pid;
+ uint32 repl_epoch;
+ drsuapi_SupportedExtensionsExt supported_extensions_ext;
+ GUID config_dn_guid;
+ drsuapi_SupportedExtensionsExt supported_capabilities_ext;
+ } drsuapi_DsBindInfo52;
+
+ typedef [public] struct {
+ [flag(NDR_REMAINING)] DATA_BLOB info;
+ } drsuapi_DsBindInfoFallBack;
+
+ typedef [nopull, nopush, noprint] [nodiscriminant] union {
+ [case(24)][subcontext(0), subcontext_size(24)] drsuapi_DsBindInfo24 info24;
+ [case(28)][subcontext(0), subcontext_size(28)] drsuapi_DsBindInfo28 info28;
+ [case(32)][subcontext(0), subcontext_size(32)] drsuapi_DsBindInfo32 info32;
+ [case(48)][subcontext(0), subcontext_size(48)] drsuapi_DsBindInfo48 info48;
+ [case(52)][subcontext(0), subcontext_size(52)] drsuapi_DsBindInfo52 info52;
+ /*
+ * The size for the default case is a bit arbitrary it in fact the value
+ * of the switch but we can't reference it.
+ * As we hand(un-)marshall this structure it has 0 impact and makes
+ * pidl happy for wireshark too
+ */
+ [default][subcontext(0), subcontext_size(48)] drsuapi_DsBindInfoFallBack Fallback;
+ } drsuapi_DsBindInfo;
+
+ /* the drsuapi_DsBindInfoCtr was this before
+ * typedef [flag(NDR_PAHEX)] struct {
+ * [range(1,10000)] uint32 length;
+ * [size_is(length)] uint8 data[];
+ * } drsuapi_DsBindInfo;
+ *
+ * but we don't want the caller to manually decode this blob,
+ * so we're doing it here
+ */
+
+ /*
+ * MS-DRSR.pdf gives the following definition
+ typedef struct {
+ [range(1,10000)] DWORD cb;
+ [size_is(cb)] BYTE rgb[];
+ } DRS_EXTENSIONS;
+
+ But we use a subcontext which has a slightly different signification on how
+ data are laid out.
+ With the MS-DRSR definition we will have
+ size_is_cb cv rgb_array
+ with size_is_cb being a uint3264 and cv being a uint32
+
+ We used to have
+ typedef struct {
+ [range(1,10000)] uint32 length;
+ [switch_is(length)] drsuapi_DsBindInfo info;
+ } drsuapi_DsBindInfoCtr;
+
+ typedef [nodiscriminant] union {
+ [case(24)][subcontext(4)] drsuapi_DsBindInfo24 info24;
+ [case(28)][subcontext(4)] drsuapi_DsBindInfo28 info28;
+ [case(48)][subcontext(4)] drsuapi_DsBindInfo48 info48;
+ [default][subcontext(4)] drsuapi_DsBindInfoFallBack FallBack;
+ } drsuapi_DsBindInfo;
+
+ With this definition data is laid out this way:
+ length subcontext_size drsuapi_DsBindInfoxx
+ with length being a uint32 and subcontext_size being a uint3264
+
+ It has clearly an impact on the way things are aligned when using NDR64
+ */
+ typedef [flag(NDR_NOALIGN)] struct {
+ [range(1,10000)] uint3264 length;
+ [value(length)] uint32 __ndr_length;
+ [switch_is(length)] drsuapi_DsBindInfo info;
+ } drsuapi_DsBindInfoCtr;
+
+ /* this is a magic guid you need to pass to DsBind to make drsuapi_DsWriteAccountSpn() work
+ *
+ * maybe the bind_guid could also be the invocation_id see drsuapi_DsReplicaConnection04
+ */
+ const char *DRSUAPI_DS_BIND_GUID = "e24d201a-4fd6-11d1-a3da-0000f875ae0d";
+ /*
+ * this magic guid are needed to fetch the whole tree with drsuapi_DsGetNCChanges()
+ * as administrator and this values are also used in the destination_dsa_guid field
+ * of drsuapi_DsGetNCChangesReq5/8 and the source_dsa_guid is zero.
+ */
+ const char *DRSUAPI_DS_BIND_GUID_W2K = "6abec3d1-3054-41c8-a362-5a0c5b7d5d71";
+ const char *DRSUAPI_DS_BIND_GUID_W2K3 = "6afab99c-6e26-464a-975f-f58f105218bc";
+
+ [public] WERROR drsuapi_DsBind(
+ [in,unique] GUID *bind_guid,
+ [in,out,unique] drsuapi_DsBindInfoCtr *bind_info,
+ [out] policy_handle *bind_handle
+ );
+
+ /*****************/
+ /* Function 0x01 */
+ WERROR drsuapi_DsUnbind(
+ [in,out] policy_handle *bind_handle
+ );
+
+ /*****************/
+ /* Function 0x02 */
+ typedef [public,gensize] struct {
+ [value(ndr_size_drsuapi_DsReplicaObjectIdentifier(r, ndr->flags)-4)] uint32 __ndr_size;
+ [value(ndr_size_dom_sid28(&sid, ndr->flags))] uint32 __ndr_size_sid;
+ GUID guid;
+ dom_sid28 sid;
+ [value(strlen_m(dn))] uint32 __ndr_size_dn;
+ [charset(UTF16),size_is(__ndr_size_dn+1)] uint16 dn[];
+ } drsuapi_DsReplicaObjectIdentifier;
+
+ typedef struct {
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ GUID source_dsa_guid;
+ [charset(DOS),string] char *source_dsa_dns; /* Source DSA dns_name in <guid>._msdcs.<domain_dns> form */
+ drsuapi_DrsOptions options;
+ } drsuapi_DsReplicaSyncRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsReplicaSyncRequest1 req1;
+ } drsuapi_DsReplicaSyncRequest;
+
+ WERROR drsuapi_DsReplicaSync(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,switch_is(level)] drsuapi_DsReplicaSyncRequest *req
+ );
+
+ /*****************/
+ /* Function 0x03 */
+ typedef [public] struct {
+ hyper tmp_highest_usn; /* updated after each object update */
+ hyper reserved_usn;
+ hyper highest_usn; /* updated after a full replication cycle */
+ } drsuapi_DsReplicaHighWaterMark;
+
+ typedef [public] struct {
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ hyper highest_usn; /* updated after a full replication cycle */
+ } drsuapi_DsReplicaCursor;
+
+ typedef struct {
+ [value(1)] uint32 version;
+ [value(0)] uint32 reserved1;
+ [range(0,0x100000)] uint32 count;
+ [value(0)] uint32 reserved2;
+ [size_is(count)] drsuapi_DsReplicaCursor cursors[];
+ } drsuapi_DsReplicaCursorCtrEx;
+
+ typedef [flag(NDR_PAHEX),v1_enum] enum {
+ DRSUAPI_EXOP_NONE = 0x00000000,
+ DRSUAPI_EXOP_FSMO_REQ_ROLE = 0x00000001,
+ DRSUAPI_EXOP_FSMO_RID_ALLOC = 0x00000002,
+ DRSUAPI_EXOP_FSMO_RID_REQ_ROLE = 0x00000003,
+ DRSUAPI_EXOP_FSMO_REQ_PDC = 0x00000004,
+ DRSUAPI_EXOP_FSMO_ABANDON_ROLE = 0x00000005,
+ DRSUAPI_EXOP_REPL_OBJ = 0x00000006,
+ DRSUAPI_EXOP_REPL_SECRET = 0x00000007
+ } drsuapi_DsExtendedOperation;
+
+ typedef [flag(NDR_PAHEX),v1_enum] enum {
+ DRSUAPI_EXOP_ERR_NONE = 0x00000000,
+ DRSUAPI_EXOP_ERR_SUCCESS = 0x00000001,
+ DRSUAPI_EXOP_ERR_UNKNOWN_OP = 0x00000002,
+ DRSUAPI_EXOP_ERR_FSMO_NOT_OWNER = 0x00000003,
+ DRSUAPI_EXOP_ERR_UPDATE_ERR = 0x00000004,
+ DRSUAPI_EXOP_ERR_EXCEPTION = 0x00000005,
+ DRSUAPI_EXOP_ERR_UNKNOWN_CALLER = 0x00000006,
+ DRSUAPI_EXOP_ERR_RID_ALLOC = 0x00000007,
+ DRSUAPI_EXOP_ERR_FSMO_OWNER_DELETED = 0x00000008,
+ DRSUAPI_EXOP_ERR_FMSO_PENDING_OP = 0x00000009,
+ DRSUAPI_EXOP_ERR_MISMATCH = 0x0000000A,
+ DRSUAPI_EXOP_ERR_COULDNT_CONTACT = 0x0000000B,
+ DRSUAPI_EXOP_ERR_FSMO_REFUSING_ROLES = 0x0000000C,
+ DRSUAPI_EXOP_ERR_DIR_ERROR = 0x0000000D,
+ DRSUAPI_EXOP_ERR_FSMO_MISSING_SETTINGS = 0x0000000E,
+ DRSUAPI_EXOP_ERR_ACCESS_DENIED = 0x0000000F,
+ DRSUAPI_EXOP_ERR_PARAM_ERROR = 0x00000010
+ } drsuapi_DsExtendedError;
+
+ typedef struct {
+ GUID destination_dsa_guid;
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
+ drsuapi_DrsOptions replica_flags;
+ uint32 max_object_count; /* w2k3 uses min(133,max(100,max_object_count)) */
+ uint32 max_ndr_size; /* w2k3 seems to ignore this */
+ drsuapi_DsExtendedOperation extended_op;
+ hyper fsmo_info;
+ } drsuapi_DsGetNCChangesRequest5;
+
+ /*
+ * In DRSUAPI all attributes with syntax 2.5.5.2
+ * are identified by uint32 values
+ *
+ * the following table shows the mapping used between the two representations
+ * e.g. - objectClass 'nTDSDSA' has governsID: 1.2.840.113556.1.5.7000.47
+ * and a UINT32-ID of '0x0017002F'.
+ * - so the OID 1.2.840.113556.1.5.7000.47 is split into a
+ * OID-prefix: 1.2.840.113556.1.5.7000
+ * and a value: 47 => 0x2F
+ * - the mapping table gives a UINT32-prefix: 0x00170000
+ * - and the UINT32-ID is 0x0017002F = 0x00170000 | 0x2F
+ *
+ * This prefix mapping table is replied in the drsuapi_DsReplicaOIDMapping_Ctr
+ * array. The following are the default mappings of w2k3
+ *
+ * OID-prefix => UINT32-Id prefix
+ *
+ * 2.5.4.* => 0x00000000 (standard attributes RFC2256 core.schema)
+ * 2.5.6.* => 0x00010000 (standard object classes RFC2256 core.schema)
+ * 1.2.840.113556.1.2.* => 0x00020000
+ * 1.2.840.113556.1.3.* => 0x00030000
+ * 2.5.5.* => 0x00080000 (attributeSyntax OID's)
+ * 1.2.840.113556.1.4.* => 0x00090000
+ * 1.2.840.113556.1.5.* => 0x000A0000
+ * 2.16.840.1.113730.3.* => 0x00140000
+ * 0.9.2342.19200300.100.1.* => 0x00150000
+ * 2.16.840.1.113730.3.1.* => 0x00160000
+ * 1.2.840.113556.1.5.7000.* => 0x00170000
+ * 2.5.21.* => 0x00180000 (attrs for SubSchema)
+ * 2.5.18.* => 0x00190000 (createTimeStamp,modifyTimeStamp, SubSchema)
+ * 2.5.20.* => 0x001A0000
+ * 1.3.6.1.4.1.1466.101.119.* => 0x001B0000 (dynamicObject, entryTTL)
+ * 2.16.840.1.113730.3.2.* => 0x001C0000
+ * 1.3.6.1.4.1.250.1.* => 0x001D0000
+ * 1.2.840.113549.1.9.* => 0x001E0000 (unstructuredAddress,unstructuredName)
+ * 0.9.2342.19200300.100.4.* => 0x001F0000
+ *
+ * Here's a list of used 'attributeSyntax' OID's
+ *
+ * 2.5.5.1 => Object(DS-DN) string
+ * struct drsuapi_DsObjectIdentifier3
+ *
+ * 2.5.5.2 => OID-string
+ * => all values are represented as uint32 values in drsuapi
+ * => governsID, attributeID and attributeSyntax returned as OID-Strings in LDAP
+ * => mayContain, mustContain and all other attributes with 2.5.5.2 syntax
+ * are returned as attribute names
+ *
+ * 2.5.5.4 => String(Teletex) case-insensitive string with teletex charset
+ *
+ * 2.5.5.5 => String(IA5) case-sensitive string
+ *
+ * 2.5.5.6 => String(Numeric)
+ * => eg. internationalISDNNumber
+ *
+ * 2.5.5.7 => Object(DN-Binary) B:<byte count>:<bytes>:<object DN>
+ * => e.g. wellKnownObjects
+ *
+ * 2.5.5.8 => BOOL
+ *
+ * 2.5.5.9 => int32
+ *
+ * 2.5.5.10 => DATA_BLOB
+ * => struct GUID
+ *
+ * 2.5.5.11 => LDAP timestring
+ * => NTTIME_1sec
+ *
+ * 2.5.5.12 => String(Unicode) case-insensitive string
+ * => 'standard strings'
+ *
+ * 2.5.5.13 => Object(Presentation-Address) string
+ * => used in objectClass applicationEntity
+ *
+ * 2.5.5.14 => Object(DN-String) S:<char count>:<string>:<object DN>
+ * => not used
+ *
+ * 2.5.5.15 => ntSecurityDescriptor
+ *
+ * 2.5.5.16 => int64
+ *
+ * 2.5.5.17 => dom_sid
+ */
+ typedef [noprint] struct {
+ [range(0,10000)] uint32 length;
+ [size_is(length)] uint8 *binary_oid; /* partial-binary-OID encoded with asn1_write_partial_OID_String() */
+ } drsuapi_DsReplicaOID;
+
+ typedef struct {
+ uint32 id_prefix;
+ drsuapi_DsReplicaOID oid;
+ } drsuapi_DsReplicaOIDMapping;
+
+ typedef [public] struct {
+ [range(0,0x100000)] uint32 num_mappings;
+ [size_is(num_mappings)] drsuapi_DsReplicaOIDMapping *mappings;
+ } drsuapi_DsReplicaOIDMapping_Ctr;
+
+ typedef [flag(NDR_PAHEX),v1_enum] enum {
+ DRSUAPI_OBJECTCLASS_top = 0x00010000,
+ DRSUAPI_OBJECTCLASS_classSchema = 0x0003000d,
+ DRSUAPI_OBJECTCLASS_attributeSchema = 0x0003000e
+ } drsuapi_DsObjectClassId;
+
+ typedef [flag(NDR_PAHEX),v1_enum,public] enum {
+ DRSUAPI_ATTID_objectClass = 0x00000000,
+ DRSUAPI_ATTID_cn = 0x00000003,
+ DRSUAPI_ATTID_ou = 0x0000000b,
+ DRSUAPI_ATTID_description = 0x0000000d,
+ DRSUAPI_ATTID_member = 0x0000001f,
+ DRSUAPI_ATTID_distinguishedName = 0x00000031,
+ DRSUAPI_ATTID_instanceType = 0x00020001,
+ DRSUAPI_ATTID_whenCreated = 0x00020002,
+ DRSUAPI_ATTID_possSuperiors = 0x00020008,
+ DRSUAPI_ATTID_displayName = 0x0002000d,
+ DRSUAPI_ATTID_hasMasterNCs = 0x0002000e,
+ DRSUAPI_ATTID_nCName = 0x00020010,
+ DRSUAPI_ATTID_subClassOf = 0x00020015,
+ DRSUAPI_ATTID_governsID = 0x00020016,
+ DRSUAPI_ATTID_mustContain = 0x00020018,
+ DRSUAPI_ATTID_mayContain = 0x00020019,
+ DRSUAPI_ATTID_rDNAttId = 0x0002001A,
+ DRSUAPI_ATTID_attributeID = 0x0002001e,
+ DRSUAPI_ATTID_attributeSyntax = 0x00020020,
+ DRSUAPI_ATTID_isSingleValued = 0x00020021,
+ DRSUAPI_ATTID_rangeLower = 0x00020022,
+ DRSUAPI_ATTID_rangeUpper = 0x00020023,
+ DRSUAPI_ATTID_dMDLocation = 0x00020024,
+ DRSUAPI_ATTID_isDeleted = 0x00020030,
+ DRSUAPI_ATTID_objectVersion = 0x0002004c,
+ DRSUAPI_ATTID_invocationId = 0x00020073,
+ DRSUAPI_ATTID_showInAdvancedViewOnly = 0x000200a9,
+ DRSUAPI_ATTID_adminDisplayName = 0x000200c2,
+ DRSUAPI_ATTID_adminDescription = 0x000200e2,
+ DRSUAPI_ATTID_oMSyntax = 0x000200e7,
+ DRSUAPI_ATTID_ntSecurityDescriptor = 0x00020119,
+ DRSUAPI_ATTID_searchFlags = 0x0002014e,
+ DRSUAPI_ATTID_auxiliaryClass = 0x0002015f,
+ DRSUAPI_ATTID_lDAPDisplayName = 0x000201cc,
+ DRSUAPI_ATTID_name = 0x00090001,
+ DRSUAPI_ATTID_objectGUID = 0x00090002,
+ DRSUAPI_ATTID_replPropertyMetaData = 0x00090003,
+ DRSUAPI_ATTID_userAccountControl = 0x00090008,
+ DRSUAPI_ATTID_badPwdCount = 0x0009000c,
+ DRSUAPI_ATTID_codePage = 0x00090010,
+ DRSUAPI_ATTID_countryCode = 0x00090019,
+ DRSUAPI_ATTID_currentValue = 0x0009001b,
+ DRSUAPI_ATTID_homeDirectory = 0x0009002c,
+ DRSUAPI_ATTID_homeDrive = 0x0009002d,
+ DRSUAPI_ATTID_lastLogoff = 0x00090033,
+ DRSUAPI_ATTID_lastLogon = 0x00090034,
+ DRSUAPI_ATTID_dBCSPwd = 0x00090037,/* lmPwdHash */
+ DRSUAPI_ATTID_scriptPath = 0x0009003e,
+ DRSUAPI_ATTID_logonHours = 0x00090040,
+ DRSUAPI_ATTID_userWorkstations = 0x00090056,
+ DRSUAPI_ATTID_unicodePwd = 0x0009005a,/* ntPwdHash */
+ DRSUAPI_ATTID_ntPwdHistory = 0x0009005e,
+ DRSUAPI_ATTID_pwdLastSet = 0x00090060,
+ DRSUAPI_ATTID_primaryGroupID = 0x00090062,
+ DRSUAPI_ATTID_priorValue = 0x00090064,
+ DRSUAPI_ATTID_supplementalCredentials = 0x0009007d,
+ DRSUAPI_ATTID_trustAuthIncoming = 0x00090081,
+ DRSUAPI_ATTID_trustDirection = 0x00090084,
+ DRSUAPI_ATTID_trustPartner = 0x00090085,
+ DRSUAPI_ATTID_trustPosixOffset = 0x00090086,
+ DRSUAPI_ATTID_trustAuthOutgoing = 0x00090087,
+ DRSUAPI_ATTID_trustType = 0x00090088,
+ DRSUAPI_ATTID_userParameters = 0x0009008a,
+ DRSUAPI_ATTID_profilePath = 0x0009008b,
+ DRSUAPI_ATTID_operatorCount = 0x00090090,
+ DRSUAPI_ATTID_objectSid = 0x00090092,
+ DRSUAPI_ATTID_schemaIDGUID = 0x00090094,
+ DRSUAPI_ATTID_adminCount = 0x00090096,
+ DRSUAPI_ATTID_comment = 0x0009009C,/* User-Comment */
+ DRSUAPI_ATTID_accountExpires = 0x0009009f,
+ DRSUAPI_ATTID_lmPwdHistory = 0x000900a0,
+ DRSUAPI_ATTID_logonCount = 0x000900a9,
+ DRSUAPI_ATTID_systemPossSuperiors = 0x000900c3,
+ DRSUAPI_ATTID_systemMayContain = 0x000900c4,
+ DRSUAPI_ATTID_systemMustContain = 0x000900c5,
+ DRSUAPI_ATTID_systemAuxiliaryClass = 0x000900c6,
+ DRSUAPI_ATTID_sAMAccountName = 0x000900dd,
+ DRSUAPI_ATTID_sAMAccountType = 0x0009012e,
+ DRSUAPI_ATTID_options = 0x00090133,
+ DRSUAPI_ATTID_fSMORoleOwner = 0x00090171,
+ DRSUAPI_ATTID_systemFlags = 0x00090177,
+ DRSUAPI_ATTID_trustAttributes = 0x000901d6,
+ DRSUAPI_ATTID_trustParent = 0x000901d7,
+ DRSUAPI_ATTID_flatName = 0x000901ff,
+ DRSUAPI_ATTID_serverReference = 0x00090203,
+ DRSUAPI_ATTID_serverReferenceBL = 0x00090204,
+ DRSUAPI_ATTID_nonSecurityMember = 0x00090212,
+ DRSUAPI_ATTID_initialAuthIncoming = 0x0009021b,
+ DRSUAPI_ATTID_initialAuthOutgoing = 0x0009021c,
+ DRSUAPI_ATTID_wellKnownObjects = 0x0009026a,
+ DRSUAPI_ATTID_dNSHostName = 0x0009026b,
+ DRSUAPI_ATTID_isMemberOfPartialAttributeSet = 0x0009027f,
+ DRSUAPI_ATTID_managedBy = 0x0009028d,
+ DRSUAPI_ATTID_userPrincipalName = 0x00090290,
+ DRSUAPI_ATTID_groupType = 0x000902ee,
+ DRSUAPI_ATTID_servicePrincipalName = 0x00090303,
+ DRSUAPI_ATTID_lastKnownParent = 0x0009030d,
+ DRSUAPI_ATTID_objectCategory = 0x0009030e,
+ DRSUAPI_ATTID_gPLink = 0x0009037b,
+ DRSUAPI_ATTID_transportAddressAttribute = 0x0009037f,
+ DRSUAPI_ATTID_schemaInfo = 0x0009054e,
+ DRSUAPI_ATTID_msDS_Behavior_Version = 0x000905b3,
+ DRSUAPI_ATTID_msDS_TrustForestTrustInfo = 0x000906a6,
+ DRSUAPI_ATTID_msDS_KeyVersionNumber = 0x000906f6,
+ DRSUAPI_ATTID_msDS_NonMembers = 0x00090701,
+ DRSUAPI_ATTID_msDS_MembersForAzRole = 0x0009070e,
+ DRSUAPI_ATTID_msDS_HasDomainNCs = 0x0009071c,
+ DRSUAPI_ATTID_msDS_hasMasterNCs = 0x0009072c,
+ DRSUAPI_ATTID_msDS_NeverRevealGroup = 0x00090786,
+ DRSUAPI_ATTID_msDS_RevealOnDemandGroup = 0x00090788,
+ DRSUAPI_ATTID_msDS_SupportedEncryptionTypes = 0x000907ab,
+ DRSUAPI_ATTID_msDS_HostServiceAccount = 0x00090808,
+ DRSUAPI_ATTID_isRecycled = 0x0009080a,
+
+ DRSUAPI_ATTID_INVALID = 0xFFFFFFFF
+ } drsuapi_DsAttributeId;
+
+ typedef struct {
+ [value(1)] uint32 version;
+ [value(0)] uint32 reserved1;
+ [range(1,0x100000)] uint32 num_attids;
+ [size_is(num_attids)] drsuapi_DsAttributeId attids[];
+ } drsuapi_DsPartialAttributeSet;
+
+ typedef [public] struct {
+ GUID destination_dsa_guid;
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
+ drsuapi_DrsOptions replica_flags;
+ uint32 max_object_count; /* w2k3 uses min(133,max(100,max_object_count)) */
+ uint32 max_ndr_size; /* w2k3 seems to ignore this */
+ drsuapi_DsExtendedOperation extended_op;
+ hyper fsmo_info;
+ drsuapi_DsPartialAttributeSet *partial_attribute_set;
+ drsuapi_DsPartialAttributeSet *partial_attribute_set_ex;
+ drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+ } drsuapi_DsGetNCChangesRequest8;
+
+ typedef [public] struct {
+ GUID destination_dsa_guid;
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaHighWaterMark highwatermark;
+ drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
+ drsuapi_DrsOptions replica_flags;
+ uint32 max_object_count; /* w2k3 uses min(133,max(100,max_object_count)) */
+ uint32 max_ndr_size; /* w2k3 seems to ignore this */
+ drsuapi_DsExtendedOperation extended_op;
+ hyper fsmo_info;
+ drsuapi_DsPartialAttributeSet *partial_attribute_set;
+ drsuapi_DsPartialAttributeSet *partial_attribute_set_ex;
+ drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+ drsuapi_DrsMoreOptions more_flags;
+ } drsuapi_DsGetNCChangesRequest10;
+
+ typedef [switch_type(uint32)] union {
+ [case(5)] drsuapi_DsGetNCChangesRequest5 req5;
+ [case(8)] drsuapi_DsGetNCChangesRequest8 req8;
+ [case(10)] drsuapi_DsGetNCChangesRequest10 req10;
+ } drsuapi_DsGetNCChangesRequest;
+
+ typedef [public] struct {
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ hyper highest_usn; /* updated after a full replication cycle */
+ NTTIME last_sync_success;
+ } drsuapi_DsReplicaCursor2;
+
+ typedef struct {
+ [value(2)] uint32 version;
+ [value(0)] uint32 reserved1;
+ [range(0,0x100000)] uint32 count;
+ [value(0)] uint32 reserved2;
+ [size_is(count)] drsuapi_DsReplicaCursor2 cursors[];
+ } drsuapi_DsReplicaCursor2CtrEx;
+
+ /* Generic DATA_BLOB values */
+ typedef struct {
+ [range(0,26214400),value(ndr_size_DATA_BLOB(0,blob,0))] uint32 __ndr_size;
+ DATA_BLOB *blob;
+ } drsuapi_DsAttributeValue;
+
+ typedef struct {
+ [range(0,10485760)] uint32 num_values;
+ [size_is(num_values)] drsuapi_DsAttributeValue *values;
+ } drsuapi_DsAttributeValueCtr;
+
+ /* DN String values */
+ typedef [public,gensize] struct {
+ [value(ndr_size_drsuapi_DsReplicaObjectIdentifier3(r, ndr->flags))] uint32 __ndr_size;
+ [value(ndr_size_dom_sid28(&sid,ndr->flags))] uint32 __ndr_size_sid;
+ GUID guid;
+ dom_sid28 sid;
+ [value(strlen_m(dn))] uint32 __ndr_size_dn;
+ [charset(UTF16)] uint16 dn[__ndr_size_dn+1];
+ } drsuapi_DsReplicaObjectIdentifier3;
+
+ typedef [public] struct {
+ [value(ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary_without_Binary(r, ndr->flags))] uint32 __ndr_size;
+ [value(ndr_size_dom_sid28(&sid,ndr->flags))] uint32 __ndr_size_sid;
+ GUID guid;
+ dom_sid28 sid;
+ [value(strlen_m(dn))] uint32 __ndr_size_dn;
+ [charset(UTF16)] uint16 dn[__ndr_size_dn+1];
+ [value(binary.length + 4)] uint32 __ndr_size_binary;
+ [flag(NDR_REMAINING)] DATA_BLOB binary;
+ } drsuapi_DsReplicaObjectIdentifier3Binary;
+
+ typedef [public,noprint] struct {
+ drsuapi_DsAttributeId attid;
+ drsuapi_DsAttributeValueCtr value_ctr;
+ } drsuapi_DsReplicaAttribute;
+
+ typedef struct {
+ [range(0,1048576)] uint32 num_attributes;
+ [size_is(num_attributes)] drsuapi_DsReplicaAttribute *attributes;
+ } drsuapi_DsReplicaAttributeCtr;
+
+ typedef [public] bitmap {
+ DRSUAPI_DS_REPLICA_OBJECT_FROM_MASTER = 0x00000001,
+ DRSUAPI_DS_REPLICA_OBJECT_DYNAMIC = 0x00000002,
+ DRSUAPI_DS_REPLICA_OBJECT_REMOTE_MODIFY = 0x00010000
+ } drsuapi_DsReplicaObjectFlags;
+
+ typedef [public] struct {
+ drsuapi_DsReplicaObjectIdentifier *identifier;
+ drsuapi_DsReplicaObjectFlags flags;
+ drsuapi_DsReplicaAttributeCtr attribute_ctr;
+ } drsuapi_DsReplicaObject;
+
+ typedef struct {
+ uint32 version;
+ NTTIME_1sec originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ } drsuapi_DsReplicaMetaData;
+
+ typedef [public] struct {
+ [range(0,1048576)] uint32 count;
+ [size_is(count)] drsuapi_DsReplicaMetaData meta_data[];
+ } drsuapi_DsReplicaMetaDataCtr;
+
+ typedef [public,noprint] struct {
+ [max_recursion(20000)]
+ drsuapi_DsReplicaObjectListItemEx *next_object;
+ drsuapi_DsReplicaObject object;
+ boolean32 is_nc_prefix;
+ GUID *parent_object_guid;
+ drsuapi_DsReplicaMetaDataCtr *meta_data_ctr;
+ } drsuapi_DsReplicaObjectListItemEx;
+
+ typedef [public,gensize] struct {
+ GUID source_dsa_guid; /* the 'objectGUID' field of the CN=NTDS Settings object */
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaHighWaterMark old_highwatermark;
+ drsuapi_DsReplicaHighWaterMark new_highwatermark;
+ drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
+ drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+ drsuapi_DsExtendedError extended_ret; /* w2k sends the nc_object_count value here */
+ uint32 object_count;
+ /* this +55 is sometimes +56, so I don't know where this comes from... --metze */
+ [value(ndr_size_drsuapi_DsGetNCChangesCtr1(r,ndr->flags)+55)] uint32 __ndr_size;
+ drsuapi_DsReplicaObjectListItemEx *first_object;
+ boolean32 more_data;
+ } drsuapi_DsGetNCChangesCtr1;
+
+ /*
+ * if the DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE flag
+ * isn't there it means the value is deleted
+ */
+ typedef [public] bitmap {
+ DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE = 0x00000001
+ } drsuapi_DsLinkedAttributeFlags;
+
+ typedef [public] struct {
+ drsuapi_DsReplicaObjectIdentifier *identifier;
+ drsuapi_DsAttributeId attid;
+ drsuapi_DsAttributeValue value;
+ drsuapi_DsLinkedAttributeFlags flags;
+ NTTIME_1sec originating_add_time;
+ drsuapi_DsReplicaMetaData meta_data;
+ } drsuapi_DsReplicaLinkedAttribute;
+
+ /* [MS-DRSR] section 4.1.10.2.11 DRS_MSG_GETCHGREPLY_V6 */
+ typedef [public,gensize] struct {
+ GUID source_dsa_guid; /* the 'objectGUID' field of the CN=NTDS Settings object */
+ GUID source_dsa_invocation_id; /* the 'invocationId' field of the CN=NTDS Settings object */
+ drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaHighWaterMark old_highwatermark;
+ drsuapi_DsReplicaHighWaterMark new_highwatermark;
+ drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
+ drsuapi_DsReplicaOIDMapping_Ctr mapping_ctr;
+ drsuapi_DsExtendedError extended_ret;
+ uint32 object_count;
+ /* this +55 is sometimes +56, so I don't know where this comes from... --metze */
+ [value(ndr_size_drsuapi_DsGetNCChangesCtr6(r,ndr->flags)+55)] uint32 __ndr_size;
+ drsuapi_DsReplicaObjectListItemEx *first_object;
+ boolean32 more_data;
+ uint32 nc_object_count; /* estimated amount of objects in the whole NC */
+ uint32 nc_linked_attributes_count; /* estimated amount of linked values in the whole NC */
+ [range(0,1048576)] uint32 linked_attributes_count;
+ [size_is(linked_attributes_count)] drsuapi_DsReplicaLinkedAttribute *linked_attributes;
+ WERROR drs_error;
+ } drsuapi_DsGetNCChangesCtr6;
+
+ typedef [public] struct {
+ [subcontext(0xFFFFFC01)] drsuapi_DsGetNCChangesCtr1 ctr1;
+ } drsuapi_DsGetNCChangesCtr1TS;
+
+ typedef [public] struct {
+ [subcontext(0xFFFFFC01)] drsuapi_DsGetNCChangesCtr6 ctr6;
+ } drsuapi_DsGetNCChangesCtr6TS;
+
+ typedef [nopush] struct {
+ uint32 decompressed_length;
+ uint32 compressed_length;
+ [subcontext(4),subcontext_size(compressed_length),
+ compression(NDR_COMPRESSION_MSZIP,compressed_length,decompressed_length)]
+ drsuapi_DsGetNCChangesCtr1TS *ts;
+ } drsuapi_DsGetNCChangesMSZIPCtr1;
+
+ typedef [nopush] struct {
+ uint32 decompressed_length;
+ uint32 compressed_length;
+ [subcontext(4),subcontext_size(compressed_length),
+ compression(NDR_COMPRESSION_MSZIP,compressed_length,decompressed_length)]
+ drsuapi_DsGetNCChangesCtr6TS *ts;
+ } drsuapi_DsGetNCChangesMSZIPCtr6;
+
+ typedef [nopush] struct {
+ uint32 decompressed_length;
+ uint32 compressed_length;
+ [subcontext(4),subcontext_size(compressed_length),
+ compression(NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2,compressed_length,decompressed_length)]
+ drsuapi_DsGetNCChangesCtr1TS *ts;
+ } drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr1;
+
+ typedef [nopush] struct {
+ uint32 decompressed_length;
+ uint32 compressed_length;
+ [subcontext(4),subcontext_size(compressed_length),
+ compression(NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2,compressed_length,decompressed_length)]
+ drsuapi_DsGetNCChangesCtr6TS *ts;
+ } drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr6;
+
+ typedef [enum16bit] enum {
+ DRSUAPI_COMPRESSION_TYPE_MSZIP = 2,
+ DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2 = 3 /* CompressOrDecompressWin2k3 DRS_COMP_ALG_WIN2K3 */
+ } drsuapi_DsGetNCChangesCompressionType;
+
+ typedef [nodiscriminant,flag(NDR_PAHEX)] union {
+ [case(1|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16))] drsuapi_DsGetNCChangesMSZIPCtr1 mszip1;
+ [case(6|(DRSUAPI_COMPRESSION_TYPE_MSZIP<<16))] drsuapi_DsGetNCChangesMSZIPCtr6 mszip6;
+ [case(1|(DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2<<16))] drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr1 xpress1;
+ [case(6|(DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2<<16))] drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr6 xpress6;
+ } drsuapi_DsGetNCChangesCompressedCtr;
+
+ typedef struct {
+ drsuapi_DsGetNCChangesMSZIPCtr1 mszip1;
+ } drsuapi_DsGetNCChangesCtr2;
+
+ typedef struct {
+ [range(0,6)] uint32 level;
+ [range(2,3)] drsuapi_DsGetNCChangesCompressionType type;
+ [switch_is(level | (type<<16))] drsuapi_DsGetNCChangesCompressedCtr ctr;
+ } drsuapi_DsGetNCChangesCtr7;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetNCChangesCtr1 ctr1;
+ [case(2)] drsuapi_DsGetNCChangesCtr2 ctr2;
+ [case(6)] drsuapi_DsGetNCChangesCtr6 ctr6;
+ [case(7)] drsuapi_DsGetNCChangesCtr7 ctr7;
+ } drsuapi_DsGetNCChangesCtr;
+
+ WERROR drsuapi_DsGetNCChanges(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] drsuapi_DsGetNCChangesRequest *req,
+ [out,ref] uint32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsGetNCChangesCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x04 */
+ /* [MS-DRSR] 4.1.26 */
+
+ typedef struct {
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ [ref,charset(DOS),string] uint8 *dest_dsa_dns_name;
+ GUID dest_dsa_guid;
+ drsuapi_DrsOptions options;
+ } drsuapi_DsReplicaUpdateRefsRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsReplicaUpdateRefsRequest1 req1;
+ } drsuapi_DsReplicaUpdateRefsRequest;
+
+ WERROR drsuapi_DsReplicaUpdateRefs(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,switch_is(level)] drsuapi_DsReplicaUpdateRefsRequest req
+ );
+
+ /*****************/
+ /* Function 0x05 */
+
+ typedef struct {
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ [charset(UTF16),string] uint16 *source_dsa_address;
+ uint8 schedule[84];
+ drsuapi_DrsOptions options;
+ } drsuapi_DsReplicaAddRequest1;
+
+ typedef struct {
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ drsuapi_DsReplicaObjectIdentifier *source_dsa_dn;
+ drsuapi_DsReplicaObjectIdentifier *transport_dn;
+ [charset(UTF16),string] uint16 *source_dsa_address;
+ uint8 schedule[84];
+ drsuapi_DrsOptions options;
+ } drsuapi_DsReplicaAddRequest2;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsReplicaAddRequest1 req1;
+ [case(2)] drsuapi_DsReplicaAddRequest2 req2;
+ } drsuapi_DsReplicaAddRequest;
+
+ WERROR drsuapi_DsReplicaAdd(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,switch_is(level)] drsuapi_DsReplicaAddRequest req
+ );
+
+
+ /*****************/
+ /* Function 0x06 */
+ typedef struct {
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ [charset(UTF8), string] uint8 *source_dsa_address;
+ drsuapi_DrsOptions options;
+ } drsuapi_DsReplicaDelRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsReplicaDelRequest1 req1;
+ } drsuapi_DsReplicaDelRequest;
+
+ WERROR drsuapi_DsReplicaDel(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,switch_is(level)] drsuapi_DsReplicaDelRequest req
+ );
+
+ /*****************/
+ /* Function 0x07 */
+
+ typedef struct {
+ [ref] drsuapi_DsReplicaObjectIdentifier *naming_context;
+ GUID source_dra;
+ [charset(UTF16),string] uint16 *source_dra_address;
+ uint8 schedule[84];
+ drsuapi_DrsOptions replica_flags;
+ uint32 modify_fields;
+ drsuapi_DrsOptions options;
+ } drsuapi_DsReplicaModRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsReplicaModRequest1 req1;
+ } drsuapi_DsReplicaModRequest;
+
+ WERROR drsuapi_DsReplicaMod(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,switch_is(level)] drsuapi_DsReplicaModRequest req
+ );
+
+ /*****************/
+ /* Function 0x08 */
+ [todo] WERROR DRSUAPI_VERIFY_NAMES();
+
+ /*****************/
+ /* Function 0x09 */
+
+ /* how are type 4 and 7 different from 2 and 3 ? */
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_AND_DOMAIN_GROUPS = 1,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS = 2,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS = 3,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_LOCAL_GROUPS2 = 4,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_UNIVERSAL_GROUPS = 5,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_GROUPMEMBERS = 6,
+ DRSUAPI_DS_MEMBERSHIP_TYPE_DOMAIN_GROUPS2 = 7
+ } drsuapi_DsMembershipType;
+
+ typedef struct {
+ NTSTATUS status;
+ [range(0,10000)] uint32 num_memberships;
+ [range(0,10000)] uint32 num_sids;
+ [size_is(num_memberships)] drsuapi_DsReplicaObjectIdentifier **info_array;
+ [size_is(num_memberships)] security_GroupAttrs *group_attrs;
+ [size_is(num_sids)] dom_sid28 **sids;
+ } drsuapi_DsGetMembershipsCtr1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetMembershipsCtr1 ctr1;
+ } drsuapi_DsGetMembershipsCtr;
+
+ const int DRSUAPI_DS_MEMBERSHIP_FLAG_GROUP_ATTR = 0x1;
+
+ typedef struct {
+ [range(1,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsReplicaObjectIdentifier **info_array;
+ uint32 flags;
+ [range(1,7)] drsuapi_DsMembershipType type;
+ drsuapi_DsReplicaObjectIdentifier *domain;
+ } drsuapi_DsGetMembershipsRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetMembershipsRequest1 req1;
+ } drsuapi_DsGetMembershipsRequest;
+
+ WERROR drsuapi_DsGetMemberships(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref] [switch_is(level)] drsuapi_DsGetMembershipsRequest *req,
+ [out,ref] uint32 *level_out,
+ [out,ref] [switch_is(*level_out)] drsuapi_DsGetMembershipsCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x0a */
+ [todo] WERROR DRSUAPI_INTER_DOMAIN_MOVE();
+
+ /*****************/
+ /* Function 0x0b */
+ typedef [bitmap32bit] bitmap {
+ DRSUAPI_NT4_CHANGELOG_GET_CHANGELOG = 0x00000001,
+ DRSUAPI_NT4_CHANGELOG_GET_SERIAL_NUMBERS = 0x00000002
+ } drsuapi_DsGetNT4ChangeLogFlags;
+
+ typedef struct {
+ drsuapi_DsGetNT4ChangeLogFlags flags;
+ uint32 preferred_maximum_length;
+ [range(0,0x00A00000)] uint32 restart_length;
+ [size_is(restart_length)] uint8 *restart_data;
+ } drsuapi_DsGetNT4ChangeLogRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetNT4ChangeLogRequest1 req1;
+ } drsuapi_DsGetNT4ChangeLogRequest;
+
+ typedef struct {
+ [range(0,0x00A00000)] uint32 restart_length;
+ [range(0,0x00A00000)] uint32 log_length;
+ hyper sam_serial_number;
+ NTTIME sam_creation_time;
+ hyper builtin_serial_number;
+ NTTIME builtin_creation_time;
+ hyper lsa_serial_number;
+ NTTIME lsa_creation_time;
+ NTSTATUS status;
+ [size_is(restart_length)] uint8 *restart_data;
+ [size_is(log_length)] uint8 *log_data;
+ } drsuapi_DsGetNT4ChangeLogInfo1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetNT4ChangeLogInfo1 info1;
+ } drsuapi_DsGetNT4ChangeLogInfo;
+
+ WERROR drsuapi_DsGetNT4ChangeLog(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref] [switch_is(level)] drsuapi_DsGetNT4ChangeLogRequest *req,
+ [out,ref] uint32 *level_out,
+ [out,ref] [switch_is(*level_out)] drsuapi_DsGetNT4ChangeLogInfo *info
+ );
+
+ /*****************/
+ /* Function 0x0c */
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_NAME_STATUS_OK = 0,
+ DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR = 1,
+ DRSUAPI_DS_NAME_STATUS_NOT_FOUND = 2,
+ DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE = 3,
+ DRSUAPI_DS_NAME_STATUS_NO_MAPPING = 4,
+ DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY = 5,
+ DRSUAPI_DS_NAME_STATUS_NO_SYNTACTICAL_MAPPING = 6,
+ DRSUAPI_DS_NAME_STATUS_TRUST_REFERRAL = 7
+ } drsuapi_DsNameStatus;
+
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_NAME_FLAG_NO_FLAGS = 0x0,
+ DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY = 0x1,
+ DRSUAPI_DS_NAME_FLAG_EVAL_AT_DC = 0x2,
+ DRSUAPI_DS_NAME_FLAG_GCVERIFY = 0x4,
+ DRSUAPI_DS_NAME_FLAG_TRUST_REFERRAL = 0x8
+ } drsuapi_DsNameFlags;
+
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_NAME_FORMAT_UNKNOWN = 0x00000000,
+ DRSUAPI_DS_NAME_FORMAT_FQDN_1779 = 0x00000001,
+ DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT = 0x00000002,
+ DRSUAPI_DS_NAME_FORMAT_DISPLAY = 0x00000003,
+ DRSUAPI_DS_NAME_FORMAT_GUID = 0x00000006,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL = 0x00000007,
+ DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL = 0x00000008,
+ DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX = 0x00000009,
+ DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL = 0x0000000A,
+ DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY = 0x0000000B,
+ DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN = 0x0000000C,
+ DRSUAPI_DS_NAME_FORMAT_UPN_AND_ALTSECID = 0xFFFFFFEF,
+ DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN_EX = 0xFFFFFFF0,
+ DRSUAPI_DS_NAME_FORMAT_LIST_GLOBAL_CATALOG_SERVERS = 0xFFFFFFF1,
+ DRSUAPI_DS_NAME_FORMAT_UPN_FOR_LOGON = 0xFFFFFFF2,
+ DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_WITH_DCS_IN_SITE = 0xFFFFFFF3,
+ DRSUAPI_DS_NAME_FORMAT_STRING_SID_NAME = 0xFFFFFFF4,
+ DRSUAPI_DS_NAME_FORMAT_ALT_SECURITY_IDENTITIES_NAME = 0xFFFFFFF5,
+ DRSUAPI_DS_NAME_FORMAT_LIST_NCS = 0xFFFFFFF6,
+ DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS = 0xFFFFFFF7,
+ DRSUAPI_DS_NAME_FORMAT_MAP_SCHEMA_GUID = 0xFFFFFFF8,
+ DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT_NAME_SANS_DOMAIN = 0xFFFFFFF9,
+ DRSUAPI_DS_NAME_FORMAT_LIST_ROLES = 0xFFFFFFFA,
+ DRSUAPI_DS_NAME_FORMAT_LIST_INFO_FOR_SERVER = 0xFFFFFFFB,
+ DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_FOR_DOMAIN_IN_SITE = 0xFFFFFFFC,
+ DRSUAPI_DS_NAME_FORMAT_LIST_DOMAINS_IN_SITE = 0xFFFFFFFD,
+ DRSUAPI_DS_NAME_FORMAT_LIST_SERVERS_IN_SITE = 0xFFFFFFFE,
+ DRSUAPI_DS_NAME_FORMAT_LIST_SITES = 0xFFFFFFFF
+ } drsuapi_DsNameFormat;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *str;
+ } drsuapi_DsNameString;
+
+ typedef struct {
+ uint32 codepage; /* 0x000004e4 - 1252 is german codepage*/
+ uint32 language; /* 0x00000407 - german language ID*/
+ drsuapi_DsNameFlags format_flags;
+ drsuapi_DsNameFormat format_offered;
+ drsuapi_DsNameFormat format_desired;
+ [range(1,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsNameString *names;
+ } drsuapi_DsNameRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsNameRequest1 req1;
+ } drsuapi_DsNameRequest;
+
+ typedef struct {
+ drsuapi_DsNameStatus status;
+ [charset(UTF16),string] uint16 *dns_domain_name;
+ [charset(UTF16),string] uint16 *result_name;
+ } drsuapi_DsNameInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] drsuapi_DsNameInfo1 *array;
+ } drsuapi_DsNameCtr1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsNameCtr1 *ctr1;
+ } drsuapi_DsNameCtr;
+
+ WERROR drsuapi_DsCrackNames(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] drsuapi_DsNameRequest *req,
+ [out,ref] uint32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsNameCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x0d */
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_SPN_OPERATION_ADD = 0,
+ DRSUAPI_DS_SPN_OPERATION_REPLACE= 1,
+ DRSUAPI_DS_SPN_OPERATION_DELETE = 2
+ } drsuapi_DsSpnOperation;
+
+ typedef struct {
+ drsuapi_DsSpnOperation operation;
+ uint32 unknown1;
+ [charset(UTF16),string] uint16 *object_dn;
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsNameString *spn_names;
+ } drsuapi_DsWriteAccountSpnRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsWriteAccountSpnRequest1 req1;
+ } drsuapi_DsWriteAccountSpnRequest;
+
+ typedef struct {
+ WERROR status;
+ } drsuapi_DsWriteAccountSpnResult1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsWriteAccountSpnResult1 res1;
+ } drsuapi_DsWriteAccountSpnResult;
+
+ WERROR drsuapi_DsWriteAccountSpn(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] drsuapi_DsWriteAccountSpnRequest *req,
+ [out,ref] uint32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsWriteAccountSpnResult *res
+ );
+
+ /*****************/
+ /* Function 0x0e */
+ typedef struct {
+ [charset(UTF16),string] uint16 *server_dn;
+ [charset(UTF16),string] uint16 *domain_dn;
+ boolean32 commit;
+ } drsuapi_DsRemoveDSServerRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsRemoveDSServerRequest1 req1;
+ } drsuapi_DsRemoveDSServerRequest;
+
+ typedef struct {
+ boolean32 last_dc_in_domain;
+ } drsuapi_DsRemoveDSServerResult1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsRemoveDSServerResult1 res1;
+ } drsuapi_DsRemoveDSServerResult;
+
+ WERROR drsuapi_DsRemoveDSServer(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] drsuapi_DsRemoveDSServerRequest *req,
+ [out,ref] uint32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsRemoveDSServerResult *res
+ );
+
+ /*****************/
+ /* Function 0x0f */
+ [todo] WERROR DRSUAPI_REMOVE_DS_DOMAIN();
+
+ /*****************/
+ /* Function 0x10 */
+ typedef [v1_enum] enum {
+ DRSUAPI_DC_INFO_CTR_1 = 1,
+ DRSUAPI_DC_INFO_CTR_2 = 2,
+ DRSUAPI_DC_INFO_CTR_3 = 3,
+ DRSUAPI_DC_CONNECTION_CTR_01 = 0xFFFFFFFF
+ } drsuapi_DsGetDCInfoCtrLevels;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *domain_name; /* netbios or dns */
+ drsuapi_DsGetDCInfoCtrLevels level; /* specifies the switch level for the request */
+ } drsuapi_DsGetDCInfoRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetDCInfoRequest1 req1;
+ } drsuapi_DsGetDCInfoRequest;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *netbios_name;
+ [charset(UTF16),string] uint16 *dns_name;
+ [charset(UTF16),string] uint16 *site_name;
+ [charset(UTF16),string] uint16 *computer_dn;
+ [charset(UTF16),string] uint16 *server_dn;
+ uint32 is_pdc;
+ uint32 is_enabled;
+ } drsuapi_DsGetDCInfo1;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsGetDCInfo1 *array;
+ } drsuapi_DsGetDCInfoCtr1;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *netbios_name;
+ [charset(UTF16),string] uint16 *dns_name;
+ [charset(UTF16),string] uint16 *site_name;
+ [charset(UTF16),string] uint16 *site_dn;
+ [charset(UTF16),string] uint16 *computer_dn;
+ [charset(UTF16),string] uint16 *server_dn;
+ [charset(UTF16),string] uint16 *ntds_dn;
+ uint32 is_pdc;
+ uint32 is_enabled;
+ uint32 is_gc;
+ GUID site_guid;
+ GUID computer_guid;
+ GUID server_guid;
+ GUID ntds_guid;
+ } drsuapi_DsGetDCInfo2;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsGetDCInfo2 *array;
+ } drsuapi_DsGetDCInfoCtr2;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *netbios_name;
+ [charset(UTF16),string] uint16 *dns_name;
+ [charset(UTF16),string] uint16 *site_name;
+ [charset(UTF16),string] uint16 *site_dn;
+ [charset(UTF16),string] uint16 *computer_dn;
+ [charset(UTF16),string] uint16 *server_dn;
+ [charset(UTF16),string] uint16 *ntds_dn;
+ uint32 is_pdc;
+ uint32 is_enabled;
+ uint32 is_gc;
+ uint32 is_rodc;
+ GUID site_guid;
+ GUID computer_guid;
+ GUID server_guid;
+ GUID ntds_guid;
+ } drsuapi_DsGetDCInfo3;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsGetDCInfo3 *array;
+ } drsuapi_DsGetDCInfoCtr3;
+
+ /*
+ * this represents an active connection to the
+ * Directory System Agent (DSA)
+ * this can be via LDAP or DRSUAPI
+ */
+ typedef struct {
+ [flag(NDR_BIG_ENDIAN)] ipv4address client_ip_address;
+ uint32 unknown2;
+ uint32 connection_time; /* in seconds */
+ uint32 unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ /*
+ * client_account can be the following:
+ * "W2K3\Administrator"
+ * "Administrator@W2K3"
+ * "cn=Administrator,cn=Users,DC=w2k3,DC=vmnet1,DC=vm,DC=base"
+ * ""
+ * or NULL
+ */
+ [charset(UTF16),string] uint16 *client_account;
+ } drsuapi_DsGetDCConnection01;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsGetDCConnection01 *array;
+ } drsuapi_DsGetDCConnectionCtr01;
+
+ typedef [switch_type(drsuapi_DsGetDCInfoCtrLevels)] union {
+ [case(DRSUAPI_DC_INFO_CTR_1)] drsuapi_DsGetDCInfoCtr1 ctr1;
+ [case(DRSUAPI_DC_INFO_CTR_2)] drsuapi_DsGetDCInfoCtr2 ctr2;
+ [case(DRSUAPI_DC_INFO_CTR_3)] drsuapi_DsGetDCInfoCtr3 ctr3;
+ [case(DRSUAPI_DC_CONNECTION_CTR_01)] drsuapi_DsGetDCConnectionCtr01 ctr01;
+ } drsuapi_DsGetDCInfoCtr;
+
+ WERROR drsuapi_DsGetDomainControllerInfo(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] drsuapi_DsGetDCInfoRequest *req,
+ [out,ref] drsuapi_DsGetDCInfoCtrLevels *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsGetDCInfoCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x11 */
+ typedef [public,noprint] struct {
+ [max_recursion(20000)]
+ drsuapi_DsReplicaObjectListItem *next_object;
+ drsuapi_DsReplicaObject object;
+ } drsuapi_DsReplicaObjectListItem;
+
+ /*
+ * The DsAddEntry() call which creates a nTDSDSA object,
+ * also adds a servicePrincipalName in the following form
+ * to the computer account of the new domain controller
+ * referenced by the "serverReferenece" attribute.
+ *
+ * E3514235-4B06-11D1-AB04-00C04FC2DCD2/<new-ntdsdsa-object-guid-as-string>/<domain-dns-name>
+ *
+ * also note that the "serverReference" isn't added to the new object!
+ */
+ const char *DRSUAPI_NTDSDSA_KRB5_SERVICE_GUID = "E3514235-4B06-11D1-AB04-00C04FC2DCD2";
+
+ /* Error codes to classify an error that occurs
+ * during a search for, or the update of,
+ * a directory object */
+ typedef [v1_enum] enum {
+ DRSUAPI_DIRERR_OK = 0,
+ DRSUAPI_DIRERR_ATTRIBUTE = 1,
+ DRSUAPI_DIRERR_NAME = 2,
+ DRSUAPI_DIRERR_REFERRAL = 3,
+ DRSUAPI_DIRERR_SECURITY = 4,
+ DRSUAPI_DIRERR_SERVICE = 5,
+ DRSUAPI_DIRERR_UPDATE = 6,
+ DRSUAPI_DIRERR_SYSTEM = 7
+ } drsuapi_DsAddEntry_DirErr;
+
+ /*
+ * Ref: DRS_MSG_ADDENTRYREQ_V2, [MS-DRSR]: 4.1.1.1.3
+ */
+ typedef struct {
+ drsuapi_DsReplicaObjectListItem first_object;
+ } drsuapi_DsAddEntryRequest2;
+
+ /* Buffer type is actually more
+ * like a semi Flags
+ * Ref: DRS_SecBuffer, [MS-DRSR]: 5.41 */
+ typedef [v1_enum,noprint] enum {
+ DRSUAPI_SECBUFFER_EMPTY = 0x00000000,
+ DRSUAPI_SECBUFFER_DATA = 0x00000001,
+ DRSUAPI_SECBUFFER_TOKEN = 0x00000002,
+ DRSUAPI_SECBUFFER_PKG_PARAMS = 0x00000003,
+ DRSUAPI_SECBUFFER_MISSING = 0x00000004,
+ DRSUAPI_SECBUFFER_EXTRA = 0x00000005,
+ DRSUAPI_SECBUFFER_STREAM_TRAILER = 0x00000006,
+ DRSUAPI_SECBUFFER_STREAM_HEADER = 0x00000007,
+ DRSUAPI_SECBUFFER_READONLY = 0x80000000
+ } drsuapi_SecBufferType;
+
+ typedef struct {
+ [range(0,10000)] uint32 buf_size;
+ drsuapi_SecBufferType buf_type;
+ [size_is(buf_size)] uint8 *buffer;
+ } drsuapi_SecBuffer;
+
+ typedef struct {
+ [value(0)] uint32 version;
+ [range(0,10000)] uint32 buff_count;
+ [size_is(buff_count)] drsuapi_SecBuffer *buffers;
+ } drsuapi_SecBufferDesc;
+
+ /*
+ * Ref: DRS_MSG_ADDENTRYREQ_V3, [MS-DRSR]: 4.1.1.1.4
+ */
+ typedef struct {
+ drsuapi_DsReplicaObjectListItem first_object;
+ drsuapi_SecBufferDesc *client_creds;
+ } drsuapi_DsAddEntryRequest3;
+
+ typedef [switch_type(uint32)] union {
+ [case(2)] drsuapi_DsAddEntryRequest2 req2;
+ [case(3)] drsuapi_DsAddEntryRequest3 req3;
+ } drsuapi_DsAddEntryRequest;
+
+ /* Generic extended error info
+ * commonly used in most places
+ * where rich error info is returned */
+ typedef struct {
+ uint32 dsid; /* implementation-specific diagnostic code */
+ WERROR extended_err; /* 0, STATUS code, or Windows error code */
+ uint32 extended_data; /* implementation-specific diagnostic code */
+ uint16 problem; /* 0 or PROBLEM error code */
+ } drsuapi_DsAddEntryErrorInfoX;
+
+ /* Attribute errors
+ * Ref: ATRERR_DRS_WIRE_V1, [MS-DRSR]: 4.1.1.1.11 */
+ typedef struct {
+ uint32 dsid;
+ WERROR extended_err;
+ uint32 extended_data;
+ uint16 problem;
+ drsuapi_DsAttributeId attid;
+ boolean32 is_val_returned;
+ drsuapi_DsAttributeValue attr_val;
+ } drsuapi_DsAddEntry_AttrErr_V1;
+
+ typedef [noprint] struct {
+ [max_recursion(20000)]
+ drsuapi_DsAddEntry_AttrErrListItem_V1 *next;
+ drsuapi_DsAddEntry_AttrErr_V1 err_data;
+ } drsuapi_DsAddEntry_AttrErrListItem_V1;
+
+ typedef struct {
+ drsuapi_DsReplicaObjectIdentifier *id;
+ uint32 count;
+ drsuapi_DsAddEntry_AttrErrListItem_V1 first;
+ } drsuapi_DsAddEntryErrorInfo_Attr_V1;
+
+ /* Name resolution error
+ * Ref: NAMERR_DRS_WIRE_V1, [MS-DRSR]: 4.1.1.1.14 */
+ typedef struct {
+ uint32 dsid;
+ WERROR extended_err;
+ uint32 extended_data;
+ uint16 problem;
+ drsuapi_DsReplicaObjectIdentifier *id_matched; /* The best match for the supplied object identity */
+ } drsuapi_DsAddEntryErrorInfo_Name_V1;
+
+ /* Referral error
+ * Ref: REFERR_DRS_WIRE_V1, [MS-DRSR]: 4.1.1.1.15 */
+ typedef struct {
+ [value(83)] uint8 name_res; /* Must be 'S' */
+ [value(0)] uint8 unused_pad;
+ [value(0)] uint16 next_rdn;
+ } drsuapi_NameResOp_V1;
+
+ typedef [enum16bit] enum {
+ DRSUAPI_CH_REFTYPE_SUPERIOR = 0x0000, /* referral to a superior DC */
+ DRSUAPI_CH_REFTYPE_SUBORDINATE = 0x0001, /* referral to a subordinate DC */
+ DRSUAPI_CH_REFTYPE_NSSR = 0x0002, /* Not used */
+ DRSUAPI_CH_REFTYPE_CROSS = 0x0003 /* A referral to an external crossRef object */
+ } drsuapi_DsAddEntry_RefType;
+
+ typedef [enum8bit] enum {
+ DRSUAPI_SE_CHOICE_BASE_ONLY = 0x00,
+ DRSUAPI_SE_CHOICE_IMMED_CHLDRN = 0x01,
+ DRSUAPI_SE_CHOICE_WHOLE_SUBTREE = 0x02
+ } drsuapi_DsAddEntry_ChoiceType;
+
+ /* list of network names of the DCs
+ * to which the referral is directed */
+ typedef struct {
+ [max_recursion(1024)] drsuapi_DsaAddressListItem_V1 *next;
+ lsa_String *address;
+ } drsuapi_DsaAddressListItem_V1;
+
+ typedef struct {
+ drsuapi_DsReplicaObjectIdentifier *id_target; /* object to which the referral is directed */
+ drsuapi_NameResOp_V1 op_state;
+ [value(0)] uint16 rdn_alias;
+ [value(0)] uint16 rdn_internal;
+ drsuapi_DsAddEntry_RefType ref_type;
+ uint16 addr_list_count;
+ drsuapi_DsaAddressListItem_V1 *addr_list;
+ [max_recursion(20000)]
+ drsuapi_DsAddEntry_RefErrListItem_V1 *next;
+ boolean32 is_choice_set;
+ drsuapi_DsAddEntry_ChoiceType choice;
+ } drsuapi_DsAddEntry_RefErrListItem_V1;
+
+ typedef struct {
+ uint32 dsid;
+ WERROR extended_err;
+ uint32 extended_data;
+ drsuapi_DsAddEntry_RefErrListItem_V1 refer;
+ } drsuapi_DsAddEntryErrorInfo_Referr_V1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsAddEntryErrorInfo_Attr_V1 attr_err;
+ [case(2)] drsuapi_DsAddEntryErrorInfo_Name_V1 name_err;
+ [case(3)] drsuapi_DsAddEntryErrorInfo_Referr_V1 referral_err;
+ [case(4)] drsuapi_DsAddEntryErrorInfoX security_err;
+ [case(5)] drsuapi_DsAddEntryErrorInfoX service_err;
+ [case(6)] drsuapi_DsAddEntryErrorInfoX update_err;
+ [case(7)] drsuapi_DsAddEntryErrorInfoX system_err;
+ } drsuapi_DsAddEntryErrorInfo;
+
+ typedef struct {
+ WERROR status;
+ drsuapi_DsAddEntry_DirErr dir_err;
+ [switch_is(dir_err)] drsuapi_DsAddEntryErrorInfo *info;
+ } drsuapi_DsAddEntry_ErrData_V1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsAddEntry_ErrData_V1 v1;
+ } drsuapi_DsAddEntry_ErrData;
+
+ typedef struct {
+ GUID guid;
+ dom_sid28 sid;
+ } drsuapi_DsReplicaObjectIdentifier2;
+
+ typedef struct {
+ drsuapi_DsReplicaObjectIdentifier *id;
+ drsuapi_DsAddEntry_DirErr dir_err;
+ uint32 dsid; /* implementation-specific diagnostic code */
+ WERROR extended_err; /* 0, STATUS code, or Windows error code */
+ uint32 extended_data; /* implementation-specific diagnostic code */
+ uint16 problem; /* 0 or PROBLEM error code */
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsReplicaObjectIdentifier2 *objects;
+ } drsuapi_DsAddEntryCtr2;
+
+ typedef struct {
+ drsuapi_DsReplicaObjectIdentifier *id;
+ uint32 err_ver; /* Must be 1 */
+ [switch_is(err_ver)] drsuapi_DsAddEntry_ErrData *err_data;
+ [range(0,10000)] uint32 count;
+ [size_is(count)] drsuapi_DsReplicaObjectIdentifier2 *objects;
+ } drsuapi_DsAddEntryCtr3;
+
+ typedef [switch_type(uint32)] union {
+ [case(2)] drsuapi_DsAddEntryCtr2 ctr2;
+ [case(3)] drsuapi_DsAddEntryCtr3 ctr3;
+ } drsuapi_DsAddEntryCtr;
+
+ [public] WERROR drsuapi_DsAddEntry(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] drsuapi_DsAddEntryRequest *req,
+ [out,ref] uint32 *level_out,
+ [out,ref,switch_is(*level_out)] drsuapi_DsAddEntryCtr *ctr
+ );
+
+ /*****************/
+ /* Function 0x12 */
+ typedef bitmap {
+ DRSUAPI_DS_EXECUTE_KCC_ASYNCHRONOUS_OPERATION = 0x00000001,
+ DRSUAPI_DS_EXECUTE_KCC_DAMPED = 0x00000002
+ } drsuapi_DsExecuteKCCFlags;
+
+ typedef struct {
+ uint32 taskID;
+ drsuapi_DsExecuteKCCFlags flags;
+ } drsuapi_DsExecuteKCC1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsExecuteKCC1 ctr1;
+ } drsuapi_DsExecuteKCCRequest;
+
+ WERROR drsuapi_DsExecuteKCC(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in, ref, switch_is(level)] drsuapi_DsExecuteKCCRequest *req
+ );
+
+ /*****************/
+ /* Function 0x13 */
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_REPLICA_GET_INFO = 1,
+ DRSUAPI_DS_REPLICA_GET_INFO2 = 2
+ } drsuapi_DsReplicaGetInfoLevel;
+
+ typedef [v1_enum] enum {
+ DRSUAPI_DS_REPLICA_INFO_NEIGHBORS = 0,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS = 1,
+ DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA = 2,
+ DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES = 3,
+ DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES = 4,
+ DRSUAPI_DS_REPLICA_INFO_PENDING_OPS = 5,
+ DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA = 6,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS2 = 7,
+ DRSUAPI_DS_REPLICA_INFO_CURSORS3 = 8,
+ DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2 = 9,
+ DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2 = 10,
+ DRSUAPI_DS_REPLICA_INFO_REPSTO = -2,
+ DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS = -4,
+ DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1 = -5,
+ DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS = -6
+ } drsuapi_DsReplicaInfoType;
+
+ typedef struct {
+ drsuapi_DsReplicaInfoType info_type;
+ [charset(UTF16),string] uint16 *object_dn;
+ GUID source_dsa_guid;
+ } drsuapi_DsReplicaGetInfoRequest1;
+
+ typedef struct {
+ drsuapi_DsReplicaInfoType info_type;
+ [charset(UTF16),string] uint16 *object_dn;
+ GUID source_dsa_guid;
+ uint32 flags;
+ [charset(UTF16),string] uint16 *attribute_name;
+ [charset(UTF16),string] uint16 *value_dn_str;
+ uint32 enumeration_context;
+ } drsuapi_DsReplicaGetInfoRequest2;
+
+ typedef [switch_type(drsuapi_DsReplicaGetInfoLevel)] union {
+ [case(DRSUAPI_DS_REPLICA_GET_INFO)] drsuapi_DsReplicaGetInfoRequest1 req1;
+ [case(DRSUAPI_DS_REPLICA_GET_INFO2)] drsuapi_DsReplicaGetInfoRequest2 req2;
+ } drsuapi_DsReplicaGetInfoRequest;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *naming_context_dn;
+ [charset(UTF16),string] uint16 *source_dsa_obj_dn;
+ [charset(UTF16),string] uint16 *source_dsa_address;
+ [charset(UTF16),string] uint16 *transport_obj_dn;
+ drsuapi_DrsOptions replica_flags;
+ uint32 reserved;
+ GUID naming_context_obj_guid;
+ GUID source_dsa_obj_guid;
+ GUID source_dsa_invocation_id;
+ GUID transport_obj_guid;
+ hyper tmp_highest_usn;
+ hyper highest_usn;
+ NTTIME last_success;
+ NTTIME last_attempt;
+ WERROR result_last_attempt;
+ uint32 consecutive_sync_failures;
+ } drsuapi_DsReplicaNeighbour;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaNeighbour array[];
+ } drsuapi_DsReplicaNeighbourCtr;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaCursor array[];
+ } drsuapi_DsReplicaCursorCtr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *attribute_name;
+ uint32 version;
+ NTTIME originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ } drsuapi_DsReplicaObjMetaData;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaObjMetaData array[];
+ } drsuapi_DsReplicaObjMetaDataCtr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *dsa_obj_dn;
+ GUID dsa_obj_guid;
+ NTTIME first_failure;
+ uint32 num_failures;
+ WERROR last_result;
+ } drsuapi_DsReplicaKccDsaFailure;
+
+ typedef struct {
+ uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaKccDsaFailure array[];
+ } drsuapi_DsReplicaKccDsaFailuresCtr;
+
+ typedef enum {
+ DRSUAPI_DS_REPLICA_OP_TYPE_SYNC = 0,
+ DRSUAPI_DS_REPLICA_OP_TYPE_ADD = 1,
+ DRSUAPI_DS_REPLICA_OP_TYPE_DELETE = 2,
+ DRSUAPI_DS_REPLICA_OP_TYPE_MODIFY = 3,
+ DRSUAPI_DS_REPLICA_OP_TYPE_UPDATE_REFS = 4
+ } drsuapi_DsReplicaOpType;
+
+ typedef struct {
+ NTTIME operation_start;
+ uint32 serial_num; /* unique till reboot */
+ uint32 priority;
+ drsuapi_DsReplicaOpType operation_type;
+ drsuapi_DrsOptions options;
+ [charset(UTF16),string] uint16 *nc_dn;
+ [charset(UTF16),string] uint16 *remote_dsa_obj_dn;
+ [charset(UTF16),string] uint16 *remote_dsa_address;
+ GUID nc_obj_guid;
+ GUID remote_dsa_obj_guid;
+ } drsuapi_DsReplicaOp;
+
+ typedef struct {
+ NTTIME time;
+ uint32 count;
+ [size_is(count)] drsuapi_DsReplicaOp array[];
+ } drsuapi_DsReplicaOpCtr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *attribute_name;
+ [charset(UTF16),string] uint16 *object_dn;
+ [value(ndr_size_DATA_BLOB(0,binary,0))] uint32 __ndr_size_binary;
+ DATA_BLOB *binary;
+ NTTIME deleted;
+ NTTIME created;
+ uint32 version;
+ NTTIME originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ } drsuapi_DsReplicaAttrValMetaData;
+
+ typedef struct {
+ uint32 count;
+ uint32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaAttrValMetaData array[];
+ } drsuapi_DsReplicaAttrValMetaDataCtr;
+
+ typedef struct {
+ uint32 count;
+ uint32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaCursor2 array[];
+ } drsuapi_DsReplicaCursor2Ctr;
+
+ typedef struct {
+ GUID source_dsa_invocation_id;
+ hyper highest_usn;
+ NTTIME last_sync_success;
+ [charset(UTF16),string] uint16 *source_dsa_obj_dn;
+ } drsuapi_DsReplicaCursor3;
+
+ typedef struct {
+ uint32 count;
+ uint32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaCursor3 array[];
+ } drsuapi_DsReplicaCursor3Ctr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *attribute_name;
+ uint32 version;
+ NTTIME originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ [charset(UTF16),string] uint16 *originating_dsa_dn;
+ } drsuapi_DsReplicaObjMetaData2;
+
+ typedef struct {
+ uint32 count;
+ uint32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaObjMetaData2 array[];
+ } drsuapi_DsReplicaObjMetaData2Ctr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *attribute_name;
+ [charset(UTF16),string] uint16 *object_dn;
+ [value(ndr_size_DATA_BLOB(0,binary,0))] uint32 __ndr_size_binary;
+ DATA_BLOB *binary;
+ NTTIME deleted;
+ NTTIME created;
+ uint32 version;
+ NTTIME originating_change_time;
+ GUID originating_invocation_id;
+ hyper originating_usn;
+ hyper local_usn;
+ [charset(UTF16),string] uint16 *originating_dsa_dn;
+ } drsuapi_DsReplicaAttrValMetaData2;
+
+ typedef struct {
+ uint32 count;
+ uint32 enumeration_context;
+ [size_is(count)] drsuapi_DsReplicaAttrValMetaData2 array[];
+ } drsuapi_DsReplicaAttrValMetaData2Ctr;
+
+ typedef struct {
+ hyper u1; /* session number? */
+ uint32 u2;
+ uint32 u3;
+ GUID bind_guid;
+ NTTIME_1sec bind_time;
+ [flag(NDR_BIG_ENDIAN)] ipv4address client_ip_address;
+ uint32 u5; /* this is the same value the client used as pid in the DsBindInfoX struct */
+ } drsuapi_DsReplicaConnection04;
+
+ typedef struct {
+ [range(0,10000)] uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplicaConnection04 array[];
+ } drsuapi_DsReplicaConnection04Ctr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *str1;
+ uint32 u1;
+ uint32 u2;
+ uint32 u3;
+ uint32 u4;
+ uint32 u5;
+ hyper u6;
+ uint32 u7;
+ } drsuapi_DsReplica06;
+
+ typedef struct {
+ [range(0,256)] uint32 count;
+ uint32 reserved;
+ [size_is(count)] drsuapi_DsReplica06 array[];
+ } drsuapi_DsReplica06Ctr;
+
+ typedef [switch_type(drsuapi_DsReplicaInfoType)] union {
+ [case(DRSUAPI_DS_REPLICA_INFO_NEIGHBORS)] drsuapi_DsReplicaNeighbourCtr *neighbours;
+ [case(DRSUAPI_DS_REPLICA_INFO_CURSORS)] drsuapi_DsReplicaCursorCtr *cursors;
+ [case(DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA)] drsuapi_DsReplicaObjMetaDataCtr *objmetadata;
+ [case(DRSUAPI_DS_REPLICA_INFO_KCC_DSA_CONNECT_FAILURES)] drsuapi_DsReplicaKccDsaFailuresCtr *connectfailures;
+ [case(DRSUAPI_DS_REPLICA_INFO_KCC_DSA_LINK_FAILURES)] drsuapi_DsReplicaKccDsaFailuresCtr *linkfailures;
+ [case(DRSUAPI_DS_REPLICA_INFO_PENDING_OPS)] drsuapi_DsReplicaOpCtr *pendingops;
+ [case(DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA)] drsuapi_DsReplicaAttrValMetaDataCtr *attrvalmetadata;
+ [case(DRSUAPI_DS_REPLICA_INFO_CURSORS2)] drsuapi_DsReplicaCursor2Ctr *cursors2;
+ [case(DRSUAPI_DS_REPLICA_INFO_CURSORS3)] drsuapi_DsReplicaCursor3Ctr *cursors3;
+ [case(DRSUAPI_DS_REPLICA_INFO_OBJ_METADATA2)] drsuapi_DsReplicaObjMetaData2Ctr *objmetadata2;
+ [case(DRSUAPI_DS_REPLICA_INFO_ATTRIBUTE_VALUE_METADATA2)] drsuapi_DsReplicaAttrValMetaData2Ctr *attrvalmetadata2;
+ [case(DRSUAPI_DS_REPLICA_INFO_REPSTO)] drsuapi_DsReplicaNeighbourCtr *repsto;
+ [case(DRSUAPI_DS_REPLICA_INFO_CLIENT_CONTEXTS)] drsuapi_DsReplicaConnection04Ctr *clientctx;
+ [case(DRSUAPI_DS_REPLICA_INFO_UPTODATE_VECTOR_V1)] drsuapi_DsReplicaCursorCtrEx *udv1;
+ [case(DRSUAPI_DS_REPLICA_INFO_SERVER_OUTGOING_CALLS)] drsuapi_DsReplica06Ctr *srvoutgoingcalls;
+ } drsuapi_DsReplicaInfo;
+
+ WERROR drsuapi_DsReplicaGetInfo(
+ [in] policy_handle *bind_handle,
+ [in] drsuapi_DsReplicaGetInfoLevel level,
+ [in,ref,switch_is(level)] drsuapi_DsReplicaGetInfoRequest *req,
+ [out,ref] drsuapi_DsReplicaInfoType *info_type,
+ [out,ref,switch_is(*info_type)] drsuapi_DsReplicaInfo *info
+ );
+
+ /*****************/
+ /* Function 0x14 */
+ [todo] WERROR DRSUAPI_ADD_SID_HISTORY();
+
+ /*****************/
+ /* Function 0x15 */
+
+ typedef struct {
+ [range(0,10000)] uint32 num_entries;
+ [size_is(num_entries)] drsuapi_DsGetMembershipsCtr1 **ctrl_array;
+ } drsuapi_DsGetMemberships2Ctr1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetMembershipsCtr1 ctr1;
+ } drsuapi_DsGetMemberships2Ctr;
+
+ typedef struct {
+ [range(1,10000)] uint32 num_req;
+ [size_is(num_req)] drsuapi_DsGetMembershipsRequest1 **req_array;
+ } drsuapi_DsGetMemberships2Request1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_DsGetMemberships2Request1 req1;
+ } drsuapi_DsGetMemberships2Request;
+
+ WERROR drsuapi_DsGetMemberships2(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref] [switch_is(level)] drsuapi_DsGetMemberships2Request *req,
+ [out,ref] uint32 *level_out,
+ [out,ref] [switch_is(*level_out)] drsuapi_DsGetMemberships2Ctr *ctr
+ );
+
+ /*****************/
+ /* Function 0x16 */
+ [todo] WERROR DRSUAPI_REPLICA_VERIFY_OBJECTS();
+
+ /*****************/
+ /* Function 0x17 */
+ [todo] WERROR DRSUAPI_GET_OBJECT_EXISTENCE();
+
+ /*****************/
+ /* Function 0x18 */
+ typedef struct {
+ WERROR error_code;
+ uint32 site_cost;
+ } drsuapi_DsSiteCostInfo;
+
+ typedef struct {
+ [range(0,10000)] uint32 num_info;
+ [size_is(num_info)] drsuapi_DsSiteCostInfo *info;
+ [value(0)] uint32 flags_reserved;
+ } drsuapi_QuerySitesByCostCtr1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_QuerySitesByCostCtr1 ctr1;
+ } drsuapi_QuerySitesByCostCtr;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *site_from;
+ [range(1,10000)] uint32 num_req;
+ [size_is(num_req)] [charset(UTF16),string] uint16 **site_to;
+ uint32 flags;
+ } drsuapi_QuerySitesByCostRequest1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] drsuapi_QuerySitesByCostRequest1 req1;
+ } drsuapi_QuerySitesByCostRequest;
+
+ WERROR drsuapi_QuerySitesByCost(
+ [in] policy_handle *bind_handle,
+ [in] uint32 level,
+ [in,ref] [switch_is(level)] drsuapi_QuerySitesByCostRequest *req,
+ [out,ref] uint32 *level_out,
+ [out,ref] [switch_is(*level_out)] drsuapi_QuerySitesByCostCtr *ctr
+ );
+}
diff --git a/librpc/idl/dsbackup.idl b/librpc/idl/dsbackup.idl
new file mode 100644
index 0000000..72e8bf9
--- /dev/null
+++ b/librpc/idl/dsbackup.idl
@@ -0,0 +1,34 @@
+[
+ uuid("ecec0d70-a603-11d0-96b1-00a0c91ece30"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Backup support for Active Directory")
+] interface ad_backup
+{
+ [todo] void HrRBackupPrepare();
+ [todo] void HrRBackupEnd();
+ [todo] void HrRBackupGetAttachmentInformation();
+ [todo] void HrRBackupOpenFile();
+ [todo] void HrRBackupRead();
+ [todo] void HrRBackupClose();
+ [todo] void HrRBackupGetBackupLogs();
+ [todo] void HrRBackupTruncateLogs();
+ [todo] void HrRBackupPing();
+}
+
+[
+ uuid("16e0cf3a-a604-11d0-96b1-00a0c91ece30"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Restoring Active Directory backups")
+] interface ad_restore
+{
+ [todo] void HrRIsNTDSOnline();
+ [todo] void HrRRestorePrepare();
+ [todo] void HrRRestoreRegister();
+ [todo] void HrRRestoreRegisterComplete();
+ [todo] void HrRRestoreGetDatabaseLocations();
+ [todo] void HrRRestoreEnd();
+ [todo] void HrRRestoreSetCurrentLogNumber();
+ [todo] void HrRRestoreCheckLogsForBackup();
+}
diff --git a/librpc/idl/dssetup.idl b/librpc/idl/dssetup.idl
new file mode 100644
index 0000000..14de9f7
--- /dev/null
+++ b/librpc/idl/dssetup.idl
@@ -0,0 +1,101 @@
+/*
+ dssetup interface definition
+*/
+
+import "misc.idl";
+
+[
+ uuid("3919286a-b10c-11d0-9ba8-00c04fd92ef5"),
+ version(0.0),
+ endpoint("ncacn_np:[\\pipe\\lsarpc]", "ncacn_np:[\\pipe\\lsass]", "ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique),
+ helpstring("Active Directory Setup")
+] interface dssetup
+{
+ /**********************************************/
+ /* Function 0x00 */
+
+ typedef enum {
+ DS_ROLE_STANDALONE_WORKSTATION = 0,
+ DS_ROLE_MEMBER_WORKSTATION = 1,
+ DS_ROLE_STANDALONE_SERVER = 2,
+ DS_ROLE_MEMBER_SERVER = 3,
+ DS_ROLE_BACKUP_DC = 4,
+ DS_ROLE_PRIMARY_DC = 5
+ } dssetup_DsRole;
+
+ typedef [bitmap32bit] bitmap {
+ DS_ROLE_PRIMARY_DS_RUNNING = 0x00000001,
+ DS_ROLE_PRIMARY_DS_MIXED_MODE = 0x00000002,
+ DS_ROLE_UPGRADE_IN_PROGRESS = 0x00000004,
+ DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT = 0x01000000
+ } dssetup_DsRoleFlags;
+
+ typedef struct {
+ dssetup_DsRole role;
+ dssetup_DsRoleFlags flags;
+ [charset(UTF16),string] uint16 *domain;
+ [charset(UTF16),string] uint16 *dns_domain;
+ [charset(UTF16),string] uint16 *forest;
+ GUID domain_guid;
+ } dssetup_DsRolePrimaryDomInfoBasic;
+
+ typedef [v1_enum] enum {
+ DS_ROLE_NOT_UPGRADING = 0,
+ DS_ROLE_UPGRADING = 1
+ } dssetup_DsUpgrade;
+
+ typedef enum {
+ DS_ROLE_PREVIOUS_UNKNOWN = 0,
+ DS_ROLE_PREVIOUS_PRIMARY = 1,
+ DS_ROLE_PREVIOUS_BACKUP = 2
+ } dssetup_DsPrevious;
+
+ typedef struct {
+ dssetup_DsUpgrade upgrading;
+ dssetup_DsPrevious previous_role;
+ } dssetup_DsRoleUpgradeStatus;
+
+ typedef enum {
+ DS_ROLE_OP_IDLE = 0,
+ DS_ROLE_OP_ACTIVE = 1,
+ DS_ROLE_OP_NEEDS_REBOOT = 2
+ } dssetup_DsRoleOp;
+
+ typedef struct {
+ dssetup_DsRoleOp status;
+ } dssetup_DsRoleOpStatus;
+
+ typedef enum {
+ DS_ROLE_BASIC_INFORMATION = 1,
+ DS_ROLE_UPGRADE_STATUS = 2,
+ DS_ROLE_OP_STATUS = 3
+ } dssetup_DsRoleInfoLevel;
+
+ typedef [switch_type(dssetup_DsRoleInfoLevel)] union {
+ [case(DS_ROLE_BASIC_INFORMATION)] dssetup_DsRolePrimaryDomInfoBasic basic;
+ [case(DS_ROLE_UPGRADE_STATUS)] dssetup_DsRoleUpgradeStatus upgrade;
+ [case(DS_ROLE_OP_STATUS)] dssetup_DsRoleOpStatus opstatus;
+ } dssetup_DsRoleInfo;
+
+ WERROR dssetup_DsRoleGetPrimaryDomainInformation(
+ [in] dssetup_DsRoleInfoLevel level,
+ [out,switch_is(level),unique] dssetup_DsRoleInfo *info
+ );
+
+ /*
+ w2k3 has removed all the calls below from their implementation.
+ These stubs are left here only as a way of documenting the names
+ of the calls in case they ever turn up on the wire.
+ */
+ [todo] WERROR dssetup_DsRoleDnsNameToFlatName();
+ [todo] WERROR dssetup_DsRoleDcAsDc();
+ [todo] WERROR dssetup_DsRoleDcAsReplica();
+ [todo] WERROR dssetup_DsRoleDemoteDc();
+ [todo] WERROR dssetup_DsRoleGetDcOperationProgress();
+ [todo] WERROR dssetup_DsRoleGetDcOperationResults();
+ [todo] WERROR dssetup_DsRoleCancel();
+ [todo] WERROR dssetup_DsRoleServerSaveStateForUpgrade();
+ [todo] WERROR dssetup_DsRoleUpgradeDownlevelServer();
+ [todo] WERROR dssetup_DsRoleAbortDownlevelServerUpgrade();
+}
diff --git a/librpc/idl/echo.idl b/librpc/idl/echo.idl
new file mode 100644
index 0000000..bf1e318
--- /dev/null
+++ b/librpc/idl/echo.idl
@@ -0,0 +1,127 @@
+
+[
+ uuid("60a15ec5-4de8-11d7-a637-005056a20182"),
+ endpoint("ncacn_np:[\\pipe\\rpcecho]", "ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique),
+ version(1.0),
+ helpstring("Simple echo pipe")
+]
+interface rpcecho
+{
+ /* Add one to an integer */
+ void echo_AddOne(
+ [in] uint32 in_data,
+ [out] uint32 *out_data
+ );
+ /* Echo an array of bytes back at the caller */
+ void echo_EchoData(
+ [in] uint32 len,
+ [in] [size_is(len)] uint8 in_data[],
+ [out] [size_is(len)] uint8 out_data[]
+ );
+ /* Sink data to the server */
+ void echo_SinkData(
+ [in] uint32 len,
+ [in,size_is(len)] uint8 data[]
+ );
+ /* Source data from server */
+ void echo_SourceData(
+ [in] uint32 len,
+ [out,size_is(len)] uint8 data[]
+ );
+
+ /* test strings */
+ void echo_TestCall (
+ [in,string,charset(UTF16)] uint16 *s1,
+ [out,string,charset(UTF16)] uint16 **s2
+ );
+
+
+ /* test some alignment issues */
+ typedef [public] struct {
+ uint8 v;
+ } echo_info1;
+
+ typedef struct {
+ uint16 v;
+ } echo_info2;
+
+ typedef struct {
+ uint32 v;
+ } echo_info3;
+
+ struct echo_info4 {
+ hyper v;
+ };
+
+ typedef struct {
+ uint8 v1;
+ hyper v2;
+ } echo_info5;
+
+ typedef struct {
+ uint8 v1;
+ echo_info1 info1;
+ } echo_info6;
+
+ typedef struct {
+ uint8 v1;
+ struct echo_info4 info4;
+ } echo_info7;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] echo_info1 info1;
+ [case(2)] echo_info2 info2;
+ [case(3)] echo_info3 info3;
+ [case(4)] struct echo_info4 info4;
+ [case(5)] echo_info5 info5;
+ [case(6)] echo_info6 info6;
+ [case(7)] echo_info7 info7;
+ } echo_Info;
+
+ NTSTATUS echo_TestCall2 (
+ [in] uint16 level,
+ [out,switch_is(level)] echo_Info *info
+ );
+
+ uint32 echo_TestSleep(
+ [in] uint32 seconds
+ );
+
+ typedef enum {
+ ECHO_ENUM1 = 1,
+ ECHO_ENUM2 = 2
+ } echo_Enum1;
+
+ typedef [v1_enum] enum {
+ ECHO_ENUM1_32 = 1,
+ ECHO_ENUM2_32 = 2
+ } echo_Enum1_32;
+
+ typedef struct {
+ echo_Enum1 e1;
+ echo_Enum1_32 e2;
+ } echo_Enum2;
+
+ typedef [switch_type(uint16)] union {
+ [case(ECHO_ENUM1)] echo_Enum1 e1;
+ [case(ECHO_ENUM2)] echo_Enum2 e2;
+ } echo_Enum3;
+
+ void echo_TestEnum(
+ [in,out,ref] echo_Enum1 *foo1,
+ [in,out,ref] echo_Enum2 *foo2,
+ [in,out,ref,switch_is(*foo1)] echo_Enum3 *foo3
+ );
+
+ typedef struct {
+ uint32 x;
+ [size_is(x)] uint16 surrounding[*];
+ } echo_Surrounding;
+
+ void echo_TestSurrounding(
+ [in,out,ref] echo_Surrounding *data
+ );
+
+ uint16 echo_TestDoublePointer([in] uint16 ***data);
+}
diff --git a/librpc/idl/efs.idl b/librpc/idl/efs.idl
new file mode 100644
index 0000000..4279b08
--- /dev/null
+++ b/librpc/idl/efs.idl
@@ -0,0 +1,108 @@
+/*
+ IDL definitions from original packet-dcerpc-efs.c
+ by Jean-Baptiste Marchand
+*/
+
+import "security.idl";
+
+[
+ uuid("c681d488-d850-11d0-8c52-00c04fd90f7e"),
+ version(1.0),
+ pointer_default(unique)
+] interface efs
+{
+
+WERROR EfsRpcOpenFileRaw(
+ [out,ref] policy_handle *pvContext,
+ [in] [charset(UTF16),string] uint16 FileName[],
+ [in] uint32 Flags
+ );
+
+[todo] WERROR EfsRpcReadFileRaw(
+ [in,ref] policy_handle *pvContext
+/* incomplete */
+);
+
+
+[todo] WERROR EfsRpcWriteFileRaw(
+ [in,ref] policy_handle *pvContext
+/* incomplete */
+);
+
+void EfsRpcCloseRaw(
+ [in,out,ref] policy_handle *pvContext
+);
+
+WERROR EfsRpcEncryptFileSrv(
+ [in] [charset(UTF16),string] uint16 Filename[]
+);
+
+WERROR EfsRpcDecryptFileSrv(
+ [in] [charset(UTF16),string] uint16 FileName[],
+ [in] uint32 Reserved
+);
+
+typedef struct {
+ uint32 cbData;
+ [size_is(cbData), unique] uint8 *pbData;
+} EFS_HASH_BLOB;
+
+typedef struct {
+ uint32 cbTotalLength;
+ [unique] dom_sid *pUserSid;
+ [unique] EFS_HASH_BLOB *pHash;
+ [unique] [charset(UTF16),string] uint16 *lpDisplayInformation;
+} ENCRYPTION_CERTIFICATE_HASH;
+
+typedef struct {
+ uint32 nCert_Hash;
+ /* this is a pointer to an array of pointers */
+ [size_is(nCert_Hash)] ENCRYPTION_CERTIFICATE_HASH *pUsers[*];
+} ENCRYPTION_CERTIFICATE_HASH_LIST;
+
+WERROR EfsRpcQueryUsersOnFile(
+ [in] [charset(UTF16),string] uint16 FileName[],
+ [out,ref,unique] ENCRYPTION_CERTIFICATE_HASH_LIST **pUsers
+);
+
+WERROR EfsRpcQueryRecoveryAgents(
+ [in] [charset(UTF16),string] uint16 FileName[],
+ [out,ref,unique] ENCRYPTION_CERTIFICATE_HASH_LIST **pRecoveryAgents
+);
+
+[todo] WERROR EfsRpcRemoveUsersFromFile(
+ [in] [charset(UTF16),string] uint16 FileName[]
+ /* [in] ENCRYPTION_CERTIFICATE_LIST Hashes*/
+);
+
+[todo] WERROR EfsRpcAddUsersToFile(
+ [in] [charset(UTF16),string] uint16 FileName[]
+ /* [in] ENCRYPTION_CERTIFICATE_LIST Hashes*/
+);
+
+typedef struct {
+ uint32 dwCertEncodingType;
+ uint32 cbData;
+ [size_is(cbData)] [unique] uint8 *pbData;
+} EFS_CERTIFICATE_BLOB;
+
+typedef struct {
+ uint32 TotalLength;
+ [unique] dom_sid *pUserSid;
+ [unique] EFS_CERTIFICATE_BLOB *pCertBlob;
+} ENCRYPTION_CERTIFICATE;
+
+WERROR EfsRpcSetFileEncryptionKey(
+ [in] [unique] ENCRYPTION_CERTIFICATE *pEncryptionCertificate
+);
+
+[todo] WERROR EfsRpcNotSupported(
+);
+
+[todo] WERROR EfsRpcFileKeyInfo(
+);
+
+[todo] WERROR EfsRpcDuplicateEncryptionInfoFile(
+);
+
+}
diff --git a/librpc/idl/epmapper.idl b/librpc/idl/epmapper.idl
new file mode 100644
index 0000000..fd8eeb4
--- /dev/null
+++ b/librpc/idl/epmapper.idl
@@ -0,0 +1,328 @@
+#include "idl_types.h"
+
+/*
+ endpoint mapper interface
+ Related links:
+ http://www.opengroup.org/onlinepubs/9629399/apdxo.htm : The official IDL for this pipe
+ http://www.opengroup.org/onlinepubs/9629399/apdxl.htm : Details on towers
+http://www.opengroup.org/onlinepubs/9629399/chap6.htm#tagcjh_11_02_03_01: binding strings
+
+*/
+
+import "misc.idl";
+
+[
+ uuid("e1af8308-5d1f-11c9-91a4-08002b14a0fa"),
+ version(3.0),
+ endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]",
+ "ncacn_http:[593]", "ncalrpc:[EPMAPPER]"),
+ helpstring("EndPoint Mapper"),
+ pointer_default(ptr)
+]
+interface epmapper
+{
+
+ /*
+ note that the following IDL won't work in MIDL, and in fact
+ that the full towers/floors representation of epm cannot be
+ represented in MIDL at all. I decided to represent it using
+ the extended IDL syntax in pidl to make it easier to work
+ with.
+ */
+
+ const int EPMAPPER_STATUS_CANT_PERFORM_OP = 0x6d8;
+ const int EPMAPPER_STATUS_NO_MORE_ENTRIES = 0x16c9a0d6;
+ const int EPMAPPER_STATUS_NO_MEMORY = 0x16C9A012;
+ const int EPMAPPER_STATUS_OK = 0;
+
+ typedef [enum8bit] enum {
+
+ /* Level 4 and higher */
+ EPM_PROTOCOL_DNET_NSP = 0x04,
+ EPM_PROTOCOL_OSI_TP4 = 0x05,
+ EPM_PROTOCOL_OSI_CLNS = 0x06,
+ EPM_PROTOCOL_TCP = 0x07,
+ EPM_PROTOCOL_UDP = 0x08,
+ EPM_PROTOCOL_IP = 0x09,
+ /* These 4 are protocol identifiers, always at level 3 or lower */
+ EPM_PROTOCOL_NCADG = 0x0a, /* Connectionless RPC */
+ EPM_PROTOCOL_NCACN = 0x0b,
+ EPM_PROTOCOL_NCALRPC = 0x0c, /* Local RPC */
+ EPM_PROTOCOL_UUID = 0x0d,
+ EPM_PROTOCOL_IPX = 0x0e,
+ EPM_PROTOCOL_SMB = 0x0f,
+ EPM_PROTOCOL_NAMED_PIPE = 0x10,
+ EPM_PROTOCOL_NETBIOS = 0x11,
+ EPM_PROTOCOL_NETBEUI = 0x12,
+ EPM_PROTOCOL_SPX = 0x13,
+ EPM_PROTOCOL_NB_IPX = 0x14, /* NetBIOS over IPX */
+ EPM_PROTOCOL_DSP = 0x16, /* AppleTalk Data Stream Protocol */
+ EPM_PROTOCOL_DDP = 0x17, /* AppleTalk Data Datagram Protocol */
+ EPM_PROTOCOL_APPLETALK = 0x18, /* AppleTalk */
+ EPM_PROTOCOL_VINES_SPP = 0x1a,
+ EPM_PROTOCOL_VINES_IPC = 0x1b, /* Inter Process Communication */
+ EPM_PROTOCOL_STREETTALK = 0x1c, /* Vines Streettalk */
+ EPM_PROTOCOL_HTTP = 0x1f,
+ EPM_PROTOCOL_UNIX_DS = 0x20, /* Unix domain socket */
+ EPM_PROTOCOL_NULL = 0x21
+ } epm_protocol;
+
+ typedef struct {
+ /*FIXME */
+ } epm_rhs_dnet_nsp;
+
+ typedef struct {
+ /*FIXME*/
+ } epm_rhs_osi_tp4;
+
+ typedef struct {
+ /*FIXME*/
+ } epm_rhs_osi_clns;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_udp;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_tcp;
+
+ typedef struct {
+ ipv4address ipaddr;
+ } epm_rhs_ip;
+
+ typedef struct {
+ uint16 minor_version;
+ } epm_rhs_ncadg;
+
+ typedef struct {
+ uint16 minor_version;
+ } epm_rhs_ncacn;
+
+ typedef struct {
+ [flag(NDR_REMAINING)] DATA_BLOB unknown;
+ } epm_rhs_uuid;
+
+ typedef struct {
+ /*FIXME */
+ } epm_rhs_ipx;
+
+ typedef struct {
+ astring unc;
+ } epm_rhs_smb;
+
+ typedef struct {
+ astring path;
+ } epm_rhs_named_pipe;
+
+ typedef struct {
+ astring name;
+ } epm_rhs_netbios;
+
+ typedef struct {
+ } epm_rhs_netbeui;
+
+ typedef struct {
+ } epm_rhs_spx;
+
+ typedef struct {
+ } epm_rhs_nb_ipx;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_http;
+
+ typedef struct {
+ astring path;
+ } epm_rhs_unix_ds;
+
+ typedef struct {
+ } epm_rhs_null;
+
+ typedef struct {
+ uint16 minor_version;
+ } epm_rhs_ncalrpc;
+
+ typedef struct {
+ } epm_rhs_appletalk;
+
+ typedef struct {
+ } epm_rhs_atalk_stream;
+
+ typedef struct {
+ } epm_rhs_atalk_datagram;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_vines_spp;
+
+ typedef struct {
+ uint16 port;
+ } epm_rhs_vines_ipc;
+
+ typedef struct {
+ astring streettalk;
+ } epm_rhs_streettalk;
+
+ typedef [flag(NDR_BIG_ENDIAN),nodiscriminant] union {
+ [case(EPM_PROTOCOL_DNET_NSP)] epm_rhs_dnet_nsp dnet_nsp;
+ [case(EPM_PROTOCOL_OSI_TP4)] epm_rhs_osi_tp4 osi_tp4;
+ [case(EPM_PROTOCOL_OSI_CLNS)] epm_rhs_osi_clns osi_clns;
+ [case(EPM_PROTOCOL_TCP)] epm_rhs_tcp tcp;
+ [case(EPM_PROTOCOL_UDP)] epm_rhs_udp udp;
+ [case(EPM_PROTOCOL_IP)] epm_rhs_ip ip;
+ [case(EPM_PROTOCOL_NCADG)] epm_rhs_ncadg ncadg;
+ [case(EPM_PROTOCOL_NCACN)] epm_rhs_ncacn ncacn;
+ [case(EPM_PROTOCOL_NCALRPC)] epm_rhs_ncalrpc ncalrpc;
+ [case(EPM_PROTOCOL_UUID)] epm_rhs_uuid uuid;
+ [case(EPM_PROTOCOL_IPX)] epm_rhs_ipx ipx;
+ [case(EPM_PROTOCOL_SMB)] epm_rhs_smb smb;
+ [case(EPM_PROTOCOL_NAMED_PIPE)] epm_rhs_named_pipe named_pipe;
+ [case(EPM_PROTOCOL_NETBIOS)] epm_rhs_netbios netbios;
+ [case(EPM_PROTOCOL_NETBEUI)] epm_rhs_netbeui netbeui;
+ [case(EPM_PROTOCOL_SPX)] epm_rhs_spx spx;
+ [case(EPM_PROTOCOL_NB_IPX)] epm_rhs_nb_ipx nb_ipx;
+ [case(EPM_PROTOCOL_DSP)] epm_rhs_atalk_stream atalk_stream;
+ [case(EPM_PROTOCOL_DDP)] epm_rhs_atalk_datagram atalk_datagram;
+ [case(EPM_PROTOCOL_APPLETALK)] epm_rhs_appletalk appletalk;
+ [case(EPM_PROTOCOL_VINES_SPP)] epm_rhs_vines_spp vines_spp;
+ [case(EPM_PROTOCOL_VINES_IPC)] epm_rhs_vines_ipc vines_ipc;
+ [case(EPM_PROTOCOL_STREETTALK)] epm_rhs_streettalk streettalk;
+ [case(EPM_PROTOCOL_HTTP)] epm_rhs_http http;
+ [case(EPM_PROTOCOL_UNIX_DS)] epm_rhs_unix_ds unix_ds;
+ [case(EPM_PROTOCOL_NULL)] epm_rhs_null null;
+ [default] [flag(NDR_REMAINING)] DATA_BLOB unknown;
+ } epm_rhs;
+
+ typedef struct {
+ epm_protocol protocol;
+ [flag(NDR_REMAINING)] DATA_BLOB lhs_data;
+ } epm_lhs;
+
+ typedef struct {
+ [subcontext(2)] epm_lhs lhs;
+ [subcontext(2),switch_is(lhs.protocol)] epm_rhs rhs;
+ } epm_floor;
+
+ /* note that the NDR_NOALIGN flag is inherited by all nested
+ structures. All of the towers/floors stuff is
+ non-aligned. I wonder what sort of wicked substance these
+ guys were smoking?
+ */
+ typedef [gensize,flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN)] struct {
+ uint16 num_floors;
+ epm_floor floors[num_floors];
+ } epm_tower;
+
+ typedef [public] struct {
+ [value(ndr_size_epm_tower(&tower, ndr->flags))] uint32 tower_length;
+ [subcontext(4)] epm_tower tower;
+ } epm_twr_t;
+
+ typedef struct {
+ GUID object;
+ epm_twr_t *tower;
+ /*
+ * In theory this should be:
+ * [charset(DOS),string] uint8 annotation[64]
+ * But midl treats this as:
+ * [charset(DOS),string] uint8 annotation[]
+ * and pidl doesn't support this yet
+ */
+ [value(0)] uint32 __annotation_offset;
+ [value(strlen(annotation)+1)] uint32 __annotation_length;
+ [charset(DOS)] uint8 annotation[__annotation_length];
+ } epm_entry_t;
+
+ typedef struct {
+ GUID uuid;
+ uint16 vers_major;
+ uint16 vers_minor;
+ } rpc_if_id_t;
+
+ /**********************/
+ /* Function 0x0 */
+ error_status_t epm_Insert(
+ [in] uint32 num_ents,
+ [in,size_is(num_ents)] epm_entry_t entries[],
+ [in] uint32 replace
+ );
+
+ /**********************/
+ /* Function 0x1 */
+ error_status_t epm_Delete(
+ [in] uint32 num_ents,
+ [in, size_is(num_ents)] epm_entry_t entries[]
+ );
+
+ typedef [v1_enum] enum {
+ RPC_C_EP_ALL_ELTS = 0x00000000,
+ RPC_C_EP_MATCH_BY_IF = 0x00000001,
+ RPC_C_EP_MATCH_BY_OBJ = 0x00000002,
+ RPC_C_EP_MATCH_BY_BOTH = 0x00000003
+ } epm_InquiryType;
+
+ typedef [v1_enum] enum {
+ RPC_C_VERS_ALL = 0x00000000,
+ RPC_C_VERS_COMPATIBLE = 0x00000001,
+ RPC_C_VERS_EXACT = 0x00000002,
+ RPC_C_VERS_MAJOR_ONLY = 0x00000003,
+ RPC_C_VERS_UPTO = 0x00000004
+ } epm_VersionOption;
+
+ /**********************/
+ /* Function 0x02 */
+ error_status_t epm_Lookup(
+ [in] epm_InquiryType inquiry_type,
+ [in,ptr] GUID *object,
+ [in,ptr] rpc_if_id_t *interface_id,
+ [in] epm_VersionOption vers_option,
+ [in,out] policy_handle *entry_handle,
+ [in] uint32 max_ents,
+ [out] uint32 *num_ents,
+ [out, length_is(*num_ents), size_is(max_ents)] epm_entry_t entries[]
+ );
+
+
+ /**********************/
+ /* Function 0x03 */
+
+ typedef struct {
+ epm_twr_t *twr;
+ } epm_twr_p_t;
+
+ [public] error_status_t epm_Map(
+ [in,ptr] GUID *object,
+ [in,ptr] epm_twr_t *map_tower,
+ [in,out] policy_handle *entry_handle,
+ [in] uint32 max_towers,
+ [out] uint32 *num_towers,
+ [out, length_is(*num_towers), size_is(max_towers)] epm_twr_p_t towers[]
+ );
+
+
+ /**********************/
+ /* Function 0x04 */
+ error_status_t epm_LookupHandleFree(
+ [in,out] policy_handle *entry_handle
+ );
+
+ /**********************/
+ /* Function 0x05 */
+ error_status_t epm_InqObject(
+ [in] GUID *epm_object
+ );
+
+
+ /**********************/
+ /* Function 0x06 */
+ error_status_t epm_MgmtDelete(
+ [in] uint32 object_speced,
+ [in,ptr] GUID *object,
+ [in,ptr] epm_twr_t *tower
+ );
+
+ /**********************/
+ /* Function 0x07 */
+ [todo] error_status_t epm_MapAuth();
+}
diff --git a/librpc/idl/eventlog.idl b/librpc/idl/eventlog.idl
new file mode 100644
index 0000000..e269467
--- /dev/null
+++ b/librpc/idl/eventlog.idl
@@ -0,0 +1,324 @@
+#include "idl_types.h"
+
+/*
+ eventlog interface definition
+*/
+
+import "lsa.idl", "security.idl";
+
+[ uuid("82273fdc-e32a-18c3-3f78-827929dc23ea"),
+ version(0.0),
+ helpstring("Event Logger")
+] interface eventlog
+{
+ typedef [bitmap32bit] bitmap {
+ EVENTLOG_SEQUENTIAL_READ = 0x0001,
+ EVENTLOG_SEEK_READ = 0x0002,
+ EVENTLOG_FORWARDS_READ = 0x0004,
+ EVENTLOG_BACKWARDS_READ = 0x0008
+ } eventlogReadFlags;
+
+ typedef [public] enum {
+ EVENTLOG_SUCCESS = 0x0000,
+ EVENTLOG_ERROR_TYPE = 0x0001,
+ EVENTLOG_WARNING_TYPE = 0x0002,
+ EVENTLOG_INFORMATION_TYPE = 0x0004,
+ EVENTLOG_AUDIT_SUCCESS = 0x0008,
+ EVENTLOG_AUDIT_FAILURE = 0x0010
+ } eventlogEventTypes;
+
+ typedef struct {
+ uint16 unknown0;
+ uint16 unknown1;
+ } eventlog_OpenUnknown0;
+
+ /* compat structure for samba3 on-disc eventlog format,
+ this is *NOT* used on the wire. - gd */
+
+ typedef [flag(NDR_NOALIGN|NDR_PAHEX),public] struct {
+ uint32 size;
+ [charset(DOS),value("eLfL")] uint8 reserved[4];
+ uint32 record_number;
+ time_t time_generated;
+ time_t time_written;
+ uint32 event_id;
+ eventlogEventTypes event_type;
+ [range(0,256)] uint16 num_of_strings;
+ uint16 event_category;
+ uint16 reserved_flags;
+ uint32 closing_record_number;
+ uint32 stringoffset;
+ [value(sid.length)] uint32 sid_length;
+ uint32 sid_offset;
+ [value(data.length)] uint32 data_length;
+ uint32 data_offset;
+ [value(2*strlen_m_term(source_name))] uint32 source_name_len;
+ nstring source_name;
+ [value(2*strlen_m_term(computer_name))] uint32 computer_name_len;
+ nstring computer_name;
+ uint32 sid_padding;
+ DATA_BLOB sid;
+ [value(2*ndr_size_string_array(strings, num_of_strings, STR_NULLTERM))] uint32 strings_len;
+ nstring strings[num_of_strings];
+ DATA_BLOB data;
+ uint32 padding;
+ } eventlog_Record_tdb;
+
+ typedef [v1_enum] enum {
+ ELF_LOGFILE_HEADER_DIRTY = 0x0001,
+ ELF_LOGFILE_HEADER_WRAP = 0x0002,
+ ELF_LOGFILE_LOGFULL_WRITTEN = 0x0004,
+ ELF_LOGFILE_ARCHIVE_SET = 0x0008
+ } EVENTLOG_HEADER_FLAGS;
+
+ typedef [public] struct {
+ [value(0x30)] uint32 HeaderSize;
+ [charset(DOS),value("LfLe")] uint8 Signature[4];
+ [value(1)] uint32 MajorVersion;
+ [value(1)] uint32 MinorVersion;
+ uint32 StartOffset;
+ uint32 EndOffset;
+ uint32 CurrentRecordNumber;
+ uint32 OldestRecordNumber;
+ uint32 MaxSize;
+ EVENTLOG_HEADER_FLAGS Flags;
+ uint32 Retention;
+ [value(0x30)] uint32 EndHeaderSize;
+ } EVENTLOGHEADER;
+
+ typedef [public,gensize] struct {
+ uint32 Length;
+ [charset(DOS),value("LfLe")] uint8 Reserved[4];
+ uint32 RecordNumber;
+ time_t TimeGenerated;
+ time_t TimeWritten;
+ uint32 EventID;
+ eventlogEventTypes EventType;
+ uint16 NumStrings;
+ uint16 EventCategory;
+ uint16 ReservedFlags;
+ uint32 ClosingRecordNumber;
+ [value(56+2*(strlen_m_term(SourceName)+strlen_m_term(Computername))+UserSidLength)] uint32 StringOffset;
+ [value(ndr_size_dom_sid0(&UserSid, ndr->flags))] uint32 UserSidLength;
+ [value(56+2*(strlen_m_term(SourceName)+strlen_m_term(Computername)))] uint32 UserSidOffset;
+ uint32 DataLength;
+ [value(56+2*(strlen_m_term(SourceName)+strlen_m_term(Computername))+UserSidLength+(2*ndr_size_string_array(Strings, NumStrings, STR_NULLTERM)))] uint32 DataOffset;
+ nstring SourceName;
+ nstring Computername;
+ [flag(NDR_ALIGN4),subcontext(0),subcontext_size(UserSidLength)] dom_sid0 UserSid;
+ nstring Strings[NumStrings];
+ [flag(NDR_PAHEX)] uint8 Data[DataLength];
+ astring Pad;
+ [value(Length)] uint32 Length2;
+ } EVENTLOGRECORD;
+
+ typedef [public] struct {
+ [value(0x28)] uint32 RecordSizeBeginning;
+ [value(0x11111111)] uint32 One;
+ [value(0x22222222)] uint32 Two;
+ [value(0x33333333)] uint32 Three;
+ [value(0x44444444)] uint32 Four;
+ uint32 BeginRecord;
+ uint32 EndRecord;
+ uint32 CurrentRecordNumber;
+ uint32 OldestRecordNumber;
+ [value(0x28)] uint32 RecordSizeEnd;
+ } EVENTLOGEOF;
+
+ /* the following is true for a non-wrapped evt file (e.g. backups
+ * generated and viewed with eventvwr) */
+
+ typedef [public] struct {
+ EVENTLOGHEADER hdr;
+ EVENTLOGRECORD records[hdr.CurrentRecordNumber-hdr.OldestRecordNumber];
+ EVENTLOGEOF eof;
+ } EVENTLOG_EVT_FILE;
+
+ /******************/
+ /* Function: 0x00 */
+ NTSTATUS eventlog_ClearEventLogW(
+ [in] policy_handle *handle,
+ [in,unique] lsa_String *backupfile
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ NTSTATUS eventlog_BackupEventLogW(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *backup_filename
+ );
+
+ /******************/
+ /* Function: 0x02 */
+ NTSTATUS eventlog_CloseEventLog(
+ [in,out] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x03 */
+ NTSTATUS eventlog_DeregisterEventSource(
+ [in,out] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ NTSTATUS eventlog_GetNumRecords(
+ [in] policy_handle *handle,
+ [out,ref] uint32 *number
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ NTSTATUS eventlog_GetOldestRecord(
+ [in] policy_handle *handle,
+ [out,ref] uint32 *oldest_entry
+ );
+
+ /******************/
+ /* Function: 0x06 */
+ [todo] NTSTATUS eventlog_ChangeNotify();
+
+ /******************/
+ /* Function: 0x07 */
+ NTSTATUS eventlog_OpenEventLogW(
+ [in,unique] eventlog_OpenUnknown0 *unknown0,
+ [in,ref] lsa_String *logname,
+ [in,ref] lsa_String *servername,
+ [in] uint32 major_version,
+ [in] uint32 minor_version,
+ [out] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x08 */
+ NTSTATUS eventlog_RegisterEventSourceW(
+ [in,unique] eventlog_OpenUnknown0 *unknown0,
+ [in,ref] lsa_String *module_name,
+ [in,ref] lsa_String *reg_module_name,
+ [in] uint32 major_version,
+ [in] uint32 minor_version,
+ [out] policy_handle *log_handle
+ );
+
+ /******************/
+ /* Function: 0x09 */
+ NTSTATUS eventlog_OpenBackupEventLogW(
+ [in,unique] eventlog_OpenUnknown0 *unknown0,
+ [in,ref] lsa_String *backup_logname,
+ [in] uint32 major_version,
+ [in] uint32 minor_version,
+ [out] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x0a */
+ NTSTATUS eventlog_ReadEventLogW(
+ [in] policy_handle *handle,
+ [in] eventlogReadFlags flags,
+ [in] uint32 offset,
+ [in] [range(0,0x7FFFF)] uint32 number_of_bytes,
+ [out,ref,size_is(number_of_bytes)] uint8 *data,
+ [out,ref] uint32 *sent_size,
+ [out,ref] uint32 *real_size
+ );
+
+ /*****************/
+ /* Function 0x0b */
+ NTSTATUS eventlog_ReportEventW(
+ [in] policy_handle *handle,
+ [in] time_t timestamp,
+ [in] eventlogEventTypes event_type,
+ [in] uint16 event_category,
+ [in] uint32 event_id,
+ [in] [range(0,256)] uint16 num_of_strings,
+ [in] [range(0,0x3FFFF)] uint32 data_size,
+ [in,ref] lsa_String *servername,
+ [in,unique] dom_sid *user_sid,
+ [in,unique] [size_is(num_of_strings)] lsa_String **strings,
+ [in,unique] [size_is(data_size)] uint8 *data,
+ [in] uint16 flags,
+ [in,out,unique] uint32 *record_number,
+ [in,out,unique] time_t *time_written
+ );
+
+ /*****************/
+ /* Function 0x0c */
+ [todo] NTSTATUS eventlog_ClearEventLogA();
+
+ /******************/
+ /* Function: 0x0d */
+ [todo] NTSTATUS eventlog_BackupEventLogA();
+
+ /*****************/
+ /* Function 0x0e */
+ [todo] NTSTATUS eventlog_OpenEventLogA();
+
+ /*****************/
+ /* Function 0x0f */
+ [todo] NTSTATUS eventlog_RegisterEventSourceA();
+
+ /*****************/
+ /* Function 0x10 */
+ [todo] NTSTATUS eventlog_OpenBackupEventLogA();
+
+ /*****************/
+ /* Function 0x11 */
+ [todo] NTSTATUS eventlog_ReadEventLogA();
+
+ /*****************/
+ /* Function 0x12 */
+ [todo] NTSTATUS eventlog_ReportEventA();
+
+ /*****************/
+ /* Function 0x13 */
+ [todo] NTSTATUS eventlog_RegisterClusterSvc();
+
+ /*****************/
+ /* Function 0x14 */
+ [todo] NTSTATUS eventlog_DeregisterClusterSvc();
+
+ /*****************/
+ /* Function 0x15 */
+ [todo] NTSTATUS eventlog_WriteClusterEvents();
+
+ /*****************/
+ /* Function 0x16 */
+
+ typedef [public] struct {
+ boolean32 full;
+ } EVENTLOG_FULL_INFORMATION;
+
+ NTSTATUS eventlog_GetLogInformation(
+ [in] policy_handle *handle,
+ [in] uint32 level,
+ [out,ref] [size_is(buf_size)] uint8 *buffer,
+ [in] [range(0,1024)] uint32 buf_size,
+ [out,ref] uint32 *bytes_needed
+ );
+
+ /*****************/
+ /* Function 0x17 */
+ NTSTATUS eventlog_FlushEventLog(
+ [in] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x18 */
+ NTSTATUS eventlog_ReportEventAndSourceW(
+ [in] policy_handle *handle,
+ [in] time_t timestamp,
+ [in] eventlogEventTypes event_type,
+ [in] uint16 event_category,
+ [in] uint32 event_id,
+ [in,ref] lsa_String *sourcename,
+ [in] [range(0,256)] uint16 num_of_strings,
+ [in] [range(0,0x3FFFF)] uint32 data_size,
+ [in,ref] lsa_String *servername,
+ [in,unique] dom_sid *user_sid,
+ [in,unique] [size_is(num_of_strings)] lsa_String **strings,
+ [in,unique] [size_is(data_size)] uint8 *data,
+ [in] uint16 flags,
+ [in,out,unique] uint32 *record_number,
+ [in,out,unique] time_t *time_written
+ );
+}
diff --git a/librpc/idl/eventlog6.idl b/librpc/idl/eventlog6.idl
new file mode 100644
index 0000000..57216cd
--- /dev/null
+++ b/librpc/idl/eventlog6.idl
@@ -0,0 +1,343 @@
+#include "idl_types.h"
+
+
+import "misc.idl";
+
+cpp_quote("#define MAX_RPC_GUID_ARRAY_COUNT (MAX_PAYLOAD / sizeof(struct GUID))")
+cpp_quote("#define eventlog6_EvtRpcSubscribePull 0x10000000")
+cpp_quote("#define eventlog6_EvtRpcVarFlagsModified 0x00000001")
+
+[
+ uuid (f6beaff7-1e19-4fbb-9f8f-b89e2018337c),
+ version(1.0),
+ endpoint("ncacn_ip_tcp:"),
+ helpstring("Eventlog6"),
+ pointer_default(unique)
+]
+interface eventlog6
+{
+ const int MAX_PAYLOAD = 2 * 1024 * 1024;
+ const int MAX_RPC_QUERY_LENGTH = MAX_PAYLOAD / sizeof(uint16_t);
+ const int MAX_RPC_CHANNEL_NAME_LENGTH = 512;
+ const int MAX_RPC_QUERY_CHANNEL_SIZE = 512;
+ const int MAX_RPC_EVENT_ID_SIZE = 256;
+ const int MAX_RPC_FILE_PATH_LENGTH = 32768;
+ const int MAX_RPC_CHANNEL_PATH_LENGTH = 32768;
+ const int MAX_RPC_BOOKMARK_LENGTH = MAX_PAYLOAD / sizeof(uint16_t);
+ const int MAX_RPC_PUBLISHER_ID_LENGTH = 2048;
+ const int MAX_RPC_PROPERTY_BUFFER_SIZE = MAX_PAYLOAD;
+ const int MAX_RPC_FILTER_LENGTH = MAX_RPC_QUERY_LENGTH;
+ const int MAX_RPC_RECORD_COUNT = 1024;
+ const int MAX_RPC_EVENT_SIZE = MAX_PAYLOAD;
+ const int MAX_RPC_BATCH_SIZE = MAX_PAYLOAD;
+ const int MAX_RPC_RENDERED_STRING_SIZE = MAX_PAYLOAD;
+ const int MAX_RPC_CHANNEL_COUNT = 8192;
+ const int MAX_RPC_PUBLISHER_COUNT = 8192;
+ const int MAX_RPC_EVENT_METADATA_COUNT = 256;
+ const int MAX_RPC_VARIANT_LIST_COUNT = 256;
+ const int MAX_RPC_BOOLEAN8_ARRAY_COUNT = MAX_PAYLOAD / sizeof(uint8_t);
+ const int MAX_RPC_UINT32_ARRAY_COUNT = MAX_PAYLOAD / sizeof(uint32_t);
+ const int MAX_RPC_UINT64_ARRAY_COUNT = MAX_PAYLOAD / sizeof(uint64_t);
+ const int MAX_RPC_STRING_ARRAY_COUNT = MAX_PAYLOAD / 512;
+ const int MAX_RPC_STRING_LENGTH = MAX_PAYLOAD / sizeof(uint16_t);
+
+ typedef struct {
+ uint32 error;
+ uint32 sub_err;
+ uint32 sub_err_param;
+ } eventlog6_RpcInfo;
+
+ typedef struct {
+ [range(0, MAX_RPC_BOOLEAN8_ARRAY_COUNT)] uint32 count;
+ [size_is(count)] boolean8* ptr;
+ } eventlog6_boolean8Array;
+
+ typedef struct {
+ [range(0, MAX_RPC_UINT32_ARRAY_COUNT)] uint32 count;
+ [size_is(count)] uint32* ptr;
+ } eventlog6_UInt32Array;
+
+ typedef struct {
+ [range(0, MAX_RPC_UINT64_ARRAY_COUNT)] uint32 count;
+ [size_is(count)] hyper* ptr;
+ } eventlog6_UInt64Array;
+
+ typedef struct {
+ [range(0, MAX_RPC_STRING_ARRAY_COUNT)] uint32 count;
+ [size_is(count),charset(UTF16),string] uint16 **ptr;
+ } eventlog6_StringArray;
+
+ typedef struct {
+ [range(0, MAX_RPC_GUID_ARRAY_COUNT)] uint32 count;
+ [size_is(count)] GUID* ptr;
+ } eventlog6_GuidArray;
+
+ typedef [v1_enum] enum {
+ EvtRpcVarTypeNull = 0,
+ EvtRpcVarTypeboolean8 = 1,
+ EvtRpcVarTypeUInt32 = 2,
+ EvtRpcVarTypeUInt64 = 3,
+ EvtRpcVarTypeString = 4,
+ EvtRpcVarTypeGuid = 5,
+ EvtRpcVarTypeboolean8Array = 6,
+ EvtRpcVarTypeUInt32Array = 7,
+ EvtRpcVarTypeUInt64Array = 8,
+ EvtRpcVarTypeStringArray = 9,
+ EvtRpcVarTypeGuidArray = 10
+ } eventlog6_EvtRpcVariantType;
+
+ typedef [v1_enum] enum {
+ EvtRpcChannelPath = 0,
+ EvtRpcPublisherName = 1
+ } eventlog6_EvtRpcAssertConfigFlags;
+
+ typedef [switch_type(eventlog6_EvtRpcVariantType)] union {
+ [case(EvtRpcVarTypeNull)] int nullVal;
+ [case(EvtRpcVarTypeboolean8)] boolean8 boolean8Val;
+ [case(EvtRpcVarTypeUInt32)] uint32 uint32Val;
+ [case(EvtRpcVarTypeUInt64)] hyper uint64Val;
+ [case(EvtRpcVarTypeString)] [charset(UTF16),string] uint16 *stringVal;
+ [case(EvtRpcVarTypeGuid)] GUID *guidVal;
+ [case(EvtRpcVarTypeboolean8Array)] eventlog6_boolean8Array boolean8Array;
+ [case(EvtRpcVarTypeUInt32Array)] eventlog6_UInt32Array uint32Array;
+ [case(EvtRpcVarTypeUInt64Array)] eventlog6_UInt64Array uint64Array;
+ [case(EvtRpcVarTypeStringArray)] eventlog6_StringArray stringArray;
+ [case(EvtRpcVarTypeGuidArray)] eventlog6_GuidArray guidArray;
+ } eventlog6_EvtRpcVariantUnion;
+
+ typedef struct {
+ eventlog6_EvtRpcVariantType type;
+ uint32 flags;
+ [in,ref,switch_is(type)] eventlog6_EvtRpcVariantUnion *var;
+ } eventlog6_EvtRpcVariant;
+
+ typedef struct {
+ [range(0, MAX_RPC_VARIANT_LIST_COUNT)] uint32 count;
+ [size_is(count)] eventlog6_EvtRpcVariant* props;
+ } eventlog6_EvtRpcVariantList;
+
+ typedef struct {
+ [charset(UTF16),string] uint16 *name;
+ uint32 status;
+ } eventlog6_EvtRpcQueryChannelInfo;
+
+ WERROR eventlog6_EvtRpcRegisterRemoteSubscription(
+ [in, unique, range(0, MAX_RPC_CHANNEL_NAME_LENGTH),charset(UTF16),string] uint16 *channelPath,
+ [in, range(1, MAX_RPC_QUERY_LENGTH),charset(UTF16),string] uint16 *query,
+ [in, unique, range(0, MAX_RPC_BOOKMARK_LENGTH),charset(UTF16),string] uint16 *bookmarkXml,
+ [in] uint32 flags,
+ [out, ref] policy_handle *handle,
+ [out, ref] policy_handle *control,
+ [out, ref] uint32 *queryChannelInfoSize,
+ [out, size_is(,*queryChannelInfoSize), range(0, MAX_RPC_QUERY_CHANNEL_SIZE)]
+ eventlog6_EvtRpcQueryChannelInfo **queryChannelInfo,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcRemoteSubscriptionNextAsync(
+ [in, ref] policy_handle *handle,
+ [in] uint32 numRequestedRecords,
+ [in] uint32 flags,
+ [out, ref] uint32 *numActualRecords,
+ [out, size_is(,*numActualRecords), range(0, MAX_RPC_RECORD_COUNT)]
+ uint32 **eventDataIndices,
+ [out, size_is(,*numActualRecords), range(0, MAX_RPC_RECORD_COUNT)]
+ uint32 **eventDataSizes,
+ [out, ref] uint32* resultBufferSize,
+ [out, size_is(,*resultBufferSize), range(0, MAX_RPC_BATCH_SIZE)]
+ uint8 **resultBuffer);
+
+ WERROR eventlog6_EvtRpcRemoteSubscriptionNext(
+ [in, ref] policy_handle *handle,
+ [in] uint32 numRequestedRecords,
+ [in] uint32 timeOut,
+ [in] uint32 flags,
+ [out, ref] uint32 *numActualRecords,
+ [out, size_is(,*numActualRecords), range(0, MAX_RPC_RECORD_COUNT)]
+ uint32 **eventDataIndices,
+ [out, size_is(,*numActualRecords), range(0, MAX_RPC_RECORD_COUNT)]
+ uint32 **eventDataSizes,
+ [out, ref] uint32 *resultBufferSize,
+ [out, size_is(,*resultBufferSize), range(0, MAX_RPC_BATCH_SIZE)]
+ uint8 **resultBuffer);
+
+ WERROR eventlog6_EvtRpcRemoteSubscriptionWaitAsync(
+ [in, ref] policy_handle *handle);
+
+ WERROR eventlog6_EvtRpcRegisterControllableOperation(
+ [out, ref] policy_handle *handle);
+
+ WERROR eventlog6_EvtRpcRegisterLogQuery(
+ [in, unique, range(0, MAX_RPC_CHANNEL_PATH_LENGTH),charset(UTF16),string] uint16 *path,
+ [in, range(1, MAX_RPC_QUERY_LENGTH),charset(UTF16),string] uint16 *query,
+ [in] uint32 flags,
+ [out, ref] policy_handle *handle,
+ [out, ref] policy_handle *opControl,
+ [out, ref] uint32 *queryChannelInfoSize,
+ [out, size_is(,*queryChannelInfoSize), range(0, MAX_RPC_QUERY_CHANNEL_SIZE)]
+ eventlog6_EvtRpcQueryChannelInfo **queryChannelInfo,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcClearLog(
+ [in, ref] policy_handle *control,
+ [in, range(0, MAX_RPC_CHANNEL_NAME_LENGTH),charset(UTF16),string] uint16 *channelPath,
+ [in, unique, range(0, MAX_RPC_FILE_PATH_LENGTH),charset(UTF16),string] uint16 *backupPath,
+ [in] uint32 flags,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcExportLog(
+ [in, ref] policy_handle *control,
+ [in, unique, range(0, MAX_RPC_CHANNEL_NAME_LENGTH),charset(UTF16),string] uint16 *channelPath,
+ [in, range(1, MAX_RPC_QUERY_LENGTH),charset(UTF16),string] uint16 *query,
+ [in, range(1, MAX_RPC_FILE_PATH_LENGTH),charset(UTF16),string] uint16 *backupPath,
+ [in] uint32 flags,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcLocalizeExportLog(
+ [in, ref] policy_handle *control,
+ [in, range(1, MAX_RPC_FILE_PATH_LENGTH),charset(UTF16),string] uint16 *logFilePath,
+ [in] uint32 locale,
+ [in] uint32 flags,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcMessageRender(
+ [in, ref] policy_handle *pubCfgObj,
+ [in, range(1, MAX_RPC_EVENT_ID_SIZE)] uint32 sizeEventId,
+ [in, size_is(sizeEventId)] uint8 *eventId,
+ [in] uint32 messageId,
+ [in] eventlog6_EvtRpcVariantList *values,
+ [in] uint32 flags,
+ [in] uint32 maxSizeString,
+ [out, ref] uint32 *actualSizeString,
+ [out, ref] uint32 *neededSizeString,
+ [out, size_is(,*actualSizeString), range(0, MAX_RPC_RENDERED_STRING_SIZE)]
+ uint8 **string,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcMessageRenderDefault(
+ [in, range(1, MAX_RPC_EVENT_ID_SIZE)] uint32 sizeEventId,
+ [in, size_is(sizeEventId)] uint8 *eventId,
+ [in] uint32 messageId,
+ [in] eventlog6_EvtRpcVariantList *values,
+ [in] uint32 flags,
+ [in] uint32 maxSizeString,
+ [out, ref] uint32 *actualSizeString,
+ [out, ref] uint32 *neededSizeString,
+ [out, size_is(,*actualSizeString), range(0, MAX_RPC_RENDERED_STRING_SIZE)]
+ uint8 **string,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcQueryNext(
+ [in, ref] policy_handle *logQuery,
+ [in] uint32 numRequestedRecords,
+ [in] uint32 timeOutEnd,
+ [in] uint32 flags,
+ [out, ref] uint32 *numActualRecords,
+ [out, size_is(,*numActualRecords), range(0, MAX_RPC_RECORD_COUNT)]
+ uint32 **eventDataIndices,
+ [out, size_is(,*numActualRecords), range(0, MAX_RPC_RECORD_COUNT)]
+ uint32 **eventDataSizes,
+ [out, ref] uint32 *resultBufferSize,
+ [out, size_is(,*resultBufferSize), range(0, MAX_RPC_BATCH_SIZE)]
+ uint8 **resultBuffer);
+
+ WERROR eventlog6_EvtRpcQuerySeek(
+ [in, ref] policy_handle *logQuery,
+ [in] hyper pos,
+ [in, unique, range(0, MAX_RPC_BOOKMARK_LENGTH),charset(UTF16),string] uint16 *bookmarkXml,
+ [in] uint32 timeOut,
+ [in] uint32 flags,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcClose(
+ [in, out, ref] policy_handle **handle);
+
+ WERROR eventlog6_EvtRpcCancel(
+ [in, ref] policy_handle *handle);
+
+ WERROR eventlog6_EvtRpcAssertConfig(
+ [in, range(1, MAX_RPC_CHANNEL_NAME_LENGTH),charset(UTF16),string] uint16 *path,
+ [in] uint32 flags);
+
+ WERROR eventlog6_EvtRpcRetractConfig(
+ [in, range(1, MAX_RPC_CHANNEL_NAME_LENGTH),charset(UTF16),string] uint16 *path,
+ [in] uint32 flags );
+
+ WERROR eventlog6_EvtRpcOpenLogHandle(
+ [in, range(1, MAX_RPC_CHANNEL_NAME_LENGTH),charset(UTF16),string] uint16 *channel,
+ [in] uint32 flags,
+ [out, ref] policy_handle *handle,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcGetLogFileInfo(
+ [in, ref] policy_handle *logHandle,
+ [in] uint32 propertyId,
+ [in, range(0, MAX_RPC_PROPERTY_BUFFER_SIZE)]
+ uint32 propertyValueBufferSize,
+ [out, size_is(propertyValueBufferSize)] uint8 *propertyValueBuffer,
+ [out, ref] uint32 *propertyValueBufferLength);
+
+ WERROR eventlog6_EvtRpcGetChannelList(
+ [in] uint32 flags,
+ [out, ref] uint32 *numChannelPaths,
+ [out, size_is(,*numChannelPaths), range(0, MAX_RPC_CHANNEL_COUNT),charset(UTF16),string]
+ uint16 ***channelPaths);
+
+ WERROR eventlog6_EvtRpcGetChannelConfig(
+ [in, range(1, MAX_RPC_CHANNEL_NAME_LENGTH),charset(UTF16),string] uint16 *channelPath,
+ [in] uint32 flags,
+ [out, ref] eventlog6_EvtRpcVariantList* props);
+
+ WERROR eventlog6_EvtRpcPutChannelConfig(
+ [in, range(1, MAX_RPC_CHANNEL_NAME_LENGTH),charset(UTF16),string] uint16 *channelPath,
+ [in] uint32 flags,
+ [in] eventlog6_EvtRpcVariantList* props,
+ [out, ref] eventlog6_RpcInfo *error);
+
+ WERROR eventlog6_EvtRpcGetPublisherList(
+ [in] uint32 flags,
+ [out, ref] uint32 *numPublisherIds,
+ [out, size_is(,*numPublisherIds), range(0, MAX_RPC_PUBLISHER_COUNT),charset(UTF16),string]
+ uint16 ***publisherIds);
+
+ WERROR eventlog6_EvtRpcGetPublisherListForChannel(
+ [in] uint16 *channelName,
+ [in] uint32 flags,
+ [out, ref] uint32* numPublisherIds,
+ [out, size_is(,*numPublisherIds), range(0, MAX_RPC_PUBLISHER_COUNT),charset(UTF16),string]
+ uint16 ***publisherIds);
+
+ WERROR eventlog6_EvtRpcGetPublisherMetadata(
+ [in, unique, range(0, MAX_RPC_PUBLISHER_ID_LENGTH),charset(UTF16),string] uint16 *publisherId,
+ [in, unique, range(0, MAX_RPC_FILE_PATH_LENGTH),charset(UTF16),string] uint16 *logFilePath,
+ [in] uint32 locale,
+ [in] uint32 flags,
+ [out, ref] eventlog6_EvtRpcVariantList* pubMetadataProps,
+ [out, ref] policy_handle *pubMetadata);
+
+ WERROR eventlog6_EvtRpcGetPublisherResourceMetadata(
+ [in, ref] policy_handle *handle,
+ [in] uint32 propertyId,
+ [in] uint32 flags,
+ [out, ref] eventlog6_EvtRpcVariantList *pubMetadataProps);
+
+ WERROR eventlog6_EvtRpcGetEventMetadataEnum(
+ [in, ref] policy_handle *pubMetadata,
+ [in] uint32 flags,
+ [in, unique, range(0, MAX_RPC_FILTER_LENGTH),charset(UTF16),string] uint16 *reservedForFilter,
+ [out, ref] policy_handle *eventMetaDataEnum);
+
+ WERROR eventlog6_EvtRpcGetNextEventMetadata(
+ [in, ref] policy_handle *eventMetaDataEnum,
+ [in] uint32 flags,
+ [in] uint32 numRequested,
+ [out, ref] uint32 *numReturned,
+ [out, size_is(,*numReturned), range(0, MAX_RPC_EVENT_METADATA_COUNT)]
+ eventlog6_EvtRpcVariantList **eventMetadataInstances);
+
+ WERROR eventlog6_EvtRpcGetClassicLogDisplayName(
+ [in, range(1, MAX_RPC_CHANNEL_NAME_LENGTH),charset(UTF16),string] uint16 *logName,
+ [in] uint32 locale,
+ [in] uint32 flags,
+ [out] uint16 **displayName);
+}
+
diff --git a/librpc/idl/file_id.idl b/librpc/idl/file_id.idl
new file mode 100644
index 0000000..cd1febe
--- /dev/null
+++ b/librpc/idl/file_id.idl
@@ -0,0 +1,14 @@
+[
+ pointer_default(unique)
+]
+interface file_id
+{
+ typedef [public] struct {
+ /* we don't use SMB_DEV_T and SMB_INO_T as we want a fixed size here,
+ and we may be using file system specific code to fill in something
+ other than a dev_t for the device */
+ udlong devid;
+ udlong inode;
+ udlong extid; /* Support systems that use an extended id (e.g. snapshots). */
+ } file_id;
+}
diff --git a/librpc/idl/frsapi.idl b/librpc/idl/frsapi.idl
new file mode 100644
index 0000000..ea7880c
--- /dev/null
+++ b/librpc/idl/frsapi.idl
@@ -0,0 +1,128 @@
+#include "idl_types.h"
+
+import "misc.idl";
+
+[
+ uuid("d049b186-814f-11d1-9a3c-00c04fc9b232"),
+ version(1.1),
+ endpoint("ncacn_ip_tcp:", "ncalrpc:"),
+ helpstring("File Replication API"),
+ pointer_default(unique)
+]
+interface frsapi
+{
+ /****************/
+ /* Function 0x00 */
+ [todo] void FRSAPI_VERIFY_PROMOTION();
+
+ /****************/
+ /* Function 0x01 */
+ [todo] void FRSAPI_PROMOTION_STATUS();
+
+ /****************/
+ /* Function 0x02 */
+ [todo] void FRSAPI_START_DEMOTION();
+
+ /****************/
+ /* Function 0x03 */
+ [todo] void FRSAPI_COMMIT_DEMOTION();
+
+ /****************/
+ /* Function 0x04 */
+
+ /* The DsPollingLongInterval and DsPollingShortInterval attributes
+ represent registry attributes below HKLM\System\CCS\Services\NtFrs */
+
+ WERROR frsapi_SetDsPollingIntervalW(
+ [in] uint32 CurrentInterval,
+ [in] uint32 DsPollingLongInterval,
+ [in] uint32 DsPollingShortInterval
+ );
+
+ /****************/
+ /* Function 0x05 */
+ WERROR frsapi_GetDsPollingIntervalW(
+ [out] uint32 *CurrentInterval,
+ [out] uint32 *DsPollingLongInterval,
+ [out] uint32 *DsPollingShortInterval
+ );
+
+ /****************/
+ /* Function 0x06 */
+ [todo] void FRSAPI_VERIFY_PROMOTION_W();
+
+ /****************/
+ /* Function 0x07 */
+ typedef [v1_enum] enum {
+ FRSAPI_INFO_VERSION = 0,
+ FRSAPI_INFO_SETS = 1,
+ FRSAPI_INFO_DS = 2,
+ FRSAPI_INFO_MEMORY = 3,
+ FRSAPI_INFO_IDTABLE = 4,
+ FRSAPI_INFO_OUTLOG = 5,
+ FRSAPI_INFO_INLOG = 6,
+ FRSAPI_INFO_THREADS = 7,
+ FRSAPI_INFO_STAGE = 8,
+ FRSAPI_INFO_CONFIGTABLE = 9
+ } frsapi_InfoEnum;
+
+ typedef struct {
+ uint32 length;
+ GUID guid;
+ uint32 length2;
+ uint32 unknown1;
+ frsapi_InfoEnum level;
+ uint32 query_counter;
+ uint32 unknown2;
+ uint32 offset;
+ uint32 blob_len;
+ /* [size_is(length-offset)] uint8 *data; */
+ [subcontext_size(length-offset),subcontext(0),flag(NDR_REMAINING)] DATA_BLOB blob;
+ } frsapi_Info;
+
+ WERROR frsapi_InfoW(
+ [in] [range(0,0x10000)] uint32 length,
+ /* [in,out] [size_is(length)] [unique] uint8 *data */
+ [in,out,unique] frsapi_Info *info
+
+ );
+
+ /****************/
+ /* Function 0x08 */
+ typedef [v1_enum] enum {
+ FRSAPI_REPLICA_SET_TYPE_0 = 0x00000000,
+ FRSAPI_REPLICA_SET_TYPE_DOMAIN = 0x00000002,
+ FRSAPI_REPLICA_SET_TYPE_DFS = 0x00000003
+ } frsapi_ReplicaSetType;
+
+ WERROR frsapi_IsPathReplicated(
+ [in,unique] [string,charset(UTF16)] uint16 *path,
+ [in] frsapi_ReplicaSetType replica_set_type,
+ [out] uint32 *replicated,
+ [out] uint32 *primary,
+ [out] uint32 *root,
+ [out] GUID *replica_set_guid
+ );
+
+ /****************/
+ /* Function 0x09 */
+ typedef [v1_enum] enum {
+ FRSAPI_WRITER_COMMAND_FREEZE = 0x00000001,
+ FRSAPI_WRITER_COMMAND_THAW = 0x00000002
+ } frsapi_WriterCommandsValues;
+
+ WERROR frsapi_WriterCommand(
+ [in] frsapi_WriterCommandsValues command
+ );
+
+ /****************/
+ /* Function 0x0a */
+ /* not supported before w2k3 sp2 */
+ WERROR frsapi_ForceReplication(
+ [in,unique] GUID *replica_set_guid,
+ [in,unique] GUID *connection_guid,
+ [in,unique] [charset(UTF16),string] uint16 *replica_set_name,
+ [in,unique] [charset(UTF16),string] uint16 *partner_dns_name
+ );
+
+}
diff --git a/librpc/idl/frsrpc.idl b/librpc/idl/frsrpc.idl
new file mode 100644
index 0000000..016095f
--- /dev/null
+++ b/librpc/idl/frsrpc.idl
@@ -0,0 +1,458 @@
+#include "idl_types.h"
+
+import "misc.idl";
+import "fscc.idl";
+import "bkupblobs.idl";
+
+[
+ uuid("f5cc59b4-4264-101a-8c59-08002b2f8426"),
+ version(1.1),
+ endpoint("ncacn_ip_tcp:", "ncalrpc:"),
+ helpstring("File Replication Service"),
+ helper("../librpc/ndr/ndr_frsrpc.h"),
+ pointer_default(unique)
+]
+interface frsrpc
+{
+
+ /*****************/
+ /* Function 0x00 */
+
+ typedef struct {
+ [subcontext(4)] GUID guid;
+ [subcontext(4)] nstring name;
+ } frsrpc_CommPktChunkGuidName;
+
+ typedef struct {
+ hyper vsn;
+ GUID guid;
+ } frsrpc_CommPktGSVN;
+
+ typedef [bitmap32bit,flag(NDR_PAHEX)] bitmap {
+ FRSRPC_CO_FLAG_ABORT_CO = 0x00000001,
+ FRSRPC_CO_FLAG_VV_ACTIVATED = 0x00000002,
+ FRSRPC_CO_FLAG_CONTENT_CMD = 0x00000004,
+ FRSRPC_CO_FLAG_LOCATION_CMD = 0x00000008,
+ FRSRPC_CO_FLAG_ONLIST = 0x00000010,
+ FRSRPC_CO_FLAG_LOCALCO = 0x00000020,
+ FRSRPC_CO_FLAG_RETRY = 0x00000040,
+ FRSRPC_CO_FLAG_INST_INCOMPLETE = 0x00000080,
+ FRSRPC_CO_FLAG_OUT_OF_ORDER = 0x00000200,
+ FRSRPC_CO_FLAG_NEW_FILE = 0x00000400,
+ FRSRPC_CO_FLAG_CONTROL = 0x00001000,
+ FRSRPC_CO_FLAG_DIRECTED_CO = 0x00002000,
+ FRSRPC_CO_FLAG_VVJOIN_TO_ORIG = 0x00040000,
+ FRSRPC_CO_FLAG_SKIP_ORIG_REC_C = 0x00100000,
+ FRSRPC_CO_FLAG_MOVEIN_GEN = 0x00200000,
+ FRSRPC_CO_FLAG_MORPH_GEN_HEAD = 0x00400000,
+ FRSRPC_CO_FLAG_JUST_OID_RESET = 0x00800000,
+ FRSRPC_CO_FLAG_COMPRESSED_STAGE = 0x01000000,
+ FRSRPC_CO_FLAG_SKIP_VV_UPDATE = 0x02000000
+ } frsrpc_CommPktCoCmdFlags;
+
+ const uint32 FRSRPC_CO_IFLAG_NONE = 0x0000000;
+
+ const string FRSRPC_COMPRESSION_GUID = "64d2f7d2-2695-436d-8830-8d3c58701e15";
+
+
+ typedef [bitmap32bit,flag(NDR_PAHEX)] bitmap {
+ FRSRPC_CO_IFLAG_VVRETIRE_EXEC = 0x00000001,
+ FRSRPC_CO_IFLAG_CO_ABORT = 0x00000002,
+ FRSRPC_CO_IFLAG_DIR_ENUM_PENDING= 0x00000004
+ } frsrpc_CommPktCoCmdIFlags;
+
+ typedef [v1_enum,flag(NDR_PAHEX)] enum {
+ FRSRPC_CO_STATUS_CO_ENTERED_LOG = 0x00000000,
+ FRSRPC_CO_STATUS_ALLOC_STAGING_LOCAL_CO = 0x00000001,
+ FRSRPC_CO_STATUS_LOCAL_CO_STAGING_STARTED = 0x00000002,
+ FRSRPC_CO_STATUS_LOCAL_CO_STAGING_COMPLETED = 0x00000003,
+ FRSRPC_CO_STATUS_WAIT_RETRY_LOCAL_CO_STAGING = 0x00000004,
+ FRSRPC_CO_STATUS_ALLOC_STAGING_REMOTE_CO = 0x00000005,
+ FRSRPC_CO_STATUS_REMOTE_CO_STAGING_STARTED = 0x00000006,
+ FRSRPC_CO_STATUS_REMOTE_CO_STAGING_COMPLETED = 0x00000007,
+ FRSRPC_CO_STATUS_WAIT_RETRY_REMOTE_CO_STAGING = 0x00000008,
+ FRSRPC_CO_STATUS_FILE_INSTALL_REQUESTED = 0x00000009,
+ FRSRPC_CO_STATUS_FILE_INSTALL_STARTED = 0x0000000A,
+ FRSRPC_CO_STATUS_FILE_INSTALL_COMPLETED = 0x0000000B,
+ FRSRPC_CO_STATUS_FILE_INSTALL_WAIT_RETRY = 0x0000000C,
+ FRSRPC_CO_STATUS_FILE_INSTALL_RETRYING = 0x0000000D,
+ FRSRPC_CO_STATUS_FILE_INSTALL_RENAME_RETRYING = 0x0000000E,
+ FRSRPC_CO_STATUS_FILE_INSTALL_DELETE_RETRYING = 0x0000000F,
+ FRSRPC_CO_STATUS_CO_RECYCLED_FOR_ENUM = 0x00000013,
+ FRSRPC_CO_STATUS_REQUEST_OUTBOUND_PROPAGATION = 0x00000014,
+ FRSRPC_CO_STATUS_REQUEST_ACCEPTED_OUTBOUND_LOG = 0x00000015,
+ FRSRPC_CO_STATUS_DB_STATE_UPDATE_STARTED = 0x00000016,
+ FRSRPC_CO_STATUS_DB_STATE_UPDATE_COMPLETED = 0x00000017,
+ FRSRPC_CO_STATUS_CO_ABORTED = 0x00000018
+ } frsrpc_CommPktCoCmdStatus;
+
+ typedef [bitmap32bit,flag(NDR_PAHEX)] bitmap {
+ FRSRPC_CONTENT_REASON_DATA_OVERWRITE = 0x00000001,
+ FRSRPC_CONTENT_REASON_DATA_EXTEND = 0x00000002,
+ FRSRPC_CONTENT_REASON_DATA_TRUNCATION = 0x00000004,
+ FRSRPC_CONTENT_REASON_NAMED_DATA_OVERWRITE = 0x00000010,
+ FRSRPC_CONTENT_REASON_NAMED_DATA_EXTEND = 0x00000020,
+ FRSRPC_CONTENT_REASON_NAMED_DATA_TRUNCATION = 0x00000040,
+ FRSRPC_CONTENT_REASON_FILE_CREATE = 0x00000100,
+ FRSRPC_CONTENT_REASON_FILE_DELETE = 0x00000200,
+ FRSRPC_CONTENT_REASON_EA_CHANGE = 0x00000400,
+ FRSRPC_CONTENT_REASON_SECURITY_CHANGE = 0x00000800,
+ FRSRPC_CONTENT_REASON_OLD_NAME = 0x00001000,
+ FRSRPC_CONTENT_REASON_NEW_NAME = 0x00002000,
+ FRSRPC_CONTENT_REASON_BASIC_INFO_CHANGE = 0x00004000,
+ FRSRPC_CONTENT_REASON_COMPRESSION_CHANGE = 0x00020000
+ } frsrpc_CommPktCoCmdContentCmd;
+
+ typedef [v1_enum,flag(NDR_PAHEX)] enum {
+ FRSRPC_CO_LOCATION_FILE_CREATE = 0x00000000,
+ FRSRPC_CO_LOCATION_DIR_CREATE = 0x00000000 | 0x00000001,
+ FRSRPC_CO_LOCATION_FILE_DELETE = 0x00000002,
+ FRSRPC_CO_LOCATION_DIR_DELETE = 0x00000002 | 0x00000001,
+ FRSRPC_CO_LOCATION_FILE_MOVEIN = 0x00000004,
+ FRSRPC_CO_LOCATION_DIR_MOVEIN = 0x00000004 | 0x00000001,
+ FRSRPC_CO_LOCATION_FILE_MOVEIN2 = 0x00000006,
+ FRSRPC_CO_LOCATION_DIR_MOVEIN2 = 0x00000006 | 0x00000001,
+ FRSRPC_CO_LOCATION_FILE_MOVEOUT = 0x00000008,
+ FRSRPC_CO_LOCATION_DIR_MOVEOUT = 0x00000008 | 0x00000001,
+ FRSRPC_CO_LOCATION_FILE_MOVERS = 0x0000000a,
+ FRSRPC_CO_LOCATION_DIR_MOVERS = 0x0000000a | 0x00000001,
+ FRSRPC_CO_LOCATION_FILE_MOVEDIR = 0x0000000c,
+ FRSRPC_CO_LOCATION_DIR_MOVEDIR = 0x0000000c | 0x00000001,
+ FRSRPC_CO_LOCATION_FILE_NO_CMD = 0x0000000e,
+ FRSRPC_CO_LOCATION_DIR_NO_CMD = 0x0000000e | 0x00000001
+ } frsrpc_CommPktCoCmdLocationCmd;
+
+ [public] typedef struct {
+ uint32 sequence_number;
+ frsrpc_CommPktCoCmdFlags flags;
+ frsrpc_CommPktCoCmdIFlags iflags;
+ frsrpc_CommPktCoCmdStatus status;
+ frsrpc_CommPktCoCmdContentCmd content_cmd;
+ frsrpc_CommPktCoCmdLocationCmd location_cmd;
+ uint32 file_attributes;
+ uint32 file_version_number;
+ uint32 partern_ack_sequence_number;
+ [value(0)] uint32 not_used;
+ hyper file_size;
+ hyper file_offset;
+ hyper frs_vsn;
+ hyper file_usn;
+ hyper jrnl_usn;
+ hyper jrnl_first_usn;
+ uint32 original_replica_num;
+ uint32 new_replica_num;
+ GUID change_order_guid;
+ GUID originator_guid;
+ GUID file_guid;
+ GUID old_parent_guid;
+ GUID new_parent_guid;
+ GUID connection_guid;
+ hyper ack_version;
+ [value(0)] hyper spare2ul1;
+ [value(0)] hyper spare1guid_p1;
+ [value(0)] hyper spare1guid_p2;
+ [value(0)] hyper spare2guid_p1;
+ [value(0)] hyper spare3guid_p2;
+ [value(0)] uint32 spare1wcs;
+ [value(0)] uint32 spare2wcs;
+ [value(0)] uint32 extension;
+ [value(0)] uint32 spare2bin;
+ NTTIME event_time;
+ [value(2*strlen_m(file_name))] uint16 file_name_length;
+#define FRSRPC_MAX_PATH 260
+ [charset(UTF16)] uint16 file_name[FRSRPC_MAX_PATH+1];
+ [value(0)] uint8 padding1;
+ [value(0)] uint8 padding2;
+ [value(0)] uint8 padding3;
+ [value(0)] uint8 padding4;
+ } frsrpc_CommPktChangeOrderCommand;
+
+ typedef [v1_enum,flag(NDR_PAHEX)] enum {
+ FRSRPC_DATA_EXTENSION_TERMINATOR = 0x00000000,
+ FRSRPC_DATA_EXTENSION_MD5_CHECKSUM = 0x00000001,
+ FRSRPC_DATA_EXTENSION_RETRY_TIMEOUT = 0x00000002
+ } frsrpc_CommPktDataExtensionType;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ [value(0x00000018)] uint32 prefix_size;
+ [value(FRSRPC_DATA_EXTENSION_MD5_CHECKSUM)]
+ frsrpc_CommPktDataExtensionType prefix_type;
+ uint8 data[16];
+ } frsrpc_CommPktDataExtensionChecksum;
+
+ typedef struct {
+ [value(0x00000018)] uint32 prefix_size;
+ [value(FRSRPC_DATA_EXTENSION_RETRY_TIMEOUT)]
+ frsrpc_CommPktDataExtensionType prefix_type;
+ uint32 count;
+ [value(0)] uint32 not_used;
+ NTTIME first_try_time;
+ } frsrpc_CommPktDataExtensionRetryTimeout;
+
+ typedef [flag(NDR_PAHEX)] enum {
+ FRSRPC_CO_RECORD_EXTENSION_VERSION_WIN2K = 0x0000,
+ FRSRPC_CO_RECORD_EXTENSION_VERSION_1 = 0x0001
+ } frsrpc_CommPktCoRecordExtensionMajor;
+
+ typedef struct {
+ [value(0x00000028)] uint32 field_size;
+ [value(FRSRPC_CO_RECORD_EXTENSION_VERSION_WIN2K)]
+ frsrpc_CommPktCoRecordExtensionMajor major;
+ [value(0x0001)] uint16 offset_count;
+ [value(0x00000010)] uint32 offset;
+ [value(0)] uint32 offset_last;
+ frsrpc_CommPktDataExtensionChecksum data_checksum;
+ } frsrpc_CommPktCoRecordExtensionWin2k;
+
+ typedef struct {
+ [value(0x00000048)] uint32 field_size;
+ frsrpc_CommPktCoRecordExtensionMajor major;
+ [value(0x0002)] uint16 offset_count;
+ [value(0x00000018)] uint32 offset0;
+ [value(0x00000030)] uint32 offset1;
+ [value(0)] uint32 offset_last;
+ [value(0)] uint32 not_used;
+ frsrpc_CommPktDataExtensionChecksum data_checksum;
+ frsrpc_CommPktDataExtensionRetryTimeout data_retry_timeout;
+ } frsrpc_CommPktChangeOrderRecordExtension;
+
+ typedef [v1_enum,flag(NDR_PAHEX)] enum {
+ FRSRPC_COMMAND_REMOTE_CO = 0x00000218,
+ FRSRPC_COMMAND_RECEIVING_STATE = 0x00000238,
+ FRSRPC_COMMAND_REMOTE_CO_DONE = 0x00000250,
+ FRSRPC_COMMAND_ABORT_FETCH = 0x00000246,
+ FRSRPC_COMMAND_RETRY_FETCH = 0x00000244,
+ FRSRPC_COMMAND_NEED_JOIN = 0x00000121,
+ FRSRPC_COMMAND_START_JOIN = 0x00000122,
+ FRSRPC_COMMAND_JOINING = 0x00000130,
+ FRSRPC_COMMAND_JOINED = 0x00000128,
+ FRSRPC_COMMAND_UNJOIN_REMOTE = 0x00000148,
+ FRSRPC_COMMAND_VVJOIN_DONE = 0x00000136,
+ FRSRPC_COMMAND_SEND_STAGE = 0x00000228
+ } frsrpc_CommPktCommand;
+
+ typedef [flag(NDR_PAHEX)] enum {
+ FRSRPC_COMM_PKT_CHUNK_BOP = 0x0001,
+ FRSRPC_COMM_PKT_CHUNK_COMMAND = 0x0002,
+ FRSRPC_COMM_PKT_CHUNK_TO = 0x0003,
+ FRSRPC_COMM_PKT_CHUNK_FROM = 0x0004,
+ FRSRPC_COMM_PKT_CHUNK_REPLICA = 0x0005,
+ FRSRPC_COMM_PKT_CHUNK_CONNECTION = 0x0008,
+ FRSRPC_COMM_PKT_CHUNK_JOIN_GUID = 0x0006,
+ FRSRPC_COMM_PKT_CHUNK_LAST_JOIN_TIME = 0x0012,
+
+ FRSRPC_COMM_PKT_CHUNK_VVECTOR = 0x0007,
+ FRSRPC_COMM_PKT_CHUNK_JOIN_TIME = 0x0011,
+ FRSRPC_COMM_PKT_CHUNK_REPLICA_VERSION_GUID = 0x0014,
+ FRSRPC_COMM_PKT_CHUNK_COMPRESSION_GUID = 0x0018,
+
+ FRSRPC_COMM_PKT_CHUNK_BLOCK = 0x0009,
+ FRSRPC_COMM_PKT_CHUNK_BLOCK_SIZE = 0x000A,
+ FRSRPC_COMM_PKT_CHUNK_FILE_SIZE = 0x000B,
+ FRSRPC_COMM_PKT_CHUNK_FILE_OFFSET = 0x000C,
+ FRSRPC_COMM_PKT_CHUNK_GVSN = 0x000E,
+ FRSRPC_COMM_PKT_CHUNK_CO_GUID = 0x000F,
+ FRSRPC_COMM_PKT_CHUNK_CO_SEQUENCE_NUMBER = 0x0010,
+
+ FRSRPC_COMM_PKT_CHUNK_REMOTE_CO = 0x000D,
+ FRSRPC_COMM_PKT_CHUNK_CO_EXT_WIN2K = 0x0016,
+ FRSRPC_COMM_PKT_CHUNK_CO_EXTENTION_2 = 0x0017,
+
+ FRSRPC_COMM_PKT_CHUNK_EOP = 0x0013
+ } frsrpc_CommPktChunkType;
+
+ typedef [nodiscriminant] union {
+ [default,flag(NDR_REMAINING)] DATA_BLOB blob;
+ [case(FRSRPC_COMM_PKT_CHUNK_BOP)]
+ [value(0)] uint32 bop;
+ [case(FRSRPC_COMM_PKT_CHUNK_COMMAND)]
+ frsrpc_CommPktCommand command;
+ [case(FRSRPC_COMM_PKT_CHUNK_TO)]
+ frsrpc_CommPktChunkGuidName to;
+ [case(FRSRPC_COMM_PKT_CHUNK_FROM)]
+ frsrpc_CommPktChunkGuidName from;
+ [case(FRSRPC_COMM_PKT_CHUNK_REPLICA)]
+ frsrpc_CommPktChunkGuidName replica;
+ [case(FRSRPC_COMM_PKT_CHUNK_CONNECTION)]
+ frsrpc_CommPktChunkGuidName connection;
+ [case(FRSRPC_COMM_PKT_CHUNK_JOIN_GUID)][subcontext(4)]
+ GUID join_guid;
+ [case(FRSRPC_COMM_PKT_CHUNK_LAST_JOIN_TIME)]
+ NTTIME last_join_time;
+ [case(FRSRPC_COMM_PKT_CHUNK_VVECTOR)][subcontext(4)]
+ frsrpc_CommPktGSVN vvector;
+ [case(FRSRPC_COMM_PKT_CHUNK_JOIN_TIME)][subcontext(4)]
+ NTTIME join_time;
+ [case(FRSRPC_COMM_PKT_CHUNK_REPLICA_VERSION_GUID)][subcontext(4)]
+ GUID replica_version_guid;
+ [case(FRSRPC_COMM_PKT_CHUNK_COMPRESSION_GUID)]
+ GUID compression_guid;
+ [case(FRSRPC_COMM_PKT_CHUNK_BLOCK)]
+ DATA_BLOB block;
+ [case(FRSRPC_COMM_PKT_CHUNK_BLOCK_SIZE)]
+ hyper block_size;
+ [case(FRSRPC_COMM_PKT_CHUNK_FILE_SIZE)]
+ hyper file_size;
+ [case(FRSRPC_COMM_PKT_CHUNK_FILE_OFFSET)]
+ hyper file_offset;
+ [case(FRSRPC_COMM_PKT_CHUNK_GVSN)][subcontext(4)]
+ frsrpc_CommPktGSVN gvsn;
+ [case(FRSRPC_COMM_PKT_CHUNK_CO_GUID)][subcontext(4)]
+ GUID co_guid;
+ [case(FRSRPC_COMM_PKT_CHUNK_CO_SEQUENCE_NUMBER)]
+ uint32 co_sequence_number;
+ [case(FRSRPC_COMM_PKT_CHUNK_REMOTE_CO)][subcontext(4)]
+ frsrpc_CommPktChangeOrderCommand remote_co;
+ [case(FRSRPC_COMM_PKT_CHUNK_CO_EXT_WIN2K)][subcontext(4)]
+ frsrpc_CommPktCoRecordExtensionWin2k co_ext_win2k;
+ [case(FRSRPC_COMM_PKT_CHUNK_CO_EXTENTION_2)]
+ frsrpc_CommPktChangeOrderRecordExtension co_extension2;
+ [case(FRSRPC_COMM_PKT_CHUNK_EOP)]
+ [value(0xFFFFFFFF)] uint32 bopend;
+ } frsrpc_CommPktChunkData;
+
+ typedef [public,flag(NDR_NOALIGN)] struct {
+ frsrpc_CommPktChunkType type;
+ [subcontext(4),switch_is(type)] frsrpc_CommPktChunkData data;
+ } frsrpc_CommPktChunk;
+
+ typedef [nopull,nopush,flag(NDR_NOALIGN)] struct {
+ uint32 num_chunks; /* this doesn't appear on the wire */
+ frsrpc_CommPktChunk chunks[num_chunks];
+ } frsrpc_CommPktChunkCtr;
+
+ typedef [v1_enum] enum {
+ FRSRPC_COMM_PKT_MAJOR_0 = 0x00000000
+ } frsrpc_CommPktMajor;
+
+ typedef [v1_enum] enum {
+ FRSRPC_COMM_PKT_MINOR_0 = 0x00000000,
+ FRSRPC_COMM_PKT_MINOR_1 = 0x00000001,
+ FRSRPC_COMM_PKT_MINOR_2 = 0x00000002,
+ FRSRPC_COMM_PKT_MINOR_3 = 0x00000003,
+ FRSRPC_COMM_PKT_MINOR_4 = 0x00000004,
+ FRSRPC_COMM_PKT_MINOR_5 = 0x00000005,
+ FRSRPC_COMM_PKT_MINOR_6 = 0x00000006,
+ FRSRPC_COMM_PKT_MINOR_7 = 0x00000007,
+ FRSRPC_COMM_PKT_MINOR_8 = 0x00000008,
+ FRSRPC_COMM_PKT_MINOR_9 = 0x00000009
+ } frsrpc_CommPktMinor;
+
+ [public] typedef struct {
+ frsrpc_CommPktMajor major;
+ frsrpc_CommPktMinor minor;
+ [value(1)] uint32 cs_id;
+ [value(pkt_len+12)] uint32 memory_len;
+ [value(ndr_size_frsrpc_CommPktChunkCtr(r->ctr,
+ ndr->flags))]
+ [range(0, 262144)]
+ uint32 pkt_len;
+ [value(0)] uint32 upk_len;
+ [subcontext(4),subcontext_size(pkt_len)]
+ frsrpc_CommPktChunkCtr *ctr;
+ [value(0)] uint3264 data_name;
+ [value(0)] uint3264 data_handle;
+ } frsrpc_FrsSendCommPktReq;
+
+ WERROR frsrpc_FrsSendCommPkt(
+ [in] frsrpc_FrsSendCommPktReq req
+ );
+
+ /*****************/
+ /* Function 0x01 */
+ /* this function always return WERR_CALL_NOT_IMPLEMENTED */
+ WERROR frsrpc_FrsVerifyPromotionParent(
+ [in,unique,string,charset(UTF16)] uint16 *parent_account,
+ [in,unique,string,charset(UTF16)] uint16 *parent_password,
+ [in,unique,string,charset(UTF16)] uint16 *replica_set_name,
+ [in,unique,string,charset(UTF16)] uint16 *replica_set_type,
+ [in] frsrpc_PartnerAuthLevel partner_auth_level,
+ [in] uint32 __ndr_guid_size
+ );
+
+ /*****************/
+ /* Function 0x02 */
+ typedef [v1_enum,flag(NDR_PAHEX)] enum {
+ FRSRPC_PARENT_AUTH_LEVEL_ENCRYPTED_KERBEROS = 0x00000000,
+ FRSRPC_PARENT_AUTH_LEVEL_NO_AUTHENTICATION = 0x00000001
+ } frsrpc_PartnerAuthLevel;
+
+ WERROR frsrpc_FrsStartPromotionParent(
+ [in,unique,string,charset(UTF16)] uint16 *parent_account,
+ [in,unique,string,charset(UTF16)] uint16 *parent_password,
+ [in,unique,string,charset(UTF16)] uint16 *replica_set_name,
+ [in,unique,string,charset(UTF16)] uint16 *replica_set_type,
+ [in,unique,string,charset(UTF16)] uint16 *connection_name,
+ [in,unique,string,charset(UTF16)] uint16 *partner_name,
+ [in,unique,string,charset(UTF16)] uint16 *partner_princ_name,
+ [in] frsrpc_PartnerAuthLevel partner_auth_level,
+ [in,value(16),range(16,16)] uint32 __ndr_guid_size,
+ [in,unique,subcontext(4),subcontext_size(16)]
+ GUID *connection_guid,
+ [in,unique,subcontext(4),subcontext_size(16)]
+ GUID *partner_guid,
+ [in,out,unique,subcontext(4),subcontext_size(16)]
+ GUID *parent_guid
+ );
+
+ typedef [public,flag(NDR_NOALIGN)] struct {
+ uint32 major;
+ uint32 minor;
+ uint32 dataHigh;
+ uint32 dataLow;
+ uint16 compression;
+ uint8 unused[6];
+ fscc_FileNetworkOpenInformation attributes;
+ frsrpc_CommPktChangeOrderCommand command;
+ fscc_FileObjectIdBuffer_2 fileObjId;
+ frsrpc_CommPktCoRecordExtensionWin2k cocExt;
+ GUID compressionGuid;
+ uint32 encDataHigh;
+ uint32 encDataLow;
+ hyper dataSize;
+ uint32 reparseDataPresent;
+ uint32 reparseDataHigh;
+ uint32 reparseDataLow;
+ uint32 padding2;
+ } frsrpc_StageHeader;
+
+ /*****************/
+ /* Function 0x03 */
+ WERROR frsrpc_FrsNOP();
+
+ /*
+ *For Op from 4 to 10 Microsoft use
+ *the notation OpnumxxNotUsedOnWire
+ *where xx is the number of the OP.
+ *They are only declared in the IDL of MS-FRS1.pdf.
+ *Not in the core of the document.
+ */
+
+ /*****************/
+ /* Function 0x04 */
+ /*[todo] void FRSRPC_BACKUP_COMPLETE();*/
+
+ /*****************/
+ /* Function 0x05 */
+ /*[todo] void FRSRPC_BACKUP_COMPLETE_5();*/
+
+ /*****************/
+ /* Function 0x06 */
+ /*[todo] void FRSRPC_BACKUP_COMPLETE_6();*/
+
+ /*****************/
+ /* Function 0x07 */
+ /*[todo] void FRSRPC_BACKUP_COMPLETE_7();*/
+
+ /*****************/
+ /* Function 0x08 */
+ /*[todo] void FRSRPC_BACKUP_COMPLETE_8();*/
+
+ /*****************/
+ /* Function 0x09 */
+ /*[todo] void FRSRPC_BACKUP_COMPLETE_9();*/
+
+ /*****************/
+ /* Function 0x0a */
+ /*[todo] void FRSRPC_VERIFY_PROMOTION_PARENT_EX();*/
+}
diff --git a/librpc/idl/frstrans.idl b/librpc/idl/frstrans.idl
new file mode 100644
index 0000000..ed5b105
--- /dev/null
+++ b/librpc/idl/frstrans.idl
@@ -0,0 +1,295 @@
+#include "idl_types.h"
+
+import "misc.idl";
+
+[
+ uuid("897e2e5f-93f3-4376-9c9c-fd2277495c27"),
+ version(1.0),
+ endpoint("ncacn_ip_tcp:", "ncalrpc:"),
+ helpstring("File Replication Service DFS-R"),
+ pointer_default(unique)
+]
+interface frstrans
+{
+ /*****************/
+ /* Function 0x00 */
+ WERROR frstrans_CheckConnectivity(
+ [in] GUID replica_set_guid,
+ [in] GUID connection_guid
+ );
+
+ /*****************/
+ /* Function 0x01 */
+ typedef [v1_enum,flag(NDR_PAHEX)] enum {
+ FRSTRANS_PROTOCOL_VERSION_W2K3R2 = 0x00050000,
+ FRSTRANS_PROTOCOL_VERSION_LONGHORN_SERVER = 0x00050002
+ } frstrans_ProtocolVersion;
+
+ typedef [bitmap32bit] bitmap {
+ FRSTRANS_TRANSPORT_SUPPORTS_RDC_SIMILARITY = 0x00000001
+ } frstrans_TransportFlags;
+
+ WERROR frstrans_EstablishConnection(
+ [in] GUID replica_set_guid,
+ [in] GUID connection_guid,
+ [in] frstrans_ProtocolVersion downstream_protocol_version,
+ [in] frstrans_TransportFlags downstream_flags,
+ [out,ref] frstrans_ProtocolVersion *upstream_protocol_version,
+ [out,ref] frstrans_TransportFlags *upstream_flags
+ );
+
+ /*****************/
+ /* Function 0x02 */
+ WERROR frstrans_EstablishSession(
+ [in] GUID connection_guid,
+ [in] GUID content_set_guid
+ );
+
+ /*****************/
+ /* Function 0x03 */
+ typedef enum {
+ FRSTRANS_UPDATE_REQUEST_ALL = 0x0000,
+ FRSTRANS_UPDATE_REQUEST_TOMBSTONES = 0x0001,
+ FRSTRANS_UPDATE_REQUEST_LIVE = 0x0002
+ } frstrans_UpdateRequestType;
+
+ typedef enum {
+ FRSTRANS_UPDATE_STATUS_DONE = 0x0002,
+ FRSTRANS_UPDATE_STATUS_MORE = 0x0003
+ } frstrans_UpdateStatus;
+
+ typedef [public] struct {
+ GUID db_guid;
+ hyper low;
+ hyper high;
+ } frstrans_VersionVector;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ boolean32 present;
+ boolean32 name_conflict;
+ uint32 attributes;
+ NTTIME fence;
+ NTTIME clock;
+ NTTIME create_time;
+ GUID content_set_guid;
+ uint8 sha1_hash[20];
+ uint8 rdc_similarity[16];
+ GUID uid_db_guid;
+ hyper uid_version;
+ GUID gsvn_db_guid;
+ hyper gsvn_version;
+ GUID parent_db_guid;
+ hyper parent_version;
+ [string,charset(UTF16)] uint16 name[261];
+ uint32 flags;
+ } frstrans_Update;
+
+ WERROR frstrans_RequestUpdates(
+ [in] GUID connection_guid,
+ [in] GUID content_set_guid,
+ [in,range(0,256)] uint32 credits_available,
+ [in,range(0,1)] boolean32 hash_requested,
+ [in,range(0,2)]
+ frstrans_UpdateRequestType update_request_type,
+ [in] uint32 version_vector_diff_count,
+ [in,size_is(version_vector_diff_count)]
+ frstrans_VersionVector *version_vector_diff,
+ [out,ref,size_is(credits_available),length_is(*update_count)]
+ frstrans_Update *frs_update,
+ [out,ref] uint32 *update_count,
+ [out,ref] frstrans_UpdateStatus *update_status,
+ [out,ref] GUID *gvsn_db_guid,
+ [out,ref] hyper *gvsn_version
+ );
+
+ /*****************/
+ /* Function 0x04 */
+ typedef enum {
+ FRSTRANS_VERSION_REQUEST_NORNAL_SYNC = 0x0000,
+ FRSTRANS_VERSION_REQUEST_SLOW_SYNC = 0x0001,
+ FRSTRANS_VERSION_REQUEST_SLAVE_SYNC = 0x0002
+ } frstrans_VersionRequestType;
+
+ typedef enum {
+ FRSTRANS_VERSION_CHANGE_NOTIFY = 0x0000,
+ FRSTRANS_VERSION_CHANGE_ALL = 0x0002
+ } frstrans_VersionChangeType;
+
+ WERROR frstrans_RequestVersionVector(
+ [in] uint32 sequence_number,
+ [in] GUID connection_guid,
+ [in] GUID content_set_guid,
+ [in,range(0,2)] frstrans_VersionRequestType request_type,
+ [in,range(0,2)] frstrans_VersionChangeType change_type,
+ [in] hyper vv_generation
+ );
+
+ /*****************/
+ /* Function 0x05 */
+ typedef struct {
+ GUID machine_guid;
+ uint32 year;
+ uint32 month;
+ uint32 day_of_week;
+ uint32 day;
+ uint32 hour;
+ uint32 minute;
+ uint32 second;
+ uint32 milli_seconds;
+ } frstrans_EpoqueVector;
+
+ typedef struct {
+ hyper vv_generation;
+ uint32 version_vector_count;
+ [size_is(version_vector_count)]
+ frstrans_VersionVector *version_vector;
+ uint32 epoque_vector_count;
+ [size_is(epoque_vector_count)]
+ frstrans_EpoqueVector *epoque_vector;
+ } frstrans_AsyncVersionVectorResponse;
+
+ typedef struct {
+ uint32 sequence_number;
+ WERROR status;
+ frstrans_AsyncVersionVectorResponse response;
+ } frstrans_AsyncResponseContext;
+
+ WERROR frstrans_AsyncPoll(
+ [in] GUID connection_guid,
+ [out,ref] frstrans_AsyncResponseContext *response
+ );
+
+ /*****************/
+ /* Function 0x06 */
+ [todo] void FRSTRANS_REQUEST_RECORDS();
+
+ /*****************/
+ /* Function 0x07 */
+ [todo] void FRSTRANS_UPDATE_CANCEL();
+
+ /*****************/
+ /* Function 0x08 */
+ [todo] void FRSTRANS_RAW_GET_FILE_DATA();
+
+ /*****************/
+ /* Function 0x09 */
+ [todo] void FRSTRANS_RDC_GET_SIGNATURES();
+
+ /*****************/
+ /* Function 0x0a */
+ [todo] void FRSTRANS_RDC_PUSH_SOURCE_NEEDS();
+
+ /*****************/
+ /* Function 0x0b */
+ [todo] void FRSTRANS_RDC_GET_FILE_DATA();
+
+ /*****************/
+ /* Function 0x0c */
+ WERROR frstrans_RdcClose(
+ [in,out,ref] policy_handle *server_context
+ );
+
+ /*****************/
+ /* Function 0x0d */
+ typedef enum {
+ FRSTRANS_STAGING_POLICY_SERVER_DEFAULTY = 0x0000,
+ FRSTRANS_STAGING_POLICY_STATGING_REQUIRED = 0x0001,
+ FRSTRANS_STAGING_POLICY_RESTATGING_REQUIRED = 0x0002
+ } frstrans_RequestedStagingPolicy;
+
+ typedef enum {
+ FRSTRANS_RDC_FILTER_GENERIC = 0x0000,
+ FRSTRANS_RDC_FILTER_MAX = 0x0001,
+ FRSTRANS_RDC_FILTER_POINT = 0x0002,
+ FRSTRANS_RDC_MAX_ALGORITHM = 0x0003
+ } frstrans_RdcChunckerAlgorithm;
+
+ typedef struct {
+ frstrans_RdcChunckerAlgorithm chunker_type;
+ uint8 chunker_parameters[64];
+ } frstrans_RdcParameterGeneric;
+
+ typedef struct {
+ [range(128,1024*16)] uint16 min_horizon_size;
+ [range(2,96)] uint16 max_window_size;
+ } frstrans_RdcParameterFilterMax;
+
+ typedef struct {
+ uint16 min_chunk_size;
+ uint16 max_chunk_size;
+ } frstrans_RdcParameterFilterPoint;
+
+ typedef [switch_type(frstrans_RdcChunckerAlgorithm)] union {
+ [case(FRSTRANS_RDC_FILTER_GENERIC)]
+ frstrans_RdcParameterGeneric filter_generic;
+ [case(FRSTRANS_RDC_FILTER_MAX)]
+ frstrans_RdcParameterFilterMax filter_max;
+ [case(FRSTRANS_RDC_FILTER_POINT)]
+ frstrans_RdcParameterFilterPoint filter_point;
+ } frstrans_RdcParameterUnion;
+
+ typedef struct {
+ frstrans_RdcChunckerAlgorithm rdc_chunker_algorithm;
+ [switch_is(rdc_chunker_algorithm)] frstrans_RdcParameterUnion u;
+ } frstrans_RdcParameters;
+
+ typedef enum {
+ FRSTRANS_RDC_VERSION = 0x0001
+ } frstrans_RdcVersion;
+
+ typedef enum {
+ FRSTRANS_RDC_VERSION_COMPATIBLE = 0x0001
+ } frstrans_RdcVersionCompatible;
+
+ typedef enum {
+ FRSTRANS_RDC_UNCOMPRESSED = 0x0000,
+ FRSTRANS_RDC_XPRESS = 0x0001
+ } frstrans_RdcCompressionAlgorithm;
+
+ typedef struct {
+ hyper on_disk_file_size;
+ hyper file_size_estimate;
+ frstrans_RdcVersion rdc_version;
+ frstrans_RdcVersionCompatible rdc_minimum_compatible_version;
+ [range(0,8)] uint8 rdc_signature_levels;
+ frstrans_RdcCompressionAlgorithm compression_algorithm;
+ [size_is(rdc_signature_levels)]
+ frstrans_RdcParameters rdc_filter_parameters[*];
+ } frstrans_RdcFileInfo;
+
+ WERROR frstrans_InitializeFileTransferAsync(
+ [in] GUID connection_guid,
+ [in,out,ref] frstrans_Update *frs_update,
+ [in,range(0,1)] boolean32 rdc_desired,
+ [in,out,ref] frstrans_RequestedStagingPolicy *staging_policy,
+ [out,ref] policy_handle *server_context,
+ [out,ref] frstrans_RdcFileInfo **rdc_file_info,
+ [out,ref,size_is(buffer_size),length_is(*size_read)]
+ uint8 *data_buffer,
+ [in,range(0,262144)] uint32 buffer_size,
+ [out,ref] uint32 *size_read,
+ [out,ref] boolean32 *is_end_of_file
+ );
+
+ /*****************/
+ /* Function 0x0e */
+ [todo] void FRSTRANS_OPNUM_0E_NOT_USED_ON_THE_WIRE();
+
+ /* The following functions are new in Windows 2008 */
+
+ /*****************/
+ /* Function 0x0f */
+ typedef [flag(NDR_PAHEX)] pipe uint8 frstrans_BytePipe;
+
+ WERROR frstrans_RawGetFileDataAsync(
+ [in,ref] policy_handle *server_context,
+ [out,ref] frstrans_BytePipe *byte_pipe
+ );
+
+ /*****************/
+ /* Function 0x10 */
+ WERROR frstrans_RdcGetFileDataAsync(
+ [in,ref] policy_handle *server_context,
+ [out,ref] frstrans_BytePipe *byte_pipe
+ );
+}
diff --git a/librpc/idl/fscc.idl b/librpc/idl/fscc.idl
new file mode 100644
index 0000000..9947dcc
--- /dev/null
+++ b/librpc/idl/fscc.idl
@@ -0,0 +1,47 @@
+#include "idl_types.h"
+
+import "misc.idl";
+/* fscc structures */
+
+[
+ pointer_default(unique),
+ helpstring("fscc structures")
+]
+
+
+interface fscc
+{
+ typedef [public] struct {
+ GUID id;
+ GUID birthVolumeId;
+ GUID initialObjectId;
+ GUID domainId;
+ } fscc_FileObjectIdBuffer_2;
+
+ typedef [bitmap32bit,flag(NDR_PAHEX)] bitmap{
+ FSCC_FILE_ATTRIBUTE_READONLY = 0x00000001,
+ FSCC_FILE_ATTRIBUTE_HIDDEN = 0x00000002,
+ FSCC_FILE_ATTRIBUTE_SYSTEM = 0x00000004,
+ FSCC_FILE_ATTRIBUTE_NORMAL = 0x00000008,
+ FSCC_FILE_ATTRIBUTE_DIRECTORY = 0x00000010,
+ FSCC_FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
+ FSCC_FILE_ATTRIBUTE_TEMPORARY = 0x00000100,
+ FSCC_FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200,
+ FSCC_FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400,
+ FSCC_FILE_ATTRIBUTE_COMPRESSED = 0x00000800,
+ FSCC_FILE_ATTRIBUTE_OFFLINE = 0x00001000,
+ FSCC_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
+ FSCC_FILE_ATTRIBUTE_ENCRYPTED = 0x00004000
+ } fscc_FileAttributes;
+
+ typedef [public] struct {
+ hyper creationTime;
+ hyper lastAccessTime;
+ hyper lastWriteTime;
+ hyper changeTime;
+ hyper allocSize;
+ hyper endOfFile;
+ fscc_FileAttributes fileAttribute;
+ uint32 reserved;
+ } fscc_FileNetworkOpenInformation;
+}
diff --git a/librpc/idl/fsrvp.idl b/librpc/idl/fsrvp.idl
new file mode 100644
index 0000000..6158f43
--- /dev/null
+++ b/librpc/idl/fsrvp.idl
@@ -0,0 +1,107 @@
+#include "idl_types.h"
+
+/*
+ * File Server Remote VSS Protocol Definitions
+ */
+
+import "misc.idl";
+
+[ uuid("a8e0653c-2744-4389-a61d-7373df8b2292"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\FssagentRpc]"),
+ helpstring("File Server Remote VSS Protocol"),
+ pointer_default(unique)
+] interface FileServerVssAgent
+{
+ const uint32 FSRVP_E_BAD_STATE = 0x80042301;
+ const uint32 FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS = 0x80042316;
+ const uint32 FSRVP_E_NOT_SUPPORTED = 0x8004230C;
+ const uint32 FSRVP_E_WAIT_TIMEOUT = 0x00000102;
+ const uint32 FSRVP_E_WAIT_FAILED = 0xFFFFFFFF;
+ const uint32 FSRVP_E_OBJECT_ALREADY_EXISTS = 0x8004230D;
+ const uint32 FSRVP_E_OBJECT_NOT_FOUND = 0x80042308;
+ const uint32 FSRVP_E_UNSUPPORTED_CONTEXT = 0x8004231B;
+ const uint32 FSRVP_E_BAD_ID = 0x80042302; /* wire, not documented */
+ const uint32 FSRVP_E_SHADOWCOPYSET_ID_MISMATCH = 0x80042501;
+ typedef struct {
+ GUID ShadowCopySetId;
+ GUID ShadowCopyId;
+ [string,charset(UTF16)] uint16 *ShareNameUNC;
+ [string,charset(UTF16)] uint16 *ShadowCopyShareName;
+ NTTIME tstamp;
+ } fssagent_share_mapping_1;
+
+ typedef union {
+ [case(1)] fssagent_share_mapping_1 *ShareMapping1;
+ [default];
+ } fssagent_share_mapping;
+
+ const uint32 FSRVP_RPC_VERSION_1 = 0x00000001;
+ DWORD fss_GetSupportedVersion(
+ [out] uint32 *MinVersion,
+ [out] uint32 *MaxVersion);
+
+ const uint32 ATTR_PERSISTENT = 0x00000001;
+ const uint32 ATTR_NO_AUTO_RECOVERY = 0x00000002;
+ const uint32 ATTR_NO_AUTO_RELEASE = 0x00000008;
+ const uint32 ATTR_NO_WRITERS = 0x00000010;
+ const uint32 ATTR_FILE_SHARE = 0x04000000;
+ const uint32 ATTR_AUTO_RECOVERY = 0x00400000;
+
+ const uint32 FSRVP_CTX_BACKUP = 0x00000000;
+ const uint32 FSRVP_CTX_FILE_SHARE_BACKUP = 0x00000010;
+ const uint32 FSRVP_CTX_NAS_ROLLBACK = 0x00000019;
+ const uint32 FSRVP_CTX_APP_ROLLBACK = 0x00000009;
+ DWORD fss_SetContext(
+ [in] uint32 Context);
+
+ DWORD fss_StartShadowCopySet(
+ [in] GUID ClientShadowCopySetId,
+ [out] GUID *pShadowCopySetId);
+
+ DWORD fss_AddToShadowCopySet(
+ [in] GUID ClientShadowCopyId,
+ [in] GUID ShadowCopySetId,
+ [in] [string,charset(UTF16)] uint16 *ShareName,
+ [out] GUID *pShadowCopyId);
+
+ DWORD fss_CommitShadowCopySet(
+ [in] GUID ShadowCopySetId,
+ [in] uint32 TimeOutInMilliseconds);
+
+ DWORD fss_ExposeShadowCopySet(
+ [in] GUID ShadowCopySetId,
+ [in] uint32 TimeOutInMilliseconds);
+
+ DWORD fss_RecoveryCompleteShadowCopySet(
+ [in] GUID ShadowCopySetId);
+
+ DWORD fss_AbortShadowCopySet(
+ [in] GUID ShadowCopySetId);
+
+ DWORD fss_IsPathSupported(
+ [in] [string,charset(UTF16)] uint16 *ShareName,
+ [out] boolean32 *SupportedByThisProvider,
+ [out] [string,charset(UTF16)] uint16 **OwnerMachineName);
+
+ DWORD fss_IsPathShadowCopied(
+ [in] [string,charset(UTF16)] uint16 *ShareName,
+ [out] boolean32 *ShadowCopyPresent,
+ [out] int32 *ShadowCopyCompatibility);
+
+ DWORD fss_GetShareMapping(
+ [in] GUID ShadowCopyId,
+ [in] GUID ShadowCopySetId,
+ [in] [string,charset(UTF16)] uint16 *ShareName,
+ [in] uint32 Level,
+ [out,switch_is(Level)] fssagent_share_mapping *ShareMapping);
+
+ DWORD fss_DeleteShareMapping(
+ [in] GUID ShadowCopySetId,
+ [in] GUID ShadowCopyId,
+ [in] [string,charset(UTF16)] uint16 *ShareName);
+
+ DWORD fss_PrepareShadowCopySet(
+ [in] GUID ShadowCopySetId,
+ [in] uint32 TimeOutInMilliseconds);
+}
diff --git a/librpc/idl/fsrvp_state.idl b/librpc/idl/fsrvp_state.idl
new file mode 100644
index 0000000..9fcec12
--- /dev/null
+++ b/librpc/idl/fsrvp_state.idl
@@ -0,0 +1,36 @@
+#include "idl_types.h"
+[
+ pointer_default(unique)
+]
+interface fsrvp_state
+{
+ /* database format version, NOT the FSRVP protocol version */
+ const uint32 FSRVP_STATE_DB_VERSION = 1;
+
+ /*
+ * These data structures describe the FSRVP server on-disk format. Any
+ * changes should result in a new DB version number, and corresponding
+ * upgrade function.
+ */
+ typedef [public] struct {
+ [flag(STR_UTF8|STR_NULLTERM)] string share_name;
+ [flag(STR_UTF8|STR_NULLTERM)] string sc_share_name;
+ [flag(STR_UTF8|STR_NULLTERM)] string sc_share_comment;
+ boolean32 is_exposed;
+ } fsrvp_state_smap;
+
+ typedef [public] struct {
+ [flag(STR_UTF8|STR_NULLTERM)] string id_str;
+ [flag(STR_UTF8|STR_NULLTERM)] string volume_name;
+ [flag(STR_UTF8|STR_NULLTERM)] string sc_path;
+ time_t create_ts;
+ int smaps_count;
+ } fsrvp_state_sc;
+
+ typedef [public] struct {
+ [flag(STR_UTF8|STR_NULLTERM)] string id_str;
+ int state;
+ int context;
+ int scs_count;
+ } fsrvp_state_sc_set;
+}
diff --git a/librpc/idl/gkdi.idl b/librpc/idl/gkdi.idl
new file mode 100644
index 0000000..233a7a0
--- /dev/null
+++ b/librpc/idl/gkdi.idl
@@ -0,0 +1,125 @@
+/*
+ * Type definitions for Group Key Distribution Service
+ *
+ * The below was initially obtained from MS-GKDI which is copyright © 2021
+ * Microsoft Corporation as permitted by the Open Specifications terms
+ * reproduced in IDL_LICENCE.txt.
+ *
+ * Only GetKey() was provided as IDL. The definitions of GroupKeyEnvelope,
+ * KdfParameters, and FfcDhParameters were derived from structure diagrams.
+ * KeyEnvelope was undocumented.
+ */
+
+#include "idl_types.h"
+
+import "misc.idl";
+
+[
+ uuid("b9785960-524f-11df-8b6d-83dcded72085"),
+ endpoint("ncacn_np:[\\pipe\\lsass]", "ncacn_ip_tcp:", "ncalrpc:"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Active Directory Group Key Distribution Service")
+]
+interface gkdi
+{
+ /* Public structures. */
+
+ typedef [bitmap32bit] bitmap {
+ ENVELOPE_FLAG_TRANSPORTING_PUBLIC_KEY = 0x00000001,
+ ENVELOPE_FLAG_KEY_MAY_ENCRYPT_NEW_DATA = 0x00000002
+ } EnvelopeFlags;
+
+ /*
+ * This is an undocumented type. It is similar to GroupKeyEnvelope, but
+ * with some fields omitted.
+ */
+ typedef [public] struct {
+ uint32 version;
+ [value(0x4b53444b), range(0x4b53444b, 0x4b53444b)] uint32 magic; /* ‘KDSK’ */
+ EnvelopeFlags flags;
+ uint32 l0_index;
+ [range(0, 31)] uint32 l1_index;
+ [range(0, 31)] uint32 l2_index;
+ GUID root_key_id;
+ uint32 additional_info_len;
+ [value(2 * ndr_charset_length(domain_name, CH_UTF16))] uint32 domain_name_len;
+ [value(2 * ndr_charset_length(forest_name, CH_UTF16))] uint32 forest_name_len;
+ /*
+ * https://lists.samba.org/archive/cifs-protocol/2023-December/004170.html
+ * This is the public key blob of an ephemeral public key used in secret
+ * agreement, or a random number used in deriving a symmetric key.
+ */
+ [flag(NDR_SECRET)] uint8 additional_info[additional_info_len];
+ nstring domain_name; /* DNS name of the domain which generated the key. */
+ nstring forest_name; /* DNS name of the forest which generated the key. */
+ } KeyEnvelope;
+
+ typedef [public] struct {
+ uint32 version; /* The version (msKds-Version) of the root key ADM element. */
+ [value(0x4b53444b), range(0x4b53444b, 0x4b53444b)] uint32 magic; /* ‘KDSK’ */
+ EnvelopeFlags flags;
+ uint32 l0_index;
+ [range(0, 31)] uint32 l1_index;
+ [range(0, 31)] uint32 l2_index;
+ GUID root_key_id;
+ [value(2 * ndr_charset_length(kdf_algorithm, CH_UTF16))] uint32 kdf_algorithm_len;
+ uint32 kdf_parameters_len;
+ [value(2 * ndr_charset_length(secret_agreement_algorithm, CH_UTF16))] uint32 secret_agreement_algorithm_len;
+ uint32 secret_agreement_parameters_len;
+ uint32 private_key_len;
+ uint32 public_key_len;
+ uint32 l1_key_len;
+ uint32 l2_key_len;
+ [value(2 * ndr_charset_length(domain_name, CH_UTF16))] uint32 domain_name_len;
+ [value(2 * ndr_charset_length(forest_name, CH_UTF16))] uint32 forest_name_len;
+ nstring kdf_algorithm;
+ uint8 kdf_parameters[kdf_parameters_len];
+ nstring secret_agreement_algorithm;
+ uint8 secret_agreement_parameters[secret_agreement_parameters_len];
+ nstring domain_name; /* DNS name of the domain which generated the key. */
+ nstring forest_name; /* DNS name of the forest which generated the key. */
+ [flag(NDR_SECRET)] uint8 l1_key[l1_key_len];
+ [flag(NDR_SECRET)] uint8 l2_key[l2_key_len];
+ } GroupKeyEnvelope;
+
+ typedef [public] struct {
+ [value(0)] uint32 padding_0;
+ [value(1)] uint32 padding_1;
+ [value(2 * ndr_charset_length(hash_algorithm, CH_UTF16))] uint32 hash_algorithm_len;
+ [value(0)] uint32 padding_2;
+ nstring hash_algorithm;
+ } KdfParameters;
+
+ typedef [public] struct {
+ /*
+ * Twelve bytes account for the length, magic number, and key
+ * length; the remaining bytes cover the two arrays of
+ * ‘key_length’ bytes each.
+ */
+ [value(12 + 2 * key_length)] uint32 length;
+ [value(0x4d504844), range(0x4d504844, 0x4d504844)] uint32 magic; /* ‘DHPM’ */
+ uint32 key_length;
+ uint8 field_order[key_length];
+ uint8 generator[key_length];
+ } FfcDhParameters;
+
+ typedef [public] struct {
+ GUID guid;
+ int32 l0_idx;
+ int32 l1_idx;
+ int32 l2_idx;
+ [flag(NDR_REMAINING)] DATA_BLOB target_security_descriptor;
+ } GkdiDerivationCtx;
+
+ HRESULT gkdi_GetKey(
+ [in] uint32 target_sd_len,
+ [in] [size_is(target_sd_len)] [ref] char *target_sd,
+ [in] [unique] GUID* root_key_id,
+ [in] int32 l0_key_id,
+ [in] int32 l1_key_id,
+ [in] int32 l2_key_id,
+ [out] uint32 *out_len,
+ [out] [size_is(,*out_len)] uint8** out
+ );
+}
diff --git a/librpc/idl/gmsa.idl b/librpc/idl/gmsa.idl
new file mode 100644
index 0000000..bad9030
--- /dev/null
+++ b/librpc/idl/gmsa.idl
@@ -0,0 +1,44 @@
+/*
+ * Type definitions for Group Managed Service Accounts
+ *
+ * Derived from [MS-ADTS] 2.2.19 MSDS-MANAGEDPASSWORD_BLOB.
+ */
+
+#include "idl_types.h"
+
+[
+ uuid("e43b8cf6-1ead-11ee-aed1-e3597136ce70"),
+ version(0.0),
+ pointer_default(unique),
+ helpstring("Active Directory Group Managed Service Accounts")
+]
+interface gmsa
+{
+ /* Public structures. */
+
+ typedef [gensize] struct {
+ [relative_short] secret_u16string *current;
+ [relative_short] secret_u16string *previous;
+ /*
+ * MS-ADTS states that these fields must be placed on a 64‐bit
+ * boundary, but samples obtained from Windows are found not to
+ * be so. In practice, they’re offset by two bytes. That’s why
+ * we need NOALIGN.
+ */
+ [relative_short, flag(NDR_NOALIGN)] hyper *query_interval;
+ [relative_short, flag(NDR_NOALIGN)] hyper *unchanged_interval;
+ } MANAGEDPASSWORD_BLOB_PASSWORDS;
+
+ typedef [public] struct {
+ [value(1)] uint16 version;
+ [value(0)] uint16 reserved;
+ /*
+ * The size of the entire blob. 8 bytes account for the
+ * ‘version’ field, the ‘reserved’ field, and the ‘length’ field
+ * itself.
+ */
+ [value(8 + ndr_size_MANAGEDPASSWORD_BLOB_PASSWORDS(&passwords,
+ ndr->flags))] uint32 length;
+ MANAGEDPASSWORD_BLOB_PASSWORDS passwords;
+ } MANAGEDPASSWORD_BLOB;
+}
diff --git a/librpc/idl/idl_types.h b/librpc/idl/idl_types.h
new file mode 100644
index 0000000..4f0e69b
--- /dev/null
+++ b/librpc/idl/idl_types.h
@@ -0,0 +1,70 @@
+#define STR_ASCII LIBNDR_FLAG_STR_ASCII
+#define STR_LEN4 LIBNDR_FLAG_STR_LEN4
+#define STR_SIZE4 LIBNDR_FLAG_STR_SIZE4
+#define STR_SIZE2 LIBNDR_FLAG_STR_SIZE2
+#define STR_NOTERM LIBNDR_FLAG_STR_NOTERM
+#define STR_NULLTERM LIBNDR_FLAG_STR_NULLTERM
+#define STR_BYTESIZE LIBNDR_FLAG_STR_BYTESIZE
+#define STR_NO_EMBEDDED_NUL LIBNDR_FLAG_STR_NO_EMBEDDED_NUL
+#define STR_CONFORMANT LIBNDR_FLAG_STR_CONFORMANT
+#define STR_CHARLEN LIBNDR_FLAG_STR_CHARLEN
+#define STR_UTF8 LIBNDR_FLAG_STR_UTF8
+#define STR_RAW8 LIBNDR_FLAG_STR_RAW8
+
+/*
+ a null terminated UCS2 string
+*/
+#define nstring [flag(STR_NULLTERM|NDR_ALIGN2)] string
+
+/*
+ a null terminated ascii string
+*/
+#define astring [flag(STR_ASCII|STR_NULLTERM)] string
+
+/*
+ a null terminated UTF8 string
+*/
+#define utf8string [flag(STR_UTF8|STR_NULLTERM)] string
+
+/*
+ a null terminated "raw" string (null terminated byte sequence)
+*/
+#define raw8string [flag(STR_RAW8|STR_NULLTERM)] string
+
+/*
+ a secret null terminated UTF‐16 string (null terminated word sequence)
+*/
+#define secret_u16string [flag(NDR_SECRET|STR_NULLTERM)] u16string
+
+/*
+ a null terminated UCS2 string
+*/
+#define nstring_array [flag(STR_NULLTERM|NDR_ALIGN2)] string_array
+
+#define NDR_NOALIGN LIBNDR_FLAG_NOALIGN
+#define NDR_REMAINING LIBNDR_FLAG_REMAINING
+#define NDR_ALIGN2 LIBNDR_FLAG_ALIGN2
+#define NDR_ALIGN4 LIBNDR_FLAG_ALIGN4
+#define NDR_ALIGN8 LIBNDR_FLAG_ALIGN8
+#define NDR_NO_COMP LIBNDR_FLAG_NO_COMPRESSION
+
+/* this flag is used to force a section of IDL as little endian. It is
+ needed for the epmapper IDL, which is defined as always being LE */
+#define NDR_LITTLE_ENDIAN LIBNDR_FLAG_LITTLE_ENDIAN
+#define NDR_BIG_ENDIAN LIBNDR_FLAG_BIGENDIAN
+
+/*
+ this is used to control formatting of uint8 arrays
+*/
+#define NDR_PAHEX LIBNDR_PRINT_ARRAY_HEX
+
+/*
+ * Mark an element as SECRET, it won't be printed by
+ * via ndr_print* unless NDR_PRINT_SECRETS is specified.
+ */
+#define NDR_SECRET LIBNDR_FLAG_IS_SECRET
+
+#define NDR_RELATIVE_REVERSE LIBNDR_FLAG_RELATIVE_REVERSE
+#define NDR_NO_RELATIVE_REVERSE LIBNDR_FLAG_NO_RELATIVE_REVERSE
+
+#define NDR_SUBCONTEXT_NO_UNREAD_BYTES LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES
diff --git a/librpc/idl/idmap.idl b/librpc/idl/idmap.idl
new file mode 100644
index 0000000..e58e392
--- /dev/null
+++ b/librpc/idl/idmap.idl
@@ -0,0 +1,53 @@
+#include "idl_types.h"
+
+import "security.idl";
+
+[
+ pointer_default(unique)
+]
+interface idmap
+{
+ typedef [public] enum {
+ ID_TYPE_NOT_SPECIFIED,
+ ID_TYPE_UID,
+ ID_TYPE_GID,
+ ID_TYPE_BOTH,
+ /*
+ * This are internal between winbindd
+ * parent and child.
+ *
+ * It means the idmap backend/child requires a valid type_hint
+ * for wbint_Sids2UnixIDs():
+ *
+ * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists
+ * - ID_TYPE_BOTH means that only the domain exist
+ */
+ ID_TYPE_WB_REQUIRE_TYPE
+ } id_type;
+
+ typedef [public] struct {
+ uint32 id;
+ id_type type;
+ } unixid;
+
+ typedef [public] enum {
+ ID_UNKNOWN,
+ ID_MAPPED,
+ ID_UNMAPPED,
+ ID_EXPIRED,
+ /*
+ * This means the idmap backend requires a valid type_hint
+ * in order to map a sid to a unix id.
+ *
+ * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists
+ * - ID_TYPE_BOTH means that only the domain exist
+ */
+ ID_REQUIRE_TYPE
+ } id_mapping;
+
+ typedef [public] struct {
+ dom_sid *sid;
+ unixid xid;
+ id_mapping status;
+ } id_map;
+}
diff --git a/librpc/idl/initshutdown.idl b/librpc/idl/initshutdown.idl
new file mode 100644
index 0000000..63cf62b
--- /dev/null
+++ b/librpc/idl/initshutdown.idl
@@ -0,0 +1,91 @@
+#include "idl_types.h"
+
+/*
+ initshutdown interface definition
+*/
+
+import "lsa.idl";
+
+[
+ uuid("894de0c0-0d55-11d3-a322-00c04fa321a1"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\InitShutdown]"),
+ pointer_default(unique),
+ helpstring("Init shutdown service")
+] interface initshutdown
+{
+ typedef [v1_enum] enum {
+ SHTDN_REASON_MAJOR_OTHER = 0x00000000,
+ SHTDN_REASON_MAJOR_HARDWARE = 0x00010000,
+ SHTDN_REASON_MAJOR_OPERATINGSYSTEM = 0x00020000,
+ SHTDN_REASON_MAJOR_SOFTWARE = 0x00030000,
+ SHTDN_REASON_MAJOR_APPLICATION = 0x00040000,
+ SHTDN_REASON_MAJOR_SYSTEM = 0x00050000,
+ SHTDN_REASON_MAJOR_POWER = 0x00060000,
+ SHTDN_REASON_MAJOR_LEGACY_API = 0x00070000
+ } initshutdown_ReasonMajor;
+
+ typedef [v1_enum] enum {
+ SHTDN_REASON_MINOR_OTHER = 0x00000000,
+ SHTDN_REASON_MINOR_MAINTENANCE = 0x00000001,
+ SHTDN_REASON_MINOR_INSTALLATION = 0x00000002,
+ SHTDN_REASON_MINOR_UPGRADE = 0x00000003,
+ SHTDN_REASON_MINOR_RECONFIG = 0x00000004,
+ SHTDN_REASON_MINOR_HUNG = 0x00000005,
+ SHTDN_REASON_MINOR_UNSTABLE = 0x00000006,
+ SHTDN_REASON_MINOR_DISK = 0x00000007,
+ SHTDN_REASON_MINOR_PROCESSOR = 0x00000008,
+ SHTDN_REASON_MINOR_NETWORKCARD = 0x00000009,
+ SHTDN_REASON_MINOR_POWER_SUPPLY = 0x0000000a,
+ SHTDN_REASON_MINOR_CORDUNPLUGGED = 0x0000000b,
+ SHTDN_REASON_MINOR_ENVIRONMENT = 0x0000000c,
+ SHTDN_REASON_MINOR_HARDWARE_DRIVER = 0x0000000d,
+ SHTDN_REASON_MINOR_OTHERDRIVER = 0x0000000e,
+ SHTDN_REASON_MINOR_BLUESCREEN = 0x0000000f,
+ SHTDN_REASON_MINOR_SERVICEPACK = 0x00000010,
+ SHTDN_REASON_MINOR_HOTFIX = 0x00000011,
+ SHTDN_REASON_MINOR_SECURITYFIX = 0x00000012,
+ SHTDN_REASON_MINOR_SECURITY = 0x00000013,
+ SHTDN_REASON_MINOR_NETWORK_CONNECTIVITY = 0x00000014,
+ SHTDN_REASON_MINOR_WMI = 0x00000015,
+ SHTDN_REASON_MINOR_SERVICEPACK_UNINSTALL= 0x00000016,
+ SHTDN_REASON_MINOR_HOTFIX_UNINSTALL = 0x00000017,
+ SHTDN_REASON_MINOR_SECURITYFIX_UNINSTALL= 0x00000018,
+ SHTDN_REASON_MINOR_MMC = 0x00000019,
+ SHTDN_REASON_MINOR_TERMSRV = 0x00000020
+ } initshutdown_ReasonMinor;
+
+ typedef [bitmap32bit] bitmap {
+ SHTDN_REASON_FLAG_USER_DEFINED = 0x40000000,
+ SHTDN_REASON_FLAG_PLANNED = 0x80000000
+ } initshutdown_ReasonFlags;
+
+ WERROR initshutdown_Init(
+ [in,unique] uint16 *hostname,
+ /*
+ * Note: lsa_String and winreg_String both result
+ * in WERR_INVALID_PARAMETER
+ */
+ [in,unique] lsa_StringLarge *message,
+ [in] uint32 timeout,
+ [in] uint8 force_apps,
+ [in] uint8 do_reboot
+ );
+
+ WERROR initshutdown_Abort(
+ [in,unique] uint16 *server
+ );
+
+ WERROR initshutdown_InitEx(
+ [in,unique] uint16 *hostname,
+ /*
+ * Note: lsa_String and winreg_String both result
+ * in WERR_INVALID_PARAMETER
+ */
+ [in,unique] lsa_StringLarge *message,
+ [in] uint32 timeout,
+ [in] uint8 force_apps,
+ [in] uint8 do_reboot,
+ [in] uint32 reason
+ );
+}
diff --git a/librpc/idl/ioctl.idl b/librpc/idl/ioctl.idl
new file mode 100644
index 0000000..7b8b1b8
--- /dev/null
+++ b/librpc/idl/ioctl.idl
@@ -0,0 +1,242 @@
+#include "idl_types.h"
+[
+ pointer_default(unique)
+]
+interface copychunk
+{
+ typedef [public] struct {
+ uint8 resume_key[24];
+ uint32 context_len;
+ /* <56> Windows sends 4 bytes of zero for the context field. */
+ uint8 context[4];
+ } req_resume_key_rsp;
+
+ const uint32 COPYCHUNK_MAX_CHUNKS = 256; /* 2k8r2 & win8 = 256 */
+ const uint32 COPYCHUNK_MAX_CHUNK_LEN = 1048576; /* 2k8r2 & win8 = 1048576 */
+ const uint32 COPYCHUNK_MAX_TOTAL_LEN = 16777216; /* 2k8r2 & win8 = 16777216 */
+
+ typedef struct {
+ hyper source_off;
+ hyper target_off;
+ uint32 length;
+ uint32 reserved;
+ } srv_copychunk;
+
+ typedef [public] struct {
+ uint8 source_key[24];
+ uint32 chunk_count;
+ uint32 reserved;
+ srv_copychunk chunks[chunk_count];
+ } srv_copychunk_copy;
+
+ typedef [public] struct {
+ uint32 chunks_written;
+ uint32 chunk_bytes_written;
+ uint32 total_bytes_written;
+ } srv_copychunk_rsp;
+
+ typedef [public] struct {
+ uint32 version;
+ uint32 size;
+ uint32 maximum_token_lifetime;
+ uint32 default_token_lifetime;
+ hyper maximum_xfer_size;
+ hyper optimal_xfer_count;
+ uint32 maximum_data_descriptors;
+ uint32 maximum_xfer_length_per_descriptor;
+ uint32 optimal_xfer_length_per_descriptor;
+ uint16 optimal_xfer_length_granularity;
+ uint8 reserved[2];
+ } device_copy_offload_descriptor;
+
+ const uint32 STORAGE_OFFLOAD_TOKEN_TYPE_ZERO_DATA = 0xffff0001;
+
+ typedef [public] struct {
+ uint32 token_type;
+ uint8 reserved[2];
+ uint16 token_id_len;
+ uint8 token[token_id_len];
+ } storage_offload_token;
+
+ typedef [public] struct {
+ uint32 size;
+ uint32 flags;
+ uint32 token_time_to_live;
+ uint32 reserved;
+ hyper file_offset;
+ hyper length;
+ } fsctl_offload_read_input;
+
+ typedef [public,bitmap32bit] bitmap {
+ OFFLOAD_READ_FLAG_FILE_TOO_SMALL = 0x01,
+ OFFLOAD_READ_FLAG_ALL_ZERO_BEYOND_RANGE = 0x02,
+ OFFLOAD_READ_FLAG_CANNOT_OFFLOAD_BEYOND_RANGE = 0x04
+ } offload_flags;
+
+ typedef [public] struct {
+ uint32 size;
+ offload_flags flags;
+ hyper xfer_length;
+ storage_offload_token token;
+ } fsctl_offload_read_output;
+
+ typedef [public] struct {
+ uint32 size;
+ offload_flags flags;
+ hyper file_offset;
+ hyper copy_length;
+ hyper xfer_offset;
+ storage_offload_token token;
+ } fsctl_offload_write_input;
+
+ typedef [public] struct {
+ uint32 size;
+ uint32 flags;
+ hyper length_written;
+ } fsctl_offload_write_output;
+
+ typedef [public] struct {
+ uint8 source_fid[16];
+ hyper source_off;
+ hyper target_off;
+ hyper byte_count;
+ } fsctl_dup_extents_to_file;
+}
+
+interface compression
+{
+ const uint16 COMPRESSION_FORMAT_NONE = 0x0000;
+ const uint16 COMPRESSION_FORMAT_DEFAULT = 0x0001;
+ const uint16 COMPRESSION_FORMAT_LZNT1 = 0x0002;
+
+ typedef [public] struct {
+ uint16 format;
+ } compression_state;
+}
+
+interface netinterface
+{
+ typedef [bitmap32bit] bitmap {
+ FSCTL_NET_IFACE_NONE_CAPABLE = 0x00000000,
+ FSCTL_NET_IFACE_RSS_CAPABLE = 0x00000001,
+ FSCTL_NET_IFACE_RDMA_CAPABLE = 0x00000002
+ } fsctl_net_iface_capability;
+
+ typedef [enum16bit] enum {
+ FSCTL_NET_IFACE_AF_INET = 0x0002,
+ FSCTL_NET_IFACE_AF_INET6 = 0x0017
+ } fsctl_sockaddr_af;
+
+ typedef [flag(NDR_NOALIGN)] struct {
+ [value(0)] uint16 port;
+ [flag(NDR_BIG_ENDIAN)] ipv4address ipv4;
+ [value(0)] hyper reserved;
+ } fsctl_sockaddr_in;
+
+ typedef [flag(NDR_NOALIGN)] struct {
+ [value(0)] uint16 port;
+ [value(0)] uint32 flowinfo;
+ [flag(NDR_BIG_ENDIAN)] ipv6address ipv6;
+ [value(0)] uint32 scopeid;
+ } fsctl_sockaddr_in6;
+
+ typedef [nodiscriminant,flag(NDR_NOALIGN)] union {
+ [case (FSCTL_NET_IFACE_AF_INET)] fsctl_sockaddr_in saddr_in;
+ [case (FSCTL_NET_IFACE_AF_INET6)] fsctl_sockaddr_in6 saddr_in6;
+ } fsctl_sockaddr_union;
+
+ typedef [flag(NDR_NOALIGN)] struct {
+ fsctl_sockaddr_af family;
+ [subcontext(0),subcontext_size(126),switch_is(family)] fsctl_sockaddr_union saddr;
+ } fsctl_sockaddr_storage;
+
+ typedef [public,relative_base,noprint] struct {
+ [relative,max_recursion(20000)] fsctl_net_iface_info *next;
+ uint32 ifindex;
+ fsctl_net_iface_capability capability;
+ [value(0)] uint32 reserved;
+ hyper linkspeed;
+ fsctl_sockaddr_storage sockaddr;
+ } fsctl_net_iface_info;
+}
+
+interface sparse
+{
+ /* MS-FSCC 2.3.33 FSCTL_QUERY_ALLOCATED_RANGES Request */
+ typedef [public] struct {
+ hyper file_off;
+ hyper len;
+ } file_alloced_range_buf;
+
+ typedef [public] struct {
+ file_alloced_range_buf buf;
+ } fsctl_query_alloced_ranges_req;
+
+ /*
+ * 2.3.34 FSCTL_QUERY_ALLOCATED_RANGES Reply
+ * ...
+ * The number of FILE_ALLOCATED_RANGE_BUFFER elements returned is
+ * computed by dividing the size of the returned output buffer (from
+ * either SMB or SMB2, the lower-layer protocol that carries the FSCTL)
+ * by the size of the FILE_ALLOCATED_RANGE_BUFFER element.
+ *
+ * This logic can't (currently) be represented in pidl, so just use a
+ * blob. Perhaps in future we'll support:
+ * [flag(NDR_REMAINING)] file_alloced_range_buf array[];
+ */
+ typedef [public] struct {
+ [flag(NDR_REMAINING)] DATA_BLOB far_buf_array;
+ } fsctl_query_alloced_ranges_rsp;
+
+ /* 2.3.65 FSCTL_SET_ZERO_DATA Request */
+ typedef [public] struct {
+ hyper file_off;
+ hyper beyond_final_zero;
+ } file_zero_data_info;
+
+ typedef [public] struct {
+ file_zero_data_info info;
+ } fsctl_set_zero_data_req;
+}
+
+interface resiliency
+{
+ /* 2.2.31.3 NETWORK_RESILIENCY_REQUEST */
+ typedef [public] struct {
+ uint32 timeout;
+ uint32 reserved;
+ } network_resiliency_request;
+}
+
+interface trim
+{
+ /* MS-FSCC 2.3.73.1 FILE_LEVEL_TRIM_RANGE */
+ typedef [public] struct {
+ hyper off;
+ hyper len;
+ } file_level_trim_range;
+
+ /* MS-FSCC 2.3.73 FSCTL_FILE_LEVEL_TRIM Request */
+ typedef [public] struct {
+ uint32 key;
+ uint32 num_ranges;
+ file_level_trim_range ranges[num_ranges];
+ } fsctl_file_level_trim_req;
+
+ /* MS-FSCC 2.3.74 FSCTL_FILE_LEVEL_TRIM Reply */
+ typedef [public] struct {
+ uint32 num_ranges_processed;
+ } fsctl_file_level_trim_rsp;
+}
+
+interface fsctl
+{
+ /* MS-FSCC 2.3.31 FSCTL_PIPE_WAIT */
+ typedef [public] struct {
+ hyper timeout;
+ [value(2*strlen_m(pipe_name))] uint32 pipe_name_len;
+ uint8 timeout_specified;
+ uint8 padding;
+ [charset(UTF16)] uint8 pipe_name[pipe_name_len];
+ } fsctl_pipe_wait;
+}
diff --git a/librpc/idl/keysvc.idl b/librpc/idl/keysvc.idl
new file mode 100644
index 0000000..9d05f7d
--- /dev/null
+++ b/librpc/idl/keysvc.idl
@@ -0,0 +1,16 @@
+/*
+ cryptographic key services interface
+*/
+
+
+/* Also seen as: 0d72a7d4-6148-11d1-b4aa-00c04fb66ea0 */
+[
+ uuid("8d0ffe72-d252-11d0-bf8f-00c04fd9126b"),
+ pointer_default(unique),
+ version(1.0),
+ helpstring("Cryptographic Key Services")
+]
+interface keysvc
+{
+ WERROR keysvc_Unknown0();
+}
diff --git a/librpc/idl/krb5ccache.idl b/librpc/idl/krb5ccache.idl
new file mode 100644
index 0000000..1f0cfa7
--- /dev/null
+++ b/librpc/idl/krb5ccache.idl
@@ -0,0 +1,115 @@
+/*
+ krb5 credentials cache (version 3 or 4)
+ specification: https://web.mit.edu/kerberos/krb5-devel/doc/formats/ccache_file_format.html
+*/
+
+#include "idl_types.h"
+
+[
+ uuid("1702b695-99ca-4f32-93e4-1e1c4d5ddb53"),
+ version(0.0),
+ pointer_default(unique),
+ helpstring("KRB5 credentials cache")
+]
+interface krb5ccache
+{
+ typedef struct {
+ uint32 name_type;
+ uint32 component_count;
+ [flag(STR_SIZE4|STR_NOTERM|STR_UTF8)] string realm;
+ [flag(STR_SIZE4|STR_NOTERM|STR_UTF8)] string components[component_count];
+ } PRINCIPAL;
+
+ typedef struct {
+ uint16 enctype;
+ DATA_BLOB data;
+ } KEYBLOCK;
+
+ typedef struct {
+ uint16 addrtype;
+ DATA_BLOB data;
+ } ADDRESS;
+
+ typedef struct {
+ uint32 count;
+ ADDRESS data[count];
+ } ADDRESSES;
+
+ typedef struct {
+ uint16 ad_type;
+ DATA_BLOB data;
+ } AUTHDATUM;
+
+ typedef struct {
+ uint32 count;
+ AUTHDATUM data[count];
+ } AUTHDATA;
+
+ typedef struct {
+ PRINCIPAL client;
+ PRINCIPAL server;
+ KEYBLOCK keyblock;
+ uint32 authtime;
+ uint32 starttime;
+ uint32 endtime;
+ uint32 renew_till;
+ uint8 is_skey;
+ uint32 ticket_flags;
+ ADDRESSES addresses;
+ AUTHDATA authdata;
+ DATA_BLOB ticket;
+ DATA_BLOB second_ticket;
+ } CREDENTIAL;
+
+ typedef struct {
+ [value(0)] int32 kdc_sec_offset;
+ [value(0)] int32 kdc_usec_offset;
+ } DELTATIME_TAG;
+
+ typedef [nodiscriminant] union {
+ [case(1)] DELTATIME_TAG deltatime_tag;
+ } FIELD;
+
+ typedef struct {
+ [value(1)] uint16 tag;
+ [subcontext(2),switch_is(tag)] FIELD field;
+ } V4TAG;
+
+ typedef struct {
+ V4TAG tag;
+ /*
+ * We should allow for more than one tag to be properly parsed, but that
+ * would require manual parsing.
+ */
+ [flag(NDR_REMAINING)] DATA_BLOB further_tags;
+ } V4TAGS;
+
+ typedef struct {
+ [subcontext(2)] V4TAGS v4tags;
+ } V4HEADER;
+
+ typedef [nodiscriminant] union {
+ /*
+ * We don't attempt to support file format versions 1 and 2 as they
+ * assume native CPU byte order, which makes no sense in PIDL.
+ */
+ [case(3)] ;
+ [case(4)] V4HEADER v4header;
+ } OPTIONAL_HEADER;
+
+ /* Public structures. */
+
+ typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ [value(5)] uint8 pvno;
+ [value(4)] uint8 version;
+ [switch_is(version)] OPTIONAL_HEADER optional_header;
+ PRINCIPAL principal;
+ CREDENTIAL cred;
+ [flag(NDR_REMAINING)] DATA_BLOB further_creds;
+ } CCACHE;
+
+ typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ CREDENTIAL cred;
+ [flag(NDR_REMAINING)] DATA_BLOB further_creds;
+ } MULTIPLE_CREDENTIALS;
+}
diff --git a/librpc/idl/krb5pac.idl b/librpc/idl/krb5pac.idl
new file mode 100644
index 0000000..77189bb
--- /dev/null
+++ b/librpc/idl/krb5pac.idl
@@ -0,0 +1,264 @@
+/*
+ krb5 PAC
+
+ Portions obtained from MS-KILE which is Copyright © 2021 Microsoft
+ Corporation as permitted by the Open Specifications terms
+ reproduced in IDL_LICENCE.txt
+
+*/
+
+#include "idl_types.h"
+
+import "security.idl", "lsa.idl", "netlogon.idl", "samr.idl";
+
+[
+ uuid("12345778-1234-abcd-0000-00000000"),
+ version(0.0),
+ pointer_default(unique),
+ helpstring("Active Directory KRB5 PAC"),
+ helper("../librpc/ndr/ndr_krb5pac.h")
+]
+interface krb5pac
+{
+ typedef struct {
+ NTTIME logon_time;
+ [value(2*strlen_m(account_name))] uint16 size;
+ [charset(UTF16)] uint8 account_name[size];
+ } PAC_LOGON_NAME;
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint32 type;
+ [flag(NDR_REMAINING)] DATA_BLOB signature;
+ } PAC_SIGNATURE_DATA;
+
+ typedef struct {
+ dom_sid2 *domain_sid;
+ samr_RidWithAttributeArray groups;
+ } PAC_DOMAIN_GROUP_MEMBERSHIP;
+
+ typedef struct {
+ netr_SamInfo3 info3;
+ /*
+ * On ndr_push:
+ * Pointers values of info3.sids[*].sid
+ * should be allocated before the following ones?
+ * (just the 0x30 0x00 0x02 0x00 value).
+ */
+ PAC_DOMAIN_GROUP_MEMBERSHIP resource_groups;
+ } PAC_LOGON_INFO;
+
+ typedef [bitmap32bit] bitmap {
+ PAC_CREDENTIAL_NTLM_HAS_LM_HASH = 0x00000001,
+ PAC_CREDENTIAL_NTLM_HAS_NT_HASH = 0x00000002
+ } PAC_CREDENTIAL_NTLM_FLAGS;
+
+ typedef [public] struct {
+ [value(0)] uint32 version;
+ PAC_CREDENTIAL_NTLM_FLAGS flags;
+ [noprint] samr_Password lm_password;
+ [noprint] samr_Password nt_password;
+ } PAC_CREDENTIAL_NTLM_SECPKG;
+
+ typedef [public] struct {
+ lsa_String package_name;
+ uint32 credential_size;
+ [size_is(credential_size), noprint] uint8 *credential;
+ } PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG;
+
+ typedef [public] struct {
+ uint32 credential_count;
+ [size_is(credential_count)] PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG credentials[*];
+ } PAC_CREDENTIAL_DATA;
+
+ typedef [public] struct {
+ PAC_CREDENTIAL_DATA *data;
+ } PAC_CREDENTIAL_DATA_CTR;
+
+ typedef [public] struct {
+ [subcontext(0xFFFFFC01)] PAC_CREDENTIAL_DATA_CTR ctr;
+ } PAC_CREDENTIAL_DATA_NDR;
+
+ typedef [public] struct {
+ [value(0)] uint32 version;
+ uint32 encryption_type;
+ [flag(NDR_REMAINING)] DATA_BLOB encrypted_data;
+ } PAC_CREDENTIAL_INFO;
+
+ typedef struct {
+ lsa_String proxy_target;
+ uint32 num_transited_services;
+ [size_is(num_transited_services)] lsa_String *transited_services;
+ } PAC_CONSTRAINED_DELEGATION;
+
+ typedef [bitmap32bit] bitmap {
+ PAC_UPN_DNS_FLAG_CONSTRUCTED = 0x00000001,
+ PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID = 0x00000002
+ } PAC_UPN_DNS_FLAGS;
+
+ typedef struct {
+ [value(2*strlen_m(samaccountname))] uint16 samaccountname_size;
+ [relative_short,subcontext(0),subcontext_size(samaccountname_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *samaccountname;
+ [value(ndr_size_dom_sid(objectsid, ndr->flags))] uint16 objectsid_size;
+ [relative_short,subcontext(0),subcontext_size(objectsid_size)] dom_sid *objectsid;
+ } PAC_UPN_DNS_INFO_SAM_NAME_AND_SID;
+
+ typedef [nodiscriminant] union {
+ [case(PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_SAM_NAME_AND_SID sam_name_and_sid;
+ [default];
+ } PAC_UPN_DNS_INFO_EX;
+
+ typedef struct {
+ [value(2*strlen_m(upn_name))] uint16 upn_name_size;
+ [relative_short,subcontext(0),subcontext_size(upn_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *upn_name;
+ [value(2*strlen_m(dns_domain_name))] uint16 dns_domain_name_size;
+ [relative_short,subcontext(0),subcontext_size(dns_domain_name_size),flag(NDR_ALIGN8|STR_NOTERM|NDR_REMAINING)] string *dns_domain_name;
+ PAC_UPN_DNS_FLAGS flags;
+ [switch_is(flags & PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID)] PAC_UPN_DNS_INFO_EX ex;
+ } PAC_UPN_DNS_INFO;
+
+ typedef [bitmap32bit] bitmap {
+ PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED = 0x00000001,
+ PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY = 0x00000002
+ } PAC_ATTRIBUTE_INFO_FLAGS;
+
+ typedef struct {
+ uint32 flags_length; /* length in bits */
+ PAC_ATTRIBUTE_INFO_FLAGS flags;
+ } PAC_ATTRIBUTES_INFO;
+
+ typedef struct {
+ dom_sid sid;
+ } PAC_REQUESTER_SID;
+
+ typedef [public] struct {
+ PAC_LOGON_INFO *info;
+ } PAC_LOGON_INFO_CTR;
+
+ typedef [public] struct {
+ PAC_CONSTRAINED_DELEGATION *info;
+ } PAC_CONSTRAINED_DELEGATION_CTR;
+
+ typedef struct {
+ uint32 rid;
+ uint32 primary_gid;
+ dom_sid2 *domain_sid;
+ samr_RidWithAttributeArray groups;
+ uint32 sid_count;
+ [size_is(sid_count)] netr_SidAttr *sids;
+ uint32 domain_group_count;
+ [size_is(domain_group_count)] PAC_DOMAIN_GROUP_MEMBERSHIP *domain_groups;
+ } PAC_DEVICE_INFO;
+
+ typedef struct {
+ PAC_DEVICE_INFO *info;
+ } PAC_DEVICE_INFO_CTR;
+
+ typedef [public,v1_enum] enum {
+ PAC_TYPE_LOGON_INFO = 1,
+ PAC_TYPE_CREDENTIAL_INFO = 2,
+ PAC_TYPE_SRV_CHECKSUM = 6,
+ PAC_TYPE_KDC_CHECKSUM = 7,
+ PAC_TYPE_LOGON_NAME = 10,
+ PAC_TYPE_CONSTRAINED_DELEGATION = 11,
+ PAC_TYPE_UPN_DNS_INFO = 12,
+ PAC_TYPE_CLIENT_CLAIMS_INFO = 13,
+ PAC_TYPE_DEVICE_INFO = 14,
+ PAC_TYPE_DEVICE_CLAIMS_INFO = 15,
+ PAC_TYPE_TICKET_CHECKSUM = 16,
+ PAC_TYPE_ATTRIBUTES_INFO = 17,
+ PAC_TYPE_REQUESTER_SID = 18,
+ PAC_TYPE_FULL_CHECKSUM = 19
+ /*
+ * Note! when adding new types, adjust the value of PAC_TYPE_END
+ * to equal one more than the highest supported type.
+ */
+ } PAC_TYPE;
+
+ const uint32 PAC_TYPE_BEGIN = 1;
+ const uint32 PAC_TYPE_END = 20;
+ const uint32 PAC_TYPE_COUNT = PAC_TYPE_END - PAC_TYPE_BEGIN;
+
+ typedef struct {
+ [flag(NDR_REMAINING)] DATA_BLOB remaining;
+ } DATA_BLOB_REM;
+
+ typedef [public,nodiscriminant,gensize] union {
+ [case(PAC_TYPE_LOGON_INFO)][subcontext(0xFFFFFC01)] PAC_LOGON_INFO_CTR logon_info;
+ [case(PAC_TYPE_CREDENTIAL_INFO)] PAC_CREDENTIAL_INFO credential_info;
+ [case(PAC_TYPE_SRV_CHECKSUM)] PAC_SIGNATURE_DATA srv_cksum;
+ [case(PAC_TYPE_KDC_CHECKSUM)] PAC_SIGNATURE_DATA kdc_cksum;
+ [case(PAC_TYPE_LOGON_NAME)] PAC_LOGON_NAME logon_name;
+ [case(PAC_TYPE_CONSTRAINED_DELEGATION)][subcontext(0xFFFFFC01)]
+ PAC_CONSTRAINED_DELEGATION_CTR constrained_delegation;
+ [case(PAC_TYPE_UPN_DNS_INFO)] PAC_UPN_DNS_INFO upn_dns_info;
+ [case(PAC_TYPE_TICKET_CHECKSUM)] PAC_SIGNATURE_DATA ticket_checksum;
+ [case(PAC_TYPE_ATTRIBUTES_INFO)] PAC_ATTRIBUTES_INFO attributes_info;
+ [case(PAC_TYPE_REQUESTER_SID)] PAC_REQUESTER_SID requester_sid;
+ /*
+ * [subcontext(0)] and DATA_BLOB_REM is used as in
+ * PAC_TYPE_CLIENT_CLAIMS_INFO
+ * PAC_TYPE_DEVICE_CLAIMS_INFO as Windows will
+ * sometimes send an empty buffer (presumably to avoid
+ * the overhead of the header around the claims) if
+ * there are no claims to send
+ */
+ [case(PAC_TYPE_CLIENT_CLAIMS_INFO)][subcontext(0)] DATA_BLOB_REM client_claims_info;
+ [case(PAC_TYPE_DEVICE_INFO)][subcontext(0xFFFFFC01)] PAC_DEVICE_INFO_CTR device_info;
+ [case(PAC_TYPE_DEVICE_CLAIMS_INFO)][subcontext(0)] DATA_BLOB_REM device_claims_info;
+ [case(PAC_TYPE_FULL_CHECKSUM)] PAC_SIGNATURE_DATA full_checksum;
+ /* when new PAC info types are added they are supposed to be done
+ in such a way that they are backwards compatible with existing
+ servers. This makes it safe to just use a [default] for
+ unknown types, which lets us ignore the data */
+ [default] [subcontext(0)] DATA_BLOB_REM unknown;
+ } PAC_INFO;
+
+ typedef [public,nopush,nopull] struct {
+ PAC_TYPE type;
+ [value(_ndr_size_PAC_INFO(info, type, LIBNDR_FLAG_ALIGN8))] uint32 _ndr_size;
+ /*
+ * We need to have two subcontexts to get the padding right,
+ * the outer subcontext uses NDR_ROUND(_ndr_size, 8), while
+ * the inner subcontext only uses _ndr_size.
+ *
+ * We do that in non-generated push/pull functions.
+ */
+ [relative,switch_is(type),subcontext(0),subcontext_size(NDR_ROUND(_ndr_size,8)),flag(NDR_ALIGN8)] PAC_INFO *info;
+ [value(0)] uint32 _pad; /* Top half of a 64 bit pointer? */
+ } PAC_BUFFER;
+
+ typedef [public] struct {
+ uint32 num_buffers;
+ uint32 version;
+ PAC_BUFFER buffers[num_buffers];
+ } PAC_DATA;
+
+ typedef [public] struct {
+ PAC_TYPE type;
+ uint32 ndr_size;
+ [relative,subcontext(0),subcontext_size(NDR_ROUND(ndr_size,8)),flag(NDR_ALIGN8)] DATA_BLOB_REM *info;
+ [value(0)] uint32 _pad; /* Top half of a 64 bit pointer? */
+ } PAC_BUFFER_RAW;
+
+ typedef [public] struct {
+ uint32 num_buffers;
+ uint32 version;
+ PAC_BUFFER_RAW buffers[num_buffers];
+ } PAC_DATA_RAW;
+
+ const int NETLOGON_GENERIC_KRB5_PAC_VALIDATE = 3;
+
+ typedef [public] struct {
+ [value(NETLOGON_GENERIC_KRB5_PAC_VALIDATE)] uint32 MessageType;
+ uint32 ChecksumLength;
+ int32 SignatureType;
+ uint32 SignatureLength;
+ [flag(NDR_REMAINING)] DATA_BLOB ChecksumAndSignature;
+ } PAC_Validate;
+
+ /* used for samba3 netsamlogon cache */
+ typedef [public] struct {
+ time_t timestamp;
+ netr_SamInfo3 info3;
+ } netsamlogoncache_entry;
+}
diff --git a/librpc/idl/lsa.idl b/librpc/idl/lsa.idl
new file mode 100644
index 0000000..ede27c9
--- /dev/null
+++ b/librpc/idl/lsa.idl
@@ -0,0 +1,1669 @@
+#include "idl_types.h"
+
+/*
+ lsa interface definition
+*/
+
+import "misc.idl", "security.idl";
+
+[ uuid("12345778-1234-abcd-ef00-0123456789ab"),
+ version(0.0),
+ endpoint("ncacn_np:[\\pipe\\lsarpc]","ncacn_np:[\\pipe\\lsass]", "ncacn_ip_tcp:", "ncalrpc:"),
+ pyhelper("librpc/ndr/py_lsa.c"),
+ pointer_default(unique),
+ helpstring("Local Security Authority")
+] interface lsarpc
+{
+ typedef bitmap security_secinfo security_secinfo;
+ typedef bitmap kerb_EncTypes kerb_EncTypes;
+
+ typedef [public] struct {
+ [value(2*strlen_m(string))] uint16 length;
+ [value(2*strlen_m(string))] uint16 size;
+ [charset(UTF16),size_is(size/2),length_is(length/2)] uint16 *string;
+ } lsa_String;
+
+ typedef [public] struct {
+ [value(2*strlen_m(string))] uint16 length;
+ [value(2*strlen_m_term(string))] uint16 size;
+ [charset(UTF16),size_is(size/2),length_is(length/2)] uint16 *string;
+ } lsa_StringLarge;
+
+ typedef [public] struct {
+ uint32 count;
+ [size_is(count)] lsa_String *names;
+ } lsa_Strings;
+
+ typedef [public] struct {
+ [value(strlen_m(string))] uint16 length;
+ [value(strlen_m(string))] uint16 size;
+ [charset(DOS),size_is(size),length_is(length)] uint8 *string;
+ } lsa_AsciiString;
+
+ typedef [public] struct {
+ [value(strlen_m(string))] uint16 length;
+ [value(strlen_m_term(string))] uint16 size;
+ [charset(DOS),size_is(size),length_is(length)] uint8 *string;
+ } lsa_AsciiStringLarge;
+
+ typedef [public] struct {
+ uint16 length;
+ uint16 size;
+ [size_is(size/2),length_is(length/2)] uint16 *array;
+ } lsa_BinaryString;
+
+ /******************/
+ /* Function: 0x00 */
+ NTSTATUS lsa_Close (
+ [in,out] policy_handle *handle
+ );
+
+
+ /******************/
+ /* Function: 0x01 */
+ [public] NTSTATUS lsa_Delete (
+ [in] policy_handle *handle
+ );
+
+
+ /******************/
+ /* Function: 0x02 */
+ typedef struct {
+ uint32 low;
+ uint32 high;
+ } lsa_LUID;
+
+ typedef struct {
+ lsa_StringLarge name;
+ lsa_LUID luid;
+ } lsa_PrivEntry;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_PrivEntry *privs;
+ } lsa_PrivArray;
+
+ [public] NTSTATUS lsa_EnumPrivs (
+ [in] policy_handle *handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] lsa_PrivArray *privs,
+ [in] uint32 max_count
+ );
+
+ /******************/
+ /* Function: 0x03 */
+ NTSTATUS lsa_QuerySecurity (
+ [in] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [out,ref] sec_desc_buf **sdbuf
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ NTSTATUS lsa_SetSecObj(
+ [in] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [in,ref] sec_desc_buf *sdbuf
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ [todo] NTSTATUS lsa_ChangePassword ();
+
+
+ /******************/
+ /* Function: 0x06 */
+
+ typedef enum {
+ LSA_SECURITY_ANONYMOUS = 0,
+ LSA_SECURITY_IDENTIFICATION = 1,
+ LSA_SECURITY_IMPERSONATION = 2,
+ LSA_SECURITY_DELEGATION = 3
+ } lsa_SecurityImpersonationLevel;
+
+ typedef struct {
+ uint3264 len; /* ignored */
+ lsa_SecurityImpersonationLevel impersonation_level;
+ uint8 context_mode;
+ uint8 effective_only;
+ } lsa_QosInfo;
+
+ typedef struct {
+ uint3264 len; /* ignored */
+ uint8 *root_dir;
+ [string,charset(UTF16)] uint16 *object_name;
+ uint32 attributes;
+ security_descriptor *sec_desc;
+ lsa_QosInfo *sec_qos;
+ } lsa_ObjectAttribute;
+
+ typedef [public,bitmap32bit] bitmap {
+ LSA_POLICY_VIEW_LOCAL_INFORMATION = 0x00000001,
+ LSA_POLICY_VIEW_AUDIT_INFORMATION = 0x00000002,
+ LSA_POLICY_GET_PRIVATE_INFORMATION = 0x00000004,
+ LSA_POLICY_TRUST_ADMIN = 0x00000008,
+ LSA_POLICY_CREATE_ACCOUNT = 0x00000010,
+ LSA_POLICY_CREATE_SECRET = 0x00000020,
+ LSA_POLICY_CREATE_PRIVILEGE = 0x00000040,
+ LSA_POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080,
+ LSA_POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100,
+ LSA_POLICY_AUDIT_LOG_ADMIN = 0x00000200,
+ LSA_POLICY_SERVER_ADMIN = 0x00000400,
+ LSA_POLICY_LOOKUP_NAMES = 0x00000800,
+ LSA_POLICY_NOTIFICATION = 0x00001000
+ } lsa_PolicyAccessMask;
+
+ const int LSA_POLICY_ALL_ACCESS =
+ (STANDARD_RIGHTS_REQUIRED_ACCESS |
+ LSA_POLICY_VIEW_LOCAL_INFORMATION |
+ LSA_POLICY_VIEW_AUDIT_INFORMATION |
+ LSA_POLICY_GET_PRIVATE_INFORMATION |
+ LSA_POLICY_TRUST_ADMIN |
+ LSA_POLICY_CREATE_ACCOUNT |
+ LSA_POLICY_CREATE_SECRET |
+ LSA_POLICY_CREATE_PRIVILEGE |
+ LSA_POLICY_SET_DEFAULT_QUOTA_LIMITS |
+ LSA_POLICY_SET_AUDIT_REQUIREMENTS |
+ LSA_POLICY_AUDIT_LOG_ADMIN |
+ LSA_POLICY_SERVER_ADMIN |
+ LSA_POLICY_LOOKUP_NAMES |
+ LSA_POLICY_NOTIFICATION);
+
+ const int LSA_POLICY_READ =
+ (STANDARD_RIGHTS_READ_ACCESS |
+ LSA_POLICY_VIEW_LOCAL_INFORMATION |
+ LSA_POLICY_VIEW_AUDIT_INFORMATION |
+ LSA_POLICY_GET_PRIVATE_INFORMATION);
+
+ const int LSA_POLICY_WRITE =
+ (STANDARD_RIGHTS_READ_ACCESS |
+ LSA_POLICY_TRUST_ADMIN |
+ LSA_POLICY_CREATE_ACCOUNT |
+ LSA_POLICY_CREATE_SECRET |
+ LSA_POLICY_CREATE_PRIVILEGE |
+ LSA_POLICY_SET_DEFAULT_QUOTA_LIMITS |
+ LSA_POLICY_SET_AUDIT_REQUIREMENTS |
+ LSA_POLICY_AUDIT_LOG_ADMIN |
+ LSA_POLICY_SERVER_ADMIN);
+
+ const int LSA_POLICY_EXECUTE =
+ (STANDARD_RIGHTS_EXECUTE_ACCESS |
+ LSA_POLICY_VIEW_LOCAL_INFORMATION |
+ LSA_POLICY_LOOKUP_NAMES);
+
+ typedef [public,bitmap32bit] bitmap {
+ LSA_ACCOUNT_VIEW = 0x00000001,
+ LSA_ACCOUNT_ADJUST_PRIVILEGES = 0x00000002,
+ LSA_ACCOUNT_ADJUST_QUOTAS = 0x00000004,
+ LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS = 0x00000008
+ } lsa_AccountAccessMask;
+
+ const int LSA_ACCOUNT_ALL_ACCESS =
+ (STANDARD_RIGHTS_REQUIRED_ACCESS |
+ LSA_ACCOUNT_VIEW |
+ LSA_ACCOUNT_ADJUST_PRIVILEGES |
+ LSA_ACCOUNT_ADJUST_QUOTAS |
+ LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS);
+
+ const int LSA_ACCOUNT_READ =
+ (STANDARD_RIGHTS_READ_ACCESS |
+ LSA_ACCOUNT_VIEW);
+
+ const int LSA_ACCOUNT_WRITE =
+ (STANDARD_RIGHTS_READ_ACCESS |
+ LSA_ACCOUNT_ADJUST_PRIVILEGES |
+ LSA_ACCOUNT_ADJUST_QUOTAS |
+ LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS);
+
+ const int LSA_ACCOUNT_EXECUTE =
+ (STANDARD_RIGHTS_EXECUTE_ACCESS);
+
+ typedef [public,bitmap32bit] bitmap {
+ LSA_SECRET_SET_VALUE = 0x00000001,
+ LSA_SECRET_QUERY_VALUE = 0x00000002
+ } lsa_SecretAccessMask;
+
+ const int LSA_SECRET_ALL_ACCESS =
+ (LSA_SECRET_QUERY_VALUE |
+ LSA_SECRET_SET_VALUE |
+ SEC_STD_DELETE |
+ STANDARD_RIGHTS_READ_ACCESS |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER); /* 0x000F0003 */
+
+ const int LSA_SECRET_READ =
+ (LSA_SECRET_QUERY_VALUE |
+ STANDARD_RIGHTS_READ_ACCESS); /* 0x00020002 */
+
+ const int LSA_SECRET_WRITE =
+ (LSA_SECRET_SET_VALUE |
+ STANDARD_RIGHTS_READ_ACCESS); /* 0x00020001 */
+
+ const int LSA_SECRET_EXECUTE =
+ (STANDARD_RIGHTS_READ_ACCESS); /* 0x00020000 */
+
+ typedef [public,bitmap32bit] bitmap {
+ LSA_TRUSTED_QUERY_DOMAIN_NAME = 0x00000001,
+ LSA_TRUSTED_QUERY_CONTROLLERS = 0x00000002,
+ LSA_TRUSTED_SET_CONTROLLERS = 0x00000004,
+ LSA_TRUSTED_QUERY_POSIX = 0x00000008,
+ LSA_TRUSTED_SET_POSIX = 0x00000010,
+ LSA_TRUSTED_SET_AUTH = 0x00000020,
+ LSA_TRUSTED_QUERY_AUTH = 0x00000040
+ } lsa_TrustedAccessMask;
+
+ const int LSA_TRUSTED_DOMAIN_ALL_ACCESS =
+ (LSA_TRUSTED_QUERY_DOMAIN_NAME |
+ LSA_TRUSTED_QUERY_CONTROLLERS |
+ LSA_TRUSTED_SET_CONTROLLERS |
+ LSA_TRUSTED_QUERY_POSIX |
+ LSA_TRUSTED_SET_POSIX |
+ LSA_TRUSTED_SET_AUTH |
+ LSA_TRUSTED_QUERY_AUTH |
+ SEC_STD_DELETE |
+ STANDARD_RIGHTS_READ_ACCESS |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER); /* 0x000F007F */
+
+ const int LSA_TRUSTED_DOMAIN_READ =
+ (LSA_TRUSTED_QUERY_DOMAIN_NAME |
+ STANDARD_RIGHTS_READ_ACCESS); /* 0x00020001 */
+
+ const int LSA_TRUSTED_DOMAIN_WRITE =
+ (LSA_TRUSTED_SET_CONTROLLERS |
+ LSA_TRUSTED_SET_POSIX |
+ LSA_TRUSTED_SET_AUTH |
+ STANDARD_RIGHTS_READ_ACCESS); /* 0x00020034 */
+
+ const int LSA_TRUSTED_DOMAIN_EXECUTE =
+ (LSA_TRUSTED_QUERY_DOMAIN_NAME |
+ LSA_TRUSTED_QUERY_POSIX |
+ STANDARD_RIGHTS_READ_ACCESS); /* 0x0002000C */
+
+
+ /* notice the screwup with the system_name - that's why MS created
+ OpenPolicy2 */
+ [public] NTSTATUS lsa_OpenPolicy (
+ [in,unique] uint16 *system_name,
+ [in] lsa_ObjectAttribute *attr,
+ [in] lsa_PolicyAccessMask access_mask,
+ [out] policy_handle *handle
+ );
+
+
+
+ /******************/
+ /* Function: 0x07 */
+
+ typedef struct {
+ uint32 percent_full;
+ uint32 maximum_log_size;
+ hyper retention_time;
+ uint8 shutdown_in_progress;
+ hyper time_to_shutdown;
+ uint32 next_audit_record;
+ } lsa_AuditLogInfo;
+
+ typedef [v1_enum] enum {
+ LSA_AUDIT_POLICY_NONE=0,
+ LSA_AUDIT_POLICY_SUCCESS=1,
+ LSA_AUDIT_POLICY_FAILURE=2,
+ LSA_AUDIT_POLICY_ALL=(LSA_AUDIT_POLICY_SUCCESS|LSA_AUDIT_POLICY_FAILURE),
+ LSA_AUDIT_POLICY_CLEAR=4
+ } lsa_PolicyAuditPolicy;
+
+ typedef enum {
+ LSA_AUDIT_CATEGORY_SYSTEM = 0,
+ LSA_AUDIT_CATEGORY_LOGON = 1,
+ LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS = 2,
+ LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS = 3,
+ LSA_AUDIT_CATEGORY_PROCCESS_TRACKING = 4,
+ LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES = 5,
+ LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT = 6,
+ LSA_AUDIT_CATEGORY_DIRECTORY_SERVICE_ACCESS = 7, /* only in win2k/2k3 */
+ LSA_AUDIT_CATEGORY_ACCOUNT_LOGON = 8 /* only in win2k/2k3 */
+ } lsa_PolicyAuditEventType;
+
+ typedef struct {
+ uint32 auditing_mode;
+ [size_is(count)] lsa_PolicyAuditPolicy *settings;
+ uint32 count;
+ } lsa_AuditEventsInfo;
+
+ typedef struct {
+ lsa_StringLarge name;
+ dom_sid2 *sid;
+ } lsa_DomainInfo;
+
+ typedef struct {
+ lsa_String name;
+ } lsa_PDAccountInfo;
+
+ typedef [v1_enum] enum {
+ LSA_ROLE_BACKUP=2,
+ LSA_ROLE_PRIMARY=3
+ } lsa_Role;
+
+ typedef struct {
+ lsa_Role role;
+ } lsa_ServerRole;
+
+ typedef struct {
+ lsa_String source;
+ lsa_String account;
+ } lsa_ReplicaSourceInfo;
+
+ typedef struct {
+ uint32 paged_pool;
+ uint32 non_paged_pool;
+ uint32 min_wss;
+ uint32 max_wss;
+ uint32 pagefile;
+ hyper unknown;
+ } lsa_DefaultQuotaInfo;
+
+ typedef struct {
+ hyper modified_id;
+ NTTIME_hyper db_create_time;
+ } lsa_ModificationInfo;
+
+ typedef struct {
+ uint8 shutdown_on_full;
+ } lsa_AuditFullSetInfo;
+
+ typedef struct {
+ uint8 shutdown_on_full;
+ uint8 log_is_full;
+ } lsa_AuditFullQueryInfo;
+
+ typedef [public] struct {
+ /* it's important that we use the lsa_StringLarge here,
+ * because otherwise windows clients result with such dns hostnames
+ * e.g. w2k3-client.samba4.samba.orgsamba4.samba.org
+ * where it should be
+ * w2k3-client.samba4.samba.org
+ */
+ lsa_StringLarge name;
+ lsa_StringLarge dns_domain;
+ lsa_StringLarge dns_forest;
+ GUID domain_guid;
+ dom_sid2 *sid;
+ } lsa_DnsDomainInfo;
+
+ typedef enum {
+ LSA_POLICY_INFO_AUDIT_LOG=1,
+ LSA_POLICY_INFO_AUDIT_EVENTS=2,
+ LSA_POLICY_INFO_DOMAIN=3,
+ LSA_POLICY_INFO_PD=4,
+ LSA_POLICY_INFO_ACCOUNT_DOMAIN=5,
+ LSA_POLICY_INFO_ROLE=6,
+ LSA_POLICY_INFO_REPLICA=7,
+ LSA_POLICY_INFO_QUOTA=8,
+ LSA_POLICY_INFO_MOD=9,
+ LSA_POLICY_INFO_AUDIT_FULL_SET=10,
+ LSA_POLICY_INFO_AUDIT_FULL_QUERY=11,
+ LSA_POLICY_INFO_DNS=12,
+ LSA_POLICY_INFO_DNS_INT=13,
+ LSA_POLICY_INFO_L_ACCOUNT_DOMAIN=14
+ } lsa_PolicyInfo;
+
+ typedef [switch_type(uint16)] union {
+ [case(LSA_POLICY_INFO_AUDIT_LOG)] lsa_AuditLogInfo audit_log;
+ [case(LSA_POLICY_INFO_AUDIT_EVENTS)] lsa_AuditEventsInfo audit_events;
+ [case(LSA_POLICY_INFO_DOMAIN)] lsa_DomainInfo domain;
+ [case(LSA_POLICY_INFO_PD)] lsa_PDAccountInfo pd;
+ [case(LSA_POLICY_INFO_ACCOUNT_DOMAIN)] lsa_DomainInfo account_domain;
+ [case(LSA_POLICY_INFO_ROLE)] lsa_ServerRole role;
+ [case(LSA_POLICY_INFO_REPLICA)] lsa_ReplicaSourceInfo replica;
+ [case(LSA_POLICY_INFO_QUOTA)] lsa_DefaultQuotaInfo quota;
+ [case(LSA_POLICY_INFO_MOD)] lsa_ModificationInfo mod;
+ [case(LSA_POLICY_INFO_AUDIT_FULL_SET)] lsa_AuditFullSetInfo auditfullset;
+ [case(LSA_POLICY_INFO_AUDIT_FULL_QUERY)] lsa_AuditFullQueryInfo auditfullquery;
+ [case(LSA_POLICY_INFO_DNS)] lsa_DnsDomainInfo dns;
+ [case(LSA_POLICY_INFO_DNS_INT)] lsa_DnsDomainInfo dns_int;
+ [case(LSA_POLICY_INFO_L_ACCOUNT_DOMAIN)] lsa_DomainInfo l_account_domain;
+ } lsa_PolicyInformation;
+
+ NTSTATUS lsa_QueryInfoPolicy(
+ [in] policy_handle *handle,
+ [in] lsa_PolicyInfo level,
+ [out,ref,switch_is(level)] lsa_PolicyInformation **info
+ );
+
+ /******************/
+ /* Function: 0x08 */
+ NTSTATUS lsa_SetInfoPolicy (
+ [in] policy_handle *handle,
+ [in] lsa_PolicyInfo level,
+ [in,switch_is(level)] lsa_PolicyInformation *info
+ );
+
+ /******************/
+ /* Function: 0x09 */
+ [todo] NTSTATUS lsa_ClearAuditLog ();
+
+ /******************/
+ /* Function: 0x0a */
+ [public] NTSTATUS lsa_CreateAccount (
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [in] lsa_AccountAccessMask access_mask,
+ [out] policy_handle *acct_handle
+ );
+
+ /******************/
+ /* NOTE: This only returns accounts that have at least
+ one privilege set
+ */
+ /* Function: 0x0b */
+ typedef struct {
+ dom_sid2 *sid;
+ } lsa_SidPtr;
+
+ typedef [public] struct {
+ [range(0,20480)] uint32 num_sids;
+ [size_is(num_sids)] lsa_SidPtr *sids;
+ } lsa_SidArray;
+
+ [public] NTSTATUS lsa_EnumAccounts(
+ [in] policy_handle *handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] lsa_SidArray *sids,
+ [in,range(0,8192)] uint32 num_entries
+ );
+
+ /*************************************************/
+ /* Function: 0x0c */
+
+ [public] NTSTATUS lsa_CreateTrustedDomain(
+ [in] policy_handle *policy_handle,
+ [in] lsa_DomainInfo *info,
+ [in] lsa_TrustedAccessMask access_mask,
+ [out] policy_handle *trustdom_handle
+ );
+
+
+ /******************/
+ /* Function: 0x0d */
+
+ /* w2k3 treats max_size as max_domains*60 */
+ const int LSA_ENUM_TRUST_DOMAIN_MULTIPLIER = 60;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_DomainInfo *domains;
+ } lsa_DomainList;
+
+ NTSTATUS lsa_EnumTrustDom(
+ [in] policy_handle *handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] lsa_DomainList *domains,
+ [in] uint32 max_size
+ );
+
+
+ /******************/
+ /* Function: 0x0e */
+ typedef [public] enum {
+ SID_NAME_USE_NONE = 0,/* NOTUSED */
+ SID_NAME_USER = 1, /* user */
+ SID_NAME_DOM_GRP = 2, /* domain group */
+ SID_NAME_DOMAIN = 3, /* domain: don't know what this is */
+ SID_NAME_ALIAS = 4, /* local group */
+ SID_NAME_WKN_GRP = 5, /* well-known group */
+ SID_NAME_DELETED = 6, /* deleted account: needed for c2 rating */
+ SID_NAME_INVALID = 7, /* invalid account */
+ SID_NAME_UNKNOWN = 8, /* oops. */
+ SID_NAME_COMPUTER = 9, /* machine */
+ SID_NAME_LABEL = 10 /* Mandatory Label */
+ } lsa_SidType;
+
+ typedef struct {
+ lsa_SidType sid_type;
+ uint32 rid;
+ uint32 sid_index;
+ } lsa_TranslatedSid;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_TranslatedSid *sids;
+ } lsa_TransSidArray;
+
+ const int LSA_REF_DOMAIN_LIST_MULTIPLIER = 32;
+ typedef [public] struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_DomainInfo *domains;
+ uint32 max_size;
+ } lsa_RefDomainList;
+
+ /* Level 1: Ask everywhere
+ * Level 2: Ask domain and trusted domains, no builtin and wkn
+ * Level 3: Only ask domain
+ * Level 4: W2k3ad: Only ask AD trusts
+ * Level 5: Only ask transitive forest trusts
+ * Level 6: Like 4
+ */
+
+ typedef [public] enum {
+ LSA_LOOKUP_NAMES_ALL = 1,
+ LSA_LOOKUP_NAMES_DOMAINS_ONLY = 2,
+ LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY = 3,
+ LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY = 4,
+ LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY = 5,
+ LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 = 6,
+ LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC = 7
+ } lsa_LookupNamesLevel;
+
+ [public] NTSTATUS lsa_LookupNames (
+ [in] policy_handle *handle,
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(num_names)] lsa_String names[],
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransSidArray *sids,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count
+ );
+
+
+ /******************/
+ /* Function: 0x0f */
+
+ typedef struct {
+ lsa_SidType sid_type;
+ lsa_String name;
+ uint32 sid_index;
+ } lsa_TranslatedName;
+
+ typedef [public] struct {
+ [range(0,20480)] uint32 count;
+ [size_is(count)] lsa_TranslatedName *names;
+ } lsa_TransNameArray;
+
+ [public] NTSTATUS lsa_LookupSids(
+ [in] policy_handle *handle,
+ [in,ref] lsa_SidArray *sids,
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransNameArray *names,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count
+ );
+
+
+ /* Function: 0x10 */
+ [public] NTSTATUS lsa_CreateSecret(
+ [in] policy_handle *handle,
+ [in] lsa_String name,
+ [in] lsa_SecretAccessMask access_mask,
+ [out] policy_handle *sec_handle
+ );
+
+
+ /*****************************************/
+ /* Function: 0x11 */
+ NTSTATUS lsa_OpenAccount(
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [in] lsa_AccountAccessMask access_mask,
+ [out] policy_handle *acct_handle
+ );
+
+
+ /****************************************/
+ /* Function: 0x12 */
+
+ typedef struct {
+ lsa_LUID luid;
+ uint32 attribute;
+ } lsa_LUIDAttribute;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ uint32 unknown;
+ [size_is(count)] lsa_LUIDAttribute set[*];
+ } lsa_PrivilegeSet;
+
+ NTSTATUS lsa_EnumPrivsAccount(
+ [in] policy_handle *handle,
+ [out,ref] lsa_PrivilegeSet **privs
+ );
+
+
+ /****************************************/
+ /* Function: 0x13 */
+ NTSTATUS lsa_AddPrivilegesToAccount(
+ [in] policy_handle *handle,
+ [in,ref] lsa_PrivilegeSet *privs
+ );
+
+
+ /****************************************/
+ /* Function: 0x14 */
+ NTSTATUS lsa_RemovePrivilegesFromAccount(
+ [in] policy_handle *handle,
+ [in] uint8 remove_all,
+ [in,unique] lsa_PrivilegeSet *privs
+ );
+
+ /* Function: 0x15 */
+ [todo] NTSTATUS lsa_GetQuotasForAccount();
+
+ /* Function: 0x16 */
+ [todo] NTSTATUS lsa_SetQuotasForAccount();
+
+ /* Function: 0x17 */
+ NTSTATUS lsa_GetSystemAccessAccount(
+ [in] policy_handle *handle,
+ [out,ref] lsa_AccountAccessMask *access_mask
+ );
+
+ /* Function: 0x18 */
+ NTSTATUS lsa_SetSystemAccessAccount(
+ [in] policy_handle *handle,
+ [in] lsa_AccountAccessMask access_mask
+ );
+
+ /* Function: 0x19 */
+ NTSTATUS lsa_OpenTrustedDomain(
+ [in] policy_handle *handle,
+ [in] dom_sid2 *sid,
+ [in] lsa_TrustedAccessMask access_mask,
+ [out] policy_handle *trustdom_handle
+ );
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint3264 length;
+ uint3264 size;
+ [size_is(size),length_is(length)] uint8 *data;
+ } lsa_DATA_BUF;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ [range(0,65536)] uint32 size;
+ [size_is(size)] uint8 *data;
+ } lsa_DATA_BUF2;
+
+ typedef enum {
+ LSA_TRUSTED_DOMAIN_INFO_NAME = 1,
+ LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS = 2,
+ LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET = 3,
+ LSA_TRUSTED_DOMAIN_INFO_PASSWORD = 4,
+ LSA_TRUSTED_DOMAIN_INFO_BASIC = 5,
+ LSA_TRUSTED_DOMAIN_INFO_INFO_EX = 6,
+ LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO = 7,
+ LSA_TRUSTED_DOMAIN_INFO_FULL_INFO = 8,
+ LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO_INTERNAL = 9,
+ LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_INTERNAL = 10,
+ LSA_TRUSTED_DOMAIN_INFO_INFO_EX2_INTERNAL = 11,
+ LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_2_INTERNAL = 12,
+ LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES = 13,
+ LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO_INTERNAL_AES= 14,
+ LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_INTERNAL_AES= 15
+ } lsa_TrustDomInfoEnum;
+
+ typedef [public,bitmap32bit] bitmap {
+ LSA_TRUST_DIRECTION_INBOUND = 0x00000001,
+ LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002
+ } lsa_TrustDirection;
+
+ typedef [public,v1_enum] enum {
+ LSA_TRUST_TYPE_DOWNLEVEL = 0x00000001,
+ LSA_TRUST_TYPE_UPLEVEL = 0x00000002,
+ LSA_TRUST_TYPE_MIT = 0x00000003,
+ LSA_TRUST_TYPE_DCE = 0x00000004
+ } lsa_TrustType;
+
+ typedef [public,bitmap32bit] bitmap {
+ LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001,
+ LSA_TRUST_ATTRIBUTE_UPLEVEL_ONLY = 0x00000002,
+ LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN = 0x00000004,
+ LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE = 0x00000008,
+ LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION = 0x00000010,
+ LSA_TRUST_ATTRIBUTE_WITHIN_FOREST = 0x00000020,
+ LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL = 0x00000040,
+ LSA_TRUST_ATTRIBUTE_USES_RC4_ENCRYPTION = 0x00000080,
+ LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION_NO_TGT_DELEGATION = 0x00000200,
+ LSA_TRUST_ATTRIBUTE_PIM_TRUST = 0x00000400,
+ LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION = 0x00000800
+ } lsa_TrustAttributes;
+
+ typedef struct {
+ lsa_StringLarge netbios_name;
+ } lsa_TrustDomainInfoName;
+
+
+ typedef struct {
+ uint32 entries;
+ [size_is(entries)] lsa_StringLarge *netbios_names;
+ } lsa_TrustDomainInfoControllers;
+
+ typedef struct {
+ uint32 posix_offset;
+ } lsa_TrustDomainInfoPosixOffset;
+
+ typedef struct {
+ lsa_DATA_BUF *password;
+ lsa_DATA_BUF *old_password;
+ } lsa_TrustDomainInfoPassword;
+
+ typedef struct {
+ lsa_String netbios_name;
+ dom_sid2 *sid;
+ } lsa_TrustDomainInfoBasic;
+
+ typedef [public] struct {
+ lsa_StringLarge domain_name;
+ lsa_StringLarge netbios_name;
+ dom_sid2 *sid;
+ lsa_TrustDirection trust_direction;
+ lsa_TrustType trust_type;
+ lsa_TrustAttributes trust_attributes;
+ } lsa_TrustDomainInfoInfoEx;
+
+ typedef [public,v1_enum] enum {
+ TRUST_AUTH_TYPE_NONE = 0,
+ TRUST_AUTH_TYPE_NT4OWF = 1,
+ TRUST_AUTH_TYPE_CLEAR = 2,
+ TRUST_AUTH_TYPE_VERSION = 3
+ } lsa_TrustAuthType;
+
+ typedef struct {
+ NTTIME_hyper last_update_time;
+ lsa_TrustAuthType AuthType;
+ lsa_DATA_BUF2 data;
+ } lsa_TrustDomainInfoBuffer;
+
+ typedef [public] struct {
+ uint32 incoming_count;
+ lsa_TrustDomainInfoBuffer *incoming_current_auth_info;
+ lsa_TrustDomainInfoBuffer *incoming_previous_auth_info;
+ uint32 outgoing_count;
+ lsa_TrustDomainInfoBuffer *outgoing_current_auth_info;
+ lsa_TrustDomainInfoBuffer *outgoing_previous_auth_info;
+ } lsa_TrustDomainInfoAuthInfo;
+
+ typedef struct {
+ lsa_TrustDomainInfoInfoEx info_ex;
+ lsa_TrustDomainInfoPosixOffset posix_offset;
+ lsa_TrustDomainInfoAuthInfo auth_info;
+ } lsa_TrustDomainInfoFullInfo;
+
+ typedef struct {
+ lsa_DATA_BUF2 auth_blob;
+ } lsa_TrustDomainInfoAuthInfoInternal;
+
+ typedef struct {
+ lsa_TrustDomainInfoInfoEx info_ex;
+ lsa_TrustDomainInfoPosixOffset posix_offset;
+ lsa_TrustDomainInfoAuthInfoInternal auth_info;
+ } lsa_TrustDomainInfoFullInfoInternal;
+
+ typedef struct {
+ uint8 auth_data[64];
+ uint8 salt[16];
+ lsa_DATA_BUF2 cipher;
+ } lsa_TrustDomainInfoAuthInfoInternalAES;
+
+ typedef struct {
+ lsa_TrustDomainInfoInfoEx info_ex;
+ lsa_TrustDomainInfoPosixOffset posix_offset;
+ lsa_TrustDomainInfoAuthInfoInternalAES auth_info;
+ } lsa_TrustDomainInfoFullInfoInternalAES;
+
+ typedef struct {
+ lsa_TrustDomainInfoInfoEx info_ex;
+ uint32 forest_trust_length;
+ [size_is(forest_trust_length)] uint8 *forest_trust_data;
+ } lsa_TrustDomainInfoInfoEx2Internal;
+
+ typedef struct {
+ lsa_TrustDomainInfoInfoEx2Internal info;
+ lsa_TrustDomainInfoPosixOffset posix_offset;
+ lsa_TrustDomainInfoAuthInfo auth_info;
+ } lsa_TrustDomainInfoFullInfo2Internal;
+
+ typedef struct {
+ kerb_EncTypes enc_types;
+ } lsa_TrustDomainInfoSupportedEncTypes;
+
+ typedef [switch_type(lsa_TrustDomInfoEnum)] union {
+ [case(LSA_TRUSTED_DOMAIN_INFO_NAME)]
+ lsa_TrustDomainInfoName name;
+ [case(LSA_TRUSTED_DOMAIN_INFO_CONTROLLERS)]
+ lsa_TrustDomainInfoControllers controllers;
+ [case(LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET)]
+ lsa_TrustDomainInfoPosixOffset posix_offset;
+ [case(LSA_TRUSTED_DOMAIN_INFO_PASSWORD)]
+ lsa_TrustDomainInfoPassword password;
+ [case(LSA_TRUSTED_DOMAIN_INFO_BASIC)]
+ lsa_TrustDomainInfoBasic info_basic;
+ [case(LSA_TRUSTED_DOMAIN_INFO_INFO_EX)]
+ lsa_TrustDomainInfoInfoEx info_ex;
+ [case(LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO)]
+ lsa_TrustDomainInfoAuthInfo auth_info;
+ [case(LSA_TRUSTED_DOMAIN_INFO_FULL_INFO)]
+ lsa_TrustDomainInfoFullInfo full_info;
+ [case(LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO_INTERNAL)]
+ lsa_TrustDomainInfoAuthInfoInternal auth_info_internal;
+ [case(LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_INTERNAL)]
+ lsa_TrustDomainInfoFullInfoInternal full_info_internal;
+ [case(LSA_TRUSTED_DOMAIN_INFO_INFO_EX2_INTERNAL)]
+ lsa_TrustDomainInfoInfoEx2Internal info_ex2_internal;
+ [case(LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_2_INTERNAL)]
+ lsa_TrustDomainInfoFullInfo2Internal full_info2_internal;
+ [case(LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES)]
+ lsa_TrustDomainInfoSupportedEncTypes enc_types;
+ [case(LSA_TRUSTED_DOMAIN_INFO_AUTH_INFO_INTERNAL_AES)]
+ lsa_TrustDomainInfoAuthInfoInternalAES auth_info_internal_aes;
+ [case(LSA_TRUSTED_DOMAIN_INFO_FULL_INFO_INTERNAL_AES)]
+ lsa_TrustDomainInfoFullInfoInternalAES full_info_internal_aes;
+ } lsa_TrustedDomainInfo;
+
+ /* Function: 0x1a */
+ NTSTATUS lsa_QueryTrustedDomainInfo(
+ [in] policy_handle *trustdom_handle,
+ [in] lsa_TrustDomInfoEnum level,
+ [out,switch_is(level),ref] lsa_TrustedDomainInfo **info
+ );
+
+ /* Function: 0x1b */
+ NTSTATUS lsa_SetInformationTrustedDomain(
+ [in] policy_handle *trustdom_handle,
+ [in] lsa_TrustDomInfoEnum level,
+ [in,switch_is(level)] lsa_TrustedDomainInfo *info
+ );
+
+ /* Function: 0x1c */
+ [public] NTSTATUS lsa_OpenSecret(
+ [in] policy_handle *handle,
+ [in] lsa_String name,
+ [in] lsa_SecretAccessMask access_mask,
+ [out] policy_handle *sec_handle
+ );
+
+ /* Function: 0x1d */
+
+ [public] NTSTATUS lsa_SetSecret(
+ [in] policy_handle *sec_handle,
+ [in,unique] lsa_DATA_BUF *new_val,
+ [in,unique] lsa_DATA_BUF *old_val
+ );
+
+ typedef struct {
+ lsa_DATA_BUF *buf;
+ } lsa_DATA_BUF_PTR;
+
+ /* Function: 0x1e */
+ [public] NTSTATUS lsa_QuerySecret (
+ [in] policy_handle *sec_handle,
+ [in,out,unique] lsa_DATA_BUF_PTR *new_val,
+ [in,out,unique] NTTIME_hyper *new_mtime,
+ [in,out,unique] lsa_DATA_BUF_PTR *old_val,
+ [in,out,unique] NTTIME_hyper *old_mtime
+ );
+
+ /* Function: 0x1f */
+ NTSTATUS lsa_LookupPrivValue(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *name,
+ [out,ref] lsa_LUID *luid
+ );
+
+
+ /* Function: 0x20 */
+ NTSTATUS lsa_LookupPrivName(
+ [in] policy_handle *handle,
+ [in,ref] lsa_LUID *luid,
+ [out,ref] lsa_StringLarge **name
+ );
+
+
+ /*******************/
+ /* Function: 0x21 */
+ NTSTATUS lsa_LookupPrivDisplayName(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *name,
+ [in] uint16 language_id,
+ [in] uint16 language_id_sys,
+ [out,ref] lsa_StringLarge **disp_name,
+ /* see http://www.microsoft.com/globaldev/nlsweb/ for
+ language definitions */
+ [out,ref] uint16 *returned_language_id
+ );
+
+ /*******************/
+ /* Function: 0x22 */
+ NTSTATUS lsa_DeleteObject (
+ [in,out] policy_handle *handle
+ );
+
+ /*******************/
+ /* Function: 0x23 */
+ NTSTATUS lsa_EnumAccountsWithUserRight (
+ [in] policy_handle *handle,
+ [in,unique] lsa_String *name,
+ [out] lsa_SidArray *sids
+ );
+
+ /* Function: 0x24 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ } lsa_RightAttribute;
+
+ typedef struct {
+ [range(0,256)] uint32 count;
+ [size_is(count)] lsa_StringLarge *names;
+ } lsa_RightSet;
+
+ NTSTATUS lsa_EnumAccountRights (
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [out,ref] lsa_RightSet *rights
+ );
+
+
+ /**********************/
+ /* Function: 0x25 */
+ NTSTATUS lsa_AddAccountRights (
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [in,ref] lsa_RightSet *rights
+ );
+
+ /**********************/
+ /* Function: 0x26 */
+ NTSTATUS lsa_RemoveAccountRights (
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *sid,
+ [in] uint8 remove_all,
+ [in,ref] lsa_RightSet *rights
+ );
+
+ /* Function: 0x27 */
+ NTSTATUS lsa_QueryTrustedDomainInfoBySid(
+ [in] policy_handle *handle,
+ [in,ref] dom_sid2 *dom_sid,
+ [in] lsa_TrustDomInfoEnum level,
+ [out,switch_is(level),ref] lsa_TrustedDomainInfo **info
+ );
+
+ /* Function: 0x28 */
+ NTSTATUS lsa_SetTrustedDomainInfo(
+ [in] policy_handle *handle,
+ [in] dom_sid2 *dom_sid,
+ [in] lsa_TrustDomInfoEnum level,
+ [in,switch_is(level)] lsa_TrustedDomainInfo *info
+ );
+
+ /* Function: 0x29 */
+ NTSTATUS lsa_DeleteTrustedDomain(
+ [in] policy_handle *handle,
+ [in] dom_sid2 *dom_sid
+ );
+
+ /* Function: 0x2a */
+ NTSTATUS lsa_StorePrivateData(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *name,
+ [in,unique] lsa_DATA_BUF *val
+ );
+
+ /* Function: 0x2b */
+ NTSTATUS lsa_RetrievePrivateData(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *name,
+ [in,out,ref] lsa_DATA_BUF **val
+ );
+
+ /**********************/
+ /* Function: 0x2c */
+ [public] NTSTATUS lsa_OpenPolicy2 (
+ [in,unique] [string,charset(UTF16)] uint16 *system_name,
+ [in] lsa_ObjectAttribute *attr,
+ [in] lsa_PolicyAccessMask access_mask,
+ [out] policy_handle *handle
+ );
+
+ /**********************/
+ /* Function: 0x2d */
+ NTSTATUS lsa_GetUserName(
+ [in,unique] [string,charset(UTF16)] uint16 *system_name,
+ [in,out,ref] lsa_String **account_name,
+ [in,out,unique] lsa_String **authority_name
+ );
+
+ /**********************/
+ /* Function: 0x2e */
+
+ NTSTATUS lsa_QueryInfoPolicy2(
+ [in] policy_handle *handle,
+ [in] lsa_PolicyInfo level,
+ [out,ref,switch_is(level)] lsa_PolicyInformation **info
+ );
+
+ /* Function 0x2f */
+ NTSTATUS lsa_SetInfoPolicy2(
+ [in] policy_handle *handle,
+ [in] lsa_PolicyInfo level,
+ [in,switch_is(level)] lsa_PolicyInformation *info
+ );
+
+ /**********************/
+ /* Function 0x30 */
+ NTSTATUS lsa_QueryTrustedDomainInfoByName(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *trusted_domain,
+ [in] lsa_TrustDomInfoEnum level,
+ [out,ref,switch_is(level)] lsa_TrustedDomainInfo **info
+ );
+
+ /**********************/
+ /* Function 0x31 */
+ [public] NTSTATUS lsa_SetTrustedDomainInfoByName(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *trusted_domain,
+ [in] lsa_TrustDomInfoEnum level,
+ [in,ref,switch_is(level)] lsa_TrustedDomainInfo *info
+ );
+
+ /* Function 0x32 */
+
+ /* w2k3 treats max_size as max_domains*82 */
+ const int LSA_ENUM_TRUST_DOMAIN_EX_MULTIPLIER = 82;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_TrustDomainInfoInfoEx *domains;
+ } lsa_DomainListEx;
+
+ NTSTATUS lsa_EnumTrustedDomainsEx (
+ [in] policy_handle *handle,
+ [in,out] uint32 *resume_handle,
+ [out] lsa_DomainListEx *domains,
+ [in] uint32 max_size
+ );
+
+ /* Function 0x33 */
+ NTSTATUS lsa_CreateTrustedDomainEx(
+ [in] policy_handle *policy_handle,
+ [in] lsa_TrustDomainInfoInfoEx *info,
+ [in] lsa_TrustDomainInfoAuthInfo *auth_info,
+ [in] lsa_TrustedAccessMask access_mask,
+ [out] policy_handle *trustdom_handle
+ );
+
+
+ /* Function 0x34 */
+ NTSTATUS lsa_CloseTrustedDomainEx(
+ [in,out] policy_handle *handle
+ );
+
+ /* Function 0x35 */
+ typedef struct {
+ uint32 quality_of_service;
+ } lsa_DomainInfoQoS;
+
+ typedef [bitmap32bit] bitmap {
+ LSA_POLICY_KERBEROS_VALIDATE_CLIENT = 0x00000080
+ } lsa_krbAuthenticationOptions;
+
+ /* w2k3 returns either 0x000bbbd000000000 or 0x000a48e800000000
+ for reserved - gd */
+ typedef struct {
+ lsa_krbAuthenticationOptions authentication_options;
+ hyper service_tkt_lifetime;
+ hyper user_tkt_lifetime;
+ hyper user_tkt_renewaltime;
+ hyper clock_skew;
+ hyper reserved;
+ } lsa_DomainInfoKerberos;
+
+ typedef struct {
+ uint32 blob_size;
+ [size_is(blob_size)] uint8 *efs_blob;
+ } lsa_DomainInfoEfs;
+
+ typedef enum {
+ LSA_DOMAIN_INFO_POLICY_QOS=1,
+ LSA_DOMAIN_INFO_POLICY_EFS=2,
+ LSA_DOMAIN_INFO_POLICY_KERBEROS=3
+ } lsa_DomainInfoEnum;
+
+ typedef [switch_type(lsa_DomainInfoEnum)] union {
+ [case(LSA_DOMAIN_INFO_POLICY_QOS)] lsa_DomainInfoQoS qos_info;
+ [case(LSA_DOMAIN_INFO_POLICY_EFS)] lsa_DomainInfoEfs efs_info;
+ [case(LSA_DOMAIN_INFO_POLICY_KERBEROS)] lsa_DomainInfoKerberos kerberos_info;
+ } lsa_DomainInformationPolicy;
+
+ NTSTATUS lsa_QueryDomainInformationPolicy(
+ [in] policy_handle *handle,
+ [in] lsa_DomainInfoEnum level,
+ [out,ref,switch_is(level)] lsa_DomainInformationPolicy **info
+ );
+
+ /* Function 0x36 */
+ NTSTATUS lsa_SetDomainInformationPolicy(
+ [in] policy_handle *handle,
+ [in] lsa_DomainInfoEnum level,
+ [in,unique,switch_is(level)] lsa_DomainInformationPolicy *info
+ );
+
+ /**********************/
+ /* Function 0x37 */
+ NTSTATUS lsa_OpenTrustedDomainByName(
+ [in] policy_handle *handle,
+ [in] lsa_String name,
+ [in] lsa_TrustedAccessMask access_mask,
+ [out] policy_handle *trustdom_handle
+ );
+
+ /* Function 0x38 */
+ [todo] NTSTATUS lsa_TestCall();
+
+ /**********************/
+ /* Function 0x39 */
+
+ typedef struct {
+ lsa_SidType sid_type;
+ lsa_String name;
+ uint32 sid_index;
+ uint32 unknown;
+ } lsa_TranslatedName2;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_TranslatedName2 *names;
+ } lsa_TransNameArray2;
+
+ typedef [v1_enum] enum {
+ LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES = 0x00000000,
+ LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES_LOCAL = 0x80000000
+ } lsa_LookupOptions;
+
+ typedef [v1_enum] enum {
+ LSA_CLIENT_REVISION_1 = 0x00000001,
+ LSA_CLIENT_REVISION_2 = 0x00000002
+ } lsa_ClientRevision;
+
+ [public] NTSTATUS lsa_LookupSids2(
+ [in] policy_handle *handle,
+ [in,ref] lsa_SidArray *sids,
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransNameArray2 *names,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count,
+ [in] lsa_LookupOptions lookup_options,
+ [in] lsa_ClientRevision client_revision
+ );
+
+ /**********************/
+ /* Function 0x3a */
+
+ typedef struct {
+ lsa_SidType sid_type;
+ uint32 rid;
+ uint32 sid_index;
+ uint32 unknown;
+ } lsa_TranslatedSid2;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_TranslatedSid2 *sids;
+ } lsa_TransSidArray2;
+
+ [public] NTSTATUS lsa_LookupNames2 (
+ [in] policy_handle *handle,
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(num_names)] lsa_String names[],
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransSidArray2 *sids,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count,
+ [in] lsa_LookupOptions lookup_options,
+ [in] lsa_ClientRevision client_revision
+ );
+
+ /* Function 0x3b */
+ NTSTATUS lsa_CreateTrustedDomainEx2(
+ [in] policy_handle *policy_handle,
+ [in] lsa_TrustDomainInfoInfoEx *info,
+ [in] lsa_TrustDomainInfoAuthInfoInternal *auth_info_internal,
+ [in] lsa_TrustedAccessMask access_mask,
+ [out] policy_handle *trustdom_handle
+ );
+
+ /* Function 0x3c */
+ [todo] NTSTATUS lsa_CREDRWRITE();
+
+ /* Function 0x3d */
+ [todo] NTSTATUS lsa_CREDRREAD();
+
+ /* Function 0x3e */
+ [todo] NTSTATUS lsa_CREDRENUMERATE();
+
+ /* Function 0x3f */
+ [todo] NTSTATUS lsa_CREDRWRITEDOMAINCREDENTIALS();
+
+ /* Function 0x40 */
+ [todo] NTSTATUS lsa_CREDRREADDOMAINCREDENTIALS();
+
+ /* Function 0x41 */
+ [todo] NTSTATUS lsa_CREDRDELETE();
+
+ /* Function 0x42 */
+ [todo] NTSTATUS lsa_CREDRGETTARGETINFO();
+
+ /* Function 0x43 */
+ [todo] NTSTATUS lsa_CREDRPROFILELOADED();
+
+ /**********************/
+ /* Function 0x44 */
+ typedef struct {
+ lsa_SidType sid_type;
+ dom_sid2 *sid;
+ uint32 sid_index;
+ uint32 flags;
+ } lsa_TranslatedSid3;
+
+ typedef struct {
+ [range(0,1000)] uint32 count;
+ [size_is(count)] lsa_TranslatedSid3 *sids;
+ } lsa_TransSidArray3;
+
+ [public] NTSTATUS lsa_LookupNames3 (
+ [in] policy_handle *handle,
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(num_names)] lsa_String names[],
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransSidArray3 *sids,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count,
+ [in] lsa_LookupOptions lookup_options,
+ [in] lsa_ClientRevision client_revision
+ );
+
+ /* Function 0x45 */
+ [todo] NTSTATUS lsa_CREDRGETSESSIONTYPES();
+
+ /* Function 0x46 */
+ [todo] NTSTATUS lsa_LSARREGISTERAUDITEVENT();
+
+ /* Function 0x47 */
+ [todo] NTSTATUS lsa_LSARGENAUDITEVENT();
+
+ /* Function 0x48 */
+ [todo] NTSTATUS lsa_LSARUNREGISTERAUDITEVENT();
+
+ /* Function 0x49 */
+ typedef [bitmap32bit,public] bitmap {
+ /* these apply to LSA_FOREST_TRUST_TOP_LEVEL_NAME */
+ LSA_TLN_DISABLED_NEW = 0x00000001,
+ LSA_TLN_DISABLED_ADMIN = 0x00000002,
+ LSA_TLN_DISABLED_CONFLICT = 0x00000004,
+
+ /* these apply to LSA_FOREST_TRUST_DOMAIN_INFO */
+ LSA_SID_DISABLED_ADMIN = 0x00000001,
+ LSA_SID_DISABLED_CONFLICT = 0x00000002,
+ LSA_NB_DISABLED_ADMIN = 0x00000004,
+ LSA_NB_DISABLED_CONFLICT = 0x00000008
+ } lsa_ForestTrustRecordFlags;
+
+ const uint32 LSA_TLN_DISABLED_MASK = (
+ LSA_TLN_DISABLED_NEW |
+ LSA_TLN_DISABLED_ADMIN |
+ LSA_TLN_DISABLED_CONFLICT);
+ const uint32 LSA_SID_DISABLED_MASK = (
+ LSA_SID_DISABLED_ADMIN |
+ LSA_SID_DISABLED_CONFLICT);
+ const uint32 LSA_NB_DISABLED_MASK = (
+ LSA_NB_DISABLED_ADMIN |
+ LSA_NB_DISABLED_CONFLICT);
+
+ typedef enum {
+ LSA_FOREST_TRUST_TOP_LEVEL_NAME = 0,
+ LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX = 1,
+ LSA_FOREST_TRUST_DOMAIN_INFO = 2,
+ LSA_FOREST_TRUST_BINARY_DATA = 3,
+ LSA_FOREST_TRUST_SCANNER_INFO = 4
+ } lsa_ForestTrustRecordType;
+ const uint32 LSA_FOREST_TRUST_RECORD_TYPE_LAST =
+ LSA_FOREST_TRUST_BINARY_DATA;
+ const uint32 LSA_FOREST_TRUST_RECORD2_TYPE_LAST =
+ LSA_FOREST_TRUST_SCANNER_INFO;
+
+ typedef struct {
+ [range(0,131072)] uint3264 length;
+ [size_is(length)] uint8 *data;
+ } lsa_ForestTrustBinaryData;
+
+ typedef struct {
+ dom_sid2 *domain_sid;
+ lsa_StringLarge dns_domain_name;
+ lsa_StringLarge netbios_domain_name;
+ } lsa_ForestTrustDomainInfo;
+
+ typedef [switch_type(lsa_ForestTrustRecordType)] union {
+ [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME)] lsa_StringLarge top_level_name;
+ [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX)] lsa_StringLarge top_level_name_ex;
+ [case(LSA_FOREST_TRUST_DOMAIN_INFO)] lsa_ForestTrustDomainInfo domain_info;
+ [default] lsa_ForestTrustBinaryData data;
+ } lsa_ForestTrustData;
+
+ typedef struct {
+ lsa_ForestTrustRecordFlags flags;
+ lsa_ForestTrustRecordType type;
+ NTTIME_hyper time;
+ [switch_is(type)] lsa_ForestTrustData forest_trust_data;
+ } lsa_ForestTrustRecord;
+
+ typedef [public] struct {
+ [range(0,4000)] uint32 count;
+ [size_is(count)] lsa_ForestTrustRecord **entries;
+ } lsa_ForestTrustInformation;
+
+ [public] NTSTATUS lsa_lsaRQueryForestTrustInformation(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *trusted_domain_name,
+ [in] lsa_ForestTrustRecordType highest_record_type,
+ [out,ref] lsa_ForestTrustInformation **forest_trust_info
+ );
+
+ /*****************
+ * Function 0x4a */
+
+ typedef [v1_enum] enum {
+ LSA_FOREST_TRUST_COLLISION_TDO = 0,
+ LSA_FOREST_TRUST_COLLISION_XREF = 1,
+ LSA_FOREST_TRUST_COLLISION_OTHER = 2
+ } lsa_ForestTrustCollisionRecordType;
+
+ typedef [public] struct {
+ uint32 index;
+ lsa_ForestTrustCollisionRecordType type;
+ lsa_ForestTrustRecordFlags flags;
+ lsa_String name;
+ } lsa_ForestTrustCollisionRecord;
+
+ typedef [public] struct {
+ uint32 count;
+ [size_is(count)] lsa_ForestTrustCollisionRecord **entries;
+ } lsa_ForestTrustCollisionInfo;
+
+ [public] NTSTATUS lsa_lsaRSetForestTrustInformation(
+ [in] policy_handle *handle,
+ [in,ref] lsa_StringLarge *trusted_domain_name,
+ [in] lsa_ForestTrustRecordType highest_record_type,
+ [in,ref] lsa_ForestTrustInformation *forest_trust_info,
+ [in] boolean8 check_only,
+ [out,ref] lsa_ForestTrustCollisionInfo **collision_info
+ );
+
+ /* Function 0x4b */
+ [todo] NTSTATUS lsa_CREDRRENAME();
+
+ /*****************/
+ /* Function 0x4c */
+
+ [public] NTSTATUS lsa_LookupSids3(
+ [in,ref] lsa_SidArray *sids,
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransNameArray2 *names,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count,
+ [in] lsa_LookupOptions lookup_options,
+ [in] lsa_ClientRevision client_revision
+ );
+
+ const int LSA_CLIENT_REVISION_NO_DNS = 0x00000001;
+ const int LSA_CLIENT_REVISION_DNS = 0x00000002;
+
+ const int LSA_LOOKUP_OPTIONS_NO_ISOLATED = 0x80000000;
+
+ /* Function 0x4d */
+ NTSTATUS lsa_LookupNames4(
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(num_names)] lsa_String names[],
+ [out,ref] lsa_RefDomainList **domains,
+ [in,out,ref] lsa_TransSidArray3 *sids,
+ [in] lsa_LookupNamesLevel level,
+ [in,out,ref] uint32 *count,
+ [in] lsa_LookupOptions lookup_options,
+ [in] lsa_ClientRevision client_revision
+ );
+
+ /* Function 0x4e */
+ [todo] NTSTATUS lsa_LSAROPENPOLICYSCE();
+
+ /* Function 0x4f */
+ [todo] NTSTATUS lsa_LSARADTREGISTERSECURITYEVENTSOURCE();
+
+ /* Function 0x50 */
+ [todo] NTSTATUS lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE();
+
+ /* Function 0x51 */
+ [todo] NTSTATUS lsa_LSARADTREPORTSECURITYEVENT();
+
+ /* Function 0x52 (82) */
+ [todo] void lsa_Opnum82NotUsedOnWire(void);
+
+ /* Function 0x53 (83) */
+ [todo] void lsa_Opnum83NotUsedOnWire(void);
+
+ /* Function 0x54 (84) */
+ [todo] void lsa_Opnum84NotUsedOnWire(void);
+
+ /* Function 0x55 (85) */
+ [todo] void lsa_Opnum85NotUsedOnWire(void);
+
+ /* Function 0x56 (86) */
+ [todo] void lsa_Opnum86NotUsedOnWire(void);
+
+ /* Function 0x57 (87) */
+ [todo] void lsa_Opnum87NotUsedOnWire(void);
+
+ /* Function 0x58 (88) */
+ [todo] void lsa_Opnum88NotUsedOnWire(void);
+
+ /* Function 0x59 (89) */
+ [todo] void lsa_Opnum89NotUsedOnWire(void);
+
+ /* Function 0x5A (90) */
+ [todo] void lsa_Opnum90NotUsedOnWire(void);
+
+ /* Function 0x5B (91) */
+ [todo] void lsa_Opnum91NotUsedOnWire(void);
+
+ /* Function 0x5C (92) */
+ [todo] void lsa_Opnum92NotUsedOnWire(void);
+
+ /* Function 0x5D (93) */
+ [todo] void lsa_Opnum93NotUsedOnWire(void);
+
+ /* Function 0x5E (94) */
+ [todo] void lsa_Opnum94NotUsedOnWire(void);
+
+ /* Function 0x5F (95) */
+ [todo] void lsa_Opnum95NotUsedOnWire(void);
+
+ /* Function 0x60 (96) */
+ [todo] void lsa_Opnum96NotUsedOnWire(void);
+
+ /* Function 0x61 (97) */
+ [todo] void lsa_Opnum97NotUsedOnWire(void);
+
+ /* Function 0x62 (98) */
+ [todo] void lsa_Opnum98NotUsedOnWire(void);
+
+ /* Function 0x63 (99) */
+ [todo] void lsa_Opnum99NotUsedOnWire(void);
+
+ /* Function 0x64 (100) */
+ [todo] void lsa_Opnum100NotUsedOnWire(void);
+
+ /* Function 0x65 (101) */
+ [todo] void lsa_Opnum101NotUsedOnWire(void);
+
+ /* Function 0x66 (102) */
+ [todo] void lsa_Opnum102NotUsedOnWire(void);
+
+ /* Function 0x67 (103) */
+ [todo] void lsa_Opnum103NotUsedOnWire(void);
+
+ /* Function 0x68 (104) */
+ [todo] void lsa_Opnum104NotUsedOnWire(void);
+
+ /* Function 0x69 (105) */
+ [todo] void lsa_Opnum105NotUsedOnWire(void);
+
+ /* Function 0x6A (106) */
+ [todo] void lsa_Opnum106NotUsedOnWire(void);
+
+ /* Function 0x6B (107) */
+ [todo] void lsa_Opnum107NotUsedOnWire(void);
+
+ /* Function 0x6C (108) */
+ [todo] void lsa_Opnum108NotUsedOnWire(void);
+
+ /* Function 0x6D (109) */
+ [todo] void lsa_Opnum109NotUsedOnWire(void);
+
+ /* Function 0x6E (110) */
+ [todo] void lsa_Opnum110NotUsedOnWire(void);
+
+ /* Function 0x6F (111) */
+ [todo] void lsa_Opnum111NotUsedOnWire(void);
+
+ /* Function 0x70 (112) */
+ [todo] void lsa_Opnum112NotUsedOnWire(void);
+
+ /* Function 0x71 (113) */
+ [todo] void lsa_Opnum113NotUsedOnWire(void);
+
+ /* Function 0x72 (114) */
+ [todo] void lsa_Opnum114NotUsedOnWire(void);
+
+ /* Function 0x73 (115) */
+ [todo] void lsa_Opnum115NotUsedOnWire(void);
+
+ /* Function 0x74 (116) */
+ [todo] void lsa_Opnum116NotUsedOnWire(void);
+
+ /* Function 0x75 (117) */
+ [todo] void lsa_Opnum117NotUsedOnWire(void);
+
+ /* Function 0x76 (118) */
+ [todo] void lsa_Opnum118NotUsedOnWire(void);
+
+ /* Function 0x77 (119) */
+ [todo] void lsa_Opnum119NotUsedOnWire(void);
+
+ /* Function 0x78 (120) */
+ [todo] void lsa_Opnum120NotUsedOnWire(void);
+
+ /* Function 0x79 (121) */
+ [todo] void lsa_Opnum121NotUsedOnWire(void);
+
+ /* Function 0x7A (122) */
+ [todo] void lsa_Opnum122NotUsedOnWire(void);
+
+ /* Function 0x7B (123) */
+ [todo] void lsa_Opnum123NotUsedOnWire(void);
+
+ /* Function 0x7C (124) */
+ [todo] void lsa_Opnum124NotUsedOnWire(void);
+
+ /* Function 0x7D (125) */
+ [todo] void lsa_Opnum125NotUsedOnWire(void);
+
+ /* Function 0x7E (126) */
+ [todo] void lsa_Opnum126NotUsedOnWire(void);
+
+ /* Function 0x7F (127) */
+ [todo] void lsa_Opnum127NotUsedOnWire(void);
+
+ /* Function 0x80 (128) */
+ [todo] void lsa_Opnum128NotUsedOnWire(void);
+
+ /***********************/
+ /* Function 0x81 (129) */
+
+ NTSTATUS lsa_CreateTrustedDomainEx3(
+ [in] policy_handle *policy_handle,
+ [in] lsa_TrustDomainInfoInfoEx *info,
+ [in] lsa_TrustDomainInfoAuthInfoInternalAES *auth_info_internal,
+ [in] lsa_TrustedAccessMask access_mask,
+ [out] policy_handle *trustdom_handle
+ );
+
+ /***********************/
+ /* Function 0x82 (130) */
+
+ typedef [bitmap32bit] bitmap {
+ LSA_FEATURE_TDO_AUTH_INFO_AES_CIPHER = 0x00000001
+ } lsa_RevisionSupportedFeature;
+
+ typedef struct {
+ uint32 revision;
+ lsa_RevisionSupportedFeature supported_features;
+ } lsa_revision_info1;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] lsa_revision_info1 info1;
+ } lsa_revision_info;
+
+ [public] NTSTATUS lsa_OpenPolicy3 (
+ [in,unique] [string,charset(UTF16)] uint16 *system_name,
+ [in] lsa_ObjectAttribute *attr,
+ [in] lsa_PolicyAccessMask access_mask,
+ [in] uint32 in_version,
+ [in,ref][switch_is(in_version)] lsa_revision_info *in_revision_info,
+ [out,ref] uint32 *out_version,
+ [out,ref][switch_is(*out_version)] lsa_revision_info *out_revision_info,
+ [out,ref] policy_handle *handle
+ );
+
+ /* Function 0x83 (131) */
+ [todo] void lsa_Opnum131NotUsedOnWire(void);
+
+ /***********************/
+ /* Function 0x84 (132) */
+ typedef [switch_type(lsa_ForestTrustRecordType)] union {
+ [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME)] lsa_StringLarge top_level_name;
+ [case(LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX)] lsa_StringLarge top_level_name_ex;
+ [case(LSA_FOREST_TRUST_DOMAIN_INFO)] lsa_ForestTrustDomainInfo domain_info;
+ [case(LSA_FOREST_TRUST_BINARY_DATA)] lsa_ForestTrustBinaryData data;
+ /*
+ * lsa_ForestTrustScannerInfo would have the same
+ * definition as lsa_ForestTrustDomainInfo
+ */
+ [case(LSA_FOREST_TRUST_SCANNER_INFO)] lsa_ForestTrustDomainInfo scanner_info;
+ } lsa_ForestTrustData2;
+
+ typedef struct {
+ lsa_ForestTrustRecordFlags flags;
+ lsa_ForestTrustRecordType type;
+ NTTIME_hyper time;
+ [switch_is(type)] lsa_ForestTrustData2 forest_trust_data;
+ } lsa_ForestTrustRecord2;
+
+ typedef [public] struct {
+ [range(0,4000)] uint32 count;
+ [size_is(count)] lsa_ForestTrustRecord2 **entries;
+ } lsa_ForestTrustInformation2;
+
+ [public] NTSTATUS lsa_lsaRQueryForestTrustInformation2(
+ [in] policy_handle *handle,
+ [in,ref] lsa_String *trusted_domain_name,
+ [in] lsa_ForestTrustRecordType highest_record_type,
+ [out,ref] lsa_ForestTrustInformation2 **forest_trust_info
+ );
+
+ /***********************/
+ /* Function 0x85 (133) */
+ [public] NTSTATUS lsa_lsaRSetForestTrustInformation2(
+ [in] policy_handle *handle,
+ [in,ref] lsa_StringLarge *trusted_domain_name,
+ [in] lsa_ForestTrustRecordType highest_record_type,
+ [in,ref] lsa_ForestTrustInformation2 *forest_trust_info,
+ [in] boolean8 check_only,
+ [out,ref] lsa_ForestTrustCollisionInfo **collision_info
+ );
+}
diff --git a/librpc/idl/mdssvc.idl b/librpc/idl/mdssvc.idl
new file mode 100644
index 0000000..b774747
--- /dev/null
+++ b/librpc/idl/mdssvc.idl
@@ -0,0 +1,68 @@
+import "misc.idl";
+[
+ uuid("885d85fb-c754-4062-a0e7-6872ce0064f4"),
+ endpoint("ncacn_np:[\\pipe\\mdssvc]", "ncalrpc:"),
+ version(2.0),
+ helpstring("Spotlight metadata search service")
+]
+interface mdssvc
+{
+ void mdssvc_open(
+ [in,out,ref] uint32 *device_id,
+ [in,out,ref] uint32 *unkn2, /* always 0x17 ? */
+ [in,out,ref] uint32 *unkn3, /* always 0 ? */
+ [in][string,charset(UTF8),size_is(1025)] uint8 share_mount_path[],
+ [in][string,charset(UTF8),size_is(1025)] uint8 share_name[],
+ [out,string,charset(UTF8),size_is(1025)] uint8 share_path[],
+ [out,ref] policy_handle *handle
+ );
+
+ void mdssvc_unknown1(
+ [in] policy_handle *handle,
+ [in] uint32 unkn1, /* always 0, some status ? */
+ [in] uint32 device_id,
+ [in] uint32 unkn3, /* = mdssvc_open.unkn2 ? */
+ [in] uint32 unkn4, /* always 0, some status ? */
+ [in] uint32 uid,
+ [in] uint32 gid,
+ [out,ref] uint32 *status,
+ [out,ref] uint32 *flags, /* always 0x6b000001 ? */
+ [out,ref] uint32 *unkn7 /* always 0 ? */
+ );
+
+ typedef [public] struct {
+ uint32 length;
+ uint32 size;
+ [size_is(size),length_is(length)] uint8 *spotlight_blob;
+ } mdssvc_blob;
+
+ void mdssvc_cmd(
+ [in] policy_handle *handle,
+ [in] uint32 unkn1, /* always 0, status ? */
+ [in] uint32 device_id,
+ [in] uint32 unkn3, /* = mdssvc_open.unkn2 ? */
+ [in] uint32 next_fragment, /* Set to 1 to request next fragment*/
+ [in] uint32 flags, /* always 0x6b000001 ? */
+ [in] mdssvc_blob request_blob,
+ [in] uint32 unkn5, /* always 0 ? */
+ [in] uint32 max_fragment_size1,
+ [in] uint32 unkn6, /* always 1 ? */
+ /* always max_fragment_size1 = max_fragment_size2 ? */
+ [in] uint32 max_fragment_size2,
+ [in] uint32 unkn7, /* always 0 ? */
+ [in] uint32 unkn8, /* always 0 ? */
+ [out,ref] uint32 *fragment,
+ [out,ref] mdssvc_blob *response_blob,
+ [out,ref] uint32 *unkn9 /* always 0 ? */
+ );
+
+ void mdssvc_close(
+ [in] policy_handle *in_handle,
+ [in] uint32 unkn1, /* always 0, some status ? */
+ [in] uint32 device_id,
+ [in] uint32 unkn2, /* = mdssvc_open.unkn2 ? */
+ [in] uint32 unkn3, /* always 0, some status ? */
+ [out,ref] policy_handle *out_handle,
+ [out,ref] uint32 *status
+ );
+}
diff --git a/librpc/idl/messaging.idl b/librpc/idl/messaging.idl
new file mode 100644
index 0000000..df579cf
--- /dev/null
+++ b/librpc/idl/messaging.idl
@@ -0,0 +1,206 @@
+#include "idl_types.h"
+
+import "server_id.idl";
+
+/*
+ IDL structures for messaging code
+*/
+
+[
+ pointer_default(unique)
+]
+interface messaging
+{
+ const int MSG_TYPE_MASK = 0xFFFF;
+
+ typedef [v1_enum,public] enum {
+
+ /* general messages */
+ MSG_DEBUG = 0x0001,
+ MSG_PING = 0x0002,
+ MSG_PONG = 0x0003,
+ MSG_PROFILE = 0x0004,
+ MSG_REQ_DEBUGLEVEL = 0x0005,
+ MSG_DEBUGLEVEL = 0x0006,
+ MSG_REQ_PROFILELEVEL = 0x0007,
+ MSG_PROFILELEVEL = 0x0008,
+ MSG_REQ_POOL_USAGE = 0x0009,
+ MSG_POOL_USAGE = 0x000A,
+
+ /* If dmalloc is included, set a steady-state mark */
+ MSG_REQ_DMALLOC_MARK = 0x000B,
+
+ /* If dmalloc is included, dump to the dmalloc log a description of
+ * what has changed since the last MARK */
+ MSG_REQ_DMALLOC_LOG_CHANGED = 0x000C,
+ MSG_SHUTDOWN = 0x000D,
+
+ /* ID_CACHE_FLUSH = 0x000E, obsoleted */
+ ID_CACHE_DELETE = 0x000F,
+ ID_CACHE_KILL = 0x0010,
+
+ /* Changes to smb.conf are really of general interest */
+ MSG_SMB_CONF_UPDATED = 0x0021,
+ MSG_RELOAD_TLS_CERTIFICATES = 0x0022,
+
+ MSG_PREFORK_CHILD_EVENT = 0x0031,
+ MSG_PREFORK_PARENT_EVENT = 0x0032,
+
+ MSG_REQ_RINGBUF_LOG = 0x0033,
+ MSG_RINGBUF_LOG = 0x0034,
+
+ MSG_DAEMON_READY_FD = 0x0035,
+
+ /* nmbd messages */
+ MSG_FORCE_ELECTION = 0x0101,
+ MSG_WINS_NEW_ENTRY = 0x0102,
+ MSG_SEND_PACKET = 0x0103,
+
+ /* printing messages */
+ /* MSG_PRINTER_NOTIFY = 0x2001, Obsoleted */
+ MSG_PRINTER_NOTIFY2 = 0x0202,
+ MSG_PRINTER_DRVUPGRADE = 0x0203,
+ MSG_PRINTERDATA_INIT_RESET = 0x0204,
+ MSG_PRINTER_UPDATE = 0x0205,
+ MSG_PRINTER_MOD = 0x0206,
+ MSG_PRINTER_PCAP = 0x0207,
+
+ /* smbd messages */
+ /* MSG_SMB_CONF_UPDATED = 0x0301, Obsoleted */
+ MSG_SMB_FORCE_TDIS = 0x0302,
+ /* MSG_SMB_SAM_SYNC = 0x0303, Obsoleted */
+ /* MSG_SMB_SAM_REPL = 0x0304, Obsoleted */
+ /* MSG_SMB_UNLOCK = 0x0305, Obsoleted */
+ MSG_SMB_BREAK_REQUEST = 0x0306,
+ /* MSG_SMB_BREAK_RESPONSE = 0x0307, Obsoleted */
+ /* MSG_SMB_ASYNC_LEVEL2_BREAK = 0x0308, Obsoleted */
+ /* MSG_SMB_OPEN_RETRY = 0x0309, Obsoleted */
+ MSG_SMB_KERNEL_BREAK = 0x030A,
+ MSG_SMB_FILE_RENAME = 0x030B,
+ MSG_SMB_INJECT_FAULT = 0x030C,
+ MSG_SMB_BLOCKING_LOCK_CANCEL = 0x030D,
+ MSG_SMB_NOTIFY = 0x030E,
+ /* MSG_SMB_STAT_CACHE_DELETE = 0x030F, Obsoleted */
+
+ /* Samba4 compatibility */
+ MSG_PVFS_NOTIFY = 0x0310,
+
+ /* cluster reconfigure events */
+ /* MSG_SMB_BRL_VALIDATE = 0x0311, Oboleted */
+
+ /*Close a specific file given a share entry. */
+ MSG_SMB_CLOSE_FILE = 0x0313,
+
+ /* Trigger a notify cleanup run */
+ MSG_SMB_NOTIFY_CLEANUP = 0x0314,
+ MSG_SMB_SCAVENGER = 0x0315,
+
+ /* shutdown connection for given client */
+ MSG_SMB_KILL_CLIENT_IP = 0x0316,
+
+ /* Tell number of child processes */
+ MSG_SMB_TELL_NUM_CHILDREN = 0x0317,
+ MSG_SMB_NUM_CHILDREN = 0x0318,
+
+ /* Cancel a notify, directory got deleted */
+ MSG_SMB_NOTIFY_CANCEL_DELETED = 0x0319,
+
+ /* notifyd messages */
+ MSG_SMB_NOTIFY_REC_CHANGE = 0x031A,
+ MSG_SMB_NOTIFY_TRIGGER = 0x031B,
+ MSG_SMB_NOTIFY_GET_DB = 0x031C,
+ MSG_SMB_NOTIFY_DB = 0x031D,
+ MSG_SMB_NOTIFY_REC_CHANGES = 0x031E,
+ MSG_SMB_NOTIFY_STARTED = 0x031F,
+ MSG_SMB_SLEEP = 0x0320,
+
+ /* smbd message */
+ MSG_SMB_FORCE_TDIS_DENIED = 0x0321,
+
+ /* winbind messages */
+ MSG_WINBIND_FINISHED = 0x0401,
+ MSG_WINBIND_FORGET_STATE = 0x0402,
+ MSG_WINBIND_ONLINE = 0x0403,
+ MSG_WINBIND_OFFLINE = 0x0404,
+ MSG_WINBIND_ONLINESTATUS = 0x0405,
+
+ MSG_WINBIND_VALIDATE_CACHE = 0x0408,
+ MSG_WINBIND_DUMP_DOMAIN_LIST = 0x0409,
+ MSG_WINBIND_IP_DROPPED = 0x040A,
+ MSG_WINBIND_DOMAIN_ONLINE = 0x040B,
+ MSG_WINBIND_DOMAIN_OFFLINE = 0x040C,
+ MSG_WINBIND_RELOAD_TRUSTED_DOMAINS = 0x040D,
+ MSG_WINBIND_DISCONNECT_DC = 0x040E,
+
+ /* event messages */
+ /* MSG_DUMP_EVENT_LIST = 0x0500, Obsoleted */
+
+ /* smbXsrv messages */
+ MSG_SMBXSRV_SESSION_CLOSE = 0x0600,
+ MSG_SMBXSRV_CONNECTION_PASS = 0x0601,
+ MSG_SMBXSRV_CONNECTION_PASSED = 0x0602,
+ MSG_SMBXSRV_CONNECTION_DROP = 0x0603,
+
+ /* rpcd_witness messages */
+ MSG_RPCD_WITNESS_REGISTRATION_UPDATE = 0x0680,
+
+ /* source4 and NTVFS smb server messages */
+ MSG_BRL_RETRY = 0x0700,
+ MSG_PVFS_RETRY_OPEN = 0x0701,
+ MSG_IRPC = 0x0702,
+ MSG_NTVFS_OPLOCK_BREAK = 0x0703,
+ MSG_DREPL_ALLOCATE_RID = 0x0704,
+
+ /*
+ * Audit, Authentication and Authorisation event
+ * messages
+ */
+ MSG_AUTH_LOG = 0x0800,
+ MSG_DSDB_LOG = 0x0801,
+ MSG_DSDB_PWD_LOG = 0x0802,
+ MSG_GROUP_LOG = 0x0803,
+
+ /* dbwrap messages 4001-4999 (0x0FA0 - 0x1387) */
+ /* MSG_DBWRAP_TDB2_CHANGES = 4001, */
+ /* MSG_DBWRAP_G_LOCK_RETRY = 4002, */
+ MSG_DBWRAP_MODIFIED = 4003,
+
+ MSG_RPC_HOST_NEW_CLIENT = 4004,
+ MSG_RPC_WORKER_STATUS = 4005,
+ MSG_RPC_DUMP_STATUS = 4006,
+
+ /*
+ * source4 allows new messages to be registered at
+ * runtime (currently used in python bindings and in
+ * smbtorture). Temporary messaging endpoints are
+ * allocated above this line
+ */
+ MSG_TMP_BASE = 0xF000
+ } messaging_type;
+
+ /* messaging struct sent across the sockets and stored in the tdb */
+
+ typedef [public] struct {
+ [skip] messaging_rec *prev;
+ [skip] messaging_rec *next;
+ uint32 msg_version;
+ messaging_type msg_type;
+ server_id dest;
+ server_id src;
+ DATA_BLOB buf;
+ uint8 num_fds;
+ dlong fds[num_fds];
+ } messaging_rec;
+
+ typedef [public] struct {
+ hyper rec_index;
+ uint32 num_recs;
+ messaging_rec *recs[num_recs];
+ } messaging_reclog;
+
+ /* This allows this well known service name to be referenced in python and C */
+ const string AUTH_EVENT_NAME = "auth_event";
+ const string DSDB_EVENT_NAME = "dsdb_event";
+ const string DSDB_PWD_EVENT_NAME = "dsdb_password_event";
+ const string DSDB_GROUP_EVENT_NAME = "dsdb_group_event";
+}
diff --git a/librpc/idl/mgmt.idl b/librpc/idl/mgmt.idl
new file mode 100644
index 0000000..376fa6d
--- /dev/null
+++ b/librpc/idl/mgmt.idl
@@ -0,0 +1,75 @@
+/*
+ dcerpc remote management interface
+*/
+
+import "misc.idl";
+
+[
+ uuid("afa8bd80-7d8a-11c9-bef4-08002b102989"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("DCE/RPC Remote Management")
+]
+interface mgmt
+{
+ typedef struct {
+ ndr_syntax_id *id;
+ } ndr_syntax_id_p;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] ndr_syntax_id_p if_id[*];
+ } rpc_if_id_vector_t;
+
+
+ /***********************/
+ /* Function 0x00 */
+ WERROR mgmt_inq_if_ids (
+ [out] rpc_if_id_vector_t **if_id_vector
+ );
+
+
+
+ /***********************/
+ /* Function 0x01 */
+
+
+ /* these are the array indexes in the statistics array */
+ const int MGMT_STATS_CALLS_IN = 0;
+ const int MGMT_STATS_CALLS_OUT = 1;
+ const int MGMT_STATS_PKTS_IN = 2;
+ const int MGMT_STATS_PKTS_OUT = 3;
+ const int MGMT_STATS_ARRAY_MAX_SIZE = 4;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] uint32 statistics[*];
+ } mgmt_statistics;
+
+ WERROR mgmt_inq_stats (
+ [in] uint32 max_count,
+ [in] uint32 unknown,
+ [out,ref] mgmt_statistics *statistics
+ );
+
+
+ /***********************/
+ /* Function 0x02 */
+ boolean32 mgmt_is_server_listening (
+ [out,ref] error_status_t *status
+ );
+
+
+ /***********************/
+ /* Function 0x03 */
+ WERROR mgmt_stop_server_listening ();
+
+
+ /***********************/
+ /* Function 0x04 */
+ WERROR mgmt_inq_princ_name (
+ [in] uint32 authn_proto,
+ [in] uint32 princ_name_size,
+ [out] [string,size_is(princ_name_size),charset(DOS)] uint8 princ_name[]
+ );
+}
diff --git a/librpc/idl/misc.idl b/librpc/idl/misc.idl
new file mode 100644
index 0000000..a705b53
--- /dev/null
+++ b/librpc/idl/misc.idl
@@ -0,0 +1,149 @@
+#include "idl_types.h"
+
+/*
+ miscellaneous IDL structures
+*/
+
+
+[
+ pyhelper("librpc/ndr/py_misc.c"),
+ pointer_default(unique)
+]
+interface misc
+{
+ /*
+ * While structures are not normally known by their order,
+ * please keep this as the first struct, we use this for a
+ * test of 'ndrdump misc 0 struct' (this helps debug failures
+ * from our NDR fuzzing tool, which doesn't use string names)
+ */
+ typedef [public,noprint,gensize] struct {
+ uint32 time_low;
+ uint16 time_mid;
+ uint16 time_hi_and_version;
+ uint8 clock_seq[2];
+ uint8 node[6];
+ } GUID;
+
+ typedef [public] struct {
+ GUID uuid;
+ /* The major version is encoded in the 16 least significant bits,
+ the minor in the 16 most significant bits.
+ http://www.opengroup.org/onlinepubs/9629399/chap12.htm */
+ uint32 if_version;
+ } ndr_syntax_id;
+
+ typedef [public] struct {
+ uint32 handle_type;
+ GUID uuid;
+ } policy_handle;
+
+ /* secure channel types */
+ /* Only SEC_CHAN_WKSTA can forward requests to other domains. */
+
+ typedef [public] enum {
+ SEC_CHAN_NULL = 0,
+ SEC_CHAN_LOCAL = 1,
+ SEC_CHAN_WKSTA = 2,
+ SEC_CHAN_DNS_DOMAIN = 3,
+ SEC_CHAN_DOMAIN = 4,
+ SEC_CHAN_LANMAN = 5,
+ SEC_CHAN_BDC = 6,
+ SEC_CHAN_RODC = 7
+ } netr_SchannelType;
+
+ typedef [public] struct {
+ NTSTATUS ntstatus;
+ uint32 unknown1;
+ uint32 unknown2; /* 0x00000001 */
+ } KRB5_EDATA_NTSTATUS;
+
+ typedef [public,v1_enum] enum {
+ REG_NONE = 0,
+ REG_SZ = 1,
+ REG_EXPAND_SZ = 2,
+ REG_BINARY = 3,
+ REG_DWORD = 4,
+ REG_DWORD_BIG_ENDIAN = 5,
+ REG_LINK = 6,
+ REG_MULTI_SZ = 7,
+ REG_RESOURCE_LIST = 8,
+ REG_FULL_RESOURCE_DESCRIPTOR = 9,
+ REG_RESOURCE_REQUIREMENTS_LIST = 10,
+ REG_QWORD = 11
+ } winreg_Type;
+
+ typedef [nodiscriminant,public,flag(NDR_LITTLE_ENDIAN)] union {
+ [case(REG_NONE)];
+ [case(REG_SZ)] nstring string;
+ [case(REG_EXPAND_SZ)] nstring string;
+ [case(REG_BINARY),flag(NDR_REMAINING)] DATA_BLOB binary;
+ [case(REG_DWORD)] uint32 value;
+ [case(REG_DWORD_BIG_ENDIAN),flag(NDR_BIG_ENDIAN)] uint32 value;
+ [case(REG_MULTI_SZ)] nstring_array string_array;
+ [case(REG_QWORD)] hyper qword;
+ [default,flag(NDR_REMAINING)] DATA_BLOB data;
+ } winreg_Data;
+
+ /*
+ * We duplicate the above winreg_Data for usage in the GPO python
+ * parsers which cannot handle nstring_array. This should be only
+ * temporary, until we can get PIDL to generate the correct bindings.
+ */
+ typedef [nodiscriminant,public,flag(NDR_LITTLE_ENDIAN),gensize] union {
+ [case(REG_NONE)];
+ [case(REG_SZ)] nstring string;
+ [case(REG_EXPAND_SZ)] nstring string;
+ [case(REG_BINARY),flag(NDR_REMAINING)] DATA_BLOB binary;
+ [case(REG_DWORD)] uint32 value;
+ [case(REG_DWORD_BIG_ENDIAN),flag(NDR_BIG_ENDIAN)] uint32 value;
+ /*
+ * There are no python handlers for nstring_array.
+ * Prefer a fallback to DATA_BLOB instead.
+ *
+ * [case(REG_MULTI_SZ)] nstring_array string_array;
+ */
+ [case(REG_QWORD)] hyper qword;
+ [default,flag(NDR_REMAINING)] DATA_BLOB data;
+ } winreg_Data_GPO;
+
+ /* SAM database types */
+ typedef [public,v1_enum] enum {
+ SAM_DATABASE_DOMAIN = 0, /* Domain users and groups */
+ SAM_DATABASE_BUILTIN = 1, /* BUILTIN users and groups */
+ SAM_DATABASE_PRIVS = 2 /* Privileges */
+ } netr_SamDatabaseID;
+
+ typedef [public,bitmap32bit] bitmap {
+ SV_TYPE_WORKSTATION = 0x00000001,
+ SV_TYPE_SERVER = 0x00000002,
+ SV_TYPE_SQLSERVER = 0x00000004,
+ SV_TYPE_DOMAIN_CTRL = 0x00000008,
+ SV_TYPE_DOMAIN_BAKCTRL = 0x00000010,
+ SV_TYPE_TIME_SOURCE = 0x00000020,
+ SV_TYPE_AFP = 0x00000040,
+ SV_TYPE_NOVELL = 0x00000080,
+
+ SV_TYPE_DOMAIN_MEMBER = 0x00000100,
+ SV_TYPE_PRINTQ_SERVER = 0x00000200,
+ SV_TYPE_DIALIN_SERVER = 0x00000400,
+ SV_TYPE_SERVER_UNIX = 0x00000800,
+ SV_TYPE_NT = 0x00001000,
+ SV_TYPE_WFW = 0x00002000,
+ SV_TYPE_SERVER_MFPN = 0x00004000,
+ SV_TYPE_SERVER_NT = 0x00008000,
+ SV_TYPE_POTENTIAL_BROWSER = 0x00010000,
+ SV_TYPE_BACKUP_BROWSER = 0x00020000,
+ SV_TYPE_MASTER_BROWSER = 0x00040000,
+ SV_TYPE_DOMAIN_MASTER = 0x00080000,
+ SV_TYPE_SERVER_OSF = 0x00100000,
+ SV_TYPE_SERVER_VMS = 0x00200000,
+ SV_TYPE_WIN95_PLUS = 0x00400000,
+ SV_TYPE_DFS_SERVER = 0x00800000,
+ SV_TYPE_ALTERNATE_XPORT = 0x20000000,
+ SV_TYPE_LOCAL_LIST_ONLY = 0x40000000,
+ SV_TYPE_DOMAIN_ENUM = 0x80000000
+ } svcctl_ServerType;
+
+ const uint32 SV_TYPE_ALL = 0xFFFFFFFF;
+}
diff --git a/librpc/idl/msgsvc.idl b/librpc/idl/msgsvc.idl
new file mode 100644
index 0000000..d196daf
--- /dev/null
+++ b/librpc/idl/msgsvc.idl
@@ -0,0 +1,22 @@
+/* Works over UDP */
+
+[
+ uuid("17fdd703-1827-4e34-79d4-24a55c53bb37"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Messaging Service")
+] interface msgsvc
+{
+ [todo] void NetrMessageNameAdd();
+ [todo] void NetrMessageNameEnum();
+ [todo] void NetrMessageNameGetInfo();
+ [todo] void NetrMessageNameDel();
+}
+
+[
+ uuid("5a7b91f8-ff00-11d0-a9b2-00c04fb6e6fc"),
+ version(1.0)
+] interface msgsvcsend
+{
+ [todo] void NetrSendMessage();
+}
diff --git a/librpc/idl/named_pipe_auth.idl b/librpc/idl/named_pipe_auth.idl
new file mode 100644
index 0000000..807a312
--- /dev/null
+++ b/librpc/idl/named_pipe_auth.idl
@@ -0,0 +1,58 @@
+#include "idl_types.h"
+/*
+ miscellaneous IDL structures
+*/
+
+import "netlogon.idl", "security.idl", "auth.idl";
+
+[
+ pointer_default(unique)
+]
+interface named_pipe_auth
+{
+ const char *NAMED_PIPE_AUTH_MAGIC = "NPAM";
+
+ typedef [public] struct {
+ uint8 transport;
+ [charset(UTF8),string] uint8 *remote_client_name;
+ [charset(DOS),string] uint8 *remote_client_addr;
+ uint16 remote_client_port;
+ [charset(UTF8),string] uint8 *local_server_name;
+ [charset(DOS),string] uint8 *local_server_addr;
+ uint16 local_server_port;
+ auth_session_info_transport *session_info;
+ } named_pipe_auth_req_info8;
+
+ typedef [switch_type(uint32)] union {
+ [case(8)] named_pipe_auth_req_info8 info8;
+ } named_pipe_auth_req_info;
+
+ typedef [public,gensize] struct {
+ [flag(NDR_BIG_ENDIAN),
+ value(ndr_size_named_pipe_auth_req(r,ndr->flags)-4)]
+ uint32 length;
+ [charset(DOS),value(NAMED_PIPE_AUTH_MAGIC)] uint8 magic[4];
+ uint32 level;
+ [switch_is(level)] named_pipe_auth_req_info info;
+ } named_pipe_auth_req;
+
+ typedef struct {
+ uint16 file_type;
+ uint16 device_state;
+ hyper allocation_size;
+ } named_pipe_auth_rep_info8;
+
+ typedef [switch_type(uint32)] union {
+ [case(8)] named_pipe_auth_rep_info8 info8;
+ } named_pipe_auth_rep_info;
+
+ typedef [public,gensize] struct {
+ [flag(NDR_BIG_ENDIAN),
+ value(ndr_size_named_pipe_auth_rep(r,ndr->flags)-4)]
+ uint32 length;
+ [charset(DOS),value(NAMED_PIPE_AUTH_MAGIC)] uint8 magic[4];
+ uint32 level;
+ [switch_is(level)] named_pipe_auth_rep_info info;
+ NTSTATUS status;
+ } named_pipe_auth_rep;
+}
diff --git a/librpc/idl/nbt.idl b/librpc/idl/nbt.idl
new file mode 100644
index 0000000..46be2ea
--- /dev/null
+++ b/librpc/idl/nbt.idl
@@ -0,0 +1,689 @@
+#include "idl_types.h"
+
+/*
+ IDL structures for NBT operations
+
+ NBT is not traditionally encoded using IDL/NDR. This is a bit of an
+ experiment, and I may well switch us back to a more traditional
+ encoding if it doesn't work out
+*/
+
+import "misc.idl", "security.idl";
+[
+ helper("../librpc/ndr/ndr_nbt.h"),
+ helpstring("NBT messages"),
+ uuid("6def41b6-86e4-4c32-997c-ed33af7bcd8e")
+]
+interface nbt
+{
+ const int NBT_NAME_SERVICE_PORT = 137;
+ const int NBT_DGRAM_SERVICE_PORT = 138;
+
+ typedef [bitmap16bit] bitmap {
+ NBT_RCODE = 0x000F,
+ NBT_FLAG_BROADCAST = 0x0010,
+ NBT_FLAG_RECURSION_AVAIL = 0x0080,
+ NBT_FLAG_RECURSION_DESIRED = 0x0100,
+ NBT_FLAG_TRUNCATION = 0x0200,
+ NBT_FLAG_AUTHORITATIVE = 0x0400,
+ NBT_OPCODE = 0x7800,
+ NBT_FLAG_REPLY = 0x8000
+ } nbt_operation;
+
+ /* the opcodes are in the operation field, masked with
+ NBT_OPCODE */
+ typedef enum {
+ NBT_OPCODE_QUERY = (0x0<<11),
+ NBT_OPCODE_REGISTER = (0x5<<11),
+ NBT_OPCODE_RELEASE = (0x6<<11),
+ NBT_OPCODE_WACK = (0x7<<11),
+ NBT_OPCODE_REFRESH = (0x8<<11),
+ NBT_OPCODE_REFRESH2 = (0x9<<11),
+ NBT_OPCODE_MULTI_HOME_REG = (0xf<<11)
+ } nbt_opcode;
+
+ /* rcode values */
+ typedef enum {
+ NBT_RCODE_OK = 0x0,
+ NBT_RCODE_FMT = 0x1,
+ NBT_RCODE_SVR = 0x2,
+ NBT_RCODE_NAM = 0x3,
+ NBT_RCODE_IMP = 0x4,
+ NBT_RCODE_RFS = 0x5,
+ NBT_RCODE_ACT = 0x6,
+ NBT_RCODE_CFT = 0x7
+ } nbt_rcode;
+
+ /* we support any 8bit name type, but by defining the common
+ ones here we get better debug displays */
+ typedef [enum8bit] enum {
+ NBT_NAME_CLIENT = 0x00,
+ NBT_NAME_MS = 0x01,
+ NBT_NAME_USER = 0x03,
+ NBT_NAME_SERVER = 0x20,
+ NBT_NAME_PDC = 0x1B,
+ NBT_NAME_LOGON = 0x1C,
+ NBT_NAME_MASTER = 0x1D,
+ NBT_NAME_BROWSER = 0x1E
+ } nbt_name_type;
+
+ /* the ndr parser for nbt_name is separately defined in
+ nbtname.c (along with the parsers for nbt_string) */
+ typedef [public,nopull,nopush] struct {
+ string name;
+ string scope;
+ nbt_name_type type;
+ } nbt_name;
+
+ typedef [public,enum16bit] enum {
+ NBT_QCLASS_IP = 0x01
+ } nbt_qclass;
+
+ typedef [public,enum16bit,nopush] enum {
+ NBT_QTYPE_ADDRESS = 0x0001,
+ NBT_QTYPE_NAMESERVICE = 0x0002,
+ NBT_QTYPE_NULL = 0x000A,
+ NBT_QTYPE_NETBIOS = 0x0020,
+ NBT_QTYPE_STATUS = 0x0021,
+ /*
+ * Indicates that this is a WACK packet. As long as the size of
+ * ‘int’ is larger than 16 bits, this value cannot appear on the
+ * wire. We’ll encode it instead as NBT_QTYPE_NETBIOS.
+ */
+ NBT_QTYPE_WACK = -1
+ } nbt_qtype;
+
+ typedef struct {
+ nbt_name name;
+ nbt_qtype question_type;
+ nbt_qclass question_class;
+ } nbt_name_question;
+
+ /* these are the possible values of the NBT_NM_OWNER_TYPE
+ field */
+ typedef enum {
+ NBT_NODE_B = 0x0000,
+ NBT_NODE_P = 0x2000,
+ NBT_NODE_M = 0x4000,
+ NBT_NODE_H = 0x6000
+ } nbt_node_type;
+
+ typedef [bitmap16bit] bitmap {
+ NBT_NM_PERMANENT = 0x0200,
+ NBT_NM_ACTIVE = 0x0400,
+ NBT_NM_CONFLICT = 0x0800,
+ NBT_NM_DEREGISTER = 0x1000,
+ NBT_NM_OWNER_TYPE = 0x6000,
+ NBT_NM_GROUP = 0x8000
+ } nb_flags;
+
+ typedef struct {
+ nb_flags nb_flags;
+ ipv4address ipaddr;
+ } nbt_rdata_address;
+
+ typedef struct {
+ uint16 length;
+ nbt_rdata_address addresses[length/6];
+ } nbt_rdata_netbios;
+
+ typedef struct {
+ uint8 unit_id[6];
+ uint8 jumpers;
+ uint8 test_result;
+ uint16 version_number;
+ uint16 period_of_statistics;
+ uint16 number_of_crcs;
+ uint16 number_alignment_errors;
+ uint16 number_of_collisions;
+ uint16 number_send_aborts;
+ uint32 number_good_sends;
+ uint32 number_good_receives;
+ uint16 number_retransmits;
+ uint16 number_no_resource_conditions;
+ uint16 number_free_command_blocks;
+ uint16 total_number_command_blocks;
+ uint16 max_total_number_command_blocks;
+ uint16 number_pending_sessions;
+ uint16 max_number_pending_sessions;
+ uint16 max_total_sessions_possible;
+ uint16 session_data_packet_size;
+ } nbt_statistics;
+
+ typedef struct {
+ [charset(DOS)] uint8 name[15];
+ nbt_name_type type;
+ nb_flags nb_flags;
+ } nbt_status_name;
+
+ typedef struct {
+ [value(num_names * 18 + 47)] uint16 length;
+ uint8 num_names;
+ nbt_status_name names[num_names];
+ nbt_statistics statistics;
+ } nbt_rdata_status;
+
+ typedef struct {
+ uint16 length;
+ uint8 data[length];
+ } nbt_rdata_data;
+
+ typedef [nodiscriminant,public] union {
+ [case(NBT_QTYPE_NETBIOS)] nbt_rdata_netbios netbios;
+ [case(NBT_QTYPE_STATUS)] nbt_rdata_status status;
+ [default] nbt_rdata_data data;
+ } nbt_rdata;
+
+ typedef [flag(LIBNDR_PRINT_ARRAY_HEX)] struct {
+ nbt_name name;
+ nbt_qtype rr_type;
+ nbt_qclass rr_class;
+ uint32 ttl;
+ [switch_is(rr_type)] nbt_rdata rdata;
+ } nbt_res_rec;
+
+ typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ uint16 name_trn_id;
+ nbt_operation operation;
+ uint16 qdcount;
+ uint16 ancount;
+ uint16 nscount;
+ uint16 arcount;
+ nbt_name_question questions[qdcount];
+ nbt_res_rec answers[ancount];
+ nbt_res_rec nsrecs[nscount];
+ nbt_res_rec additional[arcount];
+ [flag(NDR_REMAINING)] DATA_BLOB padding;
+ } nbt_name_packet;
+
+
+ /*
+ NBT DGRAM packets (UDP/138)
+ */
+
+ typedef [enum8bit] enum {
+ DGRAM_DIRECT_UNIQUE = 0x10,
+ DGRAM_DIRECT_GROUP = 0x11,
+ DGRAM_BCAST = 0x12,
+ DGRAM_ERROR = 0x13,
+ DGRAM_QUERY = 0x14,
+ DGRAM_QUERY_POSITIVE = 0x15,
+ DGRAM_QUERY_NEGATIVE = 0x16
+ } dgram_msg_type;
+
+ typedef [bitmap8bit] bitmap {
+ DGRAM_FLAG_MORE = 0x01,
+ DGRAM_FLAG_FIRST = 0x02,
+ DGRAM_FLAG_NODE_TYPE = 0x0C
+ } dgram_flags;
+
+ typedef [enum8bit] enum {
+ DGRAM_NODE_B = 0x00,
+ DGRAM_NODE_P = 0x04,
+ DGRAM_NODE_M = 0x08,
+ DGRAM_NODE_NBDD = 0x0C
+ } dgram_node_type;
+
+ /* a dgram_message is the main dgram body in general use */
+
+ /* the most common datagram type is a SMB_TRANSACTION
+ operation, where a SMB packet is used in the data section
+ of a dgram_message to hold a trans request, which in turn
+ holds a small command structure. It's a very strange beast
+ indeed. To make the code cleaner we define a basic SMB
+ packet in IDL here. This is not a general purpose SMB
+ packet, and won't be used in the core SMB client/server
+ code, but it does make working with these types of dgrams
+ easier */
+
+ const string NBT_MAILSLOT_NETLOGON = "\\MAILSLOT\\NET\\NETLOGON";
+ const string NBT_MAILSLOT_NTLOGON = "\\MAILSLOT\\NET\\NTLOGON";
+ const string NBT_MAILSLOT_GETDC = "\\MAILSLOT\\NET\\GETDC";
+ const string NBT_MAILSLOT_BROWSE = "\\MAILSLOT\\BROWSE";
+
+ typedef [enum8bit] enum {
+ SMB_TRANSACTION = 0x25
+ } smb_command;
+
+ typedef struct {
+ [range(17,17),value(17)] uint8 wct;
+ uint16 total_param_count;
+ uint16 total_data_count;
+ uint16 max_param_count;
+ uint16 max_data_count;
+ uint8 max_setup_count;
+ uint8 pad;
+ uint16 trans_flags;
+ uint32 timeout;
+ uint16 reserved;
+ uint16 param_count;
+ uint16 param_offset;
+ uint16 data_count;
+ uint16 data_offset;
+ [range(3,3),value(3)] uint8 setup_count;
+ uint8 pad2;
+ uint16 opcode;
+ uint16 priority;
+ uint16 _class;
+ [value(strlen(mailslot_name)+1+data.length)]
+ uint16 byte_count;
+ astring mailslot_name;
+ [flag(NDR_REMAINING)] DATA_BLOB data;
+ } smb_trans_body;
+
+ typedef [nodiscriminant] union {
+ [case(SMB_TRANSACTION)] smb_trans_body trans;
+ } smb_body;
+
+
+ typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN|NDR_PAHEX),public] struct {
+ smb_command smb_command;
+ uint8 err_class;
+ uint8 pad;
+ uint16 err_code;
+ uint8 flags;
+ uint16 flags2;
+ uint16 pid_high;
+ uint8 signature[8];
+ uint16 reserved;
+ uint16 tid;
+ uint16 pid;
+ uint16 vuid;
+ uint16 mid;
+ [switch_is(smb_command)] smb_body body;
+ } dgram_smb_packet;
+
+ const uint32 DGRAM_SMB = 0xff534d42; /* 0xffSMB */
+
+ typedef [nodiscriminant] union {
+ [case(DGRAM_SMB)] dgram_smb_packet smb;
+ } dgram_message_body;
+
+ typedef struct {
+ uint16 length;
+ uint16 offset;
+ nbt_name source_name;
+ nbt_name dest_name;
+ uint32 dgram_body_type;
+ [switch_is(dgram_body_type)] dgram_message_body body;
+ } dgram_message;
+
+ typedef [enum8bit] enum {
+ DGRAM_ERROR_NAME_NOT_PRESENT = 0x82,
+ DGRAM_ERROR_INVALID_SOURCE = 0x83,
+ DGRAM_ERROR_INVALID_DEST = 0x84
+ } dgram_err_code;
+
+ typedef [nodiscriminant] union {
+ [case(DGRAM_DIRECT_UNIQUE)] dgram_message msg;
+ [case(DGRAM_DIRECT_GROUP)] dgram_message msg;
+ [case(DGRAM_BCAST)] dgram_message msg;
+ [case(DGRAM_ERROR)] dgram_err_code error;
+ [case(DGRAM_QUERY)] nbt_name dest_name;
+ [case(DGRAM_QUERY_POSITIVE)] nbt_name dest_name;
+ [case(DGRAM_QUERY_NEGATIVE)] nbt_name dest_name;
+ } dgram_data;
+
+ typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct {
+ dgram_msg_type msg_type;
+ dgram_flags flags;
+ uint16 dgram_id;
+ ipv4address src_addr;
+ uint16 src_port;
+ [switch_is(msg_type)] dgram_data data;
+ } nbt_dgram_packet;
+
+
+ /******************************************
+ * \MAILSLOT\NET\NETLOGON mailslot requests
+ * and
+ * \MAILSLOT\NET\NTLOGON mailslot requests
+ */
+
+ typedef [public,gensize] struct {
+ uint32 sockaddr_family;
+ [flag(NDR_BIG_ENDIAN)] ipv4address pdc_ip;
+ [flag(NDR_REMAINING)] DATA_BLOB remaining;
+ } nbt_sockaddr;
+
+ typedef [bitmap32bit,public] bitmap {
+ NBT_SERVER_PDC = 0x00000001,
+ NBT_SERVER_GC = 0x00000004,
+ NBT_SERVER_LDAP = 0x00000008,
+ NBT_SERVER_DS = 0x00000010,
+ NBT_SERVER_KDC = 0x00000020,
+ NBT_SERVER_TIMESERV = 0x00000040,
+ NBT_SERVER_CLOSEST = 0x00000080,
+ NBT_SERVER_WRITABLE = 0x00000100,
+ NBT_SERVER_GOOD_TIMESERV = 0x00000200,
+ NBT_SERVER_NDNC = 0x00000400,
+ NBT_SERVER_SELECT_SECRET_DOMAIN_6 = 0x00000800, /* 2008 / RODC */
+ NBT_SERVER_FULL_SECRET_DOMAIN_6 = 0x00001000, /* 2008 */
+ NBT_SERVER_ADS_WEB_SERVICE = 0x00002000,
+ NBT_SERVER_DS_8 = 0x00004000, /* 2012 */
+ NBT_SERVER_DS_9 = 0x00008000, /* 2012R2 */
+ NBT_SERVER_DS_10 = 0x00010000, /* 2016 */
+ NBT_SERVER_HAS_DNS_NAME = 0x20000000,
+ NBT_SERVER_IS_DEFAULT_NC = 0x40000000,
+ NBT_SERVER_FOREST_ROOT = 0x80000000
+ } nbt_server_type;
+
+ typedef [bitmap32bit,public] bitmap {
+ NETLOGON_NT_VERSION_1 = 0x00000001,
+ NETLOGON_NT_VERSION_5 = 0x00000002,
+ NETLOGON_NT_VERSION_5EX = 0x00000004,
+ NETLOGON_NT_VERSION_5EX_WITH_IP = 0x00000008,
+ NETLOGON_NT_VERSION_WITH_CLOSEST_SITE = 0x00000010,
+ NETLOGON_NT_VERSION_AVOID_NT4EMUL = 0x01000000,
+ NETLOGON_NT_VERSION_PDC = 0x10000000,
+ NETLOGON_NT_VERSION_IP = 0x20000000,
+ NETLOGON_NT_VERSION_LOCAL = 0x40000000,
+ NETLOGON_NT_VERSION_GC = 0x80000000
+ } netlogon_nt_version_flags;
+
+ typedef [enum16bit,public] enum {
+ LOGON_REQUEST = 0,
+ LOGON_RESPONSE2 = 6,
+ LOGON_PRIMARY_QUERY = 7, /* Was also NETLOGON_QUERY_FOR_PDC */
+ NETLOGON_ANNOUNCE_UAS = 10,
+ NETLOGON_RESPONSE_FROM_PDC = 12,
+ LOGON_SAM_LOGON_REQUEST = 18, /* Was also NETLOGON_QUERY_FOR_PDC2, NTLOGON_SAM_LOGON */
+ LOGON_SAM_LOGON_RESPONSE = 19, /* Was also NTLOGON_SAM_LOGON_REPLY */
+ LOGON_SAM_LOGON_PAUSE_RESPONSE = 20,
+ LOGON_SAM_LOGON_USER_UNKNOWN = 21, /* Was also NTLOGON_SAM_LOGON_REPLY15 */
+ LOGON_SAM_LOGON_RESPONSE_EX = 23, /* was NETLOGON_RESPONSE_FROM_PDC2 */
+ LOGON_SAM_LOGON_PAUSE_RESPONSE_EX = 24,
+ LOGON_SAM_LOGON_USER_UNKNOWN_EX = 25 /* was NETLOGON_RESPONSE_FROM_PDC_USER */
+ } netlogon_command;
+
+ /* query to dc hand marshaled, as it has 'optional'
+ * parts */
+ typedef [nopull,nopush] struct {
+ uint16 request_count;
+ nstring computer_name;
+ nstring user_name;
+ astring mailslot_name;
+ uint32 acct_control;
+ /* samr_AcctFlags acct_control; */
+ [value(ndr_size_dom_sid0(&sid, ndr->flags))] uint32 sid_size;
+ /* The manual alignment is required because this
+ * structure is marked flag(NDR_NOALIGN) via the
+ * nbt_netlogon_packet below.
+ *
+ * However, both MUST only be present if sid_size > 0
+ */
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad;
+ [subcontext(0),subcontext_size(sid_size)] dom_sid0 sid;
+ netlogon_nt_version_flags nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } NETLOGON_SAM_LOGON_REQUEST;
+
+ typedef struct {
+ astring computer_name;
+ astring user_name;
+ astring mailslot_name;
+ uint8 request_count;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } NETLOGON_LOGON_REQUEST;
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ netlogon_command command;
+ nstring pdc_name;
+ nstring user_name;
+ nstring domain_name;
+ netlogon_nt_version_flags nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } NETLOGON_SAM_LOGON_RESPONSE_NT40;
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ netlogon_command command;
+ nstring pdc_name;
+ nstring user_name;
+ nstring domain_name;
+ GUID domain_uuid;
+ GUID zero_uuid;
+ nbt_string forest;
+ nbt_string dns_domain;
+ nbt_string pdc_dns_name;
+ ipv4address pdc_ip;
+ nbt_server_type server_type;
+ netlogon_nt_version_flags nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } NETLOGON_SAM_LOGON_RESPONSE;
+
+ /* response from pdc hand marshaled (we have an additional
+ * function that uses this structure), as it has 'optional'
+ * parts */
+ typedef [flag(NDR_NOALIGN),public] struct {
+ netlogon_command command;
+ uint16 sbz; /* From the docs */
+ nbt_server_type server_type;
+ GUID domain_uuid;
+ nbt_string forest;
+ nbt_string dns_domain;
+ nbt_string pdc_dns_name;
+ nbt_string domain_name;
+ nbt_string pdc_name;
+ nbt_string user_name;
+ nbt_string server_site;
+ nbt_string client_site;
+
+ /* Optional on NETLOGON_NT_VERSION_5EX_WITH_IP */
+ [value(ndr_size_nbt_sockaddr(&sockaddr, ndr->flags))] uint8 sockaddr_size;
+ [subcontext(0),subcontext_size(sockaddr_size)] nbt_sockaddr sockaddr;
+
+ /* Optional on NETLOGON_NT_VERSION_WITH_CLOSEST_SITE */
+ nbt_string next_closest_site;
+
+ netlogon_nt_version_flags nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } NETLOGON_SAM_LOGON_RESPONSE_EX;
+
+ typedef [nopush,nopull] union {
+ [case(NETLOGON_NT_VERSION_1)] NETLOGON_SAM_LOGON_RESPONSE_NT40 nt4;
+ [case(NETLOGON_NT_VERSION_5)] NETLOGON_SAM_LOGON_RESPONSE nt5;
+ [case(NETLOGON_NT_VERSION_5EX)] NETLOGON_SAM_LOGON_RESPONSE_EX nt5_ex;
+ } netlogon_samlogon_response_union;
+
+ typedef [nopush,nopull,noprint,public] struct {
+ uint32 ntver;
+ [switch_is(ntver)] netlogon_samlogon_response_union data;
+ } netlogon_samlogon_response;
+
+ /* query for pdc request */
+ typedef struct {
+ astring computer_name;
+ astring mailslot_name;
+ [flag(NDR_ALIGN2)] DATA_BLOB _pad;
+ nstring unicode_name;
+ netlogon_nt_version_flags nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_netlogon_query_for_pdc;
+
+ /* response from pdc */
+ typedef [public] struct {
+ netlogon_command command;
+ astring pdc_name;
+ [flag(NDR_ALIGN2)] DATA_BLOB _pad;
+ nstring unicode_pdc_name;
+ nstring domain_name;
+ netlogon_nt_version_flags nt_version;
+ uint16 lmnt_token;
+ uint16 lm20_token;
+ } nbt_netlogon_response_from_pdc;
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ netlogon_command command;
+ astring pdc_name;
+ uint16 lm20_token;
+ } nbt_netlogon_response2;
+
+ /* used to announce SAM changes - MS-NRPC 2.2.1.5.1 */
+ typedef struct {
+ netr_SamDatabaseID db_index;
+ hyper serial;
+ NTTIME timestamp;
+ } nbt_db_change_info;
+
+ typedef struct {
+ uint32 serial_lo;
+ time_t timestamp;
+ uint32 pulse;
+ uint32 random;
+ astring pdc_name;
+ astring domain;
+ [flag(NDR_ALIGN2)] DATA_BLOB _pad;
+ nstring unicode_pdc_name;
+ nstring unicode_domain;
+ uint32 db_count;
+ nbt_db_change_info dbchange[db_count];
+ [value(ndr_size_dom_sid0(&sid, ndr->flags))] uint32 sid_size;
+ [subcontext(0),subcontext_size(sid_size)] dom_sid0 sid;
+ uint32 message_format_version;
+ uint32 message_token;
+ } NETLOGON_DB_CHANGE;
+
+ typedef [nodiscriminant] union {
+ [case(LOGON_REQUEST)] NETLOGON_LOGON_REQUEST logon0;
+ [case(LOGON_SAM_LOGON_REQUEST)] NETLOGON_SAM_LOGON_REQUEST logon;
+ [case(LOGON_PRIMARY_QUERY)] nbt_netlogon_query_for_pdc pdc;
+ [case(NETLOGON_ANNOUNCE_UAS)] NETLOGON_DB_CHANGE uas;
+ } nbt_netlogon_request;
+
+#if 0
+ /* These responses are all handled manually, as they cannot be encoded in IDL fully
+
+ See push_nbt_netlogon_response()
+ */
+ [case(NETLOGON_RESPONSE_FROM_PDC)] nbt_netlogon_response_from_pdc response;
+ [case(NETLOGON_RESPONSE_FROM_PDC_USER)] nbt_netlogon_response_from_pdc2 response2;
+
+ [case(LOGON_SAM_LOGON_PAUSE_RESPONSE)] NETLOGON_SAM_LOGON_RESPONSE reply;
+ [case(LOGON_SAM_LOGON_RESPONSE)] NETLOGON_SAM_LOGON_RESPONSE reply;
+ [case(LOGON_SAM_LOGON_USER_UNKNOWN)] NETLOGON_SAM_LOGON_RESPONSE reply;
+ [case(LOGON_SAM_LOGON_RESPONSE_EX)] NETLOGON_SAM_LOGON_RESPONSE_EX reply_ex;
+ [case(LOGON_SAM_LOGON_PAUSE_RESPONSE_EX)] NETLOGON_SAM_LOGON_RESPONSE_EX reply_ex;
+ [case(LOGON_SAM_LOGON_USER_UNKNOWN_EX)] NETLOGON_SAM_LOGON_RESPONSE_EX reply_ex;
+#endif
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ netlogon_command command;
+ [switch_is(command)] nbt_netlogon_request req;
+ } nbt_netlogon_packet;
+
+ /********************************************************/
+ /* \MAILSLOT\BROWSE mailslot requests */
+ /* for details see http://ubiqx.org/cifs/Browsing.html */
+ /********************************************************/
+ typedef bitmap svcctl_ServerType svcctl_ServerType;
+
+ typedef [enum8bit] enum {
+ HostAnnouncement = 1,
+ AnnouncementRequest = 2,
+ Election = 8,
+ GetBackupListReq = 9,
+ GetBackupListResp = 10,
+ BecomeBackup = 11,
+ DomainAnnouncement = 12,
+ MasterAnnouncement = 13,
+ ResetBrowserState = 14,
+ LocalMasterAnnouncement = 15
+ } nbt_browse_opcode;
+
+ typedef struct {
+ uint8 UpdateCount;
+ uint32 Periodicity;
+ [charset(DOS)] uint8 ServerName[16];
+ uint8 OSMajor;
+ uint8 OSMinor;
+ svcctl_ServerType ServerType;
+ uint8 BroMajorVer;
+ uint8 BroMinorVer;
+ uint16 Signature;
+ astring Comment;
+ } nbt_browse_host_announcement;
+
+ typedef struct {
+ uint8 Unused;
+ astring ResponseName;
+ } nbt_browse_announcement_request;
+
+ typedef struct {
+ uint8 Version;
+ uint32 Criteria;
+ uint32 UpTime; /* In milliseconds */
+ uint32 Reserved; /* Must be zero */
+ astring ServerName;
+ } nbt_browse_election_request;
+
+ typedef struct {
+ uint8 ReqCount;
+ uint32 Token;
+ } nbt_browse_backup_list_request;
+
+ typedef struct {
+ uint8 BackupCount;
+ uint32 Token;
+ nbt_name BackupServerList[BackupCount];/* TODO: this is wrong */
+ } nbt_browse_backup_list_response;
+
+ typedef struct {
+ astring BrowserName;
+ } nbt_browse_become_backup;
+
+ typedef struct {
+ uint8 UpdateCount;
+ uint32 Periodicity;
+ [charset(DOS)] uint8 ServerName[16];
+ uint8 OSMajor;
+ uint8 OSMinor;
+ svcctl_ServerType ServerType;
+ uint32 MysteriousField;
+ astring Comment;
+ } nbt_browse_domain_announcement;
+
+ typedef struct {
+ astring ServerName;
+ } nbt_browse_master_announcement;
+
+ typedef struct {
+ uint8 Command;
+ } nbt_browse_reset_state;
+
+ typedef struct {
+ uint8 UpdateCount;
+ uint32 Periodicity;
+ [charset(DOS)] uint8 ServerName[16];
+ uint8 OSMajor;
+ uint8 OSMinor;
+ svcctl_ServerType ServerType;
+ uint8 BroMajorVer;
+ uint8 BroMinorVer;
+ uint16 Signature;
+ astring Comment;
+ } nbt_browse_local_master_announcement;
+
+ typedef [nodiscriminant] union {
+ [case(HostAnnouncement)] nbt_browse_host_announcement host_annoucement;
+ [case(AnnouncementRequest)] nbt_browse_announcement_request announcement_request;
+ [case(Election)] nbt_browse_election_request election_request;
+ [case(GetBackupListReq)] nbt_browse_backup_list_request backup_list_request;
+ [case(GetBackupListResp)] nbt_browse_backup_list_response backup_list_response;
+ [case(BecomeBackup)] nbt_browse_become_backup become_backup;
+ [case(DomainAnnouncement)] nbt_browse_domain_announcement domain_announcement;
+ [case(MasterAnnouncement)] nbt_browse_master_announcement master_announcement;
+ [case(ResetBrowserState)] nbt_browse_reset_state reset_browser_state;
+ [case(LocalMasterAnnouncement)] nbt_browse_local_master_announcement local_master_announcement;
+ } nbt_browse_payload;
+
+ typedef [public,flag(NDR_NOALIGN)] struct {
+ nbt_browse_opcode opcode;
+ [switch_is(opcode)] nbt_browse_payload payload;
+ } nbt_browse_packet;
+}
diff --git a/librpc/idl/negoex.idl b/librpc/idl/negoex.idl
new file mode 100644
index 0000000..eb3511d
--- /dev/null
+++ b/librpc/idl/negoex.idl
@@ -0,0 +1,152 @@
+#include "idl_types.h"
+
+/*
+ NEGOEX interface definition
+ See http://ietfreport.isoc.org/all-ids/draft-zhu-negoex-04.txt
+*/
+
+import "misc.idl";
+
+[
+ uuid("fcc30ddc-98d0-11e5-8a56-83e9a6706f2f"),
+ helper("../librpc/ndr/ndr_negoex.h"),
+ helpstring("NEGOEX messages")
+]
+interface negoex
+{
+ typedef [nopush,nopull,noprint] struct {
+#if 0
+ [relative,size_is(length)] uint8 *data;
+ uint32 length;
+#else
+ DATA_BLOB blob;
+ /*
+ * internal helper variable */
+ uint32 _length;
+ /*
+ * the dummy pointer is needed in order to let the
+ * callers use NDR_BUFFERS
+ */
+ [relative] uint8 *_dummy;
+#endif
+ } negoex_BYTE_VECTOR;
+
+ typedef [public] struct {
+ GUID guid;
+ } negoex_AUTH_SCHEME;
+
+ typedef [nopush,nopull] struct {
+ [relative,size_is(count)] negoex_AUTH_SCHEME *array;
+ uint32 count;
+ } negoex_AUTH_SCHEME_VECTOR;
+
+ typedef [v1_enum] enum {
+ NEGOEX_EXTENSION_TYPE_TODO = 0 /* TODO */
+ } negoex_ExtensionTypes;
+
+ typedef [public] struct {
+ negoex_ExtensionTypes type;
+ negoex_BYTE_VECTOR value;
+ } negoex_EXTENSION;
+
+ typedef [nopush,nopull] struct {
+ [relative,size_is(count)] negoex_EXTENSION *array;
+ uint32 count;
+ } negoex_EXTENSION_VECTOR;
+
+ typedef [v1_enum] enum {
+ NEGOEX_CHECKSUM_SCHEME_RFC3961 = 1
+ } negoex_ChecksumSchemes;
+
+ typedef struct {
+ [value(20)] uint32 header_length;
+ negoex_ChecksumSchemes scheme;
+ uint32 type;
+ negoex_BYTE_VECTOR value;
+ } negoex_CHECKSUM;
+
+ typedef [v1_enum] enum {
+ NEGOEX_ALERT_VERIFY_NO_KEY = 1
+ } negoex_AlertReason;
+
+ typedef [public] struct {
+ [value(4)] uint32 header_length; /* TODO: is 4 correct? */
+ negoex_AlertReason reason;
+ } negoex_ALERT_PULSE;
+
+ typedef [v1_enum] enum {
+ NEGOEX_ALERT_TYPE_PULSE = 1
+ } negoex_AlertTypes;
+
+ typedef [public] struct {
+ negoex_AlertTypes type;
+ negoex_BYTE_VECTOR value;
+ } negoex_ALERT;
+
+ typedef [nopush,nopull] struct {
+ [relative,size_is(count)] negoex_ALERT *array;
+ uint32 count;
+ } negoex_ALERT_VECTOR;
+
+ typedef [public,v1_enum] enum {
+ NEGOEX_MESSAGE_TYPE_INITIATOR_NEGO = 0,
+ NEGOEX_MESSAGE_TYPE_ACCEPTOR_NEGO = 1,
+ NEGOEX_MESSAGE_TYPE_INITIATOR_META_DATA = 2,
+ NEGOEX_MESSAGE_TYPE_ACCEPTOR_META_DATA = 3,
+ NEGOEX_MESSAGE_TYPE_CHALLENGE = 4,
+ NEGOEX_MESSAGE_TYPE_AP_REQUEST = 5,
+ NEGOEX_MESSAGE_TYPE_VERIFY = 6,
+ NEGOEX_MESSAGE_TYPE_ALERT = 7
+ } negoex_MESSAGE_TYPE;
+
+ const uint32 NEGOEX_PROTOCOL_VERSION_0 = 0;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ [flag(NDR_PAHEX)] uint8 random[32];
+ [value(NEGOEX_PROTOCOL_VERSION_0)] udlong protocol_version;
+ negoex_AUTH_SCHEME_VECTOR auth_schemes;
+ negoex_EXTENSION_VECTOR extensions;
+ } negoex_NEGO_PAYLOAD;
+
+ typedef struct {
+ negoex_AUTH_SCHEME auth_scheme;
+ negoex_BYTE_VECTOR exchange;
+ } negoex_EXCHANGE_PAYLOAD;
+
+ typedef struct {
+ negoex_AUTH_SCHEME auth_scheme;
+ negoex_CHECKSUM checksum;
+ } negoex_VERIFY_PAYLOAD;
+
+ typedef struct {
+ negoex_AUTH_SCHEME auth_scheme;
+ NTSTATUS status;
+ negoex_ALERT_VECTOR alerts;
+ } negoex_ALERT_PAYLOAD;
+
+ typedef [public,nodiscriminant] union {
+ [case(NEGOEX_MESSAGE_TYPE_INITIATOR_NEGO)] negoex_NEGO_PAYLOAD nego;
+ [case(NEGOEX_MESSAGE_TYPE_ACCEPTOR_NEGO)] negoex_NEGO_PAYLOAD nego;
+ [case(NEGOEX_MESSAGE_TYPE_INITIATOR_META_DATA)] negoex_EXCHANGE_PAYLOAD exchange;
+ [case(NEGOEX_MESSAGE_TYPE_ACCEPTOR_META_DATA)] negoex_EXCHANGE_PAYLOAD exchange;
+ [case(NEGOEX_MESSAGE_TYPE_CHALLENGE)] negoex_EXCHANGE_PAYLOAD exchange;
+ [case(NEGOEX_MESSAGE_TYPE_AP_REQUEST)] negoex_EXCHANGE_PAYLOAD exchange;
+ [case(NEGOEX_MESSAGE_TYPE_VERIFY)] negoex_VERIFY_PAYLOAD verify;
+ [case(NEGOEX_MESSAGE_TYPE_ALERT)] negoex_ALERT_PAYLOAD alert;
+ } negoex_PAYLOAD;
+
+ typedef [public,relative_base,gensize,nopull] struct {
+ [charset(DOS),value("NEGOEXTS")] uint8 signature[8];
+ negoex_MESSAGE_TYPE type;
+ uint32 sequence_number;
+ [value(ndr_negoex_MESSAGE_header_length(r))] uint32 header_length;
+ [value(ndr_size_negoex_MESSAGE(r, ndr->flags))] uint32 message_length;
+ GUID conversation_id;
+ [switch_is(type)] negoex_PAYLOAD p;
+ } negoex_MESSAGE;
+
+ typedef [public,nopush,nopull,flag(NDR_NOALIGN)] struct {
+ uint32 count;
+ negoex_MESSAGE messages[count];
+ } negoex_MESSAGE_ARRAY;
+}
diff --git a/librpc/idl/netlogon.idl b/librpc/idl/netlogon.idl
new file mode 100644
index 0000000..383c7b5
--- /dev/null
+++ b/librpc/idl/netlogon.idl
@@ -0,0 +1,1888 @@
+/*
+ netlogon interface
+ much of this was derived from the ethereal sources - thanks to everyone
+ who contributed!
+*/
+
+import "misc.idl", "lsa.idl", "samr.idl", "security.idl", "nbt.idl";
+
+#include "idl_types.h"
+
+cpp_quote("#define netr_DeltaEnum8Bit netr_DeltaEnum")
+cpp_quote("#define netr_SamDatabaseID8Bit netr_SamDatabaseID")
+
+cpp_quote("#define ENC_CRC32 KERB_ENCTYPE_DES_CBC_CRC")
+cpp_quote("#define ENC_RSA_MD5 KERB_ENCTYPE_DES_CBC_MD5")
+cpp_quote("#define ENC_RC4_HMAC_MD5 KERB_ENCTYPE_RC4_HMAC_MD5")
+cpp_quote("#define ENC_HMAC_SHA1_96_AES128 KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96")
+cpp_quote("#define ENC_HMAC_SHA1_96_AES256 KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96")
+cpp_quote("#define ENC_HMAC_SHA1_96_AES256_SK KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK")
+cpp_quote("#define ENC_FAST_SUPPORTED KERB_ENCTYPE_FAST_SUPPORTED")
+cpp_quote("#define ENC_COMPOUND_IDENTITY_SUPPORTED KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED")
+cpp_quote("#define ENC_CLAIMS_SUPPORTED KERB_ENCTYPE_CLAIMS_SUPPORTED")
+cpp_quote("#define ENC_RESOURCE_SID_COMPRESSION_DISABLED KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED")
+cpp_quote("#define NETLOGON_SERVER_PIPE_STATE_MAGIC 0x4f555358")
+
+cpp_quote("#define DS_SERVER_PDC NBT_SERVER_PDC")
+cpp_quote("#define DS_SERVER_GC NBT_SERVER_GC")
+cpp_quote("#define DS_SERVER_LDAP NBT_SERVER_LDAP")
+cpp_quote("#define DS_SERVER_DS NBT_SERVER_DS")
+cpp_quote("#define DS_SERVER_KDC NBT_SERVER_KDC")
+cpp_quote("#define DS_SERVER_TIMESERV NBT_SERVER_TIMESERV")
+cpp_quote("#define DS_SERVER_CLOSEST NBT_SERVER_CLOSEST")
+cpp_quote("#define DS_SERVER_WRITABLE NBT_SERVER_WRITABLE")
+cpp_quote("#define DS_SERVER_GOOD_TIMESERV NBT_SERVER_GOOD_TIMESERV")
+cpp_quote("#define DS_SERVER_NDNC NBT_SERVER_NDNC")
+cpp_quote("#define DS_SERVER_SELECT_SECRET_DOMAIN_6 NBT_SERVER_SELECT_SECRET_DOMAIN_6 /* 2008 / RODC */")
+cpp_quote("#define DS_SERVER_FULL_SECRET_DOMAIN_6 NBT_SERVER_FULL_SECRET_DOMAIN_6 /* 2008 */")
+cpp_quote("#define DS_SERVER_WEBSERV NBT_SERVER_ADS_WEB_SERVICE")
+cpp_quote("#define DS_SERVER_DS_8 NBT_SERVER_DS_8 /* 2012 */")
+cpp_quote("#define DS_SERVER_DS_9 NBT_SERVER_DS_9 /* 2012R2 */")
+cpp_quote("#define DS_SERVER_DS_10 NBT_SERVER_DS_10 /* 2016 */")
+cpp_quote("#define DS_DNS_CONTROLLER NBT_SERVER_HAS_DNS_NAME")
+cpp_quote("#define DS_DNS_DOMAIN NBT_SERVER_IS_DEFAULT_NC")
+cpp_quote("#define DS_DNS_FOREST_ROOT NBT_SERVER_FOREST_ROOT")
+
+[
+ uuid("12345678-1234-abcd-ef00-01234567cffb"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\netlogon]","ncacn_ip_tcp:","ncalrpc:"),
+ helper("../librpc/ndr/ndr_netlogon.h"),
+ ms_union,
+ pointer_default(unique)
+]
+
+interface netlogon
+{
+ typedef bitmap samr_AcctFlags samr_AcctFlags;
+ typedef bitmap security_GroupAttrs security_GroupAttrs;
+ typedef enum netr_DeltaEnum8Bit netr_DeltaEnum8Bit;
+ typedef enum netr_SamDatabaseID8Bit netr_SamDatabaseID8Bit;
+
+ /*****************/
+ /* Function 0x00 */
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *account_name;
+ uint32 priv;
+ uint32 auth_flags;
+ uint32 logon_count;
+ uint32 bad_pw_count;
+ time_t last_logon;
+ time_t last_logoff;
+ time_t logoff_time;
+ time_t kickoff_time;
+ uint32 password_age;
+ time_t pw_can_change;
+ time_t pw_must_change;
+ [string,charset(UTF16)] uint16 *computer;
+ [string,charset(UTF16)] uint16 *domain;
+ [string,charset(UTF16)] uint16 *script_path;
+ uint32 unknown;
+ } netr_UasInfo;
+
+ WERROR netr_LogonUasLogon(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 *account_name,
+ [in] [string,charset(UTF16)] uint16 *workstation,
+ [out,ref] netr_UasInfo **info
+ );
+
+
+ /*****************/
+ /* Function 0x01 */
+
+ typedef struct {
+ uint32 duration;
+ uint16 logon_count;
+ } netr_UasLogoffInfo;
+
+ WERROR netr_LogonUasLogoff(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 *account_name,
+ [in] [string,charset(UTF16)] uint16 *workstation,
+ [out,ref] netr_UasLogoffInfo *info
+ );
+
+
+ /*****************/
+ /* Function 0x02 */
+
+ /* in netr_AcctLockStr size seems to be be 24, and rrenard thinks
+ that the structure of the bindata looks like this:
+
+ dlong lockout_duration;
+ udlong reset_count;
+ uint32 bad_attempt_lockout;
+ uint32 dummy;
+
+ but it doesn't look as though this structure is reflected at the
+ NDR level. Maybe it is left to the application to decode the bindata array.
+ */
+ typedef [public] struct {
+ dlong lockout_duration;
+ udlong reset_count;
+ uint32 bad_attempt_lockout;
+ uint32 dummy;
+ } netr_AcctLockStr;
+
+ /* - MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
+ * sets the NETLOGON_SERVER_TRUST_ACCOUNT user_flag
+ * - MSV1_0_UPDATE_LOGON_STATISTICS
+ * sets the logon time on network logon
+ * - MSV1_0_RETURN_USER_PARAMETERS
+ * sets the user parameters in the driveletter
+ * - MSV1_0_RETURN_PROFILE_PATH
+ * returns the profilepath in the driveletter and
+ * sets LOGON_PROFILE_PATH_RETURNED user_flag
+ */
+
+ typedef [public,bitmap32bit] bitmap {
+ MSV1_0_CLEARTEXT_PASSWORD_ALLOWED = 0x00000002,
+ MSV1_0_UPDATE_LOGON_STATISTICS = 0x00000004,
+ MSV1_0_RETURN_USER_PARAMETERS = 0x00000008,
+ MSV1_0_DONT_TRY_GUEST_ACCOUNT = 0x00000010,
+ MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT = 0x00000020,
+ MSV1_0_RETURN_PASSWORD_EXPIRY = 0x00000040,
+ MSV1_0_USE_CLIENT_CHALLENGE = 0x00000080,
+ MSV1_0_TRY_GUEST_ACCOUNT_ONLY = 0x00000100,
+ MSV1_0_RETURN_PROFILE_PATH = 0x00000200,
+ MSV1_0_TRY_SPECIFIED_DOMAIN_ONLY = 0x00000400,
+ MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT = 0x00000800,
+ MSV1_0_DISABLE_PERSONAL_FALLBACK = 0x00001000,
+ MSV1_0_ALLOW_FORCE_GUEST = 0x00002000,
+ MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED = 0x00004000,
+ MSV1_0_USE_DOMAIN_FOR_ROUTING_ONLY = 0x00008000,
+ MSV1_0_ALLOW_MSVCHAPV2 = 0x00010000,
+ MSV1_0_S4U2SELF = 0x00020000,
+ MSV1_0_CHECK_LOGONHOURS_FOR_S4U = 0x00040000,
+ MSV1_0_SUBAUTHENTICATION_DLL_EX = 0x00100000
+ } netr_LogonParameterControl;
+
+ /* Summary of the of the Query and Response from Microsoft on
+ * the usage of logon_id in netr_IdendityInfo
+ *
+ * [REG:119013019612095] [MS-NRPC]: NETLOGON_LOGON_IDENTITY_INFO: Does
+ * the Reserved field have LogonId meaning?
+ *
+ * Questions:
+ * In NetrLogonSamLogonEx does the Reserved field
+ * (of NETLOGON_LOGON_IDENTITY_INFO) have LogonId meaning?
+ *
+ * What is a valid LogonID, and does have any audit usage?
+ *
+ * Samba is sending a constant "deadbeef" in hex and would like to
+ * understand any usage of this field.
+ *
+ * Response:
+ * The NRPC spec is accurate in defining the field as Reserved, and
+ * without protocol significance. In the header file in our source
+ * code, it is defined as LogonId and commented as such, but it’s
+ * effectively not used. This is probably why the API structure has
+ * that field name. It may have been intended as such but it’s not
+ * used.
+ *
+ * Samba now sends a random value in this field.
+ */
+ typedef struct {
+ lsa_String domain_name;
+ netr_LogonParameterControl parameter_control; /* see MSV1_0_* */
+ udlong logon_id;
+ lsa_String account_name;
+ lsa_String workstation;
+ } netr_IdentityInfo;
+
+ typedef struct {
+ netr_IdentityInfo identity_info;
+ samr_Password lmpassword;
+ samr_Password ntpassword;
+ } netr_PasswordInfo;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint16 length;
+ [value(length)] uint16 size;
+ [size_is(length),length_is(length)] uint8 *data;
+ } netr_ChallengeResponse;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ netr_IdentityInfo identity_info;
+ uint8 challenge[8];
+ netr_ChallengeResponse nt;
+ netr_ChallengeResponse lm;
+ } netr_NetworkInfo;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ netr_IdentityInfo identity_info;
+ lsa_String package_name;
+ uint32 length;
+ [size_is(length)] uint8 *data;
+ } netr_GenericInfo;
+
+ typedef [public] enum {
+ NetlogonInteractiveInformation = 1,
+ NetlogonNetworkInformation = 2,
+ NetlogonServiceInformation = 3,
+ NetlogonGenericInformation = 4,
+ NetlogonInteractiveTransitiveInformation = 5,
+ NetlogonNetworkTransitiveInformation = 6,
+ NetlogonServiceTransitiveInformation = 7
+ } netr_LogonInfoClass;
+
+ typedef [public,switch_type(netr_LogonInfoClass)] union {
+ [case(NetlogonInteractiveInformation)] netr_PasswordInfo *password;
+ [case(NetlogonNetworkInformation)] netr_NetworkInfo *network;
+ [case(NetlogonServiceInformation)] netr_PasswordInfo *password;
+ [case(NetlogonGenericInformation)] netr_GenericInfo *generic;
+ [case(NetlogonInteractiveTransitiveInformation)] netr_PasswordInfo *password;
+ [case(NetlogonNetworkTransitiveInformation)] netr_NetworkInfo *network;
+ [case(NetlogonServiceTransitiveInformation)] netr_PasswordInfo *password;
+ [default];
+ } netr_LogonLevel;
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint8 key[16];
+ } netr_UserSessionKey;
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint8 key[8];
+ } netr_LMSessionKey;
+
+ /* Flags for user_flags below */
+ typedef [public,bitmap32bit] bitmap {
+ NETLOGON_GUEST = 0x00000001,
+ NETLOGON_NOENCRYPTION = 0x00000002,
+ NETLOGON_CACHED_ACCOUNT = 0x00000004,
+ NETLOGON_USED_LM_PASSWORD = 0x00000008,
+ NETLOGON_EXTRA_SIDS = 0x00000020,
+ NETLOGON_SUBAUTH_SESSION_KEY = 0x00000040,
+ NETLOGON_SERVER_TRUST_ACCOUNT = 0x00000080,
+ NETLOGON_NTLMV2_ENABLED = 0x00000100,
+ NETLOGON_RESOURCE_GROUPS = 0x00000200,
+ NETLOGON_PROFILE_PATH_RETURNED = 0x00000400,
+ NETLOGON_GRACE_LOGON = 0x01000000
+ } netr_UserFlags;
+
+ typedef struct {
+ NTTIME logon_time;
+ NTTIME logoff_time;
+ NTTIME kickoff_time;
+ NTTIME last_password_change;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+ lsa_String account_name;
+ lsa_String full_name;
+ lsa_String logon_script;
+ lsa_String profile_path;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ uint16 logon_count;
+ uint16 bad_password_count;
+ uint32 rid;
+ uint32 primary_gid;
+ samr_RidWithAttributeArray groups;
+ netr_UserFlags user_flags;
+ [flag(NDR_SECRET)] netr_UserSessionKey key;
+ lsa_StringLarge logon_server;
+ lsa_StringLarge logon_domain;
+ dom_sid2 *domain_sid;
+ [flag(NDR_SECRET)] netr_LMSessionKey LMSessKey;
+ samr_AcctFlags acct_flags;
+ uint32 sub_auth_status;
+ NTTIME last_successful_logon;
+ NTTIME last_failed_logon;
+ uint32 failed_logon_count;
+ uint32 reserved;
+ } netr_SamBaseInfo;
+
+ typedef struct {
+ netr_SamBaseInfo base;
+ } netr_SamInfo2;
+
+ typedef [public] struct {
+ dom_sid2 *sid;
+ security_GroupAttrs attributes;
+ } netr_SidAttr;
+
+ typedef [public] struct {
+ netr_SamBaseInfo base;
+ uint32 sidcount;
+ [size_is(sidcount)] netr_SidAttr *sids;
+ } netr_SamInfo3;
+
+ typedef struct {
+ netr_SamBaseInfo base;
+ uint32 sidcount;
+ [size_is(sidcount)] netr_SidAttr *sids;
+ /*
+ * On ndr_push:
+ * Should pointer values be allocated
+ * of sids[*].sid before the following ones?
+ *
+ * That's at least the case for
+ * PAC_LOGON_INFO.
+ */
+ lsa_String dns_domainname;
+ lsa_String principal_name;
+ uint32 unknown4[20];
+ } netr_SamInfo6;
+
+ typedef struct {
+ uint32 pac_size;
+ [size_is(pac_size)] uint8 *pac;
+ lsa_String logon_domain;
+ lsa_String logon_server;
+ lsa_String principal_name;
+ uint32 auth_size;
+ [size_is(auth_size)] uint8 *auth;
+ netr_UserSessionKey user_session_key;
+ uint32 expansionroom[10];
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ } netr_PacInfo;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint32 length;
+ [size_is(length)] uint8 *data;
+ } netr_GenericInfo2;
+
+ typedef enum {
+ NetlogonValidationUasInfo = 1,
+ NetlogonValidationSamInfo = 2,
+ NetlogonValidationSamInfo2 = 3,
+ NetlogonValidationGenericInfo2 = 5,
+ NetlogonValidationSamInfo4 = 6
+ } netr_ValidationInfoClass;
+
+ typedef [public,switch_type(uint16)] union {
+ [case(NetlogonValidationSamInfo)] netr_SamInfo2 *sam2;
+ [case(NetlogonValidationSamInfo2)] netr_SamInfo3 *sam3;
+ [case(4)] netr_PacInfo *pac;
+ [case(NetlogonValidationGenericInfo2)] netr_GenericInfo2 *generic;
+ [case(NetlogonValidationSamInfo4)] netr_SamInfo6 *sam6;
+ [default];
+ } netr_Validation;
+
+ typedef [public, flag(NDR_PAHEX)] struct {
+ uint8 data[8];
+ } netr_Credential;
+
+ typedef [public] struct {
+ netr_Credential client_challenge;
+ netr_Credential server_challenge;
+ } netlogon_server_pipe_state;
+
+ typedef [public] struct {
+ netr_Credential cred;
+ time_t timestamp;
+ } netr_Authenticator;
+
+ [public] NTSTATUS netr_LogonSamLogon(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in,unique] netr_Authenticator *credential,
+ [in,out,unique] netr_Authenticator *return_authenticator,
+ [in] netr_LogonInfoClass logon_level,
+ [in,ref] [switch_is(logon_level)] netr_LogonLevel *logon,
+ [in] uint16 validation_level,
+ [out,ref] [switch_is(validation_level)] netr_Validation *validation,
+ [out,ref] uint8 *authoritative
+ );
+
+
+ /*****************/
+ /* Function 0x03 */
+
+ NTSTATUS netr_LogonSamLogoff(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in,unique] netr_Authenticator *credential,
+ [in,out,unique] netr_Authenticator *return_authenticator,
+ [in] netr_LogonInfoClass logon_level,
+ [in] [switch_is(logon_level)] netr_LogonLevel logon
+ );
+
+
+
+ /*****************/
+ /* Function 0x04 */
+
+ [public] NTSTATUS netr_ServerReqChallenge(
+ [in,unique,string,charset(UTF16)] uint16 *server_name,
+ [in,string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Credential *credentials,
+ [out,ref] netr_Credential *return_credentials
+ );
+
+
+ /*****************/
+ /* Function 0x05 */
+
+ typedef enum netr_SchannelType netr_SchannelType;
+
+ NTSTATUS netr_ServerAuthenticate(
+ [in,unique,string,charset(UTF16)] uint16 *server_name,
+ [in,string,charset(UTF16)] uint16 *account_name,
+ [in] netr_SchannelType secure_channel_type,
+ [in,string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Credential *credentials,
+ [out,ref] netr_Credential *return_credentials
+ );
+
+
+ /*****************/
+ /* Function 0x06 */
+
+ NTSTATUS netr_ServerPasswordSet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 *account_name,
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [in,ref] samr_Password *new_password
+ );
+
+
+ /*****************/
+ /* Function 0x07 */
+
+ typedef enum netr_SamDatabaseID netr_SamDatabaseID;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *account_name;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_DELETE_USER;
+
+ typedef struct {
+ uint16 length;
+ [value(length)] uint16 size;
+ uint32 flags;
+ samr_Password pwd;
+ } netr_USER_KEY16;
+
+ typedef struct {
+ uint16 nt_length;
+ [value(nt_length)] uint16 nt_size;
+ uint32 nt_flags;
+ uint16 lm_length;
+ [value(lm_length)] uint16 lm_size;
+ uint32 lm_flags;
+ uint8 nt_history[nt_length];
+ uint8 lm_history[lm_length];
+ } netr_PasswordHistory;
+
+ typedef struct {
+ netr_USER_KEY16 lmpassword;
+ netr_USER_KEY16 ntpassword;
+ netr_PasswordHistory history;
+ } netr_USER_KEYS2;
+
+ typedef struct { /* TODO: make this a union! */
+ netr_USER_KEYS2 keys2;
+ } netr_USER_KEY_UNION;
+
+ typedef [public] struct {
+ uint32 version;
+ netr_USER_KEY_UNION keys;
+ } netr_USER_KEYS;
+
+ typedef struct {
+ boolean8 SensitiveDataFlag;
+ uint32 DataLength;
+
+ /* netr_USER_KEYS encrypted with the session key */
+ [size_is(DataLength)][flag(NDR_PAHEX)] uint8 *SensitiveData;
+ } netr_USER_PRIVATE_INFO;
+
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ uint32 rid;
+ uint32 primary_gid;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ lsa_String logon_script;
+ lsa_String description;
+ lsa_String workstations;
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ samr_LogonHours logon_hours;
+ uint16 bad_password_count;
+ uint16 logon_count;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ samr_AcctFlags acct_flags;
+ samr_Password lmpassword;
+ samr_Password ntpassword;
+ boolean8 nt_password_present;
+ boolean8 lm_password_present;
+ boolean8 password_expired;
+ lsa_String comment;
+ lsa_BinaryString parameters;
+ uint16 country_code;
+ uint16 code_page;
+ netr_USER_PRIVATE_INFO user_private_info;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String profile_path;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_USER;
+
+ typedef struct {
+ lsa_String domain_name;
+ lsa_String oem_information; /* comment */
+ dlong force_logoff_time;
+ uint16 min_password_length;
+ uint16 password_history_length;
+ /* yes, these are signed. They are in negative 100ns */
+ dlong max_password_age;
+ dlong min_password_age;
+ udlong sequence_num;
+ NTTIME domain_create_time;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_BinaryString account_lockout;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 logon_to_chgpass;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_DOMAIN;
+
+ typedef struct {
+ lsa_String group_name;
+ uint32 rid;
+ uint32 attributes;
+ lsa_String description;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_GROUP;
+
+ typedef struct {
+ lsa_String OldName;
+ lsa_String NewName;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_RENAME;
+
+ typedef struct {
+ [size_is(num_rids)] uint32 *rids;
+ [size_is(num_rids)] uint32 *attribs;
+ uint32 num_rids;
+ uint32 unknown1;
+ uint32 unknown2;
+ uint32 unknown3;
+ uint32 unknown4;
+ } netr_DELTA_GROUP_MEMBER;
+
+ typedef struct {
+ lsa_String alias_name;
+ uint32 rid;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String description;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_ALIAS;
+
+ typedef struct {
+ lsa_SidArray sids;
+ uint32 unknown1;
+ uint32 unknown2;
+ uint32 unknown3;
+ uint32 unknown4;
+ } netr_DELTA_ALIAS_MEMBER;
+
+ typedef struct {
+ uint32 pagedpoollimit;
+ uint32 nonpagedpoollimit;
+ uint32 minimumworkingsetsize;
+ uint32 maximumworkingsetsize;
+ uint32 pagefilelimit;
+ NTTIME timelimit;
+ } netr_QUOTA_LIMITS;
+
+ typedef struct {
+ uint32 maxlogsize;
+ NTTIME auditretentionperiod;
+ boolean8 auditingmode;
+ uint32 maxauditeventcount;
+ [size_is(maxauditeventcount+1)] uint32 *eventauditoptions;
+ lsa_String primary_domain_name;
+ dom_sid2 *sid;
+ netr_QUOTA_LIMITS quota_limits;
+ udlong sequence_num;
+ NTTIME db_create_time;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_POLICY;
+
+ typedef struct {
+ lsa_String domain_name;
+ uint32 num_controllers;
+ [size_is(num_controllers)] lsa_String *controller_names;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 posix_offset;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_TRUSTED_DOMAIN;
+
+ typedef struct {
+ uint32 privilege_entries;
+ uint32 privilege_control;
+ [size_is(privilege_entries)] uint32 *privilege_attrib;
+ [size_is(privilege_entries)] lsa_String *privilege_name;
+ netr_QUOTA_LIMITS quotalimits;
+ uint32 system_flags;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_ACCOUNT;
+
+ typedef struct {
+ uint32 len;
+ uint32 maxlen;
+ [size_is(maxlen)][length_is(len)] uint8 *cipher_data;
+ } netr_CIPHER_VALUE;
+
+ typedef struct {
+ netr_CIPHER_VALUE current_cipher;
+ NTTIME current_cipher_set_time;
+ netr_CIPHER_VALUE old_cipher;
+ NTTIME old_cipher_set_time;
+ uint32 SecurityInformation;
+ sec_desc_buf sdbuf;
+ lsa_String unknown1;
+ lsa_String unknown2;
+ lsa_String unknown3;
+ lsa_String unknown4;
+ uint32 unknown5;
+ uint32 unknown6;
+ uint32 unknown7;
+ uint32 unknown8;
+ } netr_DELTA_SECRET;
+
+ typedef enum {
+ NETR_DELTA_DOMAIN = 1,
+ NETR_DELTA_GROUP = 2,
+ NETR_DELTA_DELETE_GROUP = 3,
+ NETR_DELTA_RENAME_GROUP = 4,
+ NETR_DELTA_USER = 5,
+ NETR_DELTA_DELETE_USER = 6,
+ NETR_DELTA_RENAME_USER = 7,
+ NETR_DELTA_GROUP_MEMBER = 8,
+ NETR_DELTA_ALIAS = 9,
+ NETR_DELTA_DELETE_ALIAS = 10,
+ NETR_DELTA_RENAME_ALIAS = 11,
+ NETR_DELTA_ALIAS_MEMBER = 12,
+ NETR_DELTA_POLICY = 13,
+ NETR_DELTA_TRUSTED_DOMAIN = 14,
+ NETR_DELTA_DELETE_TRUST = 15,
+ NETR_DELTA_ACCOUNT = 16,
+ NETR_DELTA_DELETE_ACCOUNT = 17,
+ NETR_DELTA_SECRET = 18,
+ NETR_DELTA_DELETE_SECRET = 19,
+ NETR_DELTA_DELETE_GROUP2 = 20,
+ NETR_DELTA_DELETE_USER2 = 21,
+ NETR_DELTA_MODIFY_COUNT = 22
+ } netr_DeltaEnum;
+
+ typedef [switch_type(netr_DeltaEnum)] union {
+ [case(NETR_DELTA_DOMAIN)] netr_DELTA_DOMAIN *domain;
+ [case(NETR_DELTA_GROUP)] netr_DELTA_GROUP *group;
+ [case(NETR_DELTA_DELETE_GROUP)] ; /* rid only */
+ [case(NETR_DELTA_RENAME_GROUP)] netr_DELTA_RENAME *rename_group;
+ [case(NETR_DELTA_USER)] netr_DELTA_USER *user;
+ [case(NETR_DELTA_DELETE_USER)] ; /* rid only */
+ [case(NETR_DELTA_RENAME_USER)] netr_DELTA_RENAME *rename_user;
+ [case(NETR_DELTA_GROUP_MEMBER)] netr_DELTA_GROUP_MEMBER *group_member;
+ [case(NETR_DELTA_ALIAS)] netr_DELTA_ALIAS *alias;
+ [case(NETR_DELTA_DELETE_ALIAS)] ; /* rid only */
+ [case(NETR_DELTA_RENAME_ALIAS)] netr_DELTA_RENAME *rename_alias;
+ [case(NETR_DELTA_ALIAS_MEMBER)] netr_DELTA_ALIAS_MEMBER *alias_member;
+ [case(NETR_DELTA_POLICY)] netr_DELTA_POLICY *policy;
+ [case(NETR_DELTA_TRUSTED_DOMAIN)] netr_DELTA_TRUSTED_DOMAIN *trusted_domain;
+ [case(NETR_DELTA_DELETE_TRUST)] ; /* sid only */
+ [case(NETR_DELTA_ACCOUNT)] netr_DELTA_ACCOUNT *account;
+ [case(NETR_DELTA_DELETE_ACCOUNT)] ; /* sid only */
+ [case(NETR_DELTA_SECRET)] netr_DELTA_SECRET *secret;
+ [case(NETR_DELTA_DELETE_SECRET)] ; /* name only */
+ [case(NETR_DELTA_DELETE_GROUP2)] netr_DELTA_DELETE_USER *delete_group;
+ [case(NETR_DELTA_DELETE_USER2)] netr_DELTA_DELETE_USER *delete_user;
+ [case(NETR_DELTA_MODIFY_COUNT)] udlong *modified_count;
+ [default];
+ } netr_DELTA_UNION;
+
+ typedef [switch_type(netr_DeltaEnum)] union {
+ [case(NETR_DELTA_DOMAIN)] uint32 rid;
+ [case(NETR_DELTA_GROUP)] uint32 rid;
+ [case(NETR_DELTA_DELETE_GROUP)] uint32 rid;
+ [case(NETR_DELTA_RENAME_GROUP)] uint32 rid;
+ [case(NETR_DELTA_USER)] uint32 rid;
+ [case(NETR_DELTA_DELETE_USER)] uint32 rid;
+ [case(NETR_DELTA_RENAME_USER)] uint32 rid;
+ [case(NETR_DELTA_GROUP_MEMBER)] uint32 rid;
+ [case(NETR_DELTA_ALIAS)] uint32 rid;
+ [case(NETR_DELTA_DELETE_ALIAS)] uint32 rid;
+ [case(NETR_DELTA_RENAME_ALIAS)] uint32 rid;
+ [case(NETR_DELTA_ALIAS_MEMBER)] uint32 rid;
+ [case(NETR_DELTA_POLICY)] dom_sid2 *sid;
+ [case(NETR_DELTA_TRUSTED_DOMAIN)] dom_sid2 *sid;
+ [case(NETR_DELTA_DELETE_TRUST)] dom_sid2 *sid;
+ [case(NETR_DELTA_ACCOUNT)] dom_sid2 *sid;
+ [case(NETR_DELTA_DELETE_ACCOUNT)] dom_sid2 *sid;
+ [case(NETR_DELTA_SECRET)] [string,charset(UTF16)] uint16 *name;
+ [case(NETR_DELTA_DELETE_SECRET)] [string,charset(UTF16)] uint16 *name;
+ [case(NETR_DELTA_DELETE_GROUP2)] uint32 rid;
+ [case(NETR_DELTA_DELETE_USER2)] uint32 rid;
+ [case(NETR_DELTA_MODIFY_COUNT)] ;
+ [default];
+ } netr_DELTA_ID_UNION;
+
+ typedef struct {
+ netr_DeltaEnum delta_type;
+ [switch_is(delta_type)] netr_DELTA_ID_UNION delta_id_union;
+ [switch_is(delta_type)] netr_DELTA_UNION delta_union;
+ } netr_DELTA_ENUM;
+
+ typedef struct {
+ uint32 num_deltas;
+ [size_is(num_deltas)] netr_DELTA_ENUM *delta_enum;
+ } netr_DELTA_ENUM_ARRAY;
+
+ NTSTATUS netr_DatabaseDeltas(
+ [in] [string,charset(UTF16)] uint16 *logon_server,
+ [in] [string,charset(UTF16)] uint16 *computername,
+ [in,ref] netr_Authenticator *credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] netr_SamDatabaseID database_id,
+ [in,out,ref] udlong *sequence_num,
+ [out,ref] netr_DELTA_ENUM_ARRAY **delta_enum_array,
+ [in] uint32 preferredmaximumlength
+ );
+
+
+ /*****************/
+ /* Function 0x08 */
+
+ NTSTATUS netr_DatabaseSync(
+ [in] [string,charset(UTF16)] uint16 *logon_server,
+ [in] [string,charset(UTF16)] uint16 *computername,
+ [in,ref] netr_Authenticator *credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] netr_SamDatabaseID database_id,
+ [in,out,ref] uint32 *sync_context,
+ [out,ref] netr_DELTA_ENUM_ARRAY **delta_enum_array,
+ [in] uint32 preferredmaximumlength
+ );
+
+
+ /*****************/
+ /* Function 0x09 */
+
+ /* w2k3 returns NT_STATUS_NOT_IMPLEMENTED for this call */
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 computer_name[16];
+ uint32 timecreated;
+ uint32 serial_number;
+ } netr_UAS_INFO_0;
+
+ typedef struct {
+ [flag(NDR_REMAINING)] DATA_BLOB blob;
+ } netr_AccountBuffer;
+
+ NTSTATUS netr_AccountDeltas(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] [string,charset(UTF16)] uint16 *computername,
+ [in] netr_Authenticator credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] netr_UAS_INFO_0 uas,
+ [in] uint32 count,
+ [in] uint32 level,
+ [in] uint32 buffersize,
+ [out,ref,subcontext(4)] netr_AccountBuffer *buffer,
+ [out,ref] uint32 *count_returned,
+ [out,ref] uint32 *total_entries,
+ [out,ref] netr_UAS_INFO_0 *recordid
+ );
+
+
+ /*****************/
+ /* Function 0x0A */
+
+ NTSTATUS netr_AccountSync(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] [string,charset(UTF16)] uint16 *computername,
+ [in] netr_Authenticator credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] uint32 reference,
+ [in] uint32 level,
+ [in] uint32 buffersize,
+ [out,ref,subcontext(4)] netr_AccountBuffer *buffer,
+ [out,ref] uint32 *count_returned,
+ [out,ref] uint32 *total_entries,
+ [out,ref] uint32 *next_reference,
+ [in,out,ref] netr_UAS_INFO_0 *recordid
+ );
+
+
+ /*****************/
+ /* Function 0x0B */
+
+ WERROR netr_GetDcName(
+ [in] [string,charset(UTF16)] uint16 *logon_server,
+ [in,unique] [string,charset(UTF16)] uint16 *domainname,
+ [out,ref] [string,charset(UTF16)] uint16 **dcname
+ );
+
+ /*****************/
+ /* Function 0x0C */
+
+ typedef [bitmap32bit] bitmap {
+ NETLOGON_REPLICATION_NEEDED = 0x00000001,
+ NETLOGON_REPLICATION_IN_PROGRESS = 0x00000002,
+ NETLOGON_FULL_SYNC_REPLICATION = 0x00000004,
+ NETLOGON_REDO_NEEDED = 0x00000008,
+ NETLOGON_HAS_IP = 0x00000010,
+ NETLOGON_HAS_TIMESERV = 0x00000020,
+ NETLOGON_DNS_UPDATE_FAILURE = 0x00000040,
+ NETLOGON_VERIFY_STATUS_RETURNED = 0x00000080
+ } netr_InfoFlags;
+
+ typedef struct {
+ netr_InfoFlags flags;
+ WERROR pdc_connection_status;
+ } netr_NETLOGON_INFO_1;
+
+ typedef struct {
+ netr_InfoFlags flags;
+ WERROR pdc_connection_status;
+ [string,charset(UTF16)] uint16 *trusted_dc_name;
+ WERROR tc_connection_status;
+ } netr_NETLOGON_INFO_2;
+
+ typedef struct {
+ netr_InfoFlags flags;
+ uint32 logon_attempts;
+ uint32 unknown1;
+ uint32 unknown2;
+ uint32 unknown3;
+ uint32 unknown4;
+ uint32 unknown5;
+ } netr_NETLOGON_INFO_3;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *trusted_dc_name;
+ [string,charset(UTF16)] uint16 *trusted_domain_name;
+ } netr_NETLOGON_INFO_4;
+
+ typedef [public] union {
+ [case(1)] netr_NETLOGON_INFO_1 *info1;
+ [case(2)] netr_NETLOGON_INFO_2 *info2;
+ [case(3)] netr_NETLOGON_INFO_3 *info3;
+ [case(4)] netr_NETLOGON_INFO_4 *info4;
+ [default] ;
+ } netr_CONTROL_QUERY_INFORMATION;
+
+ /* function_code values */
+ typedef [v1_enum,public] enum {
+ NETLOGON_CONTROL_QUERY = 0x00000001,
+ NETLOGON_CONTROL_REPLICATE = 0x00000002,
+ NETLOGON_CONTROL_SYNCHRONIZE = 0x00000003,
+ NETLOGON_CONTROL_PDC_REPLICATE = 0x00000004,
+ NETLOGON_CONTROL_REDISCOVER = 0x00000005,
+ NETLOGON_CONTROL_TC_QUERY = 0x00000006,
+ NETLOGON_CONTROL_TRANSPORT_NOTIFY = 0x00000007,
+ NETLOGON_CONTROL_FIND_USER = 0x00000008,
+ NETLOGON_CONTROL_CHANGE_PASSWORD = 0x00000009,
+ NETLOGON_CONTROL_TC_VERIFY = 0x0000000A,
+ NETLOGON_CONTROL_FORCE_DNS_REG = 0x0000000B,
+ NETLOGON_CONTROL_QUERY_DNS_REG = 0x0000000C,
+ NETLOGON_CONTROL_BACKUP_CHANGE_LOG = 0x0000FFFC,
+ NETLOGON_CONTROL_TRUNCATE_LOG = 0x0000FFFD,
+ NETLOGON_CONTROL_SET_DBFLAG = 0x0000FFFE,
+ NETLOGON_CONTROL_BREAKPOINT = 0x0000FFFF
+ } netr_LogonControlCode;
+
+ WERROR netr_LogonControl(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] netr_LogonControlCode function_code,
+ [in] uint32 level,
+ [out,ref,switch_is(level)] netr_CONTROL_QUERY_INFORMATION *query
+ );
+
+
+ /*****************/
+ /* Function 0x0D */
+
+ WERROR netr_GetAnyDCName(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in,unique] [string,charset(UTF16)] uint16 *domainname,
+ [out,ref] [string,charset(UTF16)] uint16 **dcname
+ );
+
+
+ /*****************/
+ /* Function 0x0E */
+
+ typedef [public,switch_type(netr_LogonControlCode)] union {
+ [case(NETLOGON_CONTROL_REDISCOVER)] [string,charset(UTF16)] uint16 *domain;
+ [case(NETLOGON_CONTROL_TC_QUERY)] [string,charset(UTF16)] uint16 *domain;
+ [case(NETLOGON_CONTROL_TRANSPORT_NOTIFY)] [string,charset(UTF16)] uint16 *domain;
+ [case(NETLOGON_CONTROL_CHANGE_PASSWORD)] [string,charset(UTF16)] uint16 *domain;
+ [case(NETLOGON_CONTROL_TC_VERIFY)] [string,charset(UTF16)] uint16 *domain;
+ [case(NETLOGON_CONTROL_FIND_USER)] [string,charset(UTF16)] uint16 *user;
+ [case(NETLOGON_CONTROL_SET_DBFLAG)] uint32 debug_level;
+ [default] ;
+ } netr_CONTROL_DATA_INFORMATION;
+
+ WERROR netr_LogonControl2(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] netr_LogonControlCode function_code,
+ [in] uint32 level,
+ [in,ref][switch_is(function_code)] netr_CONTROL_DATA_INFORMATION *data,
+ [out,ref][switch_is(level)] netr_CONTROL_QUERY_INFORMATION *query
+ );
+
+
+ /* If NETLOGON_NEG_ARCFOUR flag is not set, then the passwords and LM
+ * session keys are encrypted with DES calls. (And the user session key
+ * is unencrypted) */
+
+ /*****************/
+ /* Function 0x0F */
+
+ typedef [public,bitmap32bit] bitmap {
+ NETLOGON_NEG_ACCOUNT_LOCKOUT = 0x00000001,
+ NETLOGON_NEG_PERSISTENT_SAMREPL = 0x00000002,
+ NETLOGON_NEG_ARCFOUR = 0x00000004,
+ NETLOGON_NEG_PROMOTION_COUNT = 0x00000008,
+ NETLOGON_NEG_CHANGELOG_BDC = 0x00000010,
+ NETLOGON_NEG_FULL_SYNC_REPL = 0x00000020,
+ NETLOGON_NEG_MULTIPLE_SIDS = 0x00000040,
+ NETLOGON_NEG_REDO = 0x00000080,
+ NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL = 0x00000100,
+ NETLOGON_NEG_SEND_PASSWORD_INFO_PDC = 0x00000200,
+ NETLOGON_NEG_GENERIC_PASSTHROUGH = 0x00000400,
+ NETLOGON_NEG_CONCURRENT_RPC = 0x00000800,
+ NETLOGON_NEG_AVOID_ACCOUNT_DB_REPL = 0x00001000,
+ NETLOGON_NEG_AVOID_SECURITYAUTH_DB_REPL = 0x00002000,
+ NETLOGON_NEG_STRONG_KEYS = 0x00004000,
+ NETLOGON_NEG_TRANSITIVE_TRUSTS = 0x00008000,
+ NETLOGON_NEG_DNS_DOMAIN_TRUSTS = 0x00010000,
+ NETLOGON_NEG_PASSWORD_SET2 = 0x00020000,
+ NETLOGON_NEG_GETDOMAININFO = 0x00040000,
+ NETLOGON_NEG_CROSS_FOREST_TRUSTS = 0x00080000,
+ NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION = 0x00100000,
+ NETLOGON_NEG_RODC_PASSTHROUGH = 0x00200000,
+ NETLOGON_NEG_SUPPORTS_AES_SHA2 = 0x00400000,
+ NETLOGON_NEG_SUPPORTS_AES = 0x01000000,
+ NETLOGON_NEG_AUTHENTICATED_RPC_LSASS = 0x20000000,
+ NETLOGON_NEG_AUTHENTICATED_RPC = 0x40000000
+ } netr_NegotiateFlags;
+
+ const uint32 NETLOGON_NEG_128BIT = NETLOGON_NEG_STRONG_KEYS;
+ const uint32 NETLOGON_NEG_SCHANNEL = NETLOGON_NEG_AUTHENTICATED_RPC;
+
+ NTSTATUS netr_ServerAuthenticate2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 *account_name,
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Credential *credentials,
+ [out,ref] netr_Credential *return_credentials,
+ [in,out,ref] netr_NegotiateFlags *negotiate_flags
+ );
+
+
+ /*****************/
+ /* Function 0x10 */
+
+ typedef enum {
+ SYNCSTATE_NORMAL_STATE = 0,
+ SYNCSTATE_DOMAIN_STATE = 1,
+ SYNCSTATE_GROUP_STATE = 2,
+ SYNCSTATE_UAS_BUILT_IN_GROUP_STATE = 3,
+ SYNCSTATE_USER_STATE = 4,
+ SYNCSTATE_GROUP_MEMBER_STATE = 5,
+ SYNCSTATE_ALIAS_STATE = 6,
+ SYNCSTATE_ALIAS_MEMBER_STATE = 7,
+ SYNCSTATE_SAM_DONE_STATE = 8
+ } SyncStateEnum;
+
+ NTSTATUS netr_DatabaseSync2(
+ [in] [string,charset(UTF16)] uint16 *logon_server,
+ [in] [string,charset(UTF16)] uint16 *computername,
+ [in,ref] netr_Authenticator *credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] netr_SamDatabaseID database_id,
+ [in] SyncStateEnum restart_state,
+ [in,out,ref] uint32 *sync_context,
+ [out,ref] netr_DELTA_ENUM_ARRAY **delta_enum_array,
+ [in] uint32 preferredmaximumlength
+ );
+
+
+ /*****************/
+ /* Function 0x11 */
+
+ /* i'm not at all sure how this call works */
+
+ typedef [bitmap16bit] bitmap {
+ NETR_CHANGELOG_IMMEDIATE_REPL_REQUIRED = 0x0001,
+ NETR_CHANGELOG_CHANGED_PASSWORD = 0x0002,
+ NETR_CHANGELOG_SID_INCLUDED = 0x0004,
+ NETR_CHANGELOG_NAME_INCLUDED = 0x0008,
+ NETR_CHANGELOG_FIRST_PROMOTION_OBJ = 0x0010
+ } netr_ChangeLogFlags;
+
+ typedef [nodiscriminant] union {
+ [case(NETR_CHANGELOG_SID_INCLUDED)] dom_sid object_sid;
+ [case(NETR_CHANGELOG_NAME_INCLUDED)] nstring object_name;
+ [default];
+ } netr_ChangeLogObject;
+
+ typedef [public,gensize] struct {
+ uint32 serial_number1;
+ uint32 serial_number2;
+ uint32 object_rid;
+ netr_ChangeLogFlags flags;
+ netr_SamDatabaseID8Bit db_index;
+ netr_DeltaEnum8Bit delta_type;
+ [switch_is(flags & (NETR_CHANGELOG_SID_INCLUDED|NETR_CHANGELOG_NAME_INCLUDED))] netr_ChangeLogObject object;
+ } netr_ChangeLogEntry;
+
+ NTSTATUS netr_DatabaseRedo(
+ [in] [string,charset(UTF16)] uint16 *logon_server,
+ [in] [string,charset(UTF16)] uint16 *computername,
+ [in] netr_Authenticator *credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ /*
+ * we cannot use subcontext_size() here, as
+ * change_log_entry_size is encoded after the subcontext
+ */
+ [in] [subcontext(4)/*,subcontext_size(change_log_entry_size)*/]
+ netr_ChangeLogEntry change_log_entry,
+ [in] [value(ndr_size_netr_ChangeLogEntry(&change_log_entry,
+ ndr->flags))]
+ uint32 change_log_entry_size,
+ [out,ref] netr_DELTA_ENUM_ARRAY **delta_enum_array
+ );
+
+
+ /*****************/
+ /* Function 0x12 */
+
+ WERROR netr_LogonControl2Ex(
+ [in,unique] [string,charset(UTF16)] uint16 *logon_server,
+ [in] netr_LogonControlCode function_code,
+ [in] uint32 level,
+ [in,ref][switch_is(function_code)] netr_CONTROL_DATA_INFORMATION *data,
+ [out,ref][switch_is(level)] netr_CONTROL_QUERY_INFORMATION *query
+ );
+
+ /*****************/
+ /* Function 0x13 */
+ typedef struct {
+ uint32 length;
+ [size_is(length)] uint8 *data;
+ } netr_Blob;
+
+ NTSTATUS netr_NetrEnumerateTrustedDomains(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [out,ref] netr_Blob *trusted_domains_blob
+ );
+
+ /*****************/
+ /* Function 0x14 */
+
+ /* one unknown bit still: DS_IP_VERSION_AGNOSTIC - gd*/
+
+ const int DSGETDC_VALID_FLAGS = (DS_FORCE_REDISCOVERY |
+ DS_DIRECTORY_SERVICE_REQUIRED |
+ DS_DIRECTORY_SERVICE_PREFERRED |
+ DS_GC_SERVER_REQUIRED |
+ DS_PDC_REQUIRED |
+ DS_BACKGROUND_ONLY |
+ DS_IP_REQUIRED |
+ DS_KDC_REQUIRED |
+ DS_TIMESERV_REQUIRED |
+ DS_WRITABLE_REQUIRED |
+ DS_GOOD_TIMESERV_PREFERRED |
+ DS_AVOID_SELF |
+ DS_ONLY_LDAP_NEEDED |
+ DS_IS_FLAT_NAME |
+ DS_IS_DNS_NAME |
+ DS_TRY_NEXTCLOSEST_SITE |
+ DS_DIRECTORY_SERVICE_6_REQUIRED |
+ DS_WEB_SERVICE_REQUIRED |
+ DS_DIRECTORY_SERVICE_8_REQUIRED |
+ DS_DIRECTORY_SERVICE_9_REQUIRED |
+ DS_DIRECTORY_SERVICE_10_REQUIRED |
+ DS_RETURN_FLAT_NAME |
+ DS_RETURN_DNS_NAME);
+
+ typedef [bitmap32bit] bitmap {
+ DS_FORCE_REDISCOVERY = 0x00000001,
+ DS_DIRECTORY_SERVICE_REQUIRED = 0x00000010,
+ DS_DIRECTORY_SERVICE_PREFERRED = 0x00000020,
+ DS_GC_SERVER_REQUIRED = 0x00000040,
+ DS_PDC_REQUIRED = 0x00000080,
+ DS_BACKGROUND_ONLY = 0x00000100,
+ DS_IP_REQUIRED = 0x00000200,
+ DS_KDC_REQUIRED = 0x00000400,
+ DS_TIMESERV_REQUIRED = 0x00000800,
+ DS_WRITABLE_REQUIRED = 0x00001000,
+ DS_GOOD_TIMESERV_PREFERRED = 0x00002000,
+ DS_AVOID_SELF = 0x00004000,
+ DS_ONLY_LDAP_NEEDED = 0x00008000,
+ DS_IS_FLAT_NAME = 0x00010000,
+ DS_IS_DNS_NAME = 0x00020000,
+ DS_TRY_NEXTCLOSEST_SITE = 0x00040000,
+ DS_DIRECTORY_SERVICE_6_REQUIRED = 0x00080000, /* 2008 */
+ DS_WEB_SERVICE_REQUIRED = 0x00100000,
+ DS_DIRECTORY_SERVICE_8_REQUIRED = 0x00200000, /* 2012 */
+ DS_DIRECTORY_SERVICE_9_REQUIRED = 0x00400000, /* 2012R2 */
+ DS_DIRECTORY_SERVICE_10_REQUIRED= 0x00800000, /* 2016 */
+ DS_RETURN_DNS_NAME = 0x40000000,
+ DS_RETURN_FLAT_NAME = 0x80000000
+ } netr_DsRGetDCName_flags;
+
+ typedef [v1_enum] enum {
+ DS_ADDRESS_TYPE_INET = 1,
+ DS_ADDRESS_TYPE_NETBIOS = 2
+ } netr_DsRGetDCNameInfo_AddressType;
+
+ typedef [public] struct {
+ [string,charset(UTF16)] uint16 *dc_unc;
+ [string,charset(UTF16)] uint16 *dc_address;
+ netr_DsRGetDCNameInfo_AddressType dc_address_type;
+ GUID domain_guid;
+ [string,charset(UTF16)] uint16 *domain_name;
+ [string,charset(UTF16)] uint16 *forest_name;
+ nbt_server_type dc_flags;
+ [string,charset(UTF16)] uint16 *dc_site_name;
+ [string,charset(UTF16)] uint16 *client_site_name;
+ } netr_DsRGetDCNameInfo;
+
+ WERROR netr_DsRGetDCName(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] GUID *domain_guid,
+ [in,unique] GUID *site_guid,
+ [in] netr_DsRGetDCName_flags flags,
+ [out,ref] netr_DsRGetDCNameInfo **info
+ );
+
+ /*****************/
+ /* Function 0x15 */
+ typedef [switch_type(uint32)] union {
+ [case(1)] netr_NegotiateFlags server_capabilities;
+ [case(2)] netr_NegotiateFlags server_capabilities;
+ } netr_Capabilities;
+
+ NTSTATUS netr_LogonGetCapabilities(
+ [in] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] uint32 query_level,
+ [out,ref,switch_is(query_level)] netr_Capabilities *capabilities
+ );
+
+ /****************/
+ /* Function 0x16 */
+ [todo] WERROR netr_NETRLOGONSETSERVICEBITS();
+
+ /****************/
+ /* Function 0x17 */
+ WERROR netr_LogonGetTrustRid(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *domain_name,
+ [out,ref] uint32 *rid
+ );
+
+ /****************/
+ /* Function 0x18 */
+ [todo] WERROR netr_NETRLOGONCOMPUTESERVERDIGEST();
+
+ /****************/
+ /* Function 0x19 */
+ [todo] WERROR netr_NETRLOGONCOMPUTECLIENTDIGEST();
+
+ /****************/
+ /* Function 0x1a */
+ [public] NTSTATUS netr_ServerAuthenticate3(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 *account_name,
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Credential *credentials,
+ [out,ref] netr_Credential *return_credentials,
+ [in,out,ref] netr_NegotiateFlags *negotiate_flags,
+ [out,ref] uint32 *rid
+ );
+
+ /****************/
+ /* Function 0x1b */
+
+ WERROR netr_DsRGetDCNameEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] GUID *domain_guid,
+ [in,unique] [string,charset(UTF16)] uint16 *site_name,
+ [in] netr_DsRGetDCName_flags flags,
+ [out,ref] netr_DsRGetDCNameInfo **info
+ );
+
+
+ /****************/
+ /* Function 0x1c */
+ WERROR netr_DsRGetSiteName(
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [out,ref] [string,charset(UTF16)] uint16 **site
+ );
+
+ /****************/
+ /* Function 0x1d */
+ typedef [public,bitmap32bit] bitmap {
+ NETR_TRUST_FLAG_IN_FOREST = 0x00000001,
+ NETR_TRUST_FLAG_OUTBOUND = 0x00000002,
+ NETR_TRUST_FLAG_TREEROOT = 0x00000004,
+ NETR_TRUST_FLAG_PRIMARY = 0x00000008,
+ NETR_TRUST_FLAG_NATIVE = 0x00000010,
+ NETR_TRUST_FLAG_INBOUND = 0x00000020,
+ NETR_TRUST_FLAG_MIT_KRB5 = 0x00000080,
+ NETR_TRUST_FLAG_AES = 0x00000100
+ } netr_TrustFlags;
+
+ typedef [bitmap32bit] bitmap {
+ NETR_WS_FLAG_HANDLES_INBOUND_TRUSTS = 0x00000001,
+ NETR_WS_FLAG_HANDLES_SPN_UPDATE = 0x00000002
+ } netr_WorkstationFlags;
+
+ typedef [bitmap16bit] bitmap {
+ NETR_VER_SUITE_BACKOFFICE = 0x0004,
+ NETR_VER_SUITE_BLADE = 0x0400,
+ NETR_VER_SUITE_COMPUTE_SERVER = 0x4000,
+ NETR_VER_SUITE_DATACENTER = 0x0080,
+ NETR_VER_SUITE_ENTERPRISE = 0x0002,
+ NETR_VER_SUITE_EMBEDDEDNT = 0x0040,
+ NETR_VER_SUITE_PERSONAL = 0x0200,
+ NETR_VER_SUITE_SINGLEUSERTS = 0x0100,
+ NETR_VER_SUITE_SMALLBUSINESS = 0x0001,
+ NETR_VER_SUITE_SMALLBUSINESS_RESTRICTED = 0x0020,
+ NETR_VER_SUITE_STORAGE_SERVER = 0x2000,
+ NETR_VER_SUITE_TERMINAL = 0x0010,
+ NETR_VER_SUITE_WH_SERVER = 0x8000
+ } netr_SuiteMask;
+
+ typedef [bitmap8bit] bitmap {
+ NETR_VER_NT_DOMAIN_CONTROLLER = 0x02,
+ NETR_VER_NT_SERVER = 0x03,
+ NETR_VER_NT_WORKSTATION = 0x01
+ } netr_ProductType;
+
+ typedef struct {
+ uint32 policy_size;
+ [size_is(policy_size)] uint8 *policy;
+ } netr_LsaPolicyInformation;
+
+ typedef struct {
+ [value(284)] uint32 OSVersionInfoSize;
+ /*
+ * [MS-NRPC] 2.2.1.3.15 NL_OSVERSIONINFO_V1
+ *
+ * 4 The operating system is Windows NT 4.0.
+ * 5 The operating system is
+ * Windows 2000,
+ * Windows XP,
+ * Windows Server 2003, or
+ * Windows Server 2003 R2 operating system.
+ * 6 The operating system is
+ * Windows Vista, Windows Server 2008,
+ * Windows 7, Windows Server 2008 R2,
+ * Windows 8, Windows Server 2012,
+ * Windows 8.1, or Windows Server 2012 R2.
+ * 10 The operating system is
+ * Windows 10 and later.
+ */
+ uint32 MajorVersion;
+ /*
+ * [MS-NRPC] 2.2.1.3.15 NL_OSVERSIONINFO_V1
+ *
+ * 0 The operating system is
+ * Windows NT 4.0, Windows 2000,
+ * Windows Vista, Windows Server 2008,
+ * Windows 10, Windows Server 2016, and later.
+ * 1 The operating system is
+ * Windows XP, Windows 7, or Windows Server 2008 R2.
+ * 2 The operating system is
+ * Windows XP Professional x64 Edition operating system,
+ * Windows Server 2003, Windows Server 2003 R2,
+ * Windows 8, or Windows Server 2012.
+ * 3 The operating system is
+ * Windows 8.1 or Windows Server 2012 R2.
+ *
+ * I guess this results in:
+ *
+ * Windows Server 2022 => 10.0 (20348)
+ * Windows Server 2019 => 10.0
+ * Windows Server operating system => 10.0
+ * Windows 10 and Windows Server 2016 => 10.0 (14393)
+ * Windows 8.1 and Windows Server 2012 R2 => 6.3 (9600)
+ * Windows 8 and Windows Server 2012 => 6.2
+ * Windows 7 and Windows Server 2008 R2 => 6.1 (7600)
+ * Windows Vista and Windows Server 2008 => 6.0
+ * Windows XP operating system Service Pack 1 (SP1) => 5.2
+ * Windows XP and Windows Server 2003 => 5.1
+ * Windows 2000 => 5.0
+ * Windows NT 4.0 => 4.0
+ */
+ uint32 MinorVersion;
+ /*
+ * From [MS-RPRN] 7 Appendix B: Product Behavior:
+ *
+ * Windows Server 2019 >= 17633
+ * Windows Server operating system >= 16299
+ * Windows 10 and Windows Server 2016 >= 10586
+ * Windows 8.1 and Windows Server 2012 R2 >= 9431
+ * Windows 8 and Windows Server 2012 >= 9200
+ * Windows 7 and Windows Server 2008 R2 >= 7007
+ * Windows Vista operating system with Service Pack 1 (SP1) and
+ * Windows Server 2008 >= 6001
+ * Windows Vista and Windows Server 2008 >= 6000
+ * Windows XP operating system Service Pack 1 (SP1) >= 2196
+ * Windows XP and Windows Server 2003 >= 2196
+ * Windows 2000 >= 1382
+ * Windows NT 4.0 >= 1381
+ *
+ * From testing:
+ * Windows Server 2022 => 10.0 (20348)
+ */
+ uint32 BuildNumber;
+ uint32 PlatformId;
+ [subcontext(0),subcontext_size(256)] nstring CSDVersion;
+ uint16 ServicePackMajor;
+ uint16 ServicePackMinor;
+ netr_SuiteMask SuiteMask;
+ netr_ProductType ProductType;
+ uint8 Reserved;
+ } netr_OsVersionInfoEx;
+
+ typedef struct {
+ /* these first 3 values come from the fact windows
+ actually encodes this structure as a UNICODE_STRING
+ - see MS-NRPC section 2.2.1.3.9 */
+ /* 142 * 2 = 284 (length of structure "netr_OsVersionInfoEx") */
+ [value(142)] uint3264 length;
+ [value(0)] uint3264 dummy;
+ [value(142)] uint3264 size;
+ [subcontext(0),subcontext_size(size*2)]
+ netr_OsVersionInfoEx os;
+ } netr_OsVersion;
+
+ typedef struct {
+ /* value is 284 when info != os, otherwise 0 (for length and
+ size) */
+ [value(os == NULL ? 0 : 284)] uint16 length;
+ [value(os == NULL ? 0 : 284)] uint16 size;
+ netr_OsVersion *os;
+ } netr_OsVersionContainer;
+
+ typedef struct {
+ netr_LsaPolicyInformation lsa_policy;
+ [string,charset(UTF16)] uint16 *dns_hostname;
+ [string,charset(UTF16)] uint16 *sitename;
+ [string,charset(UTF16)] uint16 *dummy1;
+ [string,charset(UTF16)] uint16 *dummy2;
+ [string,charset(UTF16)] uint16 *dummy3;
+ [string,charset(UTF16)] uint16 *dummy4;
+ netr_OsVersionContainer os_version;
+ lsa_String os_name;
+ lsa_String dummy_string3;
+ lsa_String dummy_string4;
+ netr_WorkstationFlags workstation_flags;
+ kerb_EncTypes supported_enc_types;
+ uint32 dummy_long3;
+ uint32 dummy_long4;
+ } netr_WorkstationInformation;
+
+ typedef union {
+ [case(1)] netr_WorkstationInformation *workstation_info;
+ [case(2)] netr_WorkstationInformation *lsa_policy_info;
+ } netr_WorkstationInfo;
+
+ typedef struct {
+ netr_TrustFlags flags;
+ uint32 parent_index;
+ lsa_TrustType trust_type;
+ lsa_TrustAttributes trust_attributes;
+ } netr_trust_extension_info;
+
+ typedef struct {
+ /* these first 3 values come from the fact windows
+ actually encodes this structure as a UNICODE_STRING
+ - see MS-NRPC section 2.2.1.3.9 */
+ [value(8)] uint3264 length;
+ [value(0)] uint3264 dummy;
+ [value(8)] uint3264 size;
+ [subcontext(0),subcontext_size(size*2)]
+ netr_trust_extension_info info;
+ } netr_trust_extension;
+
+ typedef struct {
+ /* value is 16 when info != NULL, otherwise 0 */
+ [value(info == NULL ? 0 : 16)] uint16 length;
+ [value(info == NULL ? 0 : 16)] uint16 size;
+ netr_trust_extension *info;
+ } netr_trust_extension_container;
+
+ typedef struct {
+ lsa_StringLarge domainname;
+ lsa_StringLarge dns_domainname;
+ lsa_StringLarge dns_forestname;
+ GUID domain_guid;
+ dom_sid2 *domain_sid;
+ netr_trust_extension_container trust_extension;
+ lsa_StringLarge dummy_string2;
+ lsa_StringLarge dummy_string3;
+ lsa_StringLarge dummy_string4;
+ uint32 dummy_long1;
+ uint32 dummy_long2;
+ uint32 dummy_long3;
+ uint32 dummy_long4;
+ } netr_OneDomainInfo;
+
+ typedef struct {
+ netr_OneDomainInfo primary_domain;
+ uint32 trusted_domain_count;
+ [size_is(trusted_domain_count)] netr_OneDomainInfo *trusted_domains;
+ netr_LsaPolicyInformation lsa_policy;
+ lsa_StringLarge dns_hostname;
+ lsa_StringLarge dummy_string2;
+ lsa_StringLarge dummy_string3;
+ lsa_StringLarge dummy_string4;
+ netr_WorkstationFlags workstation_flags;
+ kerb_EncTypes supported_enc_types;
+ uint32 dummy_long3;
+ uint32 dummy_long4;
+ } netr_DomainInformation;
+
+ typedef union {
+ [case(1)] netr_DomainInformation *domain_info;
+ [case(2)] netr_LsaPolicyInformation *lsa_policy_info;
+ } netr_DomainInfo;
+
+ [public] NTSTATUS netr_LogonGetDomainInfo(
+ [in] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [in,out,ref] netr_Authenticator *return_authenticator,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] netr_WorkstationInfo *query,
+ [out,ref,switch_is(level)] netr_DomainInfo *info
+ );
+
+ /*****************/
+ /* Function 0x1e */
+
+ /* [MS-NRPC] 2.2.1.3.8 NL_PASSWORD_VERSION */
+
+ /* someone's birthday ? */
+ const int NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT = 0x02231968;
+
+ typedef struct {
+ uint32 ReservedField;
+ uint32 PasswordVersionNumber;
+ uint32 PasswordVersionPresent;
+ } NL_PASSWORD_VERSION;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 data[512];
+ uint32 length;
+ } netr_CryptPassword;
+
+ NTSTATUS netr_ServerPasswordSet2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 *account_name,
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [in,ref] netr_CryptPassword *new_password
+ );
+
+ /****************/
+ /* Function 0x1f */
+ NTSTATUS netr_ServerPasswordGet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 *account_name,
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [out,ref] samr_Password *password
+ );
+
+ typedef [public] enum {
+ SendToSamUpdatePassword = 0,
+ SendToSamResetBadPasswordCount = 1,
+ SendToSamUpdatePasswordForward = 2,
+ SendToSamUpdateLastLogonTimestamp = 3,
+ SendToSamResetSmartCardPassword = 4
+ } netr_SendToSamType;
+
+ typedef struct {
+ GUID guid;
+ } netr_SendToSamResetBadPasswordCount;
+
+ typedef [nodiscriminant, public,switch_type(netr_SendToSamType)] union {
+ /* TODO Implement other SendToSam message types
+ * [case(SendToSamUpdatePassword)] netr_SendToSamUpdatePassword ...; */
+ [case(SendToSamResetBadPasswordCount)] netr_SendToSamResetBadPasswordCount reset_bad_password;
+ /*
+ * [case(SendToSamUpdatePasswordForward)] netrSendToSamUpdatePasswordForward ...;
+ * [case(SendToSamUpdateLastLogonTimestamp)] netrSendToSamUpdateLastLogonTimestamp ...;
+ * [case(SendToSamResetSmartCardPassword)] netrSendToSamResetSmartCardPassword ...;
+ */
+ [default];
+ } netr_SendToSamMessage;
+
+ typedef [public] struct {
+ netr_SendToSamType message_type;
+ uint32 message_size;
+ [switch_is(message_type), subcontext(0), subcontext_size(message_size)] netr_SendToSamMessage message;
+ } netr_SendToSamBase;
+
+ /****************/
+ /* Function 0x20 */
+ NTSTATUS netr_NetrLogonSendToSam(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [in,ref] [size_is(buffer_len)] uint8 *opaque_buffer,
+ [in] uint32 buffer_len
+ );
+
+ /****************/
+ /* Function 0x21 */
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_String *sitename;
+ } netr_DsRAddressToSitenamesWCtr;
+
+ typedef struct {
+ [size_is(size)] uint8 *buffer;
+ uint32 size;
+ } netr_DsRAddress;
+
+ WERROR netr_DsRAddressToSitenamesW(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [range(0,32000)] uint32 count,
+ [in] [size_is(count)] [ref] netr_DsRAddress *addresses,
+ [out] [ref] netr_DsRAddressToSitenamesWCtr **ctr
+ );
+
+ /****************/
+ /* Function 0x22 */
+ WERROR netr_DsRGetDCNameEx2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *client_account,
+ [in] samr_AcctFlags mask,
+ [in,unique] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] GUID *domain_guid,
+ [in,unique] [string,charset(UTF16)] uint16 *site_name,
+ [in] netr_DsRGetDCName_flags flags,
+ [out,ref] netr_DsRGetDCNameInfo **info
+ );
+
+ /****************/
+ /* Function 0x23 */
+ [todo] WERROR netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN();
+
+ /****************/
+ /* Function 0x24 */
+
+ typedef [public] struct {
+ [string,charset(UTF16)] uint16 *netbios_name;
+ [string,charset(UTF16)] uint16 *dns_name;
+ netr_TrustFlags trust_flags;
+ uint32 parent_index;
+ lsa_TrustType trust_type;
+ lsa_TrustAttributes trust_attributes;
+ dom_sid2 *sid;
+ GUID guid;
+ } netr_DomainTrust;
+
+ typedef [public] struct {
+ uint32 count;
+ [size_is(count)] netr_DomainTrust *array;
+ } netr_DomainTrustList;
+
+ WERROR netr_NetrEnumerateTrustedDomainsEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [out,ref] netr_DomainTrustList *dom_trust_list
+ );
+
+ /****************/
+ /* Function 0x25 */
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_String *sitename;
+ [size_is(count)] lsa_String *subnetname;
+ } netr_DsRAddressToSitenamesExWCtr;
+
+ WERROR netr_DsRAddressToSitenamesExW(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [range(0,32000)] uint32 count,
+ [in] [size_is(count)] [ref] netr_DsRAddress *addresses,
+ [out] [ref] netr_DsRAddressToSitenamesExWCtr **ctr
+ );
+
+ /****************/
+ /* Function 0x26 */
+
+ typedef struct {
+ uint32 num_sites;
+ [size_is(num_sites)] [unique] lsa_String *sites;
+ } DcSitesCtr;
+
+ WERROR netr_DsrGetDcSiteCoverageW(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [out,ref] DcSitesCtr **ctr
+ );
+
+ /****************/
+ /* Function 0x27 */
+ typedef [public,bitmap32bit] bitmap {
+ /* Request MUST be passed to the domain controller at the root of the forest. */
+ NETLOGON_SAMLOGON_FLAG_PASS_TO_FOREST_ROOT = 0x00000001,
+ /* Request MUST be passed to the DC at the end of the first hop over a cross-forest trust. */
+ NETLOGON_SAMLOGON_FLAG_PASS_CROSS_FOREST_HOP = 0x00000002,
+ /* Request was passed by an RODC to a DC in a different domain. */
+ NETLOGON_SAMLOGON_FLAG_RODC_TO_OTHER_DOMAIN = 0x00000004,
+ /* Request is an NTLM authentication package request passed by an RODC. */
+ NETLOGON_SAMLOGON_FLAG_RODC_NTLM_REQUEST = 0x00000008
+ } netr_LogonSamLogon_flags;
+
+ NTSTATUS netr_LogonSamLogonEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in] netr_LogonInfoClass logon_level,
+ [in,ref] [switch_is(logon_level)] netr_LogonLevel *logon,
+ [in] uint16 validation_level,
+ [out,ref] [switch_is(validation_level)] netr_Validation *validation,
+ [out,ref] uint8 *authoritative,
+ [in,out,ref] netr_LogonSamLogon_flags *flags
+ );
+
+ /****************/
+ /* Function 0x28 */
+
+ WERROR netr_DsrEnumerateDomainTrusts(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] netr_TrustFlags trust_flags,
+ [out,ref] netr_DomainTrustList *trusts
+ );
+
+
+ /****************/
+ /* Function 0x29 */
+ WERROR netr_DsrDeregisterDNSHostRecords(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *domain,
+ [in,unique] GUID *domain_guid,
+ [in,unique] GUID *dsa_guid,
+ [in,ref] [string,charset(UTF16)] uint16 *dns_host
+ );
+
+ /****************/
+ /* Function 0x2a */
+ NTSTATUS netr_ServerTrustPasswordsGet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] [string,charset(UTF16)] uint16 *account_name,
+ [in] netr_SchannelType secure_channel_type,
+ [in] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [out,ref] samr_Password *new_owf_password,
+ [out,ref] samr_Password *old_owf_password
+ );
+
+ /****************/
+ /* Function 0x2b */
+
+ const int DS_GFTI_UPDATE_TDO = 0x1;
+
+ WERROR netr_DsRGetForestTrustInformation(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *trusted_domain_name,
+ [in] uint32 flags,
+ [out,ref] lsa_ForestTrustInformation **forest_trust_info
+ );
+
+ /****************/
+ /* Function 0x2c */
+ NTSTATUS netr_GetForestTrustInformation(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [in] uint32 flags,
+ [out,ref] lsa_ForestTrustInformation **forest_trust_info
+ );
+
+ /****************/
+ /* Function 0x2d */
+
+ /* this is the ADS variant. I don't yet know what the "flags" are for */
+ NTSTATUS netr_LogonSamLogonWithFlags(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *computer_name,
+ [in,unique] netr_Authenticator *credential,
+ [in,out,unique] netr_Authenticator *return_authenticator,
+ [in] netr_LogonInfoClass logon_level,
+ [in,ref] [switch_is(logon_level)] netr_LogonLevel *logon,
+ [in] uint16 validation_level,
+ [out,ref] [switch_is(validation_level)] netr_Validation *validation,
+ [out,ref] uint8 *authoritative,
+ [in,out,ref] netr_LogonSamLogon_flags *flags
+ );
+
+ /****************/
+ /* Function 0x2e */
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] uint32 *data;
+ uint32 entry_count;
+ [size_is(count)] lsa_String *entries;
+ } netr_TrustInfo;
+
+ NTSTATUS netr_ServerGetTrustInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *account_name,
+ [in] netr_SchannelType secure_channel_type,
+ [in,ref] [string,charset(UTF16)] uint16 *computer_name,
+ [in,ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [out,ref] samr_Password *new_owf_password,
+ [out,ref] samr_Password *old_owf_password,
+ [out,ref] netr_TrustInfo **trust_info
+ );
+
+ /****************/
+ /* Function 0x2f */
+
+ NTSTATUS netr_Unused47(void);
+
+
+ /****************/
+ /* Function 0x30 */
+
+ typedef enum {
+ NlDnsLdapAtSite = 22,
+ NlDnsGcAtSite = 25,
+ NlDnsDsaCname = 28,
+ NlDnsKdcAtSite = 30,
+ NlDnsDcAtSite = 32,
+ NlDnsRfc1510KdcAtSite = 34,
+ NlDnsGenericGcAtSite = 36
+ } netr_DnsType;
+
+ typedef enum {
+ NlDnsInfoTypeNone = 0,
+ NlDnsDomainName = 1,
+ NlDnsDomainNameAlias = 2,
+ NlDnsForestName = 3,
+ NlDnsForestNameAlias = 4,
+ NlDnsNdncDomainName = 5,
+ NlDnsRecordName = 6
+ } netr_DnsDomainInfoType;
+
+ typedef struct {
+ netr_DnsType type;
+ [string,charset(UTF16)] uint16 *dns_domain_info;
+ netr_DnsDomainInfoType dns_domain_info_type;
+ uint32 priority;
+ uint32 weight;
+ uint32 port;
+ boolean32 dns_register;
+ uint32 status;
+ } NL_DNS_NAME_INFO;
+
+ typedef [public] struct {
+ uint32 count;
+ [size_is(count)] NL_DNS_NAME_INFO *names;
+ } NL_DNS_NAME_INFO_ARRAY;
+
+ NTSTATUS netr_DsrUpdateReadOnlyServerDnsRecords(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *computer_name,
+ [in, ref] netr_Authenticator *credential,
+ [out,ref] netr_Authenticator *return_authenticator,
+ [in,unique] [string,charset(UTF16)] uint16 *site_name,
+ [in] uint32 dns_ttl,
+ [in,out,ref] NL_DNS_NAME_INFO_ARRAY *dns_names
+ );
+}
diff --git a/librpc/idl/nfs4acl.idl b/librpc/idl/nfs4acl.idl
new file mode 100644
index 0000000..10a60ed
--- /dev/null
+++ b/librpc/idl/nfs4acl.idl
@@ -0,0 +1,51 @@
+#include "idl_types.h"
+
+/*
+ NFS4 ACL format on disk
+ see http://www.suse.de/~agruen/nfs4acl/
+*/
+
+import "misc.idl", "security.idl";
+
+[
+ version(1.0),
+ pointer_default(unique)
+]
+interface nfs4acl_interface
+{
+ const char *NFS4ACL_NDR_XATTR_NAME = "security.nfs4acl_ndr";
+
+ const char *NFS4ACL_XATTR_OWNER_WHO = "OWNER@";
+ const char *NFS4ACL_XATTR_GROUP_WHO = "GROUP@";
+ const char *NFS4ACL_XATTR_EVERYONE_WHO = "EVERYONE@";
+
+ const uint8 ACL4_XATTR_VERSION_40 = 0x00;
+ const uint8 ACL4_XATTR_VERSION_41 = 0x01;
+ const uint8 ACL4_XATTR_VERSION_DEFAULT = ACL4_XATTR_VERSION_41;
+
+ const uint8 ACL4_AUTO_INHERIT = 0x01;
+ const uint8 ACL4_PROTECTED = 0x02;
+ const uint8 ACL4_DEFAULTED = 0x04;
+ const uint8 ACL4_WRITE_THROUGH = 0x40;
+
+ /* these structures use the same bit values and other constants as
+ in security.idl */
+ typedef [flag(NDR_BIG_ENDIAN)] struct {
+ uint16 e_type;
+ uint16 e_flags;
+ uint32 e_mask;
+ uint32 e_id;
+ utf8string e_who;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad;
+ } nfs4ace;
+
+ typedef [public,flag(NDR_BIG_ENDIAN)] struct {
+ uint8 a_version;
+ uint8 a_flags;
+ uint16 a_count;
+ uint32 a_owner_mask;
+ uint32 a_group_mask;
+ uint32 a_other_mask;
+ nfs4ace ace[a_count];
+ } nfs4acl;
+}
diff --git a/librpc/idl/notify.idl b/librpc/idl/notify.idl
new file mode 100644
index 0000000..5f83f4f
--- /dev/null
+++ b/librpc/idl/notify.idl
@@ -0,0 +1,94 @@
+#include "idl_types.h"
+
+import "file_id.idl", "server_id.idl";
+
+/*
+ IDL structures for notify change code
+
+ this defines the structures used in the notify database code, and
+ the change notify buffers
+*/
+
+[
+ pointer_default(unique)
+]
+interface notify
+{
+
+ /* structure used in the notify database */
+ typedef [public] struct {
+ server_id server;
+ uint32 filter; /* filter to apply in this directory */
+ uint32 subdir_filter; /* filter to apply in child directories */
+ uint32 dir_fd; /* fd of open directory */
+ file_id dir_id; /* file_id of open directory */
+ utf8string path;
+ uint32 path_len; /* saves some computation on search */
+ pointer private_data;
+ } notify_entry;
+
+ typedef [public] struct {
+ uint32 num_entries;
+ notify_entry entries[num_entries];
+ } notify_entry_array;
+
+ typedef [public] struct {
+ server_id server;
+ uint32 filter; /* filter to apply in this directory */
+ uint32 subdir_filter; /* filter to apply in child directories */
+ pointer private_data;
+ } notify_db_entry;
+
+ /*
+ to allow for efficient search for matching entries, we
+ divide them by the directory depth, with a separate array
+ per depth. The entries within each depth are sorted by path,
+ allowing for a bisection search.
+
+ The max_mask and max_mask_subdir at each depth is the
+ bitwise or of the filters and subdir filters for all entries
+ at that depth. This allows a depth to be quickly skipped if
+ no entries will match the target filter
+ */
+ typedef struct {
+ uint32 max_mask;
+ uint32 max_mask_subdir;
+ uint32 num_entries;
+ notify_entry entries[num_entries];
+ } notify_depth;
+
+ typedef [public] struct {
+ uint32 num_depths;
+ notify_depth depth[num_depths];
+ } notify_array;
+
+ /* structure sent between servers in notify messages */
+ typedef [public] struct {
+ uint32 action;
+ utf8string dir;
+ utf8string path;
+ pointer private_data;
+ } notify_event;
+
+ typedef [v1_enum] enum {
+ FILE_ACTION_ADDED = 0x00000001,
+ FILE_ACTION_REMOVED = 0x00000002,
+ FILE_ACTION_MODIFIED = 0x00000003,
+ FILE_ACTION_RENAMED_OLD_NAME = 0x00000004,
+ FILE_ACTION_RENAMED_NEW_NAME = 0x00000005,
+ FILE_ACTION_ADDED_STREAM = 0x00000006,
+ FILE_ACTION_REMOVED_STREAM = 0x00000007,
+ FILE_ACTION_MODIFIED_STREAM = 0x00000008
+ } FILE_NOTIFY_ACTION;
+
+ /* structure sent at the CIFS layer */
+ /* Align on 4-byte boundary according to MS-CIFS 2.2.7.4.2 */
+ typedef [public,gensize,flag(NDR_ALIGN4)] struct {
+ uint32 NextEntryOffset;
+ FILE_NOTIFY_ACTION Action;
+ [value(strlen_m(FileName1)*2)] uint32 FileNameLength;
+ [charset(UTF16),flag(STR_NOTERM)]
+ uint16 FileName1[strlen_m(FileName1)];
+ DATA_BLOB _pad;
+ } FILE_NOTIFY_INFORMATION;
+}
diff --git a/librpc/idl/ntlmssp.idl b/librpc/idl/ntlmssp.idl
new file mode 100644
index 0000000..0b4a7ac
--- /dev/null
+++ b/librpc/idl/ntlmssp.idl
@@ -0,0 +1,307 @@
+#include "idl_types.h"
+
+import "security.idl";
+
+/*
+ ntlmssp interface definition
+*/
+
+[
+ pointer_default(unique),
+ helper("../librpc/ndr/ndr_ntlmssp.h"),
+ helpstring("NTLM messages"),
+ uuid("6e746c6d-7373-700a-0000-00000000")
+]
+interface ntlmssp
+{
+ typedef [v1_enum] enum {
+ NtLmNegotiate = 0x00000001,
+ NtLmChallenge = 0x00000002,
+ NtLmAuthenticate = 0x00000003
+ } ntlmssp_MessageType;
+
+ /* [MS-NLMP] 2.2.2.5 NEGOTIATE */
+
+ typedef [bitmap32bit] bitmap {
+ NTLMSSP_NEGOTIATE_UNICODE = 0x00000001,
+ NTLMSSP_NEGOTIATE_OEM = 0x00000002, /* NTLM_NEGOTIATE_OEM in MS-NLMP */
+ NTLMSSP_REQUEST_TARGET = 0x00000004,
+ NTLMSSP_NEGOTIATE_SIGN = 0x00000010, /* Message integrity */
+ NTLMSSP_NEGOTIATE_SEAL = 0x00000020, /* Message confidentiality */
+ NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040,
+ NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080,
+ NTLMSSP_NEGOTIATE_NETWARE = 0x00000100, /* not mentioned in MS-NLMP */
+ NTLMSSP_NEGOTIATE_NTLM = 0x00000200,
+ NTLMSSP_NEGOTIATE_NT_ONLY = 0x00000400,
+ NTLMSSP_ANONYMOUS = 0x00000800, /* no symbol name in MS-NLMP */
+ NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000,
+ NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000,
+ NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL = 0x00004000, /* not mentioned in MS-NLMP */
+ NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000,
+ NTLMSSP_TARGET_TYPE_DOMAIN = 0x00010000,
+ NTLMSSP_TARGET_TYPE_SERVER = 0x00020000,
+ NTLMSSP_TARGET_TYPE_SHARE = 0x00040000,
+ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000,
+ NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000,
+ NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000,
+ NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000,
+ NTLMSSP_NEGOTIATE_VERSION = 0x02000000,
+ NTLMSSP_NEGOTIATE_128 = 0x20000000, /* 128-bit encryption */
+ NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000,
+ NTLMSSP_NEGOTIATE_56 = 0x80000000
+ } NEGOTIATE;
+
+ /* convenience mapping */
+ const int NTLMSSP_NEGOTIATE_NTLM2 = NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
+
+ /*
+ NTLMSSP_WINDOWS_MAJOR_VERSION_5: Windows XP SP2 and Server 2003
+ NTLMSSP_WINDOWS_MAJOR_VERSION_6: Windows Vista, Server 2008, 7, Server 2008 R2, 8, Server 2012, 8.1, Server 2012 R2
+ NTLMSSP_WINDOWS_MAJOR_VERSION_10: Windows 10, Windows Server 2016 Technical Preview
+ */
+
+ typedef [enum8bit] enum {
+ NTLMSSP_WINDOWS_MAJOR_VERSION_5 = 0x05,
+ NTLMSSP_WINDOWS_MAJOR_VERSION_6 = 0x06,
+ NTLMSSP_WINDOWS_MAJOR_VERSION_10 = 0x0A
+ } ntlmssp_WindowsMajorVersion;
+
+ /*
+ NTLMSSP_WINDOWS_MINOR_VERSION_0: Windows Vista, 10, Server 2016 Technical Preview
+ NTLMSSP_WINDOWS_MINOR_VERSION_1: Windows XP SP2, 7, Server 2008 R2
+ NTLMSSP_WINDOWS_MINOR_VERSION_2: Windows Server 2003, 8, Server 2012
+ NTLMSSP_WINDOWS_MINOR_VERSION_3: Windows 8.1, Server 2012 R2
+ */
+
+ typedef [enum8bit] enum {
+ NTLMSSP_WINDOWS_MINOR_VERSION_0 = 0x00,
+ NTLMSSP_WINDOWS_MINOR_VERSION_1 = 0x01,
+ NTLMSSP_WINDOWS_MINOR_VERSION_2 = 0x02,
+ NTLMSSP_WINDOWS_MINOR_VERSION_3 = 0x03
+ } ntlmssp_WindowsMinorVersion;
+
+ /*
+ NTLMSSP_REVISION_W2K3_RC1:
+ NTLMSSP_REVISION_W2K3: Windows XP SP2, Server 2003, Vista, Server 2008, 7, Server 2008 R2
+ */
+
+ typedef [enum8bit] enum {
+ NTLMSSP_REVISION_W2K3_RC1 = 0x0A,
+ NTLMSSP_REVISION_W2K3 = 0x0F
+ } ntlmssp_NTLMRevisionCurrent;
+
+ /* [MS-NLMP] 2.2.2.10 VERSION */
+
+ typedef [public] struct {
+ ntlmssp_WindowsMajorVersion ProductMajorVersion;
+ ntlmssp_WindowsMinorVersion ProductMinorVersion;
+ uint16 ProductBuild;
+ uint8 Reserved[3];
+ ntlmssp_NTLMRevisionCurrent NTLMRevisionCurrent;
+ } ntlmssp_VERSION;
+
+ typedef [noprint,nodiscriminant] union {
+ [case(NTLMSSP_NEGOTIATE_VERSION)] ntlmssp_VERSION version;
+ [default];
+ } ntlmssp_Version;
+
+ /* [MS-NLMP] 2.2.1.1 NEGOTIATE_MESSAGE */
+
+ typedef [public] struct {
+ [charset(DOS),value("NTLMSSP")] uint8 Signature[8];
+ [value(NtLmNegotiate)] ntlmssp_MessageType MessageType;
+ NEGOTIATE NegotiateFlags;
+ [value(DomainName ? strlen(DomainName) : 0)] uint16 DomainNameLen;
+ [value(DomainNameLen)] uint16 DomainNameMaxLen;
+ [relative] [subcontext(0),subcontext_size(DomainNameLen)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_OEM))] string *DomainName;
+ [value(Workstation ? strlen(Workstation) : 0)] uint16 WorkstationLen;
+ [value(WorkstationLen)] uint16 WorkstationMaxLen;
+ [relative] [subcontext(0),subcontext_size(WorkstationLen)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_OEM))] string *Workstation;
+ [switch_is(NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)] ntlmssp_Version Version;
+ } NEGOTIATE_MESSAGE;
+
+ typedef enum {
+ MsvAvEOL = 0,
+ MsvAvNbComputerName = 1,
+ MsvAvNbDomainName = 2,
+ MsvAvDnsComputerName = 3,
+ MsvAvDnsDomainName = 4,
+ MsvAvDnsTreeName = 5,
+ MsvAvFlags = 6,
+ MsvAvTimestamp = 7,
+ MsvAvSingleHost = 8,
+ MsvAvTargetName = 9,
+ MsvChannelBindings = 10
+ } ntlmssp_AvId;
+
+ /* [MS-NLMP] 2.2.2.2 SingleHostData */
+
+ typedef [flag(NDR_PAHEX)] struct {
+ [value(8+ndr_size_LSAP_TOKEN_INFO_INTEGRITY(&r->token_info, 0)+r->remaining.length)] uint32 Size;
+ [value(0)] uint32 Z4;
+ LSAP_TOKEN_INFO_INTEGRITY token_info;
+ [flag(NDR_REMAINING)] DATA_BLOB remaining;
+ } ntlmssp_SingleHostData;
+
+ typedef [bitmap32bit] bitmap {
+ NTLMSSP_AVFLAG_CONSTRAINTED_ACCOUNT = 0x00000001,
+ NTLMSSP_AVFLAG_MIC_IN_AUTHENTICATE_MESSAGE = 0x00000002,
+ NTLMSSP_AVFLAG_TARGET_SPN_FROM_UNTRUSTED_SOURCE = 0x00000004
+ } ntlmssp_AvFlags;
+
+ typedef [gensize,nodiscriminant,flag(NDR_NOALIGN)] union {
+ [case(MsvAvEOL)] ;
+ [case(MsvAvNbComputerName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvNbComputerName;
+ [case(MsvAvNbDomainName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvNbDomainName;
+ [case(MsvAvDnsComputerName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvDnsComputerName;
+ [case(MsvAvDnsDomainName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvDnsDomainName;
+ [case(MsvAvDnsTreeName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvDnsTreeName;
+ [case(MsvAvFlags)] ntlmssp_AvFlags AvFlags;
+ [case(MsvAvTimestamp)] NTTIME AvTimestamp;
+ [case(MsvAvSingleHost)] ntlmssp_SingleHostData AvSingleHost;
+ [case(MsvAvTargetName)] [flag(ndr_ntlmssp_negotiated_string_flags(NTLMSSP_NEGOTIATE_UNICODE))] string AvTargetName;
+ [case(MsvChannelBindings)] uint8 ChannelBindings[16];
+ [default] [flag(NDR_REMAINING)] DATA_BLOB blob;
+ } ntlmssp_AvValue;
+
+ /* [MS-NLMP] 2.2.2.1 AV_PAIR */
+
+ typedef [public,flag(NDR_NOALIGN)] struct {
+ ntlmssp_AvId AvId;
+ [value(ndr_size_ntlmssp_AvValue(&r->Value, r->AvId, 0))] uint16 AvLen;
+ [subcontext(0),subcontext_size(AvLen),switch_is(AvId)] ntlmssp_AvValue Value;
+ } AV_PAIR;
+
+ typedef [public,gensize,nopush,nopull,flag(NDR_NOALIGN)] struct {
+ uint32 count;
+ AV_PAIR pair[count];
+ } AV_PAIR_LIST;
+
+ /* [MS-NLMP] 2.2.1.2 CHALLENGE_MESSAGE */
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ [charset(DOS),value("NTLMSSP")] uint8 Signature[8];
+ [value(NtLmChallenge)] ntlmssp_MessageType MessageType;
+ [value(ndr_ntlmssp_string_length(NegotiateFlags, TargetName))] uint16 TargetNameLen;
+ [value(TargetNameLen)] uint16 TargetNameMaxLen;
+ [relative] [subcontext(0),subcontext_size(TargetNameLen)] [flag(ndr_ntlmssp_negotiated_string_flags(r->NegotiateFlags))] string *TargetName;
+ NEGOTIATE NegotiateFlags;
+ uint8 ServerChallenge[8];
+ uint8 Reserved[8];
+ [value(ndr_size_AV_PAIR_LIST(TargetInfo, ndr->flags))] uint16 TargetInfoLen;
+ [value(TargetInfoLen)] uint16 TargetInfoMaxLen;
+ [relative] [subcontext(0),subcontext_size(TargetInfoLen)] AV_PAIR_LIST *TargetInfo;
+ [switch_is(NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)] ntlmssp_Version Version;
+ } CHALLENGE_MESSAGE;
+
+ /* [MS-NLMP] 2.2.2.3 LM_RESPONSE */
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint8 Response[24];
+ } LM_RESPONSE;
+
+ /* [MS-NLMP] 2.2.2.4 LMv2_RESPONSE */
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint8 Response[16];
+ uint8 ChallengeFromClient[8];
+ } LMv2_RESPONSE;
+
+ typedef [nodiscriminant] union {
+ [case(24)] LM_RESPONSE v1;
+ [default];
+ } ntlmssp_LM_RESPONSE_with_len;
+
+ /* [MS-NLMP] 2.2.2.6 NTLM_RESPONSE */
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint8 Response[24];
+ } NTLM_RESPONSE;
+
+ /* [MS-NLMP] 2.2.2.7 NTLMv2_CLIENT_CHALLENGE */
+
+ typedef [flag(NDR_PAHEX)] struct {
+ [value(1)] uint8 RespType;
+ [value(1)] uint8 HiRespType;
+ uint16 Reserved1;
+ uint32 Reserved2;
+ NTTIME TimeStamp;
+ uint8 ChallengeFromClient[8];
+ uint32 Reserved3;
+ [subcontext(0)] [flag(NDR_REMAINING)] AV_PAIR_LIST AvPairs;
+ } NTLMv2_CLIENT_CHALLENGE;
+
+ /* [MS-NLMP] 2.2.2.8 NTLMv2_RESPONSE */
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ uint8 Response[16];
+ NTLMv2_CLIENT_CHALLENGE Challenge;
+ } NTLMv2_RESPONSE;
+
+ typedef [public,nodiscriminant] union {
+ [case(0)] ;
+ [case(0x18)] NTLM_RESPONSE v1;
+ [default] NTLMv2_RESPONSE v2;
+ } ntlmssp_NTLM_RESPONSE_with_len;
+
+ const int NTLMSSP_MIC_OFFSET = 72;
+ const int NTLMSSP_MIC_SIZE = 16;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 MIC[NTLMSSP_MIC_SIZE];
+ } ntlmssp_MIC;
+
+ /* [MS-NLMP] 2.2.1.3 AUTHENTICATE_MESSAGE */
+
+ typedef [public,flag(NDR_REMAINING)] struct {
+ [charset(DOS),value("NTLMSSP")] uint8 Signature[8];
+ [value(NtLmAuthenticate)] ntlmssp_MessageType MessageType;
+ uint16 LmChallengeResponseLen;
+ [value(LmChallengeResponseLen)] uint16 LmChallengeResponseMaxLen;
+ [relative] [subcontext(0),subcontext_size(LmChallengeResponseLen),switch_is(LmChallengeResponseLen)] ntlmssp_LM_RESPONSE_with_len *LmChallengeResponse;
+ uint16 NtChallengeResponseLen;
+ [value(NtChallengeResponseLen)] uint16 NtChallengeResponseMaxLen;
+ [relative] [subcontext(0),subcontext_size(NtChallengeResponseMaxLen),switch_is(NtChallengeResponseLen)] ntlmssp_NTLM_RESPONSE_with_len *NtChallengeResponse;
+ [value(ndr_ntlmssp_string_length(NegotiateFlags, DomainName))] uint16 DomainNameLen;
+ [value(DomainNameLen)] uint16 DomainNameMaxLen;
+ [relative] [subcontext(0),subcontext_size(DomainNameLen)] [flag(ndr_ntlmssp_negotiated_string_flags(r->NegotiateFlags))] string *DomainName;
+ [value(ndr_ntlmssp_string_length(NegotiateFlags, UserName))] uint16 UserNameLen;
+ [value(UserNameLen)] uint16 UserNameMaxLen;
+ [relative] [subcontext(0),subcontext_size(UserNameLen)] [flag(ndr_ntlmssp_negotiated_string_flags(r->NegotiateFlags))] string *UserName;
+ [value(ndr_ntlmssp_string_length(NegotiateFlags, Workstation))] uint16 WorkstationLen;
+ [value(WorkstationLen)] uint16 WorkstationMaxLen;
+ [relative] [subcontext(0),subcontext_size(WorkstationLen)] [flag(ndr_ntlmssp_negotiated_string_flags(r->NegotiateFlags))] string *Workstation;
+ [value(EncryptedRandomSessionKey == NULL ? 0 : EncryptedRandomSessionKey->length)] uint16 EncryptedRandomSessionKeyLen;
+ [value(EncryptedRandomSessionKeyLen)] uint16 EncryptedRandomSessionKeyMaxLen;
+ [relative] [subcontext(0),subcontext_size(EncryptedRandomSessionKeyLen)] DATA_BLOB *EncryptedRandomSessionKey;
+ NEGOTIATE NegotiateFlags;
+ [switch_is(NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)] ntlmssp_Version Version;
+ /* MIC (Message Integrity) is only included when the client has
+ * sent a timestamp Av struct in the CHALLENGE_MESSAGE AvPair */
+ /* [flag(NDR_REMAINING)] ntlmssp_MIC mic; */
+ } AUTHENTICATE_MESSAGE;
+
+ /* NTLMSSP signature version */
+ const int NTLMSSP_SIGN_VERSION = 0x01;
+
+ /* NTLMSSP signature size */
+ const int NTLMSSP_SIG_SIZE = 16;
+
+ /* [MS-NLMP] 2.2.2.9.1 NTLMSSP_MESSAGE_SIGNATURE */
+
+ typedef [public] struct {
+ [value(NTLMSSP_SIGN_VERSION)] uint32 Version;
+ uint32 RandomPad;
+ uint32 Checksum;
+ uint32 SeqNum;
+ } NTLMSSP_MESSAGE_SIGNATURE;
+
+ /* [MS-NLMP] 2.2.2.9.2 NTLMSSP_MESSAGE_SIGNATURE for Extended Session Security */
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ [value(NTLMSSP_SIGN_VERSION)] uint32 Version;
+ uint8 Checksum[8];
+ uint32 SeqNum;
+ } NTLMSSP_MESSAGE_SIGNATURE_NTLMv2;
+
+}
diff --git a/librpc/idl/ntprinting.idl b/librpc/idl/ntprinting.idl
new file mode 100644
index 0000000..0f82a16
--- /dev/null
+++ b/librpc/idl/ntprinting.idl
@@ -0,0 +1,156 @@
+#include "idl_types.h"
+
+/*
+ old s3 spoolss tdb on-disc interface definitions
+*/
+
+[
+ pointer_default(unique),
+ helpstring("s3 printing tdb formats"),
+ uuid("a025d3cb-c605-40d6-86e1-4cff18e7dd94"),
+ helper("../librpc/ndr/ndr_ntprinting.h")
+]
+interface ntprinting
+{
+ /* Samba 3 tdb storage format: forms
+ * "dddddddd" */
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ uint32 position;
+ uint32 flag;
+ uint32 width;
+ uint32 length;
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+ } ntprinting_form;
+
+ /*
+ * First the string flags and then the Samba 3 tdb storage
+ * format: drivers
+ * "dffffffff" followed by a remaining buffer of "f" array */
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ [skip_noinit] libndr_flags string_flags;
+
+ uint32 version;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string name;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string environment;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string driverpath;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string datafile;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string configfile;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string helpfile;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string monitorname;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string defaultdatatype;
+ [flag((ndr_ntprinting_string_flags(r->string_flags)&~STR_NULLTERM)|STR_NOTERM|NDR_REMAINING)] string_array dependent_files;
+ } ntprinting_driver;
+
+ /* Samba 3 tdb storage format: devicemode
+ * "p" ptr to devicemode
+ * "ffwwwwwwwwwwwwwwwwwwdddddddddddddd"
+ * "p" ptr to devicemode private data
+ * "B" private data blob */
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ [skip_noinit] libndr_flags string_flags;
+
+ /* uint32 devicemode_ptr; */
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string devicename;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string formname;
+ uint16 specversion;
+ uint16 driverversion;
+ uint16 size;
+ uint16 driverextra;
+ uint16 orientation;
+ uint16 papersize;
+ uint16 paperlength;
+ uint16 paperwidth;
+ uint16 scale;
+ uint16 copies;
+ uint16 defaultsource;
+ uint16 printquality;
+ uint16 color;
+ uint16 duplex;
+ uint16 yresolution;
+ uint16 ttoption;
+ uint16 collate;
+ uint16 logpixels;
+ uint32 fields;
+ uint32 bitsperpel;
+ uint32 pelswidth;
+ uint32 pelsheight;
+ uint32 displayflags;
+ uint32 displayfrequency;
+ uint32 icmmethod;
+ uint32 icmintent;
+ uint32 mediatype;
+ uint32 dithertype;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 panningwidth;
+ uint32 panningheight;
+ DATA_BLOB *nt_dev_private;
+ } ntprinting_devicemode;
+
+ /*
+ * First the string flags and then the Samba 3 tdb storage
+ * format: printer_data
+ * "p" ptr to printer_data
+ * "fdB" */
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ [skip_noinit] libndr_flags string_flags;
+
+ uint32 ptr;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string name;
+ uint32 type;
+ DATA_BLOB data;
+ } ntprinting_printer_data;
+
+ /*
+ * First the string flags and then the Samba 3 tdb storage
+ * format: printer_info
+ * "dddddddddddfffffPfffff"
+ */
+
+ typedef [flag(NDR_NOALIGN),public] struct {
+ [skip_noinit] libndr_flags string_flags;
+
+ uint32 attributes;
+ uint32 priority;
+ uint32 default_priority;
+ uint32 starttime;
+ uint32 untiltime;
+ uint32 status;
+ uint32 cjobs;
+ uint32 averageppm;
+ uint32 changeid;
+ uint32 c_setprinter;
+ uint32 setuptime;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string servername;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string printername;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string sharename;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string portname;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string drivername;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string comment;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string location;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string sepfile;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string printprocessor;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string datatype;
+ [flag(ndr_ntprinting_string_flags(r->string_flags))] string parameters;
+ } ntprinting_printer_info;
+
+ /* Abstract Samba 3 printer
+ * printer_info
+ * followed by ntprinting_devicemode
+ * followed by remaining buffer of ntprinting_printer_data array */
+
+ typedef [flag(NDR_NOALIGN),public,nopull] struct {
+ ntprinting_printer_info info;
+ ntprinting_devicemode *devmode;
+ uint32 count;
+ ntprinting_printer_data printer_data[count];
+ } ntprinting_printer;
+
+}
diff --git a/librpc/idl/ntsvcs.idl b/librpc/idl/ntsvcs.idl
new file mode 100644
index 0000000..91a85b9
--- /dev/null
+++ b/librpc/idl/ntsvcs.idl
@@ -0,0 +1,399 @@
+/*
+ plug and play services
+*/
+
+import "misc.idl";
+
+[
+ uuid("8d9f4e40-a03d-11ce-8f69-08003e30051b"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\ntsvcs]","ncacn_np:[\\pipe\\plugplay]"),
+ helpstring("Plug and Play services")
+]
+interface ntsvcs
+{
+ /******************/
+ /* Function: 0x00 */
+
+ [todo] WERROR PNP_Disconnect();
+
+ /******************/
+ /* Function: 0x01 */
+
+ [todo] WERROR PNP_Connect();
+
+ /******************/
+ /* Function: 0x02 */
+
+ WERROR PNP_GetVersion(
+ [out,ref] uint16 *version
+ );
+
+ /******************/
+ /* Function: 0x03 */
+
+ [todo] WERROR PNP_GetGlobalState();
+
+ /******************/
+ /* Function: 0x04 */
+
+ [todo] WERROR PNP_InitDetection();
+
+ /******************/
+ /* Function: 0x05 */
+
+ [todo] WERROR PNP_ReportLogOn();
+
+ /******************/
+ /* Function: 0x06 */
+
+ WERROR PNP_ValidateDeviceInstance(
+ [in,ref] [string,charset(UTF16)] uint16 *devicepath,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x07 */
+
+ [todo] WERROR PNP_GetRootDeviceInstance();
+
+ /******************/
+ /* Function: 0x08 */
+
+ [todo] WERROR PNP_GetRelatedDeviceInstance();
+
+ /******************/
+ /* Function: 0x09 */
+
+ [todo] WERROR PNP_EnumerateSubKeys();
+
+ /******************/
+ /* Function: 0x0a */
+
+ const int CM_GETIDLIST_FILTER_NONE = 0x00000000;
+
+ typedef [bitmap32bit] bitmap {
+ CM_GETIDLIST_FILTER_ENUMERATOR = 0x00000001,
+ CM_GETIDLIST_FILTER_SERVICE = 0x00000002,
+ CM_GETIDLIST_FILTER_EJECTRELATIONS = 0x00000004,
+ CM_GETIDLIST_FILTER_REMOVALRELATIONS = 0x00000008,
+ CM_GETIDLIST_FILTER_POWERRELATIONS = 0x00000010,
+ CM_GETIDLIST_FILTER_BUSRELATIONS = 0x00000020,
+ CM_GETIDLIST_DONOTGENERATE = 0x10000040,
+ CM_GETIDLIST_FILTER_TRANSPORTRELATIONS = 0x00000080,
+ CM_GETIDLIST_FILTER_PRESENT = 0x00000100,
+ CM_GETIDLIST_FILTER_CLASS = 0x00000200
+ } PNP_GetIdListFlags;
+
+ WERROR PNP_GetDeviceList(
+ [in,unique] [string,charset(UTF16)] uint16 *filter,
+ [out,ref] [size_is(*length),length_is(*length)] uint16 *buffer,
+ [in,out,ref] uint32 *length,
+ [in] PNP_GetIdListFlags flags
+ );
+
+ /******************/
+ /* Function: 0x0b */
+
+ WERROR PNP_GetDeviceListSize(
+ [in,unique] [string,charset(UTF16)] uint16 *devicename,
+ [out,ref] uint32 *size,
+ [in] PNP_GetIdListFlags flags
+ );
+
+ /******************/
+ /* Function: 0x0c */
+
+ [todo] WERROR PNP_GetDepth();
+
+ /******************/
+ /* Function: 0x0d */
+
+ const int DEV_REGPROP_DESC = 1;
+
+ WERROR PNP_GetDeviceRegProp(
+ [in,ref] [string,charset(UTF16)] uint16 *devicepath,
+ [in] uint32 property,
+ [in,out,ref] winreg_Type *reg_data_type,
+ [out,ref] [size_is(*buffer_size)] [length_is(*buffer_size)] uint8 *buffer,
+ [in,out,ref] uint32 *buffer_size,
+ [in,out,ref] uint32 *needed,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x0e */
+
+ [todo] WERROR PNP_SetDeviceRegProp();
+
+ /******************/
+ /* Function: 0x0f */
+
+ [todo] WERROR PNP_GetClassInstance();
+
+ /******************/
+ /* Function: 0x10 */
+
+ [todo] WERROR PNP_CreateKey();
+
+ /******************/
+ /* Function: 0x11 */
+
+ [todo] WERROR PNP_DeleteRegistryKey();
+
+ /******************/
+ /* Function: 0x12 */
+
+ [todo] WERROR PNP_GetClassCount();
+
+ /******************/
+ /* Function: 0x13 */
+
+ [todo] WERROR PNP_GetClassName();
+
+ /******************/
+ /* Function: 0x14 */
+
+ [todo] WERROR PNP_DeleteClassKey();
+
+ /******************/
+ /* Function: 0x15 */
+
+ [todo] WERROR PNP_GetInterfaceDeviceAlias();
+
+ /******************/
+ /* Function: 0x16 */
+
+ [todo] WERROR PNP_GetInterfaceDeviceList();
+
+ /******************/
+ /* Function: 0x17 */
+
+ [todo] WERROR PNP_GetInterfaceDeviceListSize();
+
+ /******************/
+ /* Function: 0x18 */
+
+ [todo] WERROR PNP_RegisterDeviceClassAssociation();
+
+ /******************/
+ /* Function: 0x19 */
+
+ [todo] WERROR PNP_UnregisterDeviceClassAssociation();
+
+ /******************/
+ /* Function: 0x1a */
+
+ [todo] WERROR PNP_GetClassRegProp();
+
+ /******************/
+ /* Function: 0x1b */
+
+ [todo] WERROR PNP_SetClassRegProp();
+
+ /******************/
+ /* Function: 0x1c */
+
+ [todo] WERROR PNP_CreateDevInst();
+
+ /******************/
+ /* Function: 0x1d */
+
+ [todo] WERROR PNP_DeviceInstanceAction();
+
+ /******************/
+ /* Function: 0x1e */
+
+ [todo] WERROR PNP_GetDeviceStatus();
+
+ /******************/
+ /* Function: 0x1f */
+
+ [todo] WERROR PNP_SetDeviceProblem();
+
+ /******************/
+ /* Function: 0x20 */
+
+ [todo] WERROR PNP_DisableDevInst();
+
+ /******************/
+ /* Function: 0x21 */
+
+ [todo] WERROR PNP_UninstallDevInst();
+
+ /******************/
+ /* Function: 0x22 */
+
+ [todo] WERROR PNP_AddID();
+
+ /******************/
+ /* Function: 0x23 */
+
+ [todo] WERROR PNP_RegisterDriver();
+
+ /******************/
+ /* Function: 0x24 */
+
+ [todo] WERROR PNP_QueryRemove();
+
+ /******************/
+ /* Function: 0x25 */
+
+ [todo] WERROR PNP_RequestDeviceEject();
+
+ /******************/
+ /* Function: 0x26 */
+
+ [todo] WERROR PNP_IsDockStationPresent();
+
+ /******************/
+ /* Function: 0x27 */
+
+ [todo] WERROR PNP_RequestEjectPC();
+
+ /******************/
+ /* Function: 0x28 */
+
+ WERROR PNP_HwProfFlags(
+ [in] uint32 action,
+ [in,ref] [string,charset(UTF16)] uint16 *devicepath,
+ [in] uint32 config,
+ [in,out,ref] uint32 *profile_flags,
+ [in,out,unique] uint16 *veto_type,
+ [in,unique] [string,charset(UTF16)] uint16 *unknown5,
+ [out,unique] [string,charset(UTF16)] uint16 **unknown5a,
+ [in] uint32 name_length,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x29 */
+
+ typedef struct {
+ uint32 profile_handle;
+ uint16 friendly_name[80];
+ uint32 flags;
+ } PNP_HwProfInfo;
+
+ WERROR PNP_GetHwProfInfo(
+ [in] uint32 idx,
+ [in,out,ref] PNP_HwProfInfo *info,
+ [in] uint32 size,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x2a */
+
+ [todo] WERROR PNP_AddEmptyLogConf();
+
+ /******************/
+ /* Function: 0x2b */
+
+ [todo] WERROR PNP_FreeLogConf();
+
+ /******************/
+ /* Function: 0x2c */
+
+ [todo] WERROR PNP_GetFirstLogConf();
+
+ /******************/
+ /* Function: 0x2d */
+
+ [todo] WERROR PNP_GetNextLogConf();
+
+ /******************/
+ /* Function: 0x2e */
+
+ [todo] WERROR PNP_GetLogConfPriority();
+
+ /******************/
+ /* Function: 0x2f */
+
+ [todo] WERROR PNP_AddResDes();
+
+ /******************/
+ /* Function: 0x30 */
+
+ [todo] WERROR PNP_FreeResDes();
+
+ /******************/
+ /* Function: 0x31 */
+
+ [todo] WERROR PNP_GetNextResDes();
+
+ /******************/
+ /* Function: 0x32 */
+
+ [todo] WERROR PNP_GetResDesData();
+
+ /******************/
+ /* Function: 0x33 */
+
+ [todo] WERROR PNP_GetResDesDataSize();
+
+ /******************/
+ /* Function: 0x34 */
+
+ [todo] WERROR PNP_ModifyResDes();
+
+ /******************/
+ /* Function: 0x35 */
+
+ [todo] WERROR PNP_DetectResourceLimit();
+
+ /******************/
+ /* Function: 0x36 */
+
+ [todo] WERROR PNP_QueryResConfList();
+
+ /******************/
+ /* Function: 0x37 */
+
+ [todo] WERROR PNP_SetHwProf();
+
+ /******************/
+ /* Function: 0x38 */
+
+ [todo] WERROR PNP_QueryArbitratorFreeData();
+
+ /******************/
+ /* Function: 0x39 */
+
+ [todo] WERROR PNP_QueryArbitratorFreeSize();
+
+ /******************/
+ /* Function: 0x3a */
+
+ [todo] WERROR PNP_RunDetection();
+
+ /******************/
+ /* Function: 0x3b */
+
+ [todo] WERROR PNP_RegisterNotification();
+
+ /******************/
+ /* Function: 0x3c */
+
+ [todo] WERROR PNP_UnregisterNotification();
+
+ /******************/
+ /* Function: 0x3d */
+
+ [todo] WERROR PNP_GetCustomDevProp();
+
+ /******************/
+ /* Function: 0x3e */
+
+ [todo] WERROR PNP_GetVersionInternal();
+
+ /******************/
+ /* Function: 0x3f */
+
+ [todo] WERROR PNP_GetBlockedDriverInfo();
+
+ /******************/
+ /* Function: 0x40 */
+
+ [todo] WERROR PNP_GetServerSideDeviceInstallFlags();
+}
diff --git a/librpc/idl/orpc.idl b/librpc/idl/orpc.idl
new file mode 100644
index 0000000..34a35e2
--- /dev/null
+++ b/librpc/idl/orpc.idl
@@ -0,0 +1,230 @@
+#include "idl_types.h"
+
+/**
+ DCOM interfaces
+ http://www.ietf.org/internet-drafts/draft-brown-dcom-v1-spec-04.txt
+ */
+
+import "misc.idl";
+
+[
+ pointer_default(unique)
+]
+interface ObjectRpcBaseTypes
+{
+ /* COM_MINOR_VERSION = 1 (NT4.0, SP1, SP2, DCOM95). */
+ /* - Initial Release */
+ /* - Must be used when talking to downlevel machines, including */
+ /* on Remote Activation calls. */
+ /* COM_MINOR_VERSION = 2 (NT4.0 SP3 and beyond). */
+ /* - Added ResolveOxid2 to IObjectExporter to retrieve the */
+ /* COM version number of the server. Passed to the NDR engine */
+ /* to fix fatal endian-ness flaw in the way OLEAUTOMATION marshals */
+ /* BSTRS. Previous way used trailing padding, which is not NDR */
+ /* compatible. See Bug# 69189. */
+ /* COM_MINOR_VERSION = 3 (NT4.0 SP4 and DCOM95 builds 1018 and beyond) */
+ /* - OLEAUT32 added two new types to the SAFEARRAY, but SAFEARRAY */
+ /* previously included the "default" keyword, which prevented */
+ /* downlevel NDR engines from correctly handling any extensions. */
+ /* Machines with version >=5.3 don't use "default" and will */
+ /* gracefully handle future extensions to SAFEARRAY. */
+ /* old constants (for convenience) */
+
+ /* current version */
+ const uint16 COM_MAJOR_VERSION = 5;
+ const uint16 COM_MINOR_VERSION = 1;
+
+ /* Body Extensions */
+ const string dcom_ext_debugging = "f1f19680-4d2a-11ce-a66a-0020af6e72f4";
+ const string dcom_ext_extended_error = "f1f19681-4d2a-11ce-a66a-0020af6e72f4";
+
+ /* Component Object Model version number */
+
+
+ typedef [public] struct
+ {
+ uint16 MajorVersion; /* Major version number */
+ uint16 MinorVersion; /* Minor version number */
+ } COMVERSION;
+
+ /* enumeration of additional information present in the call packet. */
+ typedef bitmap {
+ ORPCF_NULL = 0x00, /* no additional info in packet */
+ ORPCF_LOCAL = 0x01, /* call is local to this machine */
+ ORPCF_RESERVED1 = 0x02, /* reserved for local use */
+ ORPCF_RESERVED2 = 0x04, /* reserved for local use */
+ ORPCF_RESERVED3 = 0x08, /* reserved for local use */
+ ORPCF_RESERVED4 = 0x10 /* reserved for local use */
+ } ORPC_FLAGS;
+
+ /* Extension to implicit parameters. */
+ typedef [public] struct
+ {
+ GUID id; /* Extension identifier. */
+ uint32 size; /* Extension size. */
+ [size_is(((size+7)&~7))] uint8 data[]; /* Extension data. */
+ } ORPC_EXTENT;
+
+
+ /* Array of extensions. */
+ typedef struct
+ {
+ uint32 size; /* Num extents. */
+ uint32 reserved; /* Must be zero. */
+ [size_is(((size+1)&~1))] ORPC_EXTENT **extent; /* extents */
+ } ORPC_EXTENT_ARRAY;
+
+
+ /* implicit 'this' pointer which is the first [in] parameter on */
+ /* every ORPC call. */
+ typedef [public] struct
+ {
+ COMVERSION version; /* COM version number */
+ uint32 flags; /* ORPCF flags for presence of other data */
+ uint32 reserved1; /* set to zero */
+ GUID cid; /* causality id of caller */
+ /* Extensions. */
+ [unique] ORPC_EXTENT_ARRAY *extensions;
+ } ORPCTHIS;
+
+
+ /* implicit 'that' pointer which is the first [out] parameter on */
+ /* every ORPC call. */
+ typedef [public] struct
+ {
+ uint32 flags; /* ORPCF flags for presence of other data */
+ /* Extensions. */
+ [unique] ORPC_EXTENT_ARRAY *extensions;
+ } ORPCTHAT;
+
+
+ /* DUALSTRINGARRAYS are the return type for arrays of network addresses, */
+ /* arrays of endpoints and arrays of both used in many ORPC interfaces */
+ typedef [public,flag(NDR_NOALIGN)] struct
+ {
+ uint16 wTowerId; /* Cannot be zero. */
+ nstring NetworkAddr;
+ } STRINGBINDING;
+
+ typedef [public,nopush,nopull,noprint] struct
+ {
+ STRINGBINDING **stringbindings;
+ } STRINGARRAY;
+
+ typedef [public,nopush,nopull,noprint] struct
+ {
+ STRINGBINDING **stringbindings;
+ SECURITYBINDING **securitybindings;
+ } DUALSTRINGARRAY;
+
+ const uint16 COM_C_AUTHZ_NONE = 0xffff;
+ typedef [public,flag(NDR_NOALIGN)] struct
+ {
+ uint16 wAuthnSvc; /* Cannot be zero. */
+ uint16 wAuthzSvc;
+ nstring PrincName;
+ } SECURITYBINDING;
+
+ /* signature value for OBJREF (object reference, actually the */
+ /* marshaled form of a COM interface).
+ * MEOW apparently stands for "Microsoft Extended Object Wireformat"
+ */
+ const uint32 OBJREF_SIGNATURE = 0x574f454d; /* 'MEOW' */
+
+ /* flag values for OBJREF */
+ typedef enum {
+ OBJREF_NULL = 0x0, /* NULL pointer */
+ OBJREF_STANDARD = 0x1, /* standard marshaled objref */
+ OBJREF_HANDLER = 0x2, /* handler marshaled objref */
+ OBJREF_CUSTOM = 0x4 /* custom marshaled objref */
+ } OBJREF_FLAGS;
+
+ /* Flag values for a STDOBJREF (standard part of an OBJREF). */
+ /* SORF_OXRES1 - SORF_OXRES8 are reserved for the object exporters */
+ /* use only, object importers must ignore them and must not enforce MBZ. */
+ typedef bitmap {
+ SORF_NULL = 0x0000, /* convenient for initializing SORF */
+ SORF_OXRES1 = 0x0001, /* reserved for exporter */
+ SORF_OXRES2 = 0x0020, /* reserved for exporter */
+ SORF_OXRES3 = 0x0040, /* reserved for exporter */
+ SORF_OXRES4 = 0x0080, /* reserved for exporter */
+ SORF_OXRES5 = 0x0100, /* reserved for exporter */
+ SORF_OXRES6 = 0x0200, /* reserved for exporter */
+ SORF_OXRES7 = 0x0400, /* reserved for exporter */
+ SORF_OXRES8 = 0x0800, /* reserved for exporter */
+ SORF_NOPING = 0x1000 /* Pinging is not required */
+ } STDOBJREF_FLAGS;
+
+ /* standard object reference */
+ typedef [public] struct
+ {
+ uint32 flags; /* STDOBJREF flags (see above) */
+ uint32 cPublicRefs; /* count of references passed */
+ hyper oxid; /* oxid of server with this oid */
+ hyper oid; /* oid of object with this ipid */
+ GUID ipid; /* ipid of interface pointer to this object */
+ } STDOBJREF;
+
+ typedef struct
+ {
+ STDOBJREF std; /* standard objref */
+ STRINGARRAY saResAddr; /* resolver address */
+ } u_standard;
+
+ typedef struct
+ {
+ STDOBJREF std; /* standard objref */
+ GUID clsid; /* Clsid of handler code */
+ STRINGARRAY saResAddr; /* resolver address */
+ } u_handler;
+
+ typedef struct
+ {
+ GUID clsid; /* Clsid of unmarshaling code */
+ uint32 cbExtension; /* size of extension data */
+ uint32 size; /* size of data that follows */
+ uint8 pData[size]; /* extension + class specific data */
+ } u_custom;
+
+ typedef struct
+ {
+ } u_null;
+
+ typedef [nodiscriminant] union
+ {
+ [case(OBJREF_NULL)] u_null u_null;
+ [case(OBJREF_STANDARD)] u_standard u_standard;
+ [case(OBJREF_HANDLER)] u_handler u_handler;
+ [case(OBJREF_CUSTOM)] u_custom u_custom;
+ } OBJREF_Types;
+
+ /* OBJREF is the format of a marshaled interface pointer. */
+ typedef [public,flag(NDR_LITTLE_ENDIAN)] struct
+ {
+ uint32 signature;
+ uint32 flags; /* OBJREF flags (see above) */
+ GUID iid; /* interface identifier */
+ [switch_is(flags), switch_type(uint32)] OBJREF_Types u_objref;
+ } OBJREF;
+
+ /* wire representation of a marshalled interface pointer */
+ typedef [public] struct
+ {
+ uint32 size;
+ [subcontext(4)] OBJREF obj;
+ } MInterfacePointer;
+
+ typedef [v1_enum,public] enum
+ {
+ COM_OK = 0x00000000,
+ COM_OUTOFMEMORY = 0x80000002,
+ COM_INVALIDARG = 0x80000003,
+ COM_NOINTERFACE = 0x80000004,
+ COM_ACCESSDENIED = 0x80070005,
+ COM_INVALID_OXID = 0x80070776,
+ COM_INVALID_OID = 0x80070777,
+ COM_INVALID_SET = 0x80070778,
+ COM_UNEXPECTED = 0x8000FFFF,
+ COM_CLSNOTFOUND = 0x80040154
+ } COMRESULT;
+}
diff --git a/librpc/idl/oxidresolver.idl b/librpc/idl/oxidresolver.idl
new file mode 100644
index 0000000..9700a1b
--- /dev/null
+++ b/librpc/idl/oxidresolver.idl
@@ -0,0 +1,96 @@
+/**
+ DCOM interfaces
+ http://www.grimes.demon.co.uk/DCOM/DCOMSpec.htm
+ */
+
+/*
+ The OXID Resolver can turn a OXID (Object Exporter ID) into a
+ RPC binding string that can be used to contact an object
+
+ (used by DCOM)
+ */
+
+import "misc.idl", "orpc.idl";
+
+[
+ uuid("99fcfec4-5260-101b-bbcb-00aa0021347a"),
+ helpstring("Object Exporter ID Resolver"),
+ endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]", "ncalrpc:"),
+ pointer_default(unique)
+]
+interface IOXIDResolver
+{
+#define OXID hyper
+#define SETID hyper
+#define IPID GUID
+#define OID GUID
+
+ /* Method to get the protocol sequences, string bindings */
+ /* and machine id for an object server given its OXID. */
+
+ [idempotent] WERROR ResolveOxid (
+ [in] OXID pOxid,
+ [in] uint16 cRequestedProtseqs,
+ [in, size_is(cRequestedProtseqs)] uint16 arRequestedProtseqs[],
+ [out] DUALSTRINGARRAY **ppdsaOxidBindings,
+ [out,ref] IPID *pipidRemUnknown,
+ [out,ref] uint32 *pAuthnHint
+ );
+
+ /* Simple ping is used to ping a Set. Client machines use this */
+ /* to inform the object exporter that it is still using the */
+ /* members of the set. */
+ /* Returns S_TRUE if the SetId is known by the object exporter, */
+ /* S_FALSE if not. */
+ [idempotent] WERROR SimplePing (
+ [in] SETID *SetId /* Must not be zero */
+ );
+
+ /* Complex ping is used to create sets of OIDs to ping. The */
+ /* whole set can subsequently be pinged using SimplePing, */
+ /* thus reducing network traffic. */
+ [idempotent] WERROR ComplexPing (
+ [in,out,ref] SETID *SetId, /* In of 0 on first call for new set. */
+ [in] uint16 SequenceNum,
+ [in] uint16 cAddToSet,
+ [in] uint16 cDelFromSet,
+ /* add these OIDs to the set */
+ [in, size_is(cAddToSet)] OID AddToSet[],
+ /*remove these OIDs from the set */
+ [in, size_is(cDelFromSet)] OID DelFromSet[],
+ [out,ref] uint16 *PingBackoffFactor/* 2^factor = multiplier */
+ );
+
+ /* In some cases the client maybe unsure that a particular */
+ /* binding will reach the server. (For example, when the oxid */
+ /* bindings have more than one TCP/IP binding) This call */
+ /* can be used to validate the binding */
+ /* from the client. */
+ [idempotent] WERROR ServerAlive ();
+
+ /* Method to get the protocol sequences, string bindings, */
+ /* RemoteUnknown IPID and COM version for an object server */
+ /* given its OXID. Supported by DCOM */
+ /* version 5.2 and above. Looks like that means
+ * Windows 2003/XP and above */
+ [idempotent] WERROR ResolveOxid2 (
+ [in] OXID pOxid,
+ [in] uint16 cRequestedProtseqs,
+ [in, size_is(cRequestedProtseqs)] uint16 arRequestedProtseqs[],
+ [out] DUALSTRINGARRAY **pdsaOxidBindings,
+ [out,ref] IPID *ipidRemUnknown,
+ [out,ref] uint32 *AuthnHint,
+ [out,ref] COMVERSION *ComVersion
+ );
+
+ typedef struct {
+ COMVERSION version;
+ uint32 unknown1;
+ } COMINFO;
+
+ [idempotent] WERROR ServerAlive2 (
+ [out,ref] COMINFO *info,
+ [out,ref] DUALSTRINGARRAY **dualstring,
+ [out,ref] uint8 *pReserved
+ );
+}
diff --git a/librpc/idl/policyagent.idl b/librpc/idl/policyagent.idl
new file mode 100644
index 0000000..ab137fa
--- /dev/null
+++ b/librpc/idl/policyagent.idl
@@ -0,0 +1,13 @@
+
+/* IPSec policy agent (Win2k) */
+[
+ uuid("d335b8f6-cb31-11d0-b0f9-006097ba4e54"),
+ version(1.5),
+ pointer_default(unique),
+ helpstring("IPSec Policy Agent")
+] interface policyagent
+{
+ /*****************/
+ /* Function 0x00 */
+ [todo] WERROR policyagent_Dummy();
+}
diff --git a/librpc/idl/preg.idl b/librpc/idl/preg.idl
new file mode 100644
index 0000000..c3adb50
--- /dev/null
+++ b/librpc/idl/preg.idl
@@ -0,0 +1,44 @@
+#include "idl_types.h"
+
+import "misc.idl";
+
+/*
+ IDL structures defining PReg files
+
+ more info can be found at:
+ http://msdn2.microsoft.com/en-us/library/aa374407.aspx
+*/
+
+[
+ pointer_default(unique),
+ helper("../librpc/ndr/ndr_preg.h"),
+ helpstring("PReg structure"),
+ uuid("67655250-0000-0000-0000-00000000")
+]
+ interface preg
+{
+ typedef [public,flag(NDR_PAHEX)] struct {
+ [charset(DOS),value("["),noprint] uint8 _opening_bracket[2];
+ nstring keyname;
+ [charset(DOS),value(";"),noprint] uint8 _sep1[2];
+ nstring valuename;
+ [charset(DOS),value(";"),noprint] uint8 _sep2[2];
+ winreg_Type type;
+ [charset(DOS),value(";"),noprint] uint8 _sep3[2];
+ [value(ndr_size_winreg_Data_GPO(&data,type,ndr->flags))] uint32 size;
+ [charset(DOS),value(";"),noprint] uint8 _sep4[2];
+ [subcontext(0),subcontext_size(size),flag(NDR_REMAINING), switch_is(type)] winreg_Data_GPO data;
+ [charset(DOS),value("]"),noprint] uint8 _closing_bracket[2];
+ } preg_entry;
+
+ typedef [public] struct {
+ [charset(DOS),value("PReg")] uint8 signature[4];
+ [value(1)] uint32 version;
+ } preg_header;
+
+ typedef [public,flag(NDR_NOALIGN),nopush,nopull] struct {
+ preg_header header;
+ uint32 num_entries;
+ preg_entry entries[num_entries];
+ } preg_file;
+}
diff --git a/librpc/idl/printcap.idl b/librpc/idl/printcap.idl
new file mode 100644
index 0000000..d9c34f3
--- /dev/null
+++ b/librpc/idl/printcap.idl
@@ -0,0 +1,18 @@
+#include "idl_types.h"
+[
+ pointer_default(unique)
+]
+interface printcap
+{
+ typedef struct {
+ [charset(UTF8),string] uint8 *name;
+ [charset(UTF8),string] uint8 *info;
+ [charset(UTF8),string] uint8 *location;
+ } pcap_printer;
+
+ typedef [public] struct {
+ NTSTATUS status;
+ uint32 count;
+ [size_is(count)] pcap_printer printers[];
+ } pcap_data;
+}
diff --git a/librpc/idl/quota.idl b/librpc/idl/quota.idl
new file mode 100644
index 0000000..8d713c8
--- /dev/null
+++ b/librpc/idl/quota.idl
@@ -0,0 +1,54 @@
+#include "idl_types.h"
+
+import "security.idl";
+
+[
+ pointer_default(unique)
+]
+
+interface file_quota {
+
+ /* MS-FSCC 2.4.33.1 */
+ typedef [public] struct {
+ uint32 next_entry_offset;
+ uint32 sid_length;
+ dom_sid sid;
+ } file_get_quota_info;
+
+ /* MS-FSCC 2.4.33 */
+ typedef [public] struct {
+ uint32 next_entry_offset;
+ uint32 sid_length;
+ hyper change_time;
+ hyper quota_used;
+ hyper quota_threshold;
+ hyper quota_limit;
+ dom_sid sid;
+ } file_quota_information;
+}
+
+interface smb2_query_quota
+{
+ /* MS-SMB2 2.2.37.1 */
+ typedef [public] struct {
+ uint8 return_single;
+ uint8 restart_scan;
+ uint16 reserved;
+ uint32 sid_list_length;
+ uint32 start_sid_length;
+ uint32 start_sid_offset;
+ } smb2_query_quota_info;
+}
+
+interface smb1_nt_transact_query_quota
+{
+ /* MS-SMB 2.2.7.5.1 */
+ typedef [public] struct {
+ uint16 fid;
+ uint8 return_single_entry;
+ uint8 restart_scan;
+ uint32 sid_list_length;
+ uint32 start_sid_length;
+ uint32 start_sid_offset;
+ } nttrans_query_quota_params;
+}
diff --git a/librpc/idl/rap.idl b/librpc/idl/rap.idl
new file mode 100644
index 0000000..780951c
--- /dev/null
+++ b/librpc/idl/rap.idl
@@ -0,0 +1,1076 @@
+#include "idl_types.h"
+
+/*
+ rap interface definition
+*/
+
+[
+ pointer_default(unique),
+ helper("../librpc/ndr/ndr_rap.h")
+]
+interface rap
+{
+ typedef [public,noprint] enum {
+ NERR_Success = 0
+ } rap_status;
+
+ const int RAP_WshareEnum = 0;
+ const int RAP_WshareGetInfo = 1;
+ const int RAP_WshareSetInfo = 2;
+ const int RAP_WshareAdd = 3;
+ const int RAP_WshareDel = 4;
+ const int RAP_NetShareCheck = 5;
+ const int RAP_WsessionEnum = 6;
+ const int RAP_WsessionGetInfo = 7;
+ const int RAP_WsessionDel = 8;
+ const int RAP_WconnectionEnum = 9;
+ const int RAP_WfileEnum = 10;
+ const int RAP_WfileGetInfo = 11;
+ const int RAP_WfileClose = 12;
+ const int RAP_WserverGetInfo = 13;
+ const int RAP_WserverSetInfo = 14;
+ const int RAP_WserverDiskEnum = 15;
+ const int RAP_WserverAdminCommand = 16;
+ const int RAP_NetAuditOpen = 17;
+ const int RAP_WauditClear = 18;
+ const int RAP_NetErrorLogOpen = 19;
+ const int RAP_WerrorLogClear = 20;
+ const int RAP_NetCharDevEnum = 21;
+ const int RAP_NetCharDevGetInfo = 22;
+ const int RAP_WCharDevControl = 23;
+ const int RAP_NetCharDevQEnum = 24;
+ const int RAP_NetCharDevQGetInfo = 25;
+ const int RAP_WCharDevQSetInfo = 26;
+ const int RAP_WCharDevQPurge = 27;
+ const int RAP_WCharDevQPurgeSelf = 28;
+ const int RAP_WMessageNameEnum = 29;
+ const int RAP_WMessageNameGetInfo = 30;
+ const int RAP_WMessageNameAdd = 31;
+ const int RAP_WMessageNameDel = 32;
+ const int RAP_WMessageNameFwd = 33;
+ const int RAP_WMessageNameUnFwd = 34;
+ const int RAP_WMessageBufferSend = 35;
+ const int RAP_WMessageFileSend = 36;
+ const int RAP_WMessageLogFileSet = 37;
+ const int RAP_WMessageLogFileGet = 38;
+ const int RAP_WServiceEnum = 39;
+ const int RAP_WServiceInstall = 40;
+ const int RAP_WServiceControl = 41;
+ const int RAP_WAccessEnum = 42;
+ const int RAP_WAccessGetInfo = 43;
+ const int RAP_WAccessSetInfo = 44;
+ const int RAP_WAccessAdd = 45;
+ const int RAP_WAccessDel = 46;
+ const int RAP_WGroupEnum = 47;
+ const int RAP_WGroupAdd = 48;
+ const int RAP_WGroupDel = 49;
+ const int RAP_WGroupAddUser = 50;
+ const int RAP_WGroupDelUser = 51;
+ const int RAP_WGroupGetUsers = 52;
+ const int RAP_WUserEnum = 53;
+ const int RAP_WUserAdd = 54;
+ const int RAP_WUserDel = 55;
+ const int RAP_WUserGetInfo = 56;
+ const int RAP_WUserSetInfo = 57;
+ const int RAP_WUserPasswordSet = 58;
+ const int RAP_WUserGetGroups = 59;
+ const int RAP_WWkstaSetUID = 62;
+ const int RAP_WWkstaGetInfo = 63;
+ const int RAP_WWkstaSetInfo = 64;
+ const int RAP_WUseEnum = 65;
+ const int RAP_WUseAdd = 66;
+ const int RAP_WUseDel = 67;
+ const int RAP_WUseGetInfo = 68;
+ const int RAP_WPrintQEnum = 69;
+ const int RAP_WPrintQGetInfo = 70;
+ const int RAP_WPrintQSetInfo = 71;
+ const int RAP_WPrintQAdd = 72;
+ const int RAP_WPrintQDel = 73;
+ const int RAP_WPrintQPause = 74;
+ const int RAP_WPrintQContinue = 75;
+ const int RAP_WPrintJobEnum = 76;
+ const int RAP_WPrintJobGetInfo = 77;
+ const int RAP_WPrintJobSetInfo_OLD = 78;
+ const int RAP_WPrintJobDel = 81;
+ const int RAP_WPrintJobPause = 82;
+ const int RAP_WPrintJobContinue = 83;
+ const int RAP_WPrintDestEnum = 84;
+ const int RAP_WPrintDestGetInfo = 85;
+ const int RAP_WPrintDestControl = 86;
+ const int RAP_WProfileSave = 87;
+ const int RAP_WProfileLoad = 88;
+ const int RAP_WStatisticsGet = 89;
+ const int RAP_WStatisticsClear = 90;
+ const int RAP_NetRemoteTOD = 91;
+ const int RAP_WNetBiosEnum = 92;
+ const int RAP_WNetBiosGetInfo = 93;
+ const int RAP_NetServerEnum = 94;
+ const int RAP_I_NetServerEnum = 95;
+ const int RAP_WServiceGetInfo = 96;
+ const int RAP_WPrintQPurge = 103;
+ const int RAP_NetServerEnum2 = 104;
+ const int RAP_WAccessGetUserPerms = 105;
+ const int RAP_WGroupGetInfo = 106;
+ const int RAP_WGroupSetInfo = 107;
+ const int RAP_WGroupSetUsers = 108;
+ const int RAP_WUserSetGroups = 109;
+ const int RAP_WUserModalsGet = 110;
+ const int RAP_WUserModalsSet = 111;
+ const int RAP_WFileEnum2 = 112;
+ const int RAP_WUserAdd2 = 113;
+ const int RAP_WUserSetInfo2 = 114;
+ const int RAP_WUserPasswordSet2 = 115;
+ const int RAP_I_NetServerEnum2 = 116;
+ const int RAP_WConfigGet2 = 117;
+ const int RAP_WConfigGetAll2 = 118;
+ const int RAP_WGetDCName = 119;
+ const int RAP_NetHandleGetInfo = 120;
+ const int RAP_NetHandleSetInfo = 121;
+ const int RAP_WStatisticsGet2 = 122;
+ const int RAP_WBuildGetInfo = 123;
+ const int RAP_WFileGetInfo2 = 124;
+ const int RAP_WFileClose2 = 125;
+ const int RAP_WNetServerReqChallenge = 126;
+ const int RAP_WNetServerAuthenticate = 127;
+ const int RAP_WNetServerPasswordSet = 128;
+ const int RAP_WNetAccountDeltas = 129;
+ const int RAP_WNetAccountSync = 130;
+ const int RAP_WUserEnum2 = 131;
+ const int RAP_WWkstaUserLogon = 132;
+ const int RAP_WWkstaUserLogoff = 133;
+ const int RAP_WLogonEnum = 134;
+ const int RAP_WErrorLogRead = 135;
+ const int RAP_NetPathType = 136;
+ const int RAP_NetPathCanonicalize = 137;
+ const int RAP_NetPathCompare = 138;
+ const int RAP_NetNameValidate = 139;
+ const int RAP_NetNameCanonicalize = 140;
+ const int RAP_NetNameCompare = 141;
+ const int RAP_WAuditRead = 142;
+ const int RAP_WPrintDestAdd = 143;
+ const int RAP_WPrintDestSetInfo = 144;
+ const int RAP_WPrintDestDel = 145;
+ const int RAP_WUserValidate2 = 146;
+ const int RAP_WPrintJobSetInfo = 147;
+ const int RAP_TI_NetServerDiskEnum = 148;
+ const int RAP_TI_NetServerDiskGetInfo = 149;
+ const int RAP_TI_FTVerifyMirror = 150;
+ const int RAP_TI_FTAbortVerify = 151;
+ const int RAP_TI_FTGetInfo = 152;
+ const int RAP_TI_FTSetInfo = 153;
+ const int RAP_TI_FTLockDisk = 154;
+ const int RAP_TI_FTFixError = 155;
+ const int RAP_TI_FTAbortFix = 156;
+ const int RAP_TI_FTDiagnoseError = 157;
+ const int RAP_TI_FTGetDriveStats = 158;
+ const int RAP_TI_FTErrorGetInfo = 160;
+ const int RAP_NetAccessCheck = 163;
+ const int RAP_NetAlertRaise = 164;
+ const int RAP_NetAlertStart = 165;
+ const int RAP_NetAlertStop = 166;
+ const int RAP_NetAuditWrite = 167;
+ const int RAP_NetIRemoteAPI = 168;
+ const int RAP_NetServiceStatus = 169;
+ const int RAP_NetServerRegister = 170;
+ const int RAP_NetServerDeregister = 171;
+ const int RAP_NetSessionEntryMake = 172;
+ const int RAP_NetSessionEntryClear = 173;
+ const int RAP_NetSessionEntryGetInfo = 174;
+ const int RAP_NetSessionEntrySetInfo = 175;
+ const int RAP_NetConnectionEntryMake = 176;
+ const int RAP_NetConnectionEntryClear = 177;
+ const int RAP_NetConnectionEntrySetInfo = 178;
+ const int RAP_NetConnectionEntryGetInfo = 179;
+ const int RAP_NetFileEntryMake = 180;
+ const int RAP_NetFileEntryClear = 181;
+ const int RAP_NetFileEntrySetInfo = 182;
+ const int RAP_NetFileEntryGetInfo = 183;
+ const int RAP_AltSrvMessageBufferSend = 184;
+ const int RAP_AltSrvMessageFileSend = 185;
+ const int RAP_wI_NetRplWkstaEnum = 186;
+ const int RAP_wI_NetRplWkstaGetInfo = 187;
+ const int RAP_wI_NetRplWkstaSetInfo = 188;
+ const int RAP_wI_NetRplWkstaAdd = 189;
+ const int RAP_wI_NetRplWkstaDel = 190;
+ const int RAP_wI_NetRplProfileEnum = 191;
+ const int RAP_wI_NetRplProfileGetInfo = 192;
+ const int RAP_wI_NetRplProfileSetInfo = 193;
+ const int RAP_wI_NetRplProfileAdd = 194;
+ const int RAP_wI_NetRplProfileDel = 195;
+ const int RAP_wI_NetRplProfileClone = 196;
+ const int RAP_wI_NetRplBaseProfileEnum = 197;
+ const int RAP_WIServerSetInfo = 201;
+ const int RAP_WPrintDriverEnum = 205;
+ const int RAP_WPrintQProcessorEnum = 206;
+ const int RAP_WPrintPortEnum = 207;
+ const int RAP_WNetWriteUpdateLog = 208;
+ const int RAP_WNetAccountUpdate = 209;
+ const int RAP_WNetAccountConfirmUpdate = 210;
+ const int RAP_WConfigSet = 211;
+ const int RAP_WAccountsReplicate = 212;
+ const int RAP_SamOEMChgPasswordUser2_P = 214;
+ const int RAP_NetServerEnum3 = 215;
+ const int RAP_WprintDriverGetInfo = 250;
+ const int RAP_WprintDriverSetInfo = 251;
+ const int RAP_WaliasAdd = 252;
+ const int RAP_WaliasDel = 253;
+ const int RAP_WaliasGetInfo = 254;
+ const int RAP_WaliasSetInfo = 255;
+ const int RAP_WaliasEnum = 256;
+ const int RAP_WuserGetLogonAsn = 257;
+ const int RAP_WuserSetLogonAsn = 258;
+ const int RAP_WuserGetAppSel = 259;
+ const int RAP_WuserSetAppSel = 260;
+ const int RAP_WappAdd = 261;
+ const int RAP_WappDel = 262;
+ const int RAP_WappGetInfo = 263;
+ const int RAP_WappSetInfo = 264;
+ const int RAP_WappEnum = 265;
+ const int RAP_WUserDCDBInit = 266;
+ const int RAP_WDASDAdd = 267;
+ const int RAP_WDASDDel = 268;
+ const int RAP_WDASDGetInfo = 269;
+ const int RAP_WDASDSetInfo = 270;
+ const int RAP_WDASDEnum = 271;
+ const int RAP_WDASDCheck = 272;
+ const int RAP_WDASDCtl = 273;
+ const int RAP_WuserRemoteLogonCheck = 274;
+ const int RAP_WUserPasswordSet3 = 275;
+ const int RAP_WCreateRIPLMachine = 276;
+ const int RAP_WDeleteRIPLMachine = 277;
+ const int RAP_WGetRIPLMachineInfo = 278;
+ const int RAP_WSetRIPLMachineInfo = 279;
+ const int RAP_WEnumRIPLMachine = 280;
+ const int RAP_I_ShareAdd = 281;
+ const int RAP_AliasEnum = 282;
+ const int RAP_WaccessApply = 283;
+ const int RAP_WPrt16Query = 284;
+ const int RAP_WPrt16Set = 285;
+ const int RAP_WUserDel100 = 286;
+ const int RAP_WUserRemoteLogonCheck2 = 287;
+ const int RAP_WRemoteTODSet = 294;
+ const int RAP_WprintJobMoveAll = 295;
+ const int RAP_W16AppParmAdd = 296;
+ const int RAP_W16AppParmDel = 297;
+ const int RAP_W16AppParmGet = 298;
+ const int RAP_W16AppParmSet = 299;
+ const int RAP_W16RIPLMachineCreate = 300;
+ const int RAP_W16RIPLMachineGetInfo = 301;
+ const int RAP_W16RIPLMachineSetInfo = 302;
+ const int RAP_W16RIPLMachineEnum = 303;
+ const int RAP_W16RIPLMachineListParmEnum = 304;
+ const int RAP_W16RIPLMachClassGetInfo = 305;
+ const int RAP_W16RIPLMachClassEnum = 306;
+ const int RAP_W16RIPLMachClassCreate = 307;
+ const int RAP_W16RIPLMachClassSetInfo = 308;
+ const int RAP_W16RIPLMachClassDelete = 309;
+ const int RAP_W16RIPLMachClassLPEnum = 310;
+ const int RAP_W16RIPLMachineDelete = 311;
+ const int RAP_W16WSLevelGetInfo = 312;
+ const int RAP_WserverNameAdd = 313;
+ const int RAP_WserverNameDel = 314;
+ const int RAP_WserverNameEnum = 315;
+ const int RAP_I_WDASDEnum = 316;
+ const int RAP_WDASDEnumTerminate = 317;
+ const int RAP_WDASDSetInfo2 = 318;
+ const int MAX_API = 318;
+
+ /* sizes of fixed-length fields, including null terminator */
+ const int RAP_GROUPNAME_LEN = 21;
+ const int RAP_USERNAME_LEN = 21;
+ const int RAP_SHARENAME_LEN = 13;
+ const int RAP_UPASSWD_LEN = 16; /* user password */
+ const int RAP_SPASSWD_LEN = 9; /* share password */
+ const int RAP_MACHNAME_LEN = 16;
+ const int RAP_SRVCNAME_LEN = 16;
+ const int RAP_SRVCCMNT_LEN = 64;
+ const int RAP_DATATYPE_LEN = 10;
+
+ typedef struct {
+ uint8 group_name[21];
+ char reserved1;
+ astring *comment;
+ } rap_group_info_1;
+
+ typedef struct {
+ uint8 user_name[21];
+ char reserved1;
+ uint8 passwrd[16];
+ uint32 pwage;
+ uint16 priv;
+ astring *home_dir;
+ astring *comment;
+ uint16 userflags;
+ astring *logon_script;
+ } rap_user_info_1;
+
+ typedef struct {
+ uint8 service_name[16];
+ uint16 status;
+ uint32 installcode;
+ uint16 process_num;
+ astring *comment;
+ } rap_service_info_2;
+
+ typedef struct {
+ uint8 share_name[13];
+ } rap_share_info_0;
+
+ typedef struct {
+ uint8 share_name[13];
+ char reserved1;
+ uint16 share_type;
+ astring *comment;
+ } rap_share_info_1;
+
+ typedef struct {
+ uint8 share_name[13];
+ char reserved1;
+ uint16 share_type;
+ astring *comment;
+ uint16 perms;
+ uint16 maximum_users;
+ uint16 active_users;
+ astring *path;
+ uint8 password[9];
+ char reserved2;
+ } rap_share_info_2;
+
+ typedef [nodiscriminant] union {
+ [case(0)] rap_share_info_0 info0;
+ [case(1)] rap_share_info_1 info1;
+ [case(2)] rap_share_info_2 info2;
+ } rap_share_info;
+
+ [public] void rap_NetShareEnum(
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 count,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_share_info *info
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetShareAdd(
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [in,switch_is(level)] rap_share_info info,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ typedef struct {
+ uint8 name[16];
+ } rap_server_info_0;
+
+ typedef struct {
+ uint8 name[16];
+ uint8 version_major;
+ uint8 version_minor;
+ uint32 servertype;
+ astring *comment;
+ } rap_server_info_1;
+
+ typedef [nodiscriminant] union {
+ [case(0)] rap_server_info_0 info0;
+ [case(1)] rap_server_info_1 info1;
+ } rap_server_info;
+
+ [public] void rap_NetServerEnum2(
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [in] uint32 servertype,
+ [in] astring *domain,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 count,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_server_info info[count]
+ );
+
+ [public] void rap_WserverGetInfo(
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_server_info info
+ );
+
+ typedef [public] enum {
+ PRJ_QS_QUEUED = 0x0000,
+ PRJ_QS_PAUSED = 0x0001,
+ PRJ_QS_SPOOLING = 0x0002,
+ PRJ_QS_PRINTING = 0x0003,
+ PRJ_QS_ERROR = 0x0010
+ } rap_PrintJStatusCode;
+
+ typedef struct {
+ uint16 JobID;
+ } rap_PrintJobInfo0;
+
+ typedef struct {
+ uint16 JobID;
+ [charset(DOS)] uint8 UserName[21];
+ uint8 Pad;
+ [charset(DOS)] uint8 NotifyName[16];
+ [charset(DOS)] uint8 DataType[10];
+ [relative_short] astring *PrintParameterString;
+ uint16 PrintParameterStringHigh;
+ uint16 JobPosition;
+ rap_PrintJStatusCode JobStatus;
+ [relative_short] astring *JobStatusString;
+ uint16 JobStatusStringHigh;
+ time_t TimeSubmitted;
+ uint32 JobSize;
+ [relative_short] astring *JobCommentString;
+ uint16 JobCommentStringHigh;
+ } rap_PrintJobInfo1;
+
+ typedef struct {
+ uint16 JobID;
+ uint16 Priority;
+ [relative_short] astring *UserName;
+ uint16 UserNameHigh;
+ uint16 JobPosition;
+ rap_PrintJStatusCode JobStatus;
+ time_t TimeSubmitted;
+ uint32 JobSize;
+ [relative_short] astring *JobCommentString;
+ uint16 JobCommentStringHigh;
+ [relative_short] astring *DocumentName;
+ uint16 DocumentNameHigh;
+ } rap_PrintJobInfo2;
+
+ typedef struct {
+ uint16 JobID;
+ uint16 Priority;
+ [relative_short] astring *UserName;
+ uint16 UserNameHigh;
+ uint16 JobPosition;
+ rap_PrintJStatusCode JobStatus;
+ time_t TimeSubmitted;
+ uint32 JobSize;
+ [relative_short] astring *JobCommentString;
+ uint16 JobCommentStringHigh;
+ [relative_short] astring *DocumentName;
+ uint16 DocumentNameHigh;
+ [relative_short] astring *NotifyName;
+ uint16 NotifyNameHigh;
+ [relative_short] astring *DataType;
+ uint16 DataTypeHigh;
+ [relative_short] astring *PrintParameterString;
+ uint16 PrintParameterStringHigh;
+ [relative_short] astring *StatusString;
+ uint16 StatusStringHigh;
+ [relative_short] astring *QueueName;
+ uint16 QueueNameHigh;
+ [relative_short] astring *PrintProcessorName;
+ uint16 PrintProcessorNameHigh;
+ [relative_short] astring *PrintProcessorParams;
+ uint16 PrintProcessorParamsHigh;
+ [relative_short] astring *DriverName;
+ uint16 DriverNameHigh;
+ [relative_short] astring *DriverDataOffset;
+ uint16 DriverDataOffsetHigh;
+ [relative_short] astring *PrinterNameOffset;
+ uint16 PrinterNameOffsetHigh;
+ } rap_PrintJobInfo3;
+
+ typedef [public,nodiscriminant] union {
+ [case(0)] rap_PrintJobInfo0 info0;
+ [case(1)] rap_PrintJobInfo1 info1;
+ [case(2)] rap_PrintJobInfo2 info2;
+ [case(3)] rap_PrintJobInfo3 info3;
+ } rap_printj_info;
+
+ typedef [public] enum {
+ PRQ_ACTIVE = 0x0000,
+ PRQ_PAUSE = 0x0001,
+ PRQ_ERROR = 0x0002,
+ PRQ_PENDING = 0x0003
+ } rap_PrintQStatusCode;
+
+ typedef struct {
+ [charset(DOS)] uint8 PrintQName[13];
+ } rap_PrintQueue0;
+
+ typedef struct {
+ [charset(DOS)] uint8 PrintQName[13];
+ uint8 Pad1;
+ uint16 Priority;
+ uint16 StartTime;
+ uint16 UntilTime;
+ [relative_short] astring *SeparatorPageFilename;
+ uint16 SeparatorPageFilenameHigh;
+ [relative_short] astring *PrintProcessorDllName;
+ uint16 PrintProcessorDllNameHigh;
+ [relative_short] astring *PrintDestinationsName;
+ uint16 PrintDestinationsNameHigh;
+ [relative_short] astring *PrintParameterString;
+ uint16 PrintParameterStringHigh;
+ [relative_short] astring *CommentString;
+ uint16 CommentStringHigh;
+ rap_PrintQStatusCode PrintQStatus;
+ uint16 PrintJobCount;
+ } rap_PrintQueue1;
+
+ typedef struct {
+ rap_PrintQueue1 queue;
+ rap_PrintJobInfo1 job[queue.PrintJobCount];
+ } rap_PrintQueue2;
+
+ typedef [public] struct {
+ [relative_short] astring *PrintQueueName;
+ uint16 PrintQueueNameHigh;
+ uint16 Priority;
+ uint16 StartTime;
+ uint16 UntilTime;
+ uint16 Pad;
+ [relative_short] astring *SeparatorPageFilename;
+ uint16 SeparatorPageFilenameHigh;
+ [relative_short] astring *PrintProcessorDllName;
+ uint16 PrintProcessorDllNameHigh;
+ [relative_short] astring *PrintParameterString;
+ uint16 PrintParameterStringHigh;
+ [relative_short] astring *CommentString;
+ uint16 CommentStringHigh;
+ rap_PrintQStatusCode PrintQStatus;
+ uint16 PrintJobCount;
+ [relative_short] astring *Printers;
+ uint16 PrintersHigh;
+ [relative_short] astring *DriverName;
+ uint16 DriverNameHigh;
+ [relative_short] astring *PrintDriverData;
+ uint16 PrintDriverDataHigh;
+ } rap_PrintQueue3;
+
+ typedef struct {
+ rap_PrintQueue3 queue;
+ rap_PrintJobInfo2 job[queue.PrintJobCount];
+ } rap_PrintQueue4;
+
+ typedef struct {
+ [relative_short] astring *PrintQueueName;
+ uint16 PrintQueueNameHigh;
+ } rap_PrintQueue5;
+
+ typedef [public,nodiscriminant] union {
+ [case(0)] rap_PrintQueue0 info0;
+ [case(1)] rap_PrintQueue1 info1;
+ [case(2)] rap_PrintQueue2 info2;
+ [case(3)] rap_PrintQueue3 info3;
+ [case(4)] rap_PrintQueue4 info4;
+ [case(5)] rap_PrintQueue5 info5;
+ } rap_printq_info;
+
+ [public] void rap_NetPrintQEnum(
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 count,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_printq_info info[count]
+ );
+
+ [public] void rap_NetPrintQGetInfo(
+ [in] astring PrintQueueName,
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_printq_info info
+ );
+
+ [public] void rap_NetPrintJobPause(
+ [in] uint16 JobID,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ [public] void rap_NetPrintJobContinue(
+ [in] uint16 JobID,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ [public] void rap_NetPrintJobDelete(
+ [in] uint16 JobID,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetPrintQueuePause(
+ [in] astring PrintQueueName,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetPrintQueueResume(
+ [in] astring PrintQueueName,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetPrintQueuePurge(
+ [in] astring PrintQueueName,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetPrintJobEnum(
+ [in] astring PrintQueueName,
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 count,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_printj_info info[count]
+ );
+
+ [public] void rap_NetPrintJobGetInfo(
+ [in] uint16 JobID,
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_printj_info info
+ );
+
+ typedef enum {
+ RAP_PARAM_JOBNUM = 0x0001,
+ RAP_PARAM_USERNAME = 0x0002,
+ RAP_PARAM_NOTIFYNAME = 0x0003,
+ RAP_PARAM_DATATYPE = 0x0004,
+ RAP_PARAM_PARAMETERS_STRING = 0x0005,
+ RAP_PARAM_JOBPOSITION = 0x0006,
+ RAP_PARAM_JOBSTATUS = 0x0007,
+ RAP_PARAM_JOBSTATUSSTR = 0x0008,
+ RAP_PARAM_TIMESUBMITTED = 0x0009,
+ RAP_PARAM_JOBSIZE = 0x000a,
+ RAP_PARAM_JOBCOMMENT = 0x000b
+ } rap_JobInfoParamNum;
+
+ typedef [nodiscriminant] union {
+ [case (RAP_PARAM_JOBNUM)] uint16 value;
+ [case (RAP_PARAM_USERNAME)] astring string;
+ [case (RAP_PARAM_NOTIFYNAME)] astring string;
+ [case (RAP_PARAM_DATATYPE)] astring string;
+ [case (RAP_PARAM_PARAMETERS_STRING)] astring string;
+ [case (RAP_PARAM_JOBPOSITION)] uint16 value;
+ [case (RAP_PARAM_JOBSTATUS)] uint16 value;
+ [case (RAP_PARAM_JOBSTATUSSTR)] astring string;
+ [case (RAP_PARAM_TIMESUBMITTED)] uint32 value4;
+ [case (RAP_PARAM_JOBSIZE)] uint32 value4;
+ [case (RAP_PARAM_JOBCOMMENT)] astring string;
+ } rap_JobInfoParam;
+
+ [public] void rap_NetPrintJobSetInfo(
+ [in] uint16 JobID,
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [in] rap_JobInfoParamNum ParamNum,
+ [in,switch_is(ParamNum)] rap_JobInfoParam Param,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ /* all not documented in MS-RAP */
+
+ typedef struct {
+ [charset(DOS)] uint8 PrintDestName[9];
+ } rap_PrintDest0;
+
+ typedef struct {
+ [charset(DOS)] uint8 PrintDestName[9];
+ [charset(DOS)] uint8 UserName[21];
+ uint16 JobId;
+ uint16 Status;
+ [relative_short] astring *StatusStringName;
+ uint16 PrintQueueNameHigh;
+ uint16 Time;
+ } rap_PrintDest1;
+
+ typedef struct {
+ [relative_short] astring *PrinterName;
+ uint16 PrinterNameHigh;
+ } rap_PrintDest2;
+
+ typedef struct {
+ [relative_short] astring *PrinterName;
+ uint16 PrinterNameHigh;
+ [relative_short] astring *UserName;
+ uint16 UserNameHigh;
+ [relative_short] astring *LogAddr;
+ uint16 LogAddrHigh;
+ uint16 JobId;
+ uint16 Status;
+ [relative_short] astring *StatusStringName;
+ uint16 PrintQueueNameHigh;
+ [relative_short] astring *Comment;
+ uint16 CommentHigh;
+ [relative_short] astring *Drivers;
+ uint16 DriversHigh;
+ uint16 Time;
+ uint16 Pad1;
+ } rap_PrintDest3;
+
+ typedef [public,nodiscriminant] union {
+ [case(0)] rap_PrintDest0 info0;
+ [case(1)] rap_PrintDest1 info1;
+ [case(2)] rap_PrintDest2 info2;
+ [case(3)] rap_PrintDest3 info3;
+ } rap_printdest_info;
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetPrintDestEnum(
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 count,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_printdest_info info[count]
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetPrintDestGetInfo(
+ [in] astring PrintDestName,
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_printdest_info info
+ );
+
+ [public] void rap_NetUserPasswordSet2(
+ [in] astring UserName,
+ [in] uint8 OldPassword[16],
+ [in] uint8 NewPassword[16],
+ [in] uint16 EncryptedPassword,
+ [in] uint16 RealPasswordLength,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetOEMChangePassword(
+ [in] astring UserName,
+ [in] uint8 crypt_password[516],
+ [in] uint8 password_hash[16],
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ typedef struct {
+ [charset(DOS)] uint8 Name[21];
+ } rap_NetUserInfo0;
+
+ typedef [public] enum {
+ USER_PRIV_GUEST = 0,
+ USER_PRIV_USER = 1,
+ USER_PRIV_ADMIN = 2
+ } rap_UserPriv;
+
+ typedef struct {
+ [charset(DOS)] uint8 Name[21];
+ uint8 Pad;
+ uint8 Password[16];
+ time_t PasswordAge;
+ rap_UserPriv Priv;
+ [relative_short] astring *HomeDir;
+ uint16 HomeDirHigh;
+ [relative_short] astring *Comment;
+ uint16 CommentHigh;
+ uint16 Flags; /* FIXME */
+ [relative_short] astring *ScriptPath;
+ uint16 ScriptPathHigh;
+ } rap_NetUserInfo1;
+
+ typedef [public,v1_enum] enum {
+ AF_OP_PRINT = 0,
+ AF_OP_COMM = 1,
+ AF_OP_SERVER = 2,
+ AF_OP_ACCOUNTS = 3
+ } rap_AuthFlags;
+
+ typedef [public] struct {
+ uint8 LogonHours[21];
+ } rap_LogonHours;
+
+ typedef struct {
+ [charset(DOS)] uint8 Name[21];
+ uint8 Pad;
+ uint8 Password[16];
+ time_t PasswordAge;
+ rap_UserPriv Priv;
+ [relative_short] astring *HomeDir;
+ uint16 HomeDirHigh;
+ [relative_short] astring *Comment;
+ uint16 CommentHigh;
+ uint16 Flags; /* FIXME */
+ [relative_short] astring *ScriptPath;
+ uint16 ScriptPathHigh;
+ rap_AuthFlags AuthFlags;
+ [relative_short] astring *FullName;
+ uint16 FullNameHigh;
+ [relative_short] astring *UsrComment;
+ uint16 UsrCommentHigh;
+ [relative_short] astring *pParms;
+ uint16 pParmsHigh;
+ [relative_short] astring *WorkStations;
+ uint16 WorkStationsHigh;
+ time_t LastLogon;
+ time_t LastLogOff;
+ time_t AcctExpires;
+ uint32 MaxStorage;
+ uint16 UnitsPerWeek;
+ [relative_short] rap_LogonHours *LogonHours;
+ uint16 LogonHoursHigh;
+ uint16 BadPwCount;
+ uint16 NumLogons;
+ [relative_short] astring *LogonServer;
+ uint16 LogonServerHigh;
+ uint16 CountryCode;
+ uint16 CodePage;
+ } rap_NetUserInfo2;
+
+ typedef struct {
+ [charset(DOS)] uint8 Name[21];
+ uint8 Pad;
+ [relative_short] astring *Comment;
+ uint16 CommentHigh;
+ [relative_short] astring *UsrComment;
+ uint16 UsrCommentHigh;
+ [relative_short] astring *FullName;
+ uint16 FullNameHigh;
+ } rap_NetUserInfo10;
+
+ typedef struct {
+ [charset(DOS)] uint8 Name[21];
+ uint8 Pad;
+ [relative_short] astring *Comment;
+ uint16 CommentHigh;
+ [relative_short] astring *UsrComment;
+ uint16 UsrCommentHigh;
+ [relative_short] astring *FullName;
+ uint16 FullNameHigh;
+ rap_UserPriv Priv;
+ rap_AuthFlags AuthFlags;
+ time_t PasswordAge;
+ [relative_short] astring *HomeDir;
+ uint16 HomeDirHigh;
+ [relative_short] astring *Parms;
+ uint16 ParmsHigh;
+ time_t LastLogon;
+ time_t LastLogOff;
+ uint16 BadPWCount;
+ uint16 NumLogons;
+ [relative_short] astring *LogonServer;
+ uint16 LogonServerHigh;
+ uint16 CountryCode;
+ [relative_short] astring *WorkStations;
+ uint16 WorkStationsHigh;
+ uint32 MaxStorage;
+ uint16 UnitsPerWeek;
+ [relative_short] rap_LogonHours *LogonHours;
+ uint16 LogonHoursHigh;
+ uint16 CodePage;
+ } rap_NetUserInfo11;
+
+ typedef [public,nodiscriminant] union {
+ [case(0)] rap_NetUserInfo0 info0;
+ [case(1)] rap_NetUserInfo1 info1;
+ [case(2)] rap_NetUserInfo2 info2;
+ [case(10)] rap_NetUserInfo10 info10;
+ [case(11)] rap_NetUserInfo11 info11;
+ } rap_netuser_info;
+
+ [public] void rap_NetUserGetInfo(
+ [in] astring UserName,
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_netuser_info info
+ );
+
+ typedef struct {
+ [relative_short] astring *ComputerName;
+ uint16 ComputerNameHigh;
+ [relative_short] astring *UserName;
+ uint16 UserNameHigh;
+ uint16 num_conns;
+ uint16 num_opens;
+ uint16 num_users;
+ uint32 sess_time;
+ uint32 idle_time;
+ uint32 user_flags;
+ [relative_short] astring *CliTypeName;
+ uint16 CliTypeNameHigh;
+ } rap_session_info_2;
+
+ typedef [public,nodiscriminant] union {
+ [case(2)] rap_session_info_2 info2;
+ } rap_session_info;
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetSessionEnum(
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 count,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_session_info info[count]
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetSessionGetInfo(
+ [in] astring SessionName,
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] uint16 available,
+ [out,switch_is(level)] rap_session_info info
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetUserAdd(
+ [in] uint16 level,
+ [in] uint16 bufsize,
+ [in] uint16 pwdlength,
+ [in] uint16 unknown,
+ [in,switch_is(level)] rap_netuser_info info,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ /* not documented in MS-RAP */
+ [public] void rap_NetUserDelete(
+ [in] astring UserName,
+ [out] rap_status status,
+ [out] uint16 convert
+ );
+
+ typedef [public] struct {
+ uint32 TimeSinceJan11970;
+ uint32 TimeSinceBoot;
+ uint8 Hours;
+ uint8 Minutes;
+ uint8 Seconds;
+ uint8 Hundreds;
+ uint16 TimeZone;
+ uint16 ClockFrequency;
+ uint8 Day;
+ uint8 Month;
+ uint16 Year;
+ uint8 Weekday;
+ } rap_TimeOfDayInfo;
+
+ [public] void rap_NetRemoteTOD(
+ [in] uint16 bufsize,
+ [out] rap_status status,
+ [out] uint16 convert,
+ [out] rap_TimeOfDayInfo tod
+ );
+
+ /* Parameter description strings for RAP calls */
+ /* Names are defined name for RAP call with _REQ */
+ /* appended to end. */
+
+ const string RAP_WFileEnum2_REQ = "zzWrLehb8g8";
+ const string RAP_WFileGetInfo2_REQ = "DWrLh";
+ const string RAP_WFileClose2_REQ = "D";
+
+ const string RAP_NetGroupEnum_REQ = "WrLeh";
+ const string RAP_NetGroupAdd_REQ = "WsT";
+ const string RAP_NetGroupDel_REQ = "z";
+ const string RAP_NetGroupAddUser_REQ = "zz";
+ const string RAP_NetGroupDelUser_REQ = "zz";
+ const string RAP_NetGroupGetUsers_REQ = "zWrLeh";
+ const string RAP_NetGroupSetUsers_REQ = "zWsTW";
+
+ const string RAP_NetUserAdd2_REQ = "WsTWW";
+ const string RAP_NetUserEnum_REQ = "WrLeh";
+ const string RAP_NetUserEnum2_REQ = "WrLDieh";
+ const string RAP_NetUserGetGroups_REQ = "zWrLeh";
+ const string RAP_NetUserSetGroups_REQ = "zWsTW";
+ const string RAP_NetUserPasswordSet_REQ = "zb16b16w";
+ const string RAP_NetUserPasswordSet2_REQ = "zb16b16WW";
+ const string RAP_SAMOEMChgPasswordUser2_REQ = "B516B16";
+ const string RAP_NetUserValidate2_REQ = "Wb62WWrLhWW";
+
+ const string RAP_NetServerEnum2_REQ = "WrLehDz";
+ const string RAP_WserverGetInfo_REQ = "WrLh";
+ const string RAP_NetWkstatGetInfo = "WrLh";
+
+ const string RAP_WShareAdd_REQ = "WsT";
+ const string RAP_WShareEnum_REQ = "WrLeh";
+ const string RAP_WShareDel_REQ = "zW";
+ const string RAP_WWkstaGetInfo_REQ = "WrLh";
+
+ const string RAP_NetPrintQEnum_REQ = "WrLeh";
+ const string RAP_NetPrintQGetInfo_REQ = "zWrLh";
+
+ const string RAP_NetServerAdminCommand_REQ = "zhrLeh";
+ const string RAP_NetServiceEnum_REQ = "WrLeh";
+ const string RAP_NetServiceControl_REQ = "zWWrL";
+ const string RAP_NetServiceInstall_REQ = "zF88sg88T";
+ const string RAP_NetServiceGetInfo_REQ = "zWrLh";
+ const string RAP_NetSessionEnum_REQ = "WrLeh";
+ const string RAP_NetSessionGetInfo_REQ = "zWrLh";
+ const string RAP_NetSessionDel_REQ = "zW";
+
+ const string RAP_NetConnectionEnum_REQ = "zWrLeh";
+
+ const string RAP_NetWkstaUserLogoff_REQ = "zzWb38WrLh";
+
+ /* Description strings for returned data in RAP calls */
+ /* I use all caps here in part to avoid accidental */
+ /* name collisions */
+
+ const string RAP_FILE_INFO_L2 = "D";
+ const string RAP_FILE_INFO_L3 = "DWWzz";
+ const string RAP_GROUP_INFO_L0 = "B21";
+ const string RAP_GROUP_INFO_L1 = "B21Bz";
+ const string RAP_GROUP_USERS_INFO_0 = "B21";
+ const string RAP_GROUP_USERS_INFO_1 = "B21BN";
+
+ const string RAP_USER_INFO_L0 = "B21";
+ const string RAP_USER_INFO_L1 = "B21BB16DWzzWz";
+
+ const string RAP_SERVER_INFO_L0 = "B16";
+ const string RAP_SERVER_INFO_L1 = "B16BBDz";
+ const string RAP_SERVER_INFO_L2 = "B16BBDzDDDWWzWWWWWWWB21BzWWWWWWWWWWWWWWWWWWWWWWz";
+ const string RAP_SERVER_INFO_L3 = "B16BBDzDDDWWzWWWWWWWB21BzWWWWWWWWWWWWWWWWWWWWWWzDWz";
+ const string RAP_SERVICE_INFO_L0 = "B16";
+ const string RAP_SERVICE_INFO_L2 = "B16WDWB64";
+ const string RAP_SHARE_INFO_L0 = "B13";
+ const string RAP_SHARE_INFO_L1 = "B13BWz";
+ const string RAP_SHARE_INFO_L2 = "B13BWzWWWzB9B";
+
+ const string RAP_PRINTQ_INFO_L2 = "B13BWWWzzzzzWN";
+ const string RAP_SMB_PRINT_JOB_L1 = "WB21BB16B10zWWzDDz";
+
+ const string RAP_SESSION_INFO_L2 = "zzWWWDDDz";
+ const string RAP_CONNECTION_INFO_L1 = "WWWWDzz";
+
+ const string RAP_USER_LOGOFF_INFO_L1 = "WDW";
+
+ const string RAP_WKSTA_INFO_L1 = "WDzzzzBBDWDWWWWWWWWWWWWWWWWWWWzzWzzW";
+ const string RAP_WKSTA_INFO_L10 = "zzzBBzz";
+};
diff --git a/librpc/idl/remact.idl b/librpc/idl/remact.idl
new file mode 100644
index 0000000..77134e7
--- /dev/null
+++ b/librpc/idl/remact.idl
@@ -0,0 +1,46 @@
+/**
+ DCOM interfaces
+ http://www.grimes.demon.co.uk/DCOM/DCOMSpec.htm
+ */
+
+import "misc.idl", "orpc.idl";
+
+[
+ uuid("4d9f4ab8-7d1c-11cf-861e-0020af6e7c57"),
+ pointer_default(unique),
+ endpoint("ncalrpc:", "ncacn_ip_tcp:[135]", "ncacn_np:[\\pipe\\epmapper]")
+]
+interface IRemoteActivation
+{
+ typedef [v1_enum] enum {
+ RPC_C_IMP_LEVEL_DEFAULT = 0,
+ RPC_C_IMP_LEVEL_ANONYMOUS = 1,
+ RPC_C_IMP_LEVEL_IDENTIFY = 2,
+ RPC_C_IMP_LEVEL_IMPERSONATE = 3,
+ RPC_C_IMP_LEVEL_DELEGATE = 4
+ } imp_levels;
+
+ const uint32 MODE_GET_CLASS_OBJECT = 0xffffffff;
+
+ WERROR RemoteActivation (
+ [in] ORPCTHIS this_object,
+ [out,ref] ORPCTHAT *that,
+ [in] GUID Clsid,
+ [in] [unique,string,charset(UTF16)] uint16 *pwszObjectName,
+ [in] [unique] MInterfacePointer *pObjectStorage,
+ [in] imp_levels ClientImpLevel,
+ [in] uint32 Mode,
+ [in,range(1,32768)] uint32 Interfaces,
+ [in,unique,size_is(Interfaces)] GUID *pIIDs,
+ [in] uint16 num_protseqs,
+ [in, size_is(num_protseqs)] uint16 protseq[*],
+ [out,ref] hyper *pOxid,
+ [out,ref] DUALSTRINGARRAY **pdsaOxidBindings,
+ [out,ref] GUID *ipidRemUnknown,
+ [out,ref] uint32 *AuthnHint,
+ [out,ref] COMVERSION *ServerVersion,
+ [out,ref] HRESULT *hr,
+ [out,size_is(Interfaces)] MInterfacePointer **ifaces,
+ [out,size_is(Interfaces)] HRESULT results[]
+ );
+}
diff --git a/librpc/idl/rot.idl b/librpc/idl/rot.idl
new file mode 100644
index 0000000..7239111
--- /dev/null
+++ b/librpc/idl/rot.idl
@@ -0,0 +1,44 @@
+import "orpc.idl";
+
+[
+ uuid("b9e79e60-3d52-11ce-aaa1-00006901293f"),
+ version(0.2),
+ pointer_default(unique),
+ endpoint("ncacn_np:[\\pipe\\epmapper]", "ncacn_ip_tcp:[135]",
+ "ncalrpc:[EPMAPPER]")
+] interface rot
+{
+ WERROR rot_add (
+ [in] uint32 flags,
+ [in] MInterfacePointer *unk,
+ [in] MInterfacePointer *moniker,
+ [out] uint32 *rotid
+ );
+
+ WERROR rot_remove (
+ [in] uint32 rotid
+ );
+
+ WERROR rot_is_listed (
+ [in] MInterfacePointer *moniker
+ );
+
+ WERROR rot_get_interface_pointer (
+ [in] MInterfacePointer *moniker,
+ [out] MInterfacePointer *ip
+ );
+
+ WERROR rot_set_modification_time (
+ [in] uint32 rotid,
+ [in] NTTIME *t
+ );
+
+ WERROR rot_get_modification_time (
+ [in] MInterfacePointer *moniker,
+ [out] NTTIME *t
+ );
+
+ WERROR rot_enum (
+ [out] MInterfacePointer *EnumMoniker
+ );
+}
diff --git a/librpc/idl/samr.idl b/librpc/idl/samr.idl
new file mode 100644
index 0000000..5da0fd7
--- /dev/null
+++ b/librpc/idl/samr.idl
@@ -0,0 +1,1665 @@
+#include "idl_types.h"
+
+/*
+ samr interface definition
+*/
+import "misc.idl", "lsa.idl", "security.idl";
+
+/*
+ Thanks to Todd Sabin for some information from his samr.idl in acltools
+*/
+
+[ uuid("12345778-1234-abcd-ef00-0123456789ac"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\samr]","ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique)
+] interface samr
+{
+ typedef bitmap security_secinfo security_secinfo;
+ typedef bitmap security_GroupAttrs security_GroupAttrs;
+
+ /* account control (acct_flags) bits */
+ typedef [public,bitmap32bit] bitmap {
+ ACB_DISABLED = 0x00000001, /* 1 = User account disabled */
+ ACB_HOMDIRREQ = 0x00000002, /* 1 = Home directory required */
+ ACB_PWNOTREQ = 0x00000004, /* 1 = User password not required */
+ ACB_TEMPDUP = 0x00000008, /* 1 = Temporary duplicate account */
+ ACB_NORMAL = 0x00000010, /* 1 = Normal user account */
+ ACB_MNS = 0x00000020, /* 1 = MNS logon user account */
+ ACB_DOMTRUST = 0x00000040, /* 1 = Interdomain trust account */
+ ACB_WSTRUST = 0x00000080, /* 1 = Workstation trust account */
+ ACB_SVRTRUST = 0x00000100, /* 1 = Server trust account */
+ ACB_PWNOEXP = 0x00000200, /* 1 = User password does not expire */
+ ACB_AUTOLOCK = 0x00000400, /* 1 = Account auto locked */
+ ACB_ENC_TXT_PWD_ALLOWED = 0x00000800, /* 1 = Encrypted text password is allowed */
+ ACB_SMARTCARD_REQUIRED = 0x00001000, /* 1 = Smart Card required */
+ ACB_TRUSTED_FOR_DELEGATION = 0x00002000, /* 1 = Trusted for Delegation */
+ ACB_NOT_DELEGATED = 0x00004000, /* 1 = Not delegated */
+ ACB_USE_DES_KEY_ONLY = 0x00008000, /* 1 = Use DES key only */
+ ACB_DONT_REQUIRE_PREAUTH = 0x00010000, /* 1 = Preauth not required */
+ ACB_PW_EXPIRED = 0x00020000, /* 1 = Password Expired */
+ ACB_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x00040000,
+ ACB_NO_AUTH_DATA_REQD = 0x00080000, /* 1 = No authorization data required */
+ ACB_PARTIAL_SECRETS_ACCOUNT = 0x00100000,
+ ACB_USE_AES_KEYS = 0x00200000
+ } samr_AcctFlags;
+
+ /* SAM server specific access rights */
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_ACCESS_CONNECT_TO_SERVER = 0x00000001,
+ SAMR_ACCESS_SHUTDOWN_SERVER = 0x00000002,
+ SAMR_ACCESS_INITIALIZE_SERVER = 0x00000004,
+ SAMR_ACCESS_CREATE_DOMAIN = 0x00000008,
+ SAMR_ACCESS_ENUM_DOMAINS = 0x00000010,
+ SAMR_ACCESS_LOOKUP_DOMAIN = 0x00000020
+ } samr_ConnectAccessMask;
+
+ const int SAMR_ACCESS_ALL_ACCESS = 0x0000003F;
+
+ const int GENERIC_RIGHTS_SAM_ALL_ACCESS =
+ (STANDARD_RIGHTS_REQUIRED_ACCESS |
+ SAMR_ACCESS_ALL_ACCESS);
+
+ const int GENERIC_RIGHTS_SAM_READ =
+ (STANDARD_RIGHTS_READ_ACCESS |
+ SAMR_ACCESS_ENUM_DOMAINS);
+
+ const int GENERIC_RIGHTS_SAM_WRITE =
+ (STANDARD_RIGHTS_WRITE_ACCESS |
+ SAMR_ACCESS_CREATE_DOMAIN |
+ SAMR_ACCESS_INITIALIZE_SERVER |
+ SAMR_ACCESS_SHUTDOWN_SERVER);
+
+ const int GENERIC_RIGHTS_SAM_EXECUTE =
+ (STANDARD_RIGHTS_EXECUTE_ACCESS |
+ SAMR_ACCESS_LOOKUP_DOMAIN |
+ SAMR_ACCESS_CONNECT_TO_SERVER);
+
+ /* User Object specific access rights */
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_USER_ACCESS_GET_NAME_ETC = 0x00000001,
+ SAMR_USER_ACCESS_GET_LOCALE = 0x00000002,
+ SAMR_USER_ACCESS_SET_LOC_COM = 0x00000004,
+ SAMR_USER_ACCESS_GET_LOGONINFO = 0x00000008,
+ SAMR_USER_ACCESS_GET_ATTRIBUTES = 0x00000010,
+ SAMR_USER_ACCESS_SET_ATTRIBUTES = 0x00000020,
+ SAMR_USER_ACCESS_CHANGE_PASSWORD = 0x00000040,
+ SAMR_USER_ACCESS_SET_PASSWORD = 0x00000080,
+ SAMR_USER_ACCESS_GET_GROUPS = 0x00000100,
+ SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP = 0x00000200,
+ SAMR_USER_ACCESS_CHANGE_GROUP_MEMBERSHIP = 0x00000400
+ } samr_UserAccessMask;
+
+ const int SAMR_USER_ACCESS_ALL_ACCESS = 0x000007FF;
+
+ const int GENERIC_RIGHTS_USER_ALL_ACCESS =
+ (STANDARD_RIGHTS_REQUIRED_ACCESS |
+ SAMR_USER_ACCESS_ALL_ACCESS); /* 0x000f07ff */
+
+ const int GENERIC_RIGHTS_USER_READ =
+ (STANDARD_RIGHTS_READ_ACCESS |
+ SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP |
+ SAMR_USER_ACCESS_GET_GROUPS |
+ SAMR_USER_ACCESS_GET_ATTRIBUTES |
+ SAMR_USER_ACCESS_GET_LOGONINFO |
+ SAMR_USER_ACCESS_GET_LOCALE); /* 0x0002031a */
+
+ const int GENERIC_RIGHTS_USER_WRITE =
+ (STANDARD_RIGHTS_WRITE_ACCESS |
+ SAMR_USER_ACCESS_CHANGE_PASSWORD |
+ SAMR_USER_ACCESS_SET_LOC_COM |
+ SAMR_USER_ACCESS_SET_ATTRIBUTES |
+ SAMR_USER_ACCESS_SET_PASSWORD |
+ SAMR_USER_ACCESS_CHANGE_GROUP_MEMBERSHIP); /* 0x000204e4 */
+
+ const int GENERIC_RIGHTS_USER_EXECUTE =
+ (STANDARD_RIGHTS_EXECUTE_ACCESS |
+ SAMR_USER_ACCESS_CHANGE_PASSWORD |
+ SAMR_USER_ACCESS_GET_NAME_ETC); /* 0x00020041 */
+
+ /* Domain Object specific access rights */
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 = 0x00000001,
+ SAMR_DOMAIN_ACCESS_SET_INFO_1 = 0x00000002,
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 = 0x00000004,
+ SAMR_DOMAIN_ACCESS_SET_INFO_2 = 0x00000008,
+ SAMR_DOMAIN_ACCESS_CREATE_USER = 0x00000010,
+ SAMR_DOMAIN_ACCESS_CREATE_GROUP = 0x00000020,
+ SAMR_DOMAIN_ACCESS_CREATE_ALIAS = 0x00000040,
+ SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS = 0x00000080,
+ SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS = 0x00000100,
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT = 0x00000200,
+ SAMR_DOMAIN_ACCESS_SET_INFO_3 = 0x00000400
+ } samr_DomainAccessMask;
+
+ const int SAMR_DOMAIN_ACCESS_ALL_ACCESS = 0x000007FF;
+
+ const int GENERIC_RIGHTS_DOMAIN_ALL_ACCESS =
+ (STANDARD_RIGHTS_REQUIRED_ACCESS |
+ SAMR_DOMAIN_ACCESS_ALL_ACCESS);
+
+ const int GENERIC_RIGHTS_DOMAIN_READ =
+ (STANDARD_RIGHTS_READ_ACCESS |
+ SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS |
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2);
+
+ const int GENERIC_RIGHTS_DOMAIN_WRITE =
+ (STANDARD_RIGHTS_WRITE_ACCESS |
+ SAMR_DOMAIN_ACCESS_SET_INFO_3 |
+ SAMR_DOMAIN_ACCESS_CREATE_ALIAS |
+ SAMR_DOMAIN_ACCESS_CREATE_GROUP |
+ SAMR_DOMAIN_ACCESS_CREATE_USER |
+ SAMR_DOMAIN_ACCESS_SET_INFO_2 |
+ SAMR_DOMAIN_ACCESS_SET_INFO_1);
+
+ const int GENERIC_RIGHTS_DOMAIN_EXECUTE =
+ (STANDARD_RIGHTS_EXECUTE_ACCESS |
+ SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT |
+ SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
+ SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1);
+
+ /* Group Object specific access rights */
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_GROUP_ACCESS_LOOKUP_INFO = 0x00000001,
+ SAMR_GROUP_ACCESS_SET_INFO = 0x00000002,
+ SAMR_GROUP_ACCESS_ADD_MEMBER = 0x00000004,
+ SAMR_GROUP_ACCESS_REMOVE_MEMBER = 0x00000008,
+ SAMR_GROUP_ACCESS_GET_MEMBERS = 0x00000010
+ } samr_GroupAccessMask;
+
+ const int SAMR_GROUP_ACCESS_ALL_ACCESS = 0x0000001F;
+
+ const int GENERIC_RIGHTS_GROUP_ALL_ACCESS =
+ (STANDARD_RIGHTS_REQUIRED_ACCESS |
+ SAMR_GROUP_ACCESS_ALL_ACCESS); /* 0x000f001f */
+
+ const int GENERIC_RIGHTS_GROUP_READ =
+ (STANDARD_RIGHTS_READ_ACCESS |
+ SAMR_GROUP_ACCESS_GET_MEMBERS); /* 0x00020010 */
+
+ const int GENERIC_RIGHTS_GROUP_WRITE =
+ (STANDARD_RIGHTS_WRITE_ACCESS |
+ SAMR_GROUP_ACCESS_REMOVE_MEMBER |
+ SAMR_GROUP_ACCESS_ADD_MEMBER |
+ SAMR_GROUP_ACCESS_SET_INFO); /* 0x0002000e */
+
+ const int GENERIC_RIGHTS_GROUP_EXECUTE =
+ (STANDARD_RIGHTS_EXECUTE_ACCESS |
+ SAMR_GROUP_ACCESS_LOOKUP_INFO); /* 0x00020001 */
+
+ /* Alias Object specific access rights */
+
+ typedef [bitmap32bit] bitmap {
+ SAMR_ALIAS_ACCESS_ADD_MEMBER = 0x00000001,
+ SAMR_ALIAS_ACCESS_REMOVE_MEMBER = 0x00000002,
+ SAMR_ALIAS_ACCESS_GET_MEMBERS = 0x00000004,
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO = 0x00000008,
+ SAMR_ALIAS_ACCESS_SET_INFO = 0x00000010
+ } samr_AliasAccessMask;
+
+ const int SAMR_ALIAS_ACCESS_ALL_ACCESS = 0x0000001F;
+
+ const int GENERIC_RIGHTS_ALIAS_ALL_ACCESS =
+ (STANDARD_RIGHTS_REQUIRED_ACCESS |
+ SAMR_ALIAS_ACCESS_ALL_ACCESS); /* 0x000f001f */
+
+ const int GENERIC_RIGHTS_ALIAS_READ =
+ (STANDARD_RIGHTS_READ_ACCESS |
+ SAMR_ALIAS_ACCESS_GET_MEMBERS); /* 0x00020004 */
+
+ const int GENERIC_RIGHTS_ALIAS_WRITE =
+ (STANDARD_RIGHTS_WRITE_ACCESS |
+ SAMR_ALIAS_ACCESS_REMOVE_MEMBER |
+ SAMR_ALIAS_ACCESS_ADD_MEMBER |
+ SAMR_ALIAS_ACCESS_SET_INFO); /* 0x00020013 */
+
+ const int GENERIC_RIGHTS_ALIAS_EXECUTE =
+ (STANDARD_RIGHTS_EXECUTE_ACCESS |
+ SAMR_ALIAS_ACCESS_LOOKUP_INFO); /* 0x00020008 */
+
+ /******************/
+ /* Function: 0x00 */
+ NTSTATUS samr_Connect (
+ /* notice the lack of [string] */
+ [in,unique] uint16 *system_name,
+ [in] samr_ConnectAccessMask access_mask,
+ [out,ref] policy_handle *connect_handle
+ );
+
+
+ /******************/
+ /* Function: 0x01 */
+ [public] NTSTATUS samr_Close (
+ [in,out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x02 */
+
+ NTSTATUS samr_SetSecurity (
+ [in,ref] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [in,ref] sec_desc_buf *sdbuf
+ );
+
+ /******************/
+ /* Function: 0x03 */
+
+ NTSTATUS samr_QuerySecurity (
+ [in,ref] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [out,ref] sec_desc_buf **sdbuf
+ );
+
+ /******************/
+ /* Function: 0x04 */
+
+ /*
+ shutdown the SAM - once you call this the SAM will be dead
+ */
+ NTSTATUS samr_Shutdown (
+ [in,ref] policy_handle *connect_handle
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ NTSTATUS samr_LookupDomain (
+ [in,ref] policy_handle *connect_handle,
+ [in,ref] lsa_String *domain_name,
+ [out,ref] dom_sid2 **sid
+ );
+
+
+ /******************/
+ /* Function: 0x06 */
+
+ typedef struct {
+ uint32 idx;
+ lsa_String name;
+ } samr_SamEntry;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_SamEntry *entries;
+ } samr_SamArray;
+
+ NTSTATUS samr_EnumDomains (
+ [in,ref] policy_handle *connect_handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] samr_SamArray **sam,
+ [in] uint32 buf_size,
+ [out,ref] uint32 *num_entries
+ );
+
+
+ /************************/
+ /* Function 0x07 */
+ [public] NTSTATUS samr_OpenDomain(
+ [in,ref] policy_handle *connect_handle,
+ [in] samr_DomainAccessMask access_mask,
+ [in,ref] dom_sid2 *sid,
+ [out,ref] policy_handle *domain_handle
+ );
+
+ /************************/
+ /* Function 0x08 */
+
+ typedef enum {
+ DomainPasswordInformation = 1,
+ DomainGeneralInformation = 2,
+ DomainLogoffInformation = 3,
+ DomainOemInformation = 4,
+ DomainNameInformation = 5,
+ DomainReplicationInformation = 6,
+ DomainServerRoleInformation = 7,
+ DomainModifiedInformation = 8,
+ DomainStateInformation = 9,
+ DomainUasInformation = 10,
+ DomainGeneralInformation2 = 11,
+ DomainLockoutInformation = 12,
+ DomainModifiedInformation2 = 13
+ } samr_DomainInfoClass;
+
+ /* server roles */
+ typedef [v1_enum] enum {
+ SAMR_ROLE_STANDALONE = 0,
+ SAMR_ROLE_DOMAIN_MEMBER = 1,
+ SAMR_ROLE_DOMAIN_BDC = 2,
+ SAMR_ROLE_DOMAIN_PDC = 3
+ } samr_Role;
+
+ /* password properties flags */
+ typedef [public,bitmap32bit] bitmap {
+ DOMAIN_PASSWORD_COMPLEX = 0x00000001,
+ DOMAIN_PASSWORD_NO_ANON_CHANGE = 0x00000002,
+ DOMAIN_PASSWORD_NO_CLEAR_CHANGE = 0x00000004,
+ DOMAIN_PASSWORD_LOCKOUT_ADMINS = 0x00000008,
+ DOMAIN_PASSWORD_STORE_CLEARTEXT = 0x00000010,
+ DOMAIN_REFUSE_PASSWORD_CHANGE = 0x00000020
+ } samr_PasswordProperties;
+
+ typedef [v1_enum] enum {
+ DOMAIN_SERVER_ENABLED = 1,
+ DOMAIN_SERVER_DISABLED = 2
+ } samr_DomainServerState;
+
+ typedef [public] struct {
+ uint16 min_password_length;
+ uint16 password_history_length;
+ samr_PasswordProperties password_properties;
+ /* yes, these are signed. They are in negative 100ns */
+ dlong max_password_age;
+ dlong min_password_age;
+ } samr_DomInfo1;
+
+ typedef struct {
+ NTTIME force_logoff_time;
+ lsa_String oem_information; /* comment */
+ lsa_String domain_name;
+ lsa_String primary; /* PDC name if this is a BDC */
+ udlong sequence_num;
+ samr_DomainServerState domain_server_state;
+ samr_Role role;
+ uint32 unknown3;
+ uint32 num_users;
+ uint32 num_groups;
+ uint32 num_aliases;
+ } samr_DomGeneralInformation;
+
+ typedef struct {
+ NTTIME force_logoff_time;
+ } samr_DomInfo3;
+
+ typedef struct {
+ lsa_String oem_information; /* comment */
+ } samr_DomOEMInformation;
+
+ typedef struct {
+ lsa_String domain_name;
+ } samr_DomInfo5;
+
+ typedef struct {
+ lsa_String primary;
+ } samr_DomInfo6;
+
+ typedef struct {
+ samr_Role role;
+ } samr_DomInfo7;
+
+ typedef struct {
+ hyper sequence_num;
+ NTTIME domain_create_time;
+ } samr_DomInfo8;
+
+ typedef struct {
+ samr_DomainServerState domain_server_state;
+ } samr_DomInfo9;
+
+ typedef struct {
+ samr_DomGeneralInformation general;
+ hyper lockout_duration;
+ hyper lockout_window;
+ uint16 lockout_threshold;
+ } samr_DomGeneralInformation2;
+
+ typedef struct {
+ hyper lockout_duration;
+ hyper lockout_window;
+ uint16 lockout_threshold;
+ } samr_DomInfo12;
+
+ typedef struct {
+ hyper sequence_num;
+ NTTIME domain_create_time;
+ hyper modified_count_at_last_promotion;
+ } samr_DomInfo13;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_DomInfo1 info1;
+ [case(2)] samr_DomGeneralInformation general;
+ [case(3)] samr_DomInfo3 info3;
+ [case(4)] samr_DomOEMInformation oem;
+ [case(5)] samr_DomInfo5 info5;
+ [case(6)] samr_DomInfo6 info6;
+ [case(7)] samr_DomInfo7 info7;
+ [case(8)] samr_DomInfo8 info8;
+ [case(9)] samr_DomInfo9 info9;
+ [case(11)] samr_DomGeneralInformation2 general2;
+ [case(12)] samr_DomInfo12 info12;
+ [case(13)] samr_DomInfo13 info13;
+ } samr_DomainInfo;
+
+ NTSTATUS samr_QueryDomainInfo(
+ [in,ref] policy_handle *domain_handle,
+ [in] samr_DomainInfoClass level,
+ [out,ref,switch_is(level)] samr_DomainInfo **info
+ );
+
+ /************************/
+ /* Function 0x09 */
+ /*
+ only levels 1, 3, 4, 6, 7, 9, 12 are valid for this
+ call in w2k3
+ */
+ NTSTATUS samr_SetDomainInfo(
+ [in,ref] policy_handle *domain_handle,
+ [in] samr_DomainInfoClass level,
+ [in,switch_is(level),ref] samr_DomainInfo *info
+ );
+
+
+ /************************/
+ /* Function 0x0a */
+ NTSTATUS samr_CreateDomainGroup(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_String *name,
+ [in] samr_GroupAccessMask access_mask,
+ [out,ref] policy_handle *group_handle,
+ [out,ref] uint32 *rid
+ );
+
+
+ /************************/
+ /* Function 0x0b */
+ NTSTATUS samr_EnumDomainGroups(
+ [in] policy_handle *domain_handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] samr_SamArray **sam,
+ [in] uint32 max_size,
+ [out,ref] uint32 *num_entries
+ );
+
+ /************************/
+ /* Function 0x0c */
+ NTSTATUS samr_CreateUser(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_String *account_name,
+ [in] samr_UserAccessMask access_mask,
+ [out,ref] policy_handle *user_handle,
+ [out,ref] uint32 *rid
+ );
+
+ /************************/
+ /* Function 0x0d */
+
+
+ /* w2k3 treats max_size as max_users*54 and sets the
+ resume_handle as the rid of the last user sent
+ */
+ const int SAMR_ENUM_USERS_MULTIPLIER = 54;
+
+ NTSTATUS samr_EnumDomainUsers(
+ [in] policy_handle *domain_handle,
+ [in,out,ref] uint32 *resume_handle,
+ [in] samr_AcctFlags acct_flags,
+ [out,ref] samr_SamArray **sam,
+ [in] uint32 max_size,
+ [out,ref] uint32 *num_entries
+ );
+
+ /************************/
+ /* Function 0x0e */
+ NTSTATUS samr_CreateDomAlias(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_String *alias_name,
+ [in] samr_AliasAccessMask access_mask,
+ [out,ref] policy_handle *alias_handle,
+ [out,ref] uint32 *rid
+ );
+
+ /************************/
+ /* Function 0x0f */
+ NTSTATUS samr_EnumDomainAliases(
+ [in] policy_handle *domain_handle,
+ [in,out,ref] uint32 *resume_handle,
+ [out,ref] samr_SamArray **sam,
+ [in] uint32 max_size,
+ [out,ref] uint32 *num_entries
+ );
+
+ /************************/
+ /* Function 0x10 */
+
+ typedef struct {
+ [range(0,1024)] uint32 count;
+ [size_is(count)] uint32 *ids;
+ } samr_Ids;
+
+ NTSTATUS samr_GetAliasMembership(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_SidArray *sids,
+ [out,ref] samr_Ids *rids
+ );
+
+ /************************/
+ /* Function 0x11 */
+
+ [public] NTSTATUS samr_LookupNames(
+ [in,ref] policy_handle *domain_handle,
+ [in,range(0,1000)] uint32 num_names,
+ [in,size_is(1000),length_is(num_names)] lsa_String names[],
+ [out,ref] samr_Ids *rids,
+ [out,ref] samr_Ids *types
+ );
+
+
+ /************************/
+ /* Function 0x12 */
+ NTSTATUS samr_LookupRids(
+ [in,ref] policy_handle *domain_handle,
+ [in,range(0,1000)] uint32 num_rids,
+ [in,size_is(1000),length_is(num_rids)] uint32 rids[],
+ [out,ref] lsa_Strings *names,
+ [out,ref] samr_Ids *types
+ );
+
+ /************************/
+ /* Function 0x13 */
+ NTSTATUS samr_OpenGroup(
+ [in,ref] policy_handle *domain_handle,
+ [in] samr_GroupAccessMask access_mask,
+ [in] uint32 rid,
+ [out,ref] policy_handle *group_handle
+ );
+
+ /************************/
+ /* Function 0x14 */
+
+ typedef struct {
+ lsa_String name;
+ security_GroupAttrs attributes;
+ uint32 num_members;
+ lsa_String description;
+ } samr_GroupInfoAll;
+
+ typedef struct {
+ security_GroupAttrs attributes;
+ } samr_GroupInfoAttributes;
+
+ typedef struct {
+ lsa_String description;
+ } samr_GroupInfoDescription;
+
+ typedef enum {
+ GROUPINFOALL = 1,
+ GROUPINFONAME = 2,
+ GROUPINFOATTRIBUTES = 3,
+ GROUPINFODESCRIPTION = 4,
+ GROUPINFOALL2 = 5
+ } samr_GroupInfoEnum;
+
+ typedef [switch_type(samr_GroupInfoEnum)] union {
+ [case(GROUPINFOALL)] samr_GroupInfoAll all;
+ [case(GROUPINFONAME)] lsa_String name;
+ [case(GROUPINFOATTRIBUTES)] samr_GroupInfoAttributes attributes;
+ [case(GROUPINFODESCRIPTION)] lsa_String description;
+ [case(GROUPINFOALL2)] samr_GroupInfoAll all2;
+ } samr_GroupInfo;
+
+ NTSTATUS samr_QueryGroupInfo(
+ [in,ref] policy_handle *group_handle,
+ [in] samr_GroupInfoEnum level,
+ [out,ref,switch_is(level)] samr_GroupInfo **info
+ );
+
+ /************************/
+ /* Function 0x15 */
+ NTSTATUS samr_SetGroupInfo(
+ [in,ref] policy_handle *group_handle,
+ [in] samr_GroupInfoEnum level,
+ [in,switch_is(level),ref] samr_GroupInfo *info
+ );
+
+ /************************/
+ /* Function 0x16 */
+ NTSTATUS samr_AddGroupMember(
+ [in,ref] policy_handle *group_handle,
+ [in] uint32 rid,
+ [in] uint32 flags
+ );
+
+ /************************/
+ /* Function 0x17 */
+ NTSTATUS samr_DeleteDomainGroup(
+ [in,out,ref] policy_handle *group_handle
+ );
+
+ /************************/
+ /* Function 0x18 */
+ NTSTATUS samr_DeleteGroupMember(
+ [in,ref] policy_handle *group_handle,
+ [in] uint32 rid
+ );
+
+
+ /************************/
+ /* Function 0x19 */
+ typedef struct {
+ uint32 count;
+ [size_is(count)] uint32 *rids;
+ [size_is(count)] security_GroupAttrs *attributes;
+ } samr_RidAttrArray;
+
+ NTSTATUS samr_QueryGroupMember(
+ [in,ref] policy_handle *group_handle,
+ [out,ref] samr_RidAttrArray **rids
+ );
+
+
+ /************************/
+ /* Function 0x1a */
+
+ /*
+ win2003 seems to accept any data at all for the two integers
+ below, and doesn't seem to do anything with them that I can
+ see. Weird. I really expected the first integer to be a rid
+ and the second to be the attributes for that rid member.
+ */
+ NTSTATUS samr_SetMemberAttributesOfGroup(
+ [in,ref] policy_handle *group_handle,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2
+ );
+
+
+ /************************/
+ /* Function 0x1b */
+ NTSTATUS samr_OpenAlias (
+ [in,ref] policy_handle *domain_handle,
+ [in] samr_AliasAccessMask access_mask,
+ [in] uint32 rid,
+ [out,ref] policy_handle *alias_handle
+ );
+
+
+ /************************/
+ /* Function 0x1c */
+
+ typedef struct {
+ lsa_String name;
+ uint32 num_members;
+ lsa_String description;
+ } samr_AliasInfoAll;
+
+ typedef enum {
+ ALIASINFOALL = 1,
+ ALIASINFONAME = 2,
+ ALIASINFODESCRIPTION = 3
+ } samr_AliasInfoEnum;
+
+ typedef [switch_type(samr_AliasInfoEnum)] union {
+ [case(ALIASINFOALL)] samr_AliasInfoAll all;
+ [case(ALIASINFONAME)] lsa_String name;
+ [case(ALIASINFODESCRIPTION)] lsa_String description;
+ } samr_AliasInfo;
+
+ NTSTATUS samr_QueryAliasInfo(
+ [in,ref] policy_handle *alias_handle,
+ [in] samr_AliasInfoEnum level,
+ [out,ref,switch_is(level)] samr_AliasInfo **info
+ );
+
+ /************************/
+ /* Function 0x1d */
+ NTSTATUS samr_SetAliasInfo(
+ [in,ref] policy_handle *alias_handle,
+ [in] samr_AliasInfoEnum level,
+ [in,switch_is(level),ref] samr_AliasInfo *info
+ );
+
+ /************************/
+ /* Function 0x1e */
+ NTSTATUS samr_DeleteDomAlias(
+ [in,out,ref] policy_handle *alias_handle
+ );
+
+ /************************/
+ /* Function 0x1f */
+ NTSTATUS samr_AddAliasMember(
+ [in,ref] policy_handle *alias_handle,
+ [in,ref] dom_sid2 *sid
+ );
+
+ /************************/
+ /* Function 0x20 */
+ NTSTATUS samr_DeleteAliasMember(
+ [in,ref] policy_handle *alias_handle,
+ [in,ref] dom_sid2 *sid
+ );
+
+ /************************/
+ /* Function 0x21 */
+ NTSTATUS samr_GetMembersInAlias(
+ [in,ref] policy_handle *alias_handle,
+ [out,ref] lsa_SidArray *sids
+ );
+
+ /************************/
+ /* Function 0x22 */
+ [public] NTSTATUS samr_OpenUser(
+ [in,ref] policy_handle *domain_handle,
+ [in] samr_UserAccessMask access_mask,
+ [in] uint32 rid,
+ [out,ref] policy_handle *user_handle
+ );
+
+ /************************/
+ /* Function 0x23 */
+ NTSTATUS samr_DeleteUser(
+ [in,out,ref] policy_handle *user_handle
+ );
+
+ /************************/
+ /* Function 0x24 */
+
+ typedef enum {
+ UserGeneralInformation = 1,
+ UserPreferencesInformation = 2,
+ UserLogonInformation = 3,
+ UserLogonHoursInformation = 4,
+ UserAccountInformation = 5,
+ UserNameInformation = 6,
+ UserAccountNameInformation = 7,
+ UserFullNameInformation = 8,
+ UserPrimaryGroupInformation = 9,
+ UserHomeInformation = 10,
+ UserScriptInformation = 11,
+ UserProfileInformation = 12,
+ UserAdminCommentInformation = 13,
+ UserWorkStationsInformation = 14,
+ UserControlInformation = 16,
+ UserExpiresInformation = 17,
+ UserInternal1Information = 18,
+ UserParametersInformation = 20,
+ UserAllInformation = 21,
+ UserInternal4Information = 23,
+ UserInternal5Information = 24,
+ UserInternal4InformationNew = 25,
+ UserInternal5InformationNew = 26,
+ UserInternal7InformationNew = 31,
+ UserInternal8InformationNew = 32
+ } samr_UserInfoLevel;
+
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ uint32 primary_gid;
+ lsa_String description;
+ lsa_String comment;
+ } samr_UserInfo1;
+
+ typedef struct {
+ lsa_String comment;
+ lsa_String reserved; /* settable, but doesn't stick. probably obsolete */
+ uint16 country_code;
+ uint16 code_page;
+ } samr_UserInfo2;
+
+ /* this is also used in samr and netlogon */
+ typedef [public, flag(NDR_PAHEX)] struct {
+ uint16 units_per_week;
+ [size_is(1260), length_is(units_per_week/8)] uint8 *bits;
+ } samr_LogonHours;
+
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ uint32 rid;
+ uint32 primary_gid;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ lsa_String logon_script;
+ lsa_String profile_path;
+ lsa_String workstations;
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ NTTIME last_password_change;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+ samr_LogonHours logon_hours;
+ uint16 bad_password_count;
+ uint16 logon_count;
+ samr_AcctFlags acct_flags;
+ } samr_UserInfo3;
+
+ typedef struct {
+ samr_LogonHours logon_hours;
+ } samr_UserInfo4;
+
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ uint32 rid;
+ uint32 primary_gid;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ lsa_String logon_script;
+ lsa_String profile_path;
+ lsa_String description;
+ lsa_String workstations;
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ samr_LogonHours logon_hours;
+ uint16 bad_password_count;
+ uint16 logon_count;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ samr_AcctFlags acct_flags;
+ } samr_UserInfo5;
+
+ typedef struct {
+ lsa_String account_name;
+ lsa_String full_name;
+ } samr_UserInfo6;
+
+ typedef struct {
+ lsa_String account_name;
+ } samr_UserInfo7;
+
+ typedef struct {
+ lsa_String full_name;
+ } samr_UserInfo8;
+
+ typedef struct {
+ uint32 primary_gid;
+ } samr_UserInfo9;
+
+ typedef struct {
+ lsa_String home_directory;
+ lsa_String home_drive;
+ } samr_UserInfo10;
+
+ typedef struct {
+ lsa_String logon_script;
+ } samr_UserInfo11;
+
+ typedef struct {
+ lsa_String profile_path;
+ } samr_UserInfo12;
+
+ typedef struct {
+ lsa_String description;
+ } samr_UserInfo13;
+
+ typedef struct {
+ lsa_String workstations;
+ } samr_UserInfo14;
+
+ typedef struct {
+ samr_AcctFlags acct_flags;
+ } samr_UserInfo16;
+
+ typedef struct {
+ NTTIME acct_expiry;
+ } samr_UserInfo17;
+
+ typedef [public, flag(NDR_PAHEX)] struct {
+ uint8 hash[16];
+ } samr_Password;
+
+ typedef struct {
+ samr_Password nt_pwd;
+ samr_Password lm_pwd;
+ boolean8 nt_pwd_active;
+ boolean8 lm_pwd_active;
+ uint8 password_expired;
+ } samr_UserInfo18;
+
+ typedef struct {
+ lsa_BinaryString parameters;
+ } samr_UserInfo20;
+
+ /* this defines the bits used for fields_present in info21 */
+ typedef [bitmap32bit] bitmap {
+ SAMR_FIELD_ACCOUNT_NAME = 0x00000001,
+ SAMR_FIELD_FULL_NAME = 0x00000002,
+ SAMR_FIELD_RID = 0x00000004,
+ SAMR_FIELD_PRIMARY_GID = 0x00000008,
+ SAMR_FIELD_DESCRIPTION = 0x00000010,
+ SAMR_FIELD_COMMENT = 0x00000020,
+ SAMR_FIELD_HOME_DIRECTORY = 0x00000040,
+ SAMR_FIELD_HOME_DRIVE = 0x00000080,
+ SAMR_FIELD_LOGON_SCRIPT = 0x00000100,
+ SAMR_FIELD_PROFILE_PATH = 0x00000200,
+ SAMR_FIELD_WORKSTATIONS = 0x00000400,
+ SAMR_FIELD_LAST_LOGON = 0x00000800,
+ SAMR_FIELD_LAST_LOGOFF = 0x00001000,
+ SAMR_FIELD_LOGON_HOURS = 0x00002000,
+ SAMR_FIELD_BAD_PWD_COUNT = 0x00004000,
+ SAMR_FIELD_NUM_LOGONS = 0x00008000,
+ SAMR_FIELD_ALLOW_PWD_CHANGE = 0x00010000,
+ SAMR_FIELD_FORCE_PWD_CHANGE = 0x00020000,
+ SAMR_FIELD_LAST_PWD_CHANGE = 0x00040000,
+ SAMR_FIELD_ACCT_EXPIRY = 0x00080000,
+ SAMR_FIELD_ACCT_FLAGS = 0x00100000,
+ SAMR_FIELD_PARAMETERS = 0x00200000,
+ SAMR_FIELD_COUNTRY_CODE = 0x00400000,
+ SAMR_FIELD_CODE_PAGE = 0x00800000,
+ SAMR_FIELD_NT_PASSWORD_PRESENT = 0x01000000, /* either of these */
+ SAMR_FIELD_LM_PASSWORD_PRESENT = 0x02000000, /* two bits seems to work */
+ SAMR_FIELD_PRIVATE_DATA = 0x04000000,
+ SAMR_FIELD_EXPIRED_FLAG = 0x08000000,
+ SAMR_FIELD_SEC_DESC = 0x10000000,
+ SAMR_FIELD_OWF_PWD = 0x20000000
+ } samr_FieldsPresent;
+
+ /* used for 'password_expired' in samr_UserInfo21 */
+ const int PASS_MUST_CHANGE_AT_NEXT_LOGON = 0x01;
+ const int PASS_DONT_CHANGE_AT_NEXT_LOGON = 0x00;
+
+ typedef struct {
+ NTTIME last_logon;
+ NTTIME last_logoff;
+ NTTIME last_password_change;
+ NTTIME acct_expiry;
+ NTTIME allow_password_change;
+ NTTIME force_password_change;
+ lsa_String account_name;
+ lsa_String full_name;
+ lsa_String home_directory;
+ lsa_String home_drive;
+ lsa_String logon_script;
+ lsa_String profile_path;
+ lsa_String description;
+ lsa_String workstations;
+ lsa_String comment;
+ lsa_BinaryString parameters;
+ lsa_BinaryString lm_owf_password;
+ lsa_BinaryString nt_owf_password;
+ lsa_String private_data;
+ uint32 buf_count;
+ [size_is(buf_count)] uint8 *buffer;
+ uint32 rid;
+ uint32 primary_gid;
+ samr_AcctFlags acct_flags;
+ samr_FieldsPresent fields_present;
+ samr_LogonHours logon_hours;
+ uint16 bad_password_count;
+ uint16 logon_count;
+ uint16 country_code;
+ uint16 code_page;
+ uint8 lm_password_set;
+ uint8 nt_password_set;
+ uint8 password_expired;
+ uint8 private_data_sensitive;
+ } samr_UserInfo21;
+
+ typedef [public, flag(NDR_PAHEX)] struct {
+ uint8 data[516];
+ } samr_CryptPassword;
+
+ typedef struct {
+ samr_UserInfo21 info;
+ samr_CryptPassword password;
+ } samr_UserInfo23;
+
+ typedef struct {
+ samr_CryptPassword password;
+ uint8 password_expired;
+ } samr_UserInfo24;
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 data[532];
+ } samr_CryptPasswordEx;
+
+ typedef struct {
+ samr_UserInfo21 info;
+ samr_CryptPasswordEx password;
+ } samr_UserInfo25;
+
+ typedef struct {
+ samr_CryptPasswordEx password;
+ uint8 password_expired;
+ } samr_UserInfo26;
+
+ typedef struct {
+ uint8 auth_data[64];
+ uint8 salt[16];
+ uint32 cipher_len;
+ [size_is(cipher_len)] uint8 *cipher;
+ hyper PBKDF2Iterations;
+ } samr_EncryptedPasswordAES;
+
+ typedef struct {
+ samr_EncryptedPasswordAES password;
+ uint8 password_expired;
+ } samr_UserInfo31;
+
+ typedef struct {
+ samr_UserInfo21 info;
+ samr_EncryptedPasswordAES password;
+ } samr_UserInfo32;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_UserInfo1 info1;
+ [case(2)] samr_UserInfo2 info2;
+ [case(3)] samr_UserInfo3 info3;
+ [case(4)] samr_UserInfo4 info4;
+ [case(5)] samr_UserInfo5 info5;
+ [case(6)] samr_UserInfo6 info6;
+ [case(7)] samr_UserInfo7 info7;
+ [case(8)] samr_UserInfo8 info8;
+ [case(9)] samr_UserInfo9 info9;
+ [case(10)] samr_UserInfo10 info10;
+ [case(11)] samr_UserInfo11 info11;
+ [case(12)] samr_UserInfo12 info12;
+ [case(13)] samr_UserInfo13 info13;
+ [case(14)] samr_UserInfo14 info14;
+ [case(16)] samr_UserInfo16 info16;
+ [case(17)] samr_UserInfo17 info17;
+ [case(18)] samr_UserInfo18 info18;
+ [case(20)] samr_UserInfo20 info20;
+ [case(21)] samr_UserInfo21 info21;
+ [case(23)] samr_UserInfo23 info23;
+ [case(24)] samr_UserInfo24 info24;
+ [case(25)] samr_UserInfo25 info25;
+ [case(26)] samr_UserInfo26 info26;
+ [case(31)] samr_UserInfo31 info31;
+ [case(32)] samr_UserInfo32 info32;
+ } samr_UserInfo;
+
+ [public] NTSTATUS samr_QueryUserInfo(
+ [in,ref] policy_handle *user_handle,
+ [in] samr_UserInfoLevel level,
+ [out,ref,switch_is(level)] samr_UserInfo **info
+ );
+
+
+ /************************/
+ /* Function 0x25 */
+ [public] NTSTATUS samr_SetUserInfo(
+ [in,ref] policy_handle *user_handle,
+ [in] samr_UserInfoLevel level,
+ [in,ref,switch_is(level)] samr_UserInfo *info
+ );
+
+ /************************/
+ /* Function 0x26 */
+ /*
+ this is a password change interface that doesn't give
+ the server the plaintext password. Deprecated.
+ */
+ NTSTATUS samr_ChangePasswordUser(
+ [in,ref] policy_handle *user_handle,
+ [in] boolean8 lm_present,
+ [in,unique] samr_Password *old_lm_crypted,
+ [in,unique] samr_Password *new_lm_crypted,
+ [in] boolean8 nt_present,
+ [in,unique] samr_Password *old_nt_crypted,
+ [in,unique] samr_Password *new_nt_crypted,
+ [in] boolean8 cross1_present,
+ [in,unique] samr_Password *nt_cross,
+ [in] boolean8 cross2_present,
+ [in,unique] samr_Password *lm_cross
+ );
+
+ /************************/
+ /* Function 0x27 */
+
+ typedef [public] struct {
+ uint32 rid;
+ security_GroupAttrs attributes;
+ } samr_RidWithAttribute;
+
+ typedef [public] struct {
+ uint32 count;
+ [size_is(count)] samr_RidWithAttribute *rids;
+ } samr_RidWithAttributeArray;
+
+ NTSTATUS samr_GetGroupsForUser(
+ [in,ref] policy_handle *user_handle,
+ [out,ref] samr_RidWithAttributeArray **rids
+ );
+
+ /************************/
+ /* Function 0x28 */
+
+ typedef struct {
+ uint32 idx;
+ uint32 rid;
+ samr_AcctFlags acct_flags;
+ lsa_String account_name;
+ lsa_String description;
+ lsa_String full_name;
+ } samr_DispEntryGeneral;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_DispEntryGeneral *entries;
+ } samr_DispInfoGeneral;
+
+ typedef struct {
+ uint32 idx;
+ uint32 rid;
+ samr_AcctFlags acct_flags;
+ lsa_String account_name;
+ lsa_String description;
+ } samr_DispEntryFull;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_DispEntryFull *entries;
+ } samr_DispInfoFull;
+
+ typedef struct {
+ uint32 idx;
+ uint32 rid;
+ security_GroupAttrs acct_flags;
+ lsa_String account_name;
+ lsa_String description;
+ } samr_DispEntryFullGroup;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_DispEntryFullGroup *entries;
+ } samr_DispInfoFullGroups;
+
+ typedef struct {
+ uint32 idx;
+ lsa_AsciiStringLarge account_name;
+ } samr_DispEntryAscii;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] samr_DispEntryAscii *entries;
+ } samr_DispInfoAscii;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_DispInfoGeneral info1;/* users */
+ [case(2)] samr_DispInfoFull info2; /* trust accounts? */
+ [case(3)] samr_DispInfoFullGroups info3; /* groups */
+ [case(4)] samr_DispInfoAscii info4; /* users */
+ [case(5)] samr_DispInfoAscii info5; /* groups */
+ } samr_DispInfo;
+
+ NTSTATUS samr_QueryDisplayInfo(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in] uint32 start_idx,
+ [in] uint32 max_entries,
+ [in] uint32 buf_size,
+ [out,ref] uint32 *total_size,
+ [out,ref] uint32 *returned_size,
+ [out,ref,switch_is(level)] samr_DispInfo *info
+ );
+
+
+ /************************/
+ /* Function 0x29 */
+
+ /*
+ this seems to be an alphabetic search function. The returned index
+ is the index for samr_QueryDisplayInfo needed to get names occurring
+ after the specified name. The supplied name does not need to exist
+ in the database (for example you can supply just a first letter for
+ searching starting at that letter)
+
+ The level corresponds to the samr_QueryDisplayInfo level
+ */
+ NTSTATUS samr_GetDisplayEnumerationIndex(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in,ref] lsa_String *name,
+ [out,ref] uint32 *idx
+ );
+
+
+
+ /************************/
+ /* Function 0x2a */
+
+ /*
+ w2k3 returns NT_STATUS_NOT_IMPLEMENTED for this
+ */
+ NTSTATUS samr_TestPrivateFunctionsDomain(
+ [in,ref] policy_handle *domain_handle
+ );
+
+
+ /************************/
+ /* Function 0x2b */
+
+ /*
+ w2k3 returns NT_STATUS_NOT_IMPLEMENTED for this
+ */
+ NTSTATUS samr_TestPrivateFunctionsUser(
+ [in,ref] policy_handle *user_handle
+ );
+
+
+ /************************/
+ /* Function 0x2c */
+
+ typedef struct {
+ uint16 min_password_length;
+ samr_PasswordProperties password_properties;
+ } samr_PwInfo;
+
+ [public] NTSTATUS samr_GetUserPwInfo(
+ [in,ref] policy_handle *user_handle,
+ [out,ref] samr_PwInfo *info
+ );
+
+ /************************/
+ /* Function 0x2d */
+ NTSTATUS samr_RemoveMemberFromForeignDomain(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] dom_sid2 *sid
+ );
+
+ /************************/
+ /* Function 0x2e */
+
+ /*
+ how is this different from QueryDomainInfo ??
+ */
+ NTSTATUS samr_QueryDomainInfo2(
+ [in,ref] policy_handle *domain_handle,
+ [in] samr_DomainInfoClass level,
+ [out,ref,switch_is(level)] samr_DomainInfo **info
+ );
+
+ /************************/
+ /* Function 0x2f */
+
+ /*
+ how is this different from QueryUserInfo ??
+ */
+ NTSTATUS samr_QueryUserInfo2(
+ [in,ref] policy_handle *user_handle,
+ [in] samr_UserInfoLevel level,
+ [out,ref,switch_is(level)] samr_UserInfo **info
+ );
+
+ /************************/
+ /* Function 0x30 */
+
+ /*
+ how is this different from QueryDisplayInfo??
+ */
+ NTSTATUS samr_QueryDisplayInfo2(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in] uint32 start_idx,
+ [in] uint32 max_entries,
+ [in] uint32 buf_size,
+ [out,ref] uint32 *total_size,
+ [out,ref] uint32 *returned_size,
+ [out,ref,switch_is(level)] samr_DispInfo *info
+ );
+
+ /************************/
+ /* Function 0x31 */
+
+ /*
+ how is this different from GetDisplayEnumerationIndex ??
+ */
+ NTSTATUS samr_GetDisplayEnumerationIndex2(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in,ref] lsa_String *name,
+ [out,ref] uint32 *idx
+ );
+
+
+ /************************/
+ /* Function 0x32 */
+ NTSTATUS samr_CreateUser2(
+ [in,ref] policy_handle *domain_handle,
+ [in,ref] lsa_String *account_name,
+ [in] samr_AcctFlags acct_flags,
+ [in] samr_UserAccessMask access_mask,
+ [out,ref] policy_handle *user_handle,
+ [out,ref] uint32 *access_granted,
+ [out,ref] uint32 *rid
+ );
+
+
+ /************************/
+ /* Function 0x33 */
+
+ /*
+ another duplicate. There must be a reason ....
+ */
+ NTSTATUS samr_QueryDisplayInfo3(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint16 level,
+ [in] uint32 start_idx,
+ [in] uint32 max_entries,
+ [in] uint32 buf_size,
+ [out,ref] uint32 *total_size,
+ [out,ref] uint32 *returned_size,
+ [out,ref,switch_is(level)] samr_DispInfo *info
+ );
+
+ /************************/
+ /* Function 0x34 */
+ NTSTATUS samr_AddMultipleMembersToAlias(
+ [in,ref] policy_handle *alias_handle,
+ [in,ref] lsa_SidArray *sids
+ );
+
+ /************************/
+ /* Function 0x35 */
+ NTSTATUS samr_RemoveMultipleMembersFromAlias(
+ [in,ref] policy_handle *alias_handle,
+ [in,ref] lsa_SidArray *sids
+ );
+
+ /************************/
+ /* Function 0x36 */
+
+ NTSTATUS samr_OemChangePasswordUser2(
+ [in,unique] lsa_AsciiString *server,
+ [in,ref] lsa_AsciiString *account,
+ [in,unique] samr_CryptPassword *password,
+ [in,unique] samr_Password *hash
+ );
+
+ /************************/
+ /* Function 0x37 */
+ NTSTATUS samr_ChangePasswordUser2(
+ [in,unique] lsa_String *server,
+ [in,ref] lsa_String *account,
+ [in,unique] samr_CryptPassword *nt_password,
+ [in,unique] samr_Password *nt_verifier,
+ [in] boolean8 lm_change,
+ [in,unique] samr_CryptPassword *lm_password,
+ [in,unique] samr_Password *lm_verifier
+ );
+
+ /************************/
+ /* Function 0x38 */
+ NTSTATUS samr_GetDomPwInfo(
+ [in,unique] lsa_String *domain_name,
+ [out,ref] samr_PwInfo *info
+ );
+
+ /************************/
+ /* Function 0x39 */
+ NTSTATUS samr_Connect2(
+ [in,unique,string,charset(UTF16)] uint16 *system_name,
+ [in] samr_ConnectAccessMask access_mask,
+ [out,ref] policy_handle *connect_handle
+ );
+
+ /************************/
+ /* Function 0x3a */
+ /*
+ seems to be an exact alias for samr_SetUserInfo()
+ */
+ [public] NTSTATUS samr_SetUserInfo2(
+ [in,ref] policy_handle *user_handle,
+ [in] samr_UserInfoLevel level,
+ [in,ref,switch_is(level)] samr_UserInfo *info
+ );
+
+ /************************/
+ /* Function 0x3b */
+ /*
+ this one is mysterious. I have a few guesses, but nothing working yet
+ */
+ NTSTATUS samr_SetBootKeyInformation(
+ [in,ref] policy_handle *connect_handle,
+ [in] uint32 unknown1,
+ [in] uint32 unknown2,
+ [in] uint32 unknown3
+ );
+
+ /************************/
+ /* Function 0x3c */
+ NTSTATUS samr_GetBootKeyInformation(
+ [in,ref] policy_handle *domain_handle,
+ [out,ref] uint32 *unknown
+ );
+
+ /************************/
+ /* Function 0x3d */
+ NTSTATUS samr_Connect3(
+ [in,unique,string,charset(UTF16)] uint16 *system_name,
+ /* this unknown value seems to be completely ignored by w2k3 */
+ [in] uint32 unknown,
+ [in] samr_ConnectAccessMask access_mask,
+ [out,ref] policy_handle *connect_handle
+ );
+
+ /************************/
+ /* Function 0x3e */
+
+ typedef [v1_enum] enum {
+ SAMR_CONNECT_PRE_W2K = 1,
+ SAMR_CONNECT_W2K = 2,
+ SAMR_CONNECT_AFTER_W2K = 3
+ } samr_ConnectVersion;
+
+ NTSTATUS samr_Connect4(
+ [in,unique,string,charset(UTF16)] uint16 *system_name,
+ [in] samr_ConnectVersion client_version,
+ [in] samr_ConnectAccessMask access_mask,
+ [out,ref] policy_handle *connect_handle
+ );
+
+ /************************/
+ /* Function 0x3f */
+
+ typedef [public,v1_enum] enum {
+ SAM_PWD_CHANGE_NO_ERROR = 0,
+ SAM_PWD_CHANGE_PASSWORD_TOO_SHORT = 1,
+ SAM_PWD_CHANGE_PWD_IN_HISTORY = 2,
+ SAM_PWD_CHANGE_USERNAME_IN_PASSWORD = 3,
+ SAM_PWD_CHANGE_FULLNAME_IN_PASSWORD = 4,
+ SAM_PWD_CHANGE_NOT_COMPLEX = 5,
+ SAM_PWD_CHANGE_MACHINE_NOT_DEFAULT = 6,
+ SAM_PWD_CHANGE_FAILED_BY_FILTER = 7,
+ SAM_PWD_CHANGE_PASSWORD_TOO_LONG = 8
+ } samPwdChangeReason;
+
+ typedef struct {
+ samPwdChangeReason extendedFailureReason;
+ lsa_String filterModuleName;
+ } userPwdChangeFailureInformation;
+
+ [public] NTSTATUS samr_ChangePasswordUser3(
+ [in,unique] lsa_String *server,
+ [in,ref] lsa_String *account,
+ [in,unique] samr_CryptPassword *nt_password,
+ [in,unique] samr_Password *nt_verifier,
+ [in] boolean8 lm_change,
+ [in,unique] samr_CryptPassword *lm_password,
+ [in,unique] samr_Password *lm_verifier,
+ [in,unique] samr_CryptPassword *password3,
+ [out,ref] samr_DomInfo1 **dominfo,
+ [out,ref] userPwdChangeFailureInformation **reject
+ );
+
+ /************************/
+ /* Function 0x40 */
+
+ typedef [v1_enum] enum {
+ SAMR_CONNECT_FEATURE_RID_ONLY = 0x00000001,
+ SAMR_CONNECT_FEATURE_RESRVED1 = 0x00000002,
+ SAMR_CONNECT_FEATURE_RESRVED2 = 0x00000004,
+ SAMR_CONNECT_FEATURE_USE_AES = 0x00000010
+ } samr_SupportedFeatures;
+
+ typedef struct {
+ samr_ConnectVersion client_version; /* w2k3 gives 3 */
+ samr_SupportedFeatures supported_features;
+ } samr_ConnectInfo1;
+
+ typedef union {
+ [case(1)] samr_ConnectInfo1 info1;
+ } samr_ConnectInfo;
+
+ [public] NTSTATUS samr_Connect5(
+ [in,unique,string,charset(UTF16)] uint16 *system_name,
+ [in] samr_ConnectAccessMask access_mask,
+ [in] uint32 level_in,
+ [in,ref,switch_is(level_in)] samr_ConnectInfo *info_in,
+ [out,ref] uint32 *level_out,
+ [out,ref,switch_is(*level_out)] samr_ConnectInfo *info_out,
+ [out,ref] policy_handle *connect_handle
+ );
+
+ /************************/
+ /* Function 0x41 */
+ NTSTATUS samr_RidToSid(
+ [in,ref] policy_handle *domain_handle,
+ [in] uint32 rid,
+ [out,ref] dom_sid2 **sid
+ );
+
+ /************************/
+ /* Function 0x42 */
+
+ /*
+ this should set the DSRM password for the server, which is used
+ when booting into Directory Services Recovery Mode on a DC. Win2003
+ gives me NT_STATUS_NOT_SUPPORTED
+ */
+
+ NTSTATUS samr_SetDsrmPassword(
+ [in,unique] lsa_String *name,
+ [in] uint32 unknown,
+ [in,unique] samr_Password *hash
+ );
+
+
+ /************************/
+ /* Function 0x43 */
+ /************************/
+ typedef [bitmap32bit] bitmap {
+ SAMR_VALIDATE_FIELD_PASSWORD_LAST_SET = 0x00000001,
+ SAMR_VALIDATE_FIELD_BAD_PASSWORD_TIME = 0x00000002,
+ SAMR_VALIDATE_FIELD_LOCKOUT_TIME = 0x00000004,
+ SAMR_VALIDATE_FIELD_BAD_PASSWORD_COUNT = 0x00000008,
+ SAMR_VALIDATE_FIELD_PASSWORD_HISTORY_LENGTH = 0x00000010,
+ SAMR_VALIDATE_FIELD_PASSWORD_HISTORY = 0x00000020
+ } samr_ValidateFieldsPresent;
+
+ typedef enum {
+ NetValidateAuthentication = 1,
+ NetValidatePasswordChange= 2,
+ NetValidatePasswordReset = 3
+ } samr_ValidatePasswordLevel;
+
+ /* NetApi maps samr_ValidationStatus errors to WERRORs. Haven't
+ * identified the mapping of
+ * - NERR_PasswordFilterError
+ * - NERR_PasswordExpired and
+ * - NERR_PasswordCantChange
+ * yet - Guenther
+ */
+
+ typedef enum {
+ SAMR_VALIDATION_STATUS_SUCCESS = 0,
+ SAMR_VALIDATION_STATUS_PASSWORD_MUST_CHANGE = 1,
+ SAMR_VALIDATION_STATUS_ACCOUNT_LOCKED_OUT = 2,
+ SAMR_VALIDATION_STATUS_PASSWORD_EXPIRED = 3,
+ SAMR_VALIDATION_STATUS_BAD_PASSWORD = 4,
+ SAMR_VALIDATION_STATUS_PWD_HISTORY_CONFLICT = 5,
+ SAMR_VALIDATION_STATUS_PWD_TOO_SHORT = 6,
+ SAMR_VALIDATION_STATUS_PWD_TOO_LONG = 7,
+ SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH = 8,
+ SAMR_VALIDATION_STATUS_PASSWORD_TOO_RECENT = 9,
+ SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR = 10
+ } samr_ValidationStatus;
+
+ typedef struct {
+ uint32 length;
+ [size_is(length)] uint8 *data;
+ } samr_ValidationBlob;
+
+ typedef struct {
+ samr_ValidateFieldsPresent fields_present;
+ NTTIME_hyper last_password_change;
+ NTTIME_hyper bad_password_time;
+ NTTIME_hyper lockout_time;
+ uint32 bad_pwd_count;
+ uint32 pwd_history_len;
+ [size_is(pwd_history_len)] samr_ValidationBlob *pwd_history;
+ } samr_ValidatePasswordInfo;
+
+ typedef struct {
+ samr_ValidatePasswordInfo info;
+ samr_ValidationStatus status;
+ } samr_ValidatePasswordRepCtr;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_ValidatePasswordRepCtr ctr1;
+ [case(2)] samr_ValidatePasswordRepCtr ctr2;
+ [case(3)] samr_ValidatePasswordRepCtr ctr3;
+ } samr_ValidatePasswordRep;
+
+ typedef struct {
+ samr_ValidatePasswordInfo info;
+ lsa_StringLarge password;
+ lsa_StringLarge account;
+ samr_ValidationBlob hash;
+ boolean8 pwd_must_change_at_next_logon;
+ boolean8 clear_lockout;
+ } samr_ValidatePasswordReq3;
+
+ typedef struct {
+ samr_ValidatePasswordInfo info;
+ lsa_StringLarge password;
+ lsa_StringLarge account;
+ samr_ValidationBlob hash;
+ boolean8 password_matched;
+ } samr_ValidatePasswordReq2;
+
+ typedef struct {
+ samr_ValidatePasswordInfo info;
+ boolean8 password_matched;
+ } samr_ValidatePasswordReq1;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] samr_ValidatePasswordReq1 req1;
+ [case(2)] samr_ValidatePasswordReq2 req2;
+ [case(3)] samr_ValidatePasswordReq3 req3;
+ } samr_ValidatePasswordReq;
+
+ NTSTATUS samr_ValidatePassword(
+ [in] samr_ValidatePasswordLevel level,
+ [in,switch_is(level)] samr_ValidatePasswordReq *req,
+ [out,ref,switch_is(level)] samr_ValidatePasswordRep **rep
+ );
+
+ /************************/
+ /* Function 0x44 */
+ /************************/
+ [todo] void samr_Opnum68NotUsedOnWire(void);
+
+ /************************/
+ /* Function 0x45 */
+ /************************/
+ [todo] void samr_Opnum69NotUsedOnWire(void);
+
+ /************************/
+ /* Function 0x46 */
+ /************************/
+ [todo] void samr_Opnum70NotUsedOnWire(void);
+
+ /************************/
+ /* Function 0x47 */
+ /************************/
+ [todo] void samr_Opnum71NotUsedOnWire(void);
+
+ /************************/
+ /* Function 0x48 */
+ /************************/
+ [todo] void samr_Opnum72NotUsedOnWire(void);
+
+ /************************/
+ /* Function 0x49 */
+ /************************/
+ [public] NTSTATUS samr_ChangePasswordUser4(
+ [in,unique] lsa_String *server,
+ [in,ref] lsa_String *account,
+ [in,ref] samr_EncryptedPasswordAES *password
+ );
+}
diff --git a/librpc/idl/scerpc.idl b/librpc/idl/scerpc.idl
new file mode 100644
index 0000000..2c3c4f8
--- /dev/null
+++ b/librpc/idl/scerpc.idl
@@ -0,0 +1,18 @@
+/*
+ security configuration editor interface definitions
+*/
+
+[
+ uuid("93149ca2-973b-11d1-8c39-00c04fb984f9"),
+ version(0.0),
+ pointer_default(unique),
+ helpstring("Security Configuration Editor")
+]
+interface scerpc
+{
+
+ /*****************/
+ /* Function 0x00 */
+ WERROR scerpc_Unknown0();
+}
+
diff --git a/librpc/idl/schannel.idl b/librpc/idl/schannel.idl
new file mode 100644
index 0000000..3bc8a92
--- /dev/null
+++ b/librpc/idl/schannel.idl
@@ -0,0 +1,113 @@
+#include "idl_types.h"
+
+/*
+ schannel structures
+*/
+
+import "netlogon.idl", "nbt.idl", "misc.idl", "security.idl";
+
+[
+ pointer_default(unique),
+ helper("../librpc/ndr/ndr_schannel.h", "../librpc/ndr/ndr_nbt.h")
+]
+interface schannel
+{
+ /* this structure is used internally in the NETLOGON server */
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ netr_NegotiateFlags negotiate_flags;
+ uint8 session_key[16];
+ uint32 sequence;
+ netr_Credential seed;
+ netr_Credential client;
+ netr_Credential server;
+ netr_SchannelType secure_channel_type;
+ [string,charset(UTF8)] uint8 computer_name[];
+ [string,charset(UTF8)] uint8 account_name[];
+ dom_sid *sid;
+ } netlogon_creds_CredentialState;
+
+ /* This is used in the schannel_store.tdb */
+ typedef [public] struct {
+ [string,charset(UTF16)] uint16 *computer_name;
+ netr_Credential server_challenge;
+ netr_Credential client_challenge;
+ } netlogon_cache_entry;
+
+ /* MS-NRPC 2.2.1.3.1 NL_AUTH_MESSAGE */
+
+ typedef [v1_enum] enum {
+ NL_NEGOTIATE_REQUEST = 0x00000000,
+ NL_NEGOTIATE_RESPONSE = 0x00000001
+ } NL_AUTH_MESSAGE_TYPE;
+
+ typedef [bitmap32bit] bitmap {
+ NL_FLAG_OEM_NETBIOS_DOMAIN_NAME = 0x00000001,
+ NL_FLAG_OEM_NETBIOS_COMPUTER_NAME = 0x00000002,
+ NL_FLAG_UTF8_DNS_DOMAIN_NAME = 0x00000004,
+ NL_FLAG_UTF8_DNS_HOST_NAME = 0x00000008,
+ NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME = 0x00000010
+ } NL_AUTH_MESSAGE_FLAGS;
+
+ typedef [public,nodiscriminant,noprint] union {
+ [case (NL_FLAG_OEM_NETBIOS_DOMAIN_NAME)] astring a;
+ [case (NL_FLAG_OEM_NETBIOS_COMPUTER_NAME)] astring a;
+ [case (NL_FLAG_UTF8_DNS_DOMAIN_NAME)] nbt_string u;
+ [case (NL_FLAG_UTF8_DNS_HOST_NAME)] nbt_string u;
+ [case (NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME)] nbt_string u;
+ [default] ;
+ } NL_AUTH_MESSAGE_BUFFER;
+
+ typedef [public,nodiscriminant,noprint] union {
+ [case (NL_NEGOTIATE_RESPONSE)] uint32 dummy;
+ [default] ;
+ } NL_AUTH_MESSAGE_BUFFER_REPLY;
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ NL_AUTH_MESSAGE_TYPE MessageType;
+ NL_AUTH_MESSAGE_FLAGS Flags;
+ [switch_is(Flags & NL_FLAG_OEM_NETBIOS_DOMAIN_NAME)] NL_AUTH_MESSAGE_BUFFER oem_netbios_domain;
+ [switch_is(Flags & NL_FLAG_OEM_NETBIOS_COMPUTER_NAME)] NL_AUTH_MESSAGE_BUFFER oem_netbios_computer;
+ [switch_is(Flags & NL_FLAG_UTF8_DNS_DOMAIN_NAME)] NL_AUTH_MESSAGE_BUFFER utf8_dns_domain;
+ [switch_is(Flags & NL_FLAG_UTF8_DNS_HOST_NAME)] NL_AUTH_MESSAGE_BUFFER utf8_dns_host;
+ [switch_is(Flags & NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME)] NL_AUTH_MESSAGE_BUFFER utf8_netbios_computer;
+ [switch_is(MessageType & NL_NEGOTIATE_RESPONSE)] NL_AUTH_MESSAGE_BUFFER_REPLY Buffer;
+ } NL_AUTH_MESSAGE;
+
+ /* MS-NRPC 2.2.1.3.2 NL_AUTH_SIGNATURE */
+
+ typedef enum {
+ NL_SIGN_HMAC_SHA256 = 0x0013,
+ NL_SIGN_HMAC_MD5 = 0x0077
+ } NL_SIGNATURE_ALGORITHM;
+
+ typedef enum {
+ NL_SEAL_AES128 = 0x001A,
+ NL_SEAL_RC4 = 0x007A,
+ NL_SEAL_NONE = 0xFFFF
+ } NL_SEAL_ALGORITHM;
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ [value(NL_SIGN_HMAC_MD5)] NL_SIGNATURE_ALGORITHM SignatureAlgorithm;
+ NL_SEAL_ALGORITHM SealAlgorithm;
+ uint16 Pad;
+ uint16 Flags;
+ uint8 SequenceNumber[8];
+ uint8 Checksum[8];
+ uint8 Confounder[8];
+ } NL_AUTH_SIGNATURE;
+
+ const int NL_AUTH_SIGNATURE_SIZE = 0x20;
+
+ /* MS-NRPC 2.2.1.3.3 NL_AUTH_SHA2_SIGNATURE */
+
+ typedef [public,flag(NDR_PAHEX)] struct {
+ [value(NL_SIGN_HMAC_SHA256)] NL_SIGNATURE_ALGORITHM SignatureAlgorithm;
+ NL_SEAL_ALGORITHM SealAlgorithm;
+ uint16 Pad;
+ uint16 Flags;
+ uint8 SequenceNumber[8];
+ uint8 Checksum[32];
+ uint8 Confounder[8];
+ } NL_AUTH_SHA2_SIGNATURE;
+}
diff --git a/librpc/idl/security.cnf b/librpc/idl/security.cnf
new file mode 100644
index 0000000..37da8c7
--- /dev/null
+++ b/librpc/idl/security.cnf
@@ -0,0 +1 @@
+NOEMIT
diff --git a/librpc/idl/security.idl b/librpc/idl/security.idl
new file mode 100644
index 0000000..8783b67
--- /dev/null
+++ b/librpc/idl/security.idl
@@ -0,0 +1,972 @@
+#include "idl_types.h"
+
+/*
+ security IDL structures
+*/
+
+import "misc.idl";
+
+/*
+ use the same structure for dom_sid2 as dom_sid. A dom_sid2 is really
+ just a dom sid, but with the sub_auths represented as a conformant
+ array. As with all in-structure conformant arrays, the array length
+ is placed before the start of the structure. That's what gives rise
+ to the extra num_auths element. We don't want the Samba code to
+ have to bother with such esoteric NDR details, so its easier to just
+ define it as a dom_sid and use pidl magic to make it all work. It
+ just means you need to mark a sid as a "dom_sid2" in the IDL when you
+ know it is of the conformant array variety
+*/
+cpp_quote("#define dom_sid2 dom_sid")
+
+/* same struct as dom_sid but inside a 28 bytes fixed buffer in NDR */
+cpp_quote("#define dom_sid28 dom_sid")
+
+/* same struct as dom_sid but in a variable byte buffer, which is maybe empty in NDR */
+cpp_quote("#define dom_sid0 dom_sid")
+
+[
+ /*
+ * cbf7d408-2d6c-11e2-ae5b-0b5692790e18 just to make ndrdump happy
+ */
+ uuid("cbf7d408-2d6c-11e2-ae5b-0b5692790e18"),
+ version(0.0),
+ helper("../libcli/security/security.h"),
+ pyhelper("librpc/ndr/py_security.c"),
+ pointer_default(unique)
+]
+interface security
+{
+
+ typedef bitmap lsa_SystemAccessModeFlags lsa_SystemAccessModeFlags;
+
+ typedef [public,gensize,noprint,nosize,nopull,nopush] struct {
+ uint8 sid_rev_num; /**< SID revision number */
+ [range(0,15)] int8 num_auths; /**< Number of sub-authorities */
+ uint8 id_auth[6]; /**< Identifier Authority */
+ uint32 sub_auths[15];
+ } dom_sid;
+ /*
+ access masks are divided up like this:
+ 0xabccdddd
+ where
+ a = generic rights bits SEC_GENERIC_
+ b = flags SEC_FLAG_
+ c = standard rights bits SEC_STD_
+ d = object type specific bits SEC_{FILE,DIR,REG,xxx}_
+
+ common combinations of bits are prefixed with SEC_RIGHTS_
+ */
+ const int SEC_MASK_GENERIC = 0xF0000000;
+ const int SEC_MASK_FLAGS = 0x0F000000;
+ const int SEC_MASK_STANDARD = 0x00FF0000;
+ const int SEC_MASK_SPECIFIC = 0x0000FFFF;
+
+ /* generic bits */
+ const int SEC_GENERIC_ALL = 0x10000000;
+ const int SEC_GENERIC_EXECUTE = 0x20000000;
+ const int SEC_GENERIC_WRITE = 0x40000000;
+ const int SEC_GENERIC_READ = 0x80000000;
+
+ /* flag bits */
+ const int SEC_FLAG_SYSTEM_SECURITY = 0x01000000;
+ const int SEC_FLAG_MAXIMUM_ALLOWED = 0x02000000;
+
+ /* standard bits */
+ const int SEC_STD_DELETE = 0x00010000;
+ const int SEC_STD_READ_CONTROL = 0x00020000;
+ const int SEC_STD_WRITE_DAC = 0x00040000;
+ const int SEC_STD_WRITE_OWNER = 0x00080000;
+ const int SEC_STD_SYNCHRONIZE = 0x00100000;
+ const int SEC_STD_REQUIRED = 0x000F0000;
+ const int SEC_STD_ALL = 0x001F0000;
+
+ /* file specific bits */
+ const int SEC_FILE_READ_DATA = 0x00000001;
+ const int SEC_FILE_WRITE_DATA = 0x00000002;
+ const int SEC_FILE_APPEND_DATA = 0x00000004;
+ const int SEC_FILE_READ_EA = 0x00000008;
+ const int SEC_FILE_WRITE_EA = 0x00000010;
+ const int SEC_FILE_EXECUTE = 0x00000020;
+ const int SEC_FILE_READ_ATTRIBUTE = 0x00000080;
+ const int SEC_FILE_WRITE_ATTRIBUTE = 0x00000100;
+ const int SEC_FILE_ALL = 0x000001ff;
+
+ /* directory specific bits */
+ const int SEC_DIR_LIST = 0x00000001;
+ const int SEC_DIR_ADD_FILE = 0x00000002;
+ const int SEC_DIR_ADD_SUBDIR = 0x00000004;
+ const int SEC_DIR_READ_EA = 0x00000008;
+ const int SEC_DIR_WRITE_EA = 0x00000010;
+ const int SEC_DIR_TRAVERSE = 0x00000020;
+ const int SEC_DIR_DELETE_CHILD = 0x00000040;
+ const int SEC_DIR_READ_ATTRIBUTE = 0x00000080;
+ const int SEC_DIR_WRITE_ATTRIBUTE = 0x00000100;
+
+ /* registry entry specific bits */
+ const int SEC_REG_QUERY_VALUE = 0x00000001;
+ const int SEC_REG_SET_VALUE = 0x00000002;
+ const int SEC_REG_CREATE_SUBKEY = 0x00000004;
+ const int SEC_REG_ENUM_SUBKEYS = 0x00000008;
+ const int SEC_REG_NOTIFY = 0x00000010;
+ const int SEC_REG_CREATE_LINK = 0x00000020;
+
+ /* ldap specific access bits */
+ const int SEC_ADS_CREATE_CHILD = 0x00000001;
+ const int SEC_ADS_DELETE_CHILD = 0x00000002;
+ const int SEC_ADS_LIST = 0x00000004;
+ const int SEC_ADS_SELF_WRITE = 0x00000008;
+ const int SEC_ADS_READ_PROP = 0x00000010;
+ const int SEC_ADS_WRITE_PROP = 0x00000020;
+ const int SEC_ADS_DELETE_TREE = 0x00000040;
+ const int SEC_ADS_LIST_OBJECT = 0x00000080;
+ const int SEC_ADS_CONTROL_ACCESS = 0x00000100;
+
+ /* invalid bits */
+ const int SEC_MASK_INVALID = 0x0ce0fe00;
+
+ /* generic->specific mappings for files */
+ const int SEC_RIGHTS_FILE_READ = SEC_STD_READ_CONTROL |
+ SEC_STD_SYNCHRONIZE |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_READ_EA;
+
+ const int SEC_RIGHTS_FILE_WRITE = SEC_STD_READ_CONTROL |
+ SEC_STD_SYNCHRONIZE |
+ SEC_FILE_WRITE_DATA |
+ SEC_FILE_WRITE_ATTRIBUTE |
+ SEC_FILE_WRITE_EA |
+ SEC_FILE_APPEND_DATA;
+
+ const int SEC_RIGHTS_FILE_EXECUTE = SEC_STD_SYNCHRONIZE |
+ SEC_STD_READ_CONTROL |
+ SEC_FILE_READ_ATTRIBUTE |
+ SEC_FILE_EXECUTE;
+
+ const int SEC_RIGHTS_FILE_ALL = SEC_STD_ALL | SEC_FILE_ALL;
+
+ /* generic->specific mappings for directories (same as files) */
+ const int SEC_RIGHTS_DIR_READ = SEC_RIGHTS_FILE_READ;
+ const int SEC_RIGHTS_DIR_WRITE = SEC_RIGHTS_FILE_WRITE;
+ const int SEC_RIGHTS_DIR_EXECUTE = SEC_RIGHTS_FILE_EXECUTE;
+ const int SEC_RIGHTS_DIR_ALL = SEC_RIGHTS_FILE_ALL;
+
+ /* rights granted by some specific privileges */
+ const int SEC_RIGHTS_PRIV_BACKUP = SEC_STD_READ_CONTROL |
+ SEC_FLAG_SYSTEM_SECURITY |
+ SEC_RIGHTS_FILE_READ |
+ SEC_DIR_TRAVERSE;
+
+ const int SEC_RIGHTS_PRIV_RESTORE = SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER |
+ SEC_FLAG_SYSTEM_SECURITY |
+ SEC_RIGHTS_FILE_WRITE |
+ SEC_DIR_ADD_FILE |
+ SEC_DIR_ADD_SUBDIR |
+ SEC_STD_DELETE;
+
+ /* combinations of standard masks. */
+ const int STANDARD_RIGHTS_ALL_ACCESS = SEC_STD_ALL; /* 0x001f0000 */
+ const int STANDARD_RIGHTS_MODIFY_ACCESS = SEC_STD_READ_CONTROL; /* 0x00020000 */
+ const int STANDARD_RIGHTS_EXECUTE_ACCESS = SEC_STD_READ_CONTROL; /* 0x00020000 */
+ const int STANDARD_RIGHTS_READ_ACCESS = SEC_STD_READ_CONTROL; /* 0x00020000 */
+ const int STANDARD_RIGHTS_WRITE_ACCESS =
+ (SEC_STD_WRITE_OWNER |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_DELETE); /* 0x000d0000 */
+ const int STANDARD_RIGHTS_REQUIRED_ACCESS =
+ (SEC_STD_DELETE |
+ SEC_STD_READ_CONTROL |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER); /* 0x000f0000 */
+
+ /* generic->specific mappings for Directory Service objects */
+ /* directory specific part of GENERIC_ALL */
+ const int SEC_ADS_GENERIC_ALL_DS =
+ (SEC_STD_DELETE |
+ SEC_STD_WRITE_DAC |
+ SEC_STD_WRITE_OWNER |
+ SEC_ADS_CREATE_CHILD |
+ SEC_ADS_DELETE_CHILD |
+ SEC_ADS_DELETE_TREE |
+ SEC_ADS_CONTROL_ACCESS);
+ const int SEC_ADS_GENERIC_EXECUTE = SEC_STD_READ_CONTROL | SEC_ADS_LIST;
+ const int SEC_ADS_GENERIC_WRITE =
+ (SEC_STD_READ_CONTROL |
+ SEC_ADS_SELF_WRITE |
+ SEC_ADS_WRITE_PROP);
+ const int SEC_ADS_GENERIC_READ =
+ (SEC_STD_READ_CONTROL |
+ SEC_ADS_LIST |
+ SEC_ADS_READ_PROP |
+ SEC_ADS_LIST_OBJECT);
+ const int SEC_ADS_GENERIC_ALL =
+ (SEC_ADS_GENERIC_EXECUTE |
+ SEC_ADS_GENERIC_WRITE |
+ SEC_ADS_GENERIC_READ |
+ SEC_ADS_GENERIC_ALL_DS);
+
+ /*
+ * Rights implicitly granted to a user who is an owner of the security
+ * descriptor being processed.
+ */
+ typedef enum {
+ IMPLICIT_OWNER_READ_CONTROL_RIGHTS,
+ IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS
+ } implicit_owner_rights;
+
+ /***************************************************************/
+ /* WELL KNOWN SIDS */
+
+ /* a NULL sid */
+ const string SID_NULL = "S-1-0-0";
+
+ /* the world domain */
+ const string NAME_WORLD = "WORLD";
+
+ const string SID_WORLD_DOMAIN = "S-1-1";
+ const string SID_WORLD = "S-1-1-0";
+
+ /* SECURITY_CREATOR_SID_AUTHORITY */
+ const string SID_CREATOR_OWNER_DOMAIN = "S-1-3";
+ const string SID_CREATOR_OWNER = "S-1-3-0";
+ const string SID_CREATOR_GROUP = "S-1-3-1";
+ const string SID_OWNER_RIGHTS = "S-1-3-4";
+
+ /* SECURITY_NT_AUTHORITY */
+ const string NAME_NT_AUTHORITY = "NT AUTHORITY";
+
+ const string SID_NT_AUTHORITY = "S-1-5";
+ const string SID_NT_DIALUP = "S-1-5-1";
+ const string SID_NT_NETWORK = "S-1-5-2";
+ const string SID_NT_BATCH = "S-1-5-3";
+ const string SID_NT_INTERACTIVE = "S-1-5-4";
+ const string SID_NT_SERVICE = "S-1-5-6";
+ const string SID_NT_ANONYMOUS = "S-1-5-7";
+ const string SID_NT_PROXY = "S-1-5-8";
+ const string SID_NT_ENTERPRISE_DCS = "S-1-5-9";
+ const string SID_NT_SELF = "S-1-5-10";
+ const string SID_NT_AUTHENTICATED_USERS = "S-1-5-11";
+ const string SID_NT_RESTRICTED = "S-1-5-12";
+ const string SID_NT_TERMINAL_SERVER_USERS = "S-1-5-13";
+ const string SID_NT_REMOTE_INTERACTIVE = "S-1-5-14";
+ const string SID_NT_THIS_ORGANISATION = "S-1-5-15";
+ const string SID_NT_IUSR = "S-1-5-17";
+ const string SID_NT_SYSTEM = "S-1-5-18";
+ const string SID_NT_LOCAL_SERVICE = "S-1-5-19";
+ const string SID_NT_NETWORK_SERVICE = "S-1-5-20";
+ const string SID_NT_DIGEST_AUTHENTICATION = "S-1-5-64-21";
+ const string SID_NT_NTLM_AUTHENTICATION = "S-1-5-64-10";
+ const string SID_NT_SCHANNEL_AUTHENTICATION = "S-1-5-64-14";
+ const string SID_NT_OTHER_ORGANISATION = "S-1-5-1000";
+
+ /* SECURITY_BUILTIN_DOMAIN_RID */
+ const string NAME_BUILTIN = "BUILTIN";
+
+ const string SID_BUILTIN = "S-1-5-32";
+ const string SID_BUILTIN_ADMINISTRATORS = "S-1-5-32-544";
+ const string SID_BUILTIN_USERS = "S-1-5-32-545";
+ const string SID_BUILTIN_GUESTS = "S-1-5-32-546";
+ const string SID_BUILTIN_POWER_USERS = "S-1-5-32-547";
+ const string SID_BUILTIN_ACCOUNT_OPERATORS = "S-1-5-32-548";
+ const string SID_BUILTIN_SERVER_OPERATORS = "S-1-5-32-549";
+ const string SID_BUILTIN_PRINT_OPERATORS = "S-1-5-32-550";
+ const string SID_BUILTIN_BACKUP_OPERATORS = "S-1-5-32-551";
+ const string SID_BUILTIN_REPLICATOR = "S-1-5-32-552";
+ const string SID_BUILTIN_RAS_SERVERS = "S-1-5-32-553";
+ const string SID_BUILTIN_PREW2K = "S-1-5-32-554";
+ const string SID_BUILTIN_REMOTE_DESKTOP_USERS = "S-1-5-32-555";
+ const string SID_BUILTIN_NETWORK_CONF_OPERATORS = "S-1-5-32-556";
+ const string SID_BUILTIN_INCOMING_FOREST_TRUST = "S-1-5-32-557";
+ const string SID_BUILTIN_PERFMON_USERS = "S-1-5-32-558";
+ const string SID_BUILTIN_PERFLOG_USERS = "S-1-5-32-559";
+ const string SID_BUILTIN_AUTH_ACCESS = "S-1-5-32-560";
+ const string SID_BUILTIN_TS_LICENSE_SERVERS = "S-1-5-32-561";
+ const string SID_BUILTIN_DISTRIBUTED_COM_USERS = "S-1-5-32-562";
+ const string SID_BUILTIN_IUSERS = "S-1-5-32-568";
+ const string SID_BUILTIN_CRYPTO_OPERATORS = "S-1-5-32-569";
+ const string SID_BUILTIN_EVENT_LOG_READERS = "S-1-5-32-573";
+ const string SID_BUILTIN_CERT_SERV_DCOM_ACCESS = "S-1-5-32-574";
+ const string SID_BUILTIN_RDS_REMOTE_ACCESS_SERVERS = "S-1-5-32-575";
+ const string SID_BUILTIN_RDS_ENDPOINT_SERVERS = "S-1-5-32-576";
+ const string SID_BUILTIN_RDS_MANAGEMENT_SERVERS = "S-1-5-32-577";
+ const string SID_BUILTIN_HYPER_V_ADMINS = "S-1-5-32-578";
+ const string SID_BUILTIN_ACCESS_CONTROL_ASSISTANCE_OPS = "S-1-5-32-579";
+ const string SID_BUILTIN_REMOTE_MANAGEMENT_USERS = "S-1-5-32-580";
+ const string SID_BUILTIN_SYSTEM_MANAGED_ACCOUNTS_GRP = "S-1-5-32-581";
+ const string SID_BUILTIN_STORAGE_REPLICA_ADMINISTRATORS = "S-1-5-32-582";
+
+ const string SID_SECURITY_RESTRICTED_CODE = "S-1-5-33";
+
+ /* UID/GID mapping Samba style */
+ const string SID_SAMBA_UNIX_USER_OWNER = "S-1-22-1";
+ const string SID_SAMBA_UNIX_GROUP_OWNER = "S-1-22-2";
+
+ /* SECURITY_NT_SERVICE */
+ const string NAME_NT_SERVICE = "NT SERVICE";
+
+ const string SID_NT_NT_SERVICE = "S-1-5-80";
+ const string SID_NT_TRUSTED_INSTALLER =
+ "S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464";
+
+ /*
+ * This is added during the AS-REQ/AS-REP exchange after
+ * pre-authentication was successful.
+ */
+ const string SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY = "S-1-18-1";
+ /*
+ * This is added during S4U2Self PAC creation.
+ *
+ * It won't replace a possible
+ * SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY
+ * during S4U2Proxy.
+ */
+ const string SID_SERVICE_ASSERTED_IDENTITY = "S-1-18-2";
+
+ const string SID_COMPOUNDED_AUTHENTICATION = "S-1-5-21-0-0-0-496";
+ const string SID_CLAIMS_VALID = "S-1-5-21-0-0-0-497";
+
+ const string SID_USER_MODE_DRIVERS = "S-1-5-84-0-0-0-0-0";
+
+ const string SID_SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE = "S-1-15-2-1";
+
+ const string SID_SECURITY_MANDATORY_LOW = "S-1-16-4096";
+ const string SID_SECURITY_MANDATORY_MEDIUM = "S-1-16-8192";
+ const string SID_SECURITY_MANDATORY_MEDIUM_PLUS = "S-1-16-8448";
+ const string SID_SECURITY_MANDATORY_HIGH = "S-1-16-12288";
+ const string SID_SECURITY_MANDATORY_SYSTEM = "S-1-16-16384";
+
+ /*
+ * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
+ */
+ const string SID_NT_NFS_SUBSYSTEM = "S-1-5-88";
+ const string SID_NT_NFS_USER = "S-1-5-88-1";
+ const string SID_NT_NFS_GROUP = "S-1-5-88-2";
+ const string SID_NT_NFS_MASK = "S-1-5-88-3";
+ const string SID_NT_NFS_OTHERS = "S-1-5-88-4";
+
+ /* well-known domain RIDs */
+ const int DOMAIN_RID_LOGON = 9;
+ const int DOMAIN_RID_ENTERPRISE_READONLY_DCS = 498;
+ const int DOMAIN_RID_ADMINISTRATOR = 500;
+ const int DOMAIN_RID_GUEST = 501;
+ const int DOMAIN_RID_KRBTGT = 502;
+ const int DOMAIN_RID_ADMINS = 512;
+ const int DOMAIN_RID_USERS = 513;
+ const int DOMAIN_RID_GUESTS = 514;
+ const int DOMAIN_RID_DOMAIN_MEMBERS = 515;
+ const int DOMAIN_RID_DCS = 516;
+ const int DOMAIN_RID_CERT_ADMINS = 517;
+ const int DOMAIN_RID_SCHEMA_ADMINS = 518;
+ const int DOMAIN_RID_ENTERPRISE_ADMINS = 519;
+ const int DOMAIN_RID_POLICY_ADMINS = 520;
+ const int DOMAIN_RID_READONLY_DCS = 521;
+ const int DOMAIN_RID_CLONEABLE_CONTROLLERS = 522;
+ const int DOMAIN_RID_PROTECTED_USERS = 525;
+ const int DOMAIN_RID_KEY_ADMINS = 526;
+ const int DOMAIN_RID_ENTERPRISE_KEY_ADMINS = 527;
+ const int DOMAIN_RID_RAS_SERVERS = 553;
+ const int DOMAIN_RID_RODC_ALLOW = 571;
+ const int DOMAIN_RID_RODC_DENY = 572;
+
+ /* well-known builtin RIDs */
+ const int BUILTIN_RID_ADMINISTRATORS = 544;
+ const int BUILTIN_RID_USERS = 545;
+ const int BUILTIN_RID_GUESTS = 546;
+ const int BUILTIN_RID_POWER_USERS = 547;
+ const int BUILTIN_RID_ACCOUNT_OPERATORS = 548;
+ const int BUILTIN_RID_SERVER_OPERATORS = 549;
+ const int BUILTIN_RID_PRINT_OPERATORS = 550;
+ const int BUILTIN_RID_BACKUP_OPERATORS = 551;
+ const int BUILTIN_RID_REPLICATOR = 552;
+ const int BUILTIN_RID_RAS_SERVERS = 553;
+ const int BUILTIN_RID_PRE_2K_ACCESS = 554;
+ const int BUILTIN_RID_REMOTE_DESKTOP_USERS = 555;
+ const int BUILTIN_RID_NETWORK_CONF_OPERATORS = 556;
+ const int BUILTIN_RID_INCOMING_FOREST_TRUST = 557;
+ const int BUILTIN_RID_PERFMON_USERS = 558;
+ const int BUILTIN_RID_PERFLOG_USERS = 559;
+ const int BUILTIN_RID_AUTH_ACCESS = 560;
+ const int BUILTIN_RID_TS_LICENSE_SERVERS = 561;
+ const int BUILTIN_RID_DISTRIBUTED_COM_USERS = 562;
+ const int BUILTIN_RID_IUSERS = 568;
+ const int BUILTIN_RID_CRYPTO_OPERATORS = 569;
+ const int BUILTIN_RID_EVENT_LOG_READERS = 573;
+ const int BUILTIN_RID_CERT_SERV_DCOM_ACCESS = 574;
+ const int BUILTIN_RID_RDS_REMOTE_ACCESS_SERVERS = 575;
+ const int BUILTIN_RID_RDS_ENDPOINT_SERVERS = 576;
+ const int BUILTIN_RID_RDS_MANAGEMENT_SERVERS = 577;
+ const int BUILTIN_RID_HYPER_V_ADMINS = 578;
+ const int BUILTIN_RID_ACCESS_CONTROL_ASSISTANCE_OPS = 579;
+ const int BUILTIN_RID_REMOTE_MANAGEMENT_USERS = 580;
+
+/********************************************************************
+ This is a list of privileges reported by a WIndows 2008 R2 DC
+ just for reference purposes (and I know the LUID is not guaranteed
+ across reboots):
+
+0x00000002 SeCreateTokenPrivilege "Create a token object"
+0x00000003 SeAssignPrimaryTokenPrivilege "Replace a process level token"
+0x00000004 SeLockMemoryPrivilege "Lock pages in memory"
+0x00000005 SeIncreaseQuotaPrivilege "Adjust memory quotas for a process"
+0x00000006 SeMachineAccountPrivilege "Add workstations to domain"
+0x00000007 SeTcbPrivilege "Act as part of the operating system"
+0x00000008 SeSecurityPrivilege "Manage auditing and security log"
+0x00000009 SeTakeOwnershipPrivilege "Take ownership of files or other objects"
+0x0000000a SeLoadDriverPrivilege "Load and unload device drivers"
+0x0000000b SeSystemProfilePrivilege "Profile system performance"
+0x0000000c SeSystemtimePrivilege "Change the system time"
+0x0000000d SeProfileSingleProcessPrivilege "Profile single process"
+0x0000000e SeIncreaseBasePriorityPrivilege "Increase scheduling priority"
+0x0000000f SeCreatePagefilePrivilege "Create a pagefile"
+0x00000010 SeCreatePermanentPrivilege "Create permanent shared objects"
+0x00000011 SeBackupPrivilege "Back up files and directories"
+0x00000012 SeRestorePrivilege "Restore files and directories"
+0x00000013 SeShutdownPrivilege "Shut down the system"
+0x00000014 SeDebugPrivilege "Debug programs"
+0x00000015 SeAuditPrivilege "Generate security audits"
+0x00000016 SeSystemEnvironmentPrivilege "Modify firmware environment values"
+0x00000017 SeChangeNotifyPrivilege "Bypass traverse checking"
+0x00000018 SeRemoteShutdownPrivilege "Force shutdown from a remote system"
+0x00000019 SeUndockPrivilege "Remove computer from docking station"
+0x0000001a SeSyncAgentPrivilege "Synchronize directory service data"
+0x0000001b SeEnableDelegationPrivilege "Enable computer and user accounts to be trusted for delegation"
+0x0000001c SeManageVolumePrivilege "Perform volume maintenance tasks"
+0x0000001d SeImpersonatePrivilege "Impersonate a client after authentication"
+0x0000001e SeCreateGlobalPrivilege "Create global objects"
+0x0000001f SeTrustedCredManAccessPrivilege "Access Credential Manager as a trusted caller"
+0x00000020 SeRelabelPrivilege "Modify an object label"
+0x00000021 SeIncreaseWorkingSetPrivilege "Increase a process working set"
+0x00000022 SeTimeZonePrivilege "Change the time zone"
+0x00000023 SeCreateSymbolicLinkPrivilege "Create symbolic links"
+
+ ********************************************************************/
+
+ /* LUID values for privileges known about by Samba (bottom 32 bits of enum, top bits are 0) */
+
+ /* we have to define the LUID here due to a horrible check by printmig.exe
+ that requires the SeBackupPrivilege match what is in Windows. So match
+ those that we implement and start Samba privileges at 0x1001 */
+
+ typedef enum {
+ SEC_PRIV_INVALID = 0x0,
+ SEC_PRIV_INCREASE_QUOTA = 0x5,
+ SEC_PRIV_MACHINE_ACCOUNT = 0x6,
+ SEC_PRIV_SECURITY = 0x8,
+ SEC_PRIV_TAKE_OWNERSHIP = 0x09,
+ SEC_PRIV_LOAD_DRIVER = 0x0a,
+ SEC_PRIV_SYSTEM_PROFILE = 0x0b,
+ SEC_PRIV_SYSTEMTIME = 0x0c,
+ SEC_PRIV_PROFILE_SINGLE_PROCESS = 0x0d,
+ SEC_PRIV_INCREASE_BASE_PRIORITY = 0x0e,
+ SEC_PRIV_CREATE_PAGEFILE = 0x0f,
+ SEC_PRIV_BACKUP = 0x11,
+ SEC_PRIV_RESTORE = 0x12,
+ SEC_PRIV_SHUTDOWN = 0x13,
+ SEC_PRIV_DEBUG = 0x14,
+ SEC_PRIV_SYSTEM_ENVIRONMENT = 0x16,
+ SEC_PRIV_CHANGE_NOTIFY = 0x17,
+ SEC_PRIV_REMOTE_SHUTDOWN = 0x18,
+ SEC_PRIV_UNDOCK = 0x19,
+ SEC_PRIV_ENABLE_DELEGATION = 0x1b,
+ SEC_PRIV_MANAGE_VOLUME = 0x1c,
+ SEC_PRIV_IMPERSONATE = 0x1d,
+ SEC_PRIV_CREATE_GLOBAL = 0x1e,
+ /* Samba-specific privs */
+ SEC_PRIV_PRINT_OPERATOR = 0x1001,
+ SEC_PRIV_ADD_USERS = 0x1002,
+ SEC_PRIV_DISK_OPERATOR = 0x1003
+ } sec_privilege;
+
+
+ /* Bitmap of privilege values for internal use only. We need
+ * our own bitmap here as privileges.tdb records these values
+ * as a bitmap (privileges.ldb uses the string forms).
+ */
+ typedef [bitmap64bit] bitmap {
+ SEC_PRIV_MACHINE_ACCOUNT_BIT = 0x00000010,
+
+ /* Samba-specific privs */
+ SEC_PRIV_PRINT_OPERATOR_BIT = 0x00000020,
+ SEC_PRIV_ADD_USERS_BIT = 0x00000040,
+ SEC_PRIV_DISK_OPERATOR_BIT = 0x00000080,
+
+ SEC_PRIV_REMOTE_SHUTDOWN_BIT = 0x00000100,
+ SEC_PRIV_BACKUP_BIT = 0x00000200,
+ SEC_PRIV_RESTORE_BIT = 0x00000400,
+ SEC_PRIV_TAKE_OWNERSHIP_BIT = 0x00000800,
+ /* End of privileges implemented before merge to common code */
+
+ SEC_PRIV_INCREASE_QUOTA_BIT = 0x00001000,
+ SEC_PRIV_SECURITY_BIT = 0x00002000,
+ SEC_PRIV_LOAD_DRIVER_BIT = 0x00004000,
+ SEC_PRIV_SYSTEM_PROFILE_BIT = 0x00008000,
+ SEC_PRIV_SYSTEMTIME_BIT = 0x00010000,
+ SEC_PRIV_PROFILE_SINGLE_PROCESS_BIT = 0x00020000,
+ SEC_PRIV_INCREASE_BASE_PRIORITY_BIT = 0x00040000,
+ SEC_PRIV_CREATE_PAGEFILE_BIT = 0x00080000,
+ SEC_PRIV_SHUTDOWN_BIT = 0x00100000,
+ SEC_PRIV_DEBUG_BIT = 0x00200000,
+ SEC_PRIV_SYSTEM_ENVIRONMENT_BIT = 0x00400000,
+ SEC_PRIV_CHANGE_NOTIFY_BIT = 0x00800000,
+ SEC_PRIV_UNDOCK_BIT = 0x01000000,
+ SEC_PRIV_ENABLE_DELEGATION_BIT = 0x02000000,
+ SEC_PRIV_MANAGE_VOLUME_BIT = 0x04000000,
+ SEC_PRIV_IMPERSONATE_BIT = 0x08000000,
+ SEC_PRIV_CREATE_GLOBAL_BIT = 0x10000000
+ } se_privilege;
+
+ typedef [bitmap32bit] bitmap {
+ LSA_POLICY_MODE_INTERACTIVE = 0x00000001,
+ LSA_POLICY_MODE_NETWORK = 0x00000002,
+ LSA_POLICY_MODE_BATCH = 0x00000004,
+ LSA_POLICY_MODE_SERVICE = 0x00000010,
+ LSA_POLICY_MODE_PROXY = 0x00000020,
+ LSA_POLICY_MODE_DENY_INTERACTIVE = 0x00000040,
+ LSA_POLICY_MODE_DENY_NETWORK = 0x00000080,
+ LSA_POLICY_MODE_DENY_BATCH = 0x00000100,
+ LSA_POLICY_MODE_DENY_SERVICE = 0x00000200,
+ LSA_POLICY_MODE_REMOTE_INTERACTIVE = 0x00000400,
+ LSA_POLICY_MODE_DENY_REMOTE_INTERACTIVE = 0x00000800,
+ LSA_POLICY_MODE_ALL = 0x00000FF7,
+ LSA_POLICY_MODE_ALL_NT4 = 0x00000037
+ } lsa_SystemAccessModeFlags;
+
+ typedef [public,bitmap8bit] bitmap {
+ SEC_ACE_FLAG_OBJECT_INHERIT = 0x01,
+ SEC_ACE_FLAG_CONTAINER_INHERIT = 0x02,
+ SEC_ACE_FLAG_NO_PROPAGATE_INHERIT = 0x04,
+ SEC_ACE_FLAG_INHERIT_ONLY = 0x08,
+ SEC_ACE_FLAG_INHERITED_ACE = 0x10,
+ SEC_ACE_FLAG_VALID_INHERIT = 0x0f,
+ SEC_ACE_FLAG_SUCCESSFUL_ACCESS = 0x40,
+ SEC_ACE_FLAG_FAILED_ACCESS = 0x80
+ } security_ace_flags;
+
+ typedef [public,enum8bit] enum {
+ /*
+ * The following entries tagged *reserved* have been
+ * named and allocated by Microsoft but apparently not
+ * implemented (MS-DTYP 2.4.4.1).
+ *
+ * The entries marked *unused* are more or less
+ * completely ignored by Samba.
+ */
+ SEC_ACE_TYPE_ACCESS_ALLOWED = 0,
+ SEC_ACE_TYPE_ACCESS_DENIED = 1,
+ SEC_ACE_TYPE_SYSTEM_AUDIT = 2,
+ SEC_ACE_TYPE_SYSTEM_ALARM = 3, /* reserved */
+ SEC_ACE_TYPE_ALLOWED_COMPOUND = 4, /* reserved */
+ SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT = 5,
+ SEC_ACE_TYPE_ACCESS_DENIED_OBJECT = 6,
+ SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT = 7,
+ SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT = 8, /* reserved */
+ SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK = 9,
+ SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK = 10,
+ SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT = 11,
+ SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT = 12,
+ SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK = 13,
+ SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK = 14, /* reserved */
+ SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT = 15,
+ SEC_ACE_TYPE_SYSTEM_ALARM_CALLBACK_OBJECT = 16, /* reserved */
+ SEC_ACE_TYPE_SYSTEM_MANDATORY_LABEL = 17, /*unused */
+ SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE = 18,
+ SEC_ACE_TYPE_SYSTEM_SCOPED_POLICY_ID = 19 /* unused */
+ } security_ace_type;
+
+ typedef [bitmap32bit] bitmap {
+ SEC_ACE_OBJECT_TYPE_PRESENT = 0x00000001,
+ SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT = 0x00000002
+ } security_ace_object_flags;
+
+ typedef [nodiscriminant] union {
+ /* this is the 'schemaIDGUID' attribute of the attribute object in the schema naming context */
+ [case(SEC_ACE_OBJECT_TYPE_PRESENT)] GUID type;
+ [default];
+ } security_ace_object_type;
+
+ typedef [nodiscriminant] union {
+ /* this is the 'schemaIDGUID' attribute of the objectclass object in the schema naming context
+ * (of the parent container)
+ */
+ [case(SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)] GUID inherited_type;
+ [default];
+ } security_ace_object_inherited_type;
+
+ typedef struct {
+ security_ace_object_flags flags;
+ [switch_is(flags & SEC_ACE_OBJECT_TYPE_PRESENT)] security_ace_object_type type;
+ [switch_is(flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)] security_ace_object_inherited_type inherited_type;
+ } security_ace_object;
+
+
+
+ /*
+ * flags that might occur in
+ * CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1.flags.
+ *
+ * Not all of them do anything. Conditional ACEs also use some
+ * of these flags.
+ */
+ typedef [bitmap32bit] bitmap {
+ CLAIM_SECURITY_ATTRIBUTE_NON_INHERITABLE = 1,
+ CLAIM_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE = 2,
+ CLAIM_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY = 4, /*reserved*/
+ CLAIM_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT = 8,
+ CLAIM_SECURITY_ATTRIBUTE_DISABLED = 0x10, /*reserved*/
+ CLAIM_SECURITY_ATTRIBUTE_MANDATORY = 0x20,
+
+ /*
+ * These next two are curiously defined in [MS-DTYP] 2.4.10.1:
+ *
+ * > Flags: The upper two bytes of this DWORD are available for
+ * > application-specific data. The two lowest-order bits in the
+ * > lower of these two bytes are reserved. These two bytes
+ * > MAY contain only one of the following values in those two
+ * > bits:
+ * >
+ * > FCI_CLAIM_SECURITY_ATTRIBUTE_MANUAL 0x0001
+ * > FCI_CLAIM_SECURITY_ATTRIBUTE_POLICY_DERIVED 0x0002
+ *
+ * That is saying these mutually exclusive flags have offset
+ * values that are measured from the middle of flags field. We
+ * instead measure from the start.
+ */
+ CLAIM_SECURITY_ATTRIBUTE_MANUAL = 1 << 16,
+ CLAIM_SECURITY_ATTRIBUTE_POLICY_DERIVED = 1 << 17,
+
+ /*
+ * As the quote from [MS-DTYP] 2.4.10.1 above says,
+ * the upper 14 bits are for application-specific
+ * data. In Samba's case, we have one application
+ * specific flag to help us remember when we have
+ * sorted a claim and checked that it contains no
+ * duplicate values. We need to check this, and the
+ * check can be expensive, so it helps to remember.
+ * Having the values sorted is useful for comparisons
+ * in conditional ACEs.
+ *
+ * We can't just sort every claim_v1 we see, because
+ * resource attribute ACEs in SACLs contain them and
+ * are not meant to be evaluated prematurely (i.e. you
+ * can parse and reserialise a SACL even if it
+ * contains an ACE that would cause an error when used
+ * as a claim).
+ *
+ * In the case of string claims, evaluating uniqueness
+ * depends on the _CASE_SENSITIVE flag.
+ */
+ CLAIM_SECURITY_ATTRIBUTE_UNIQUE_AND_SORTED = 1 << 30,
+ /*
+ * Conditional ACEs use some of the above flags in
+ * combination with an internal one defined in
+ * conditional_ace.idl.
+ * This next definition is warning us in case a clash
+ * develops (which seems very unlikely).
+ */
+ CLAIM_SECURITY_ATTRIBUTE_RESERVED_FOR_SAMBA = 1UL << 31
+ } claim_flags;
+
+ /*
+ * These claim types for v1 claims mirror those of on-the-wire
+ * PAC claims, but not conditional ace literal token types.
+ */
+ typedef [public] enum {
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64 = 0x0001,
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64 = 0x0002,
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING = 0x0003,
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_SID = 0x0005,
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN = 0x0006,
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING = 0x0010
+ } security_claim_value_type;
+
+ typedef [nodiscriminant,flag(NDR_NOALIGN)] union {
+ [case(CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64),relative] int64 *int_value;
+ [case(CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64),relative] hyper *uint_value;
+ [case(CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING),relative] nstring *string_value;
+ [case(CLAIM_SECURITY_ATTRIBUTE_TYPE_SID),relative] DATA_BLOB *sid_value;
+ [case(CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING),relative] DATA_BLOB *octet_value;
+ [case(CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN),relative] hyper *uint_value;
+ } claim_values;
+
+ typedef [public,gensize] struct {
+ [relative] nstring *name;
+ uint16 value_type;
+ uint32 flags;
+ uint32 value_count;
+ [switch_is(value_type)] claim_values values[value_count];
+ } CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1;
+
+ typedef [public,nodiscriminant] union {
+ [default] security_ace_object object;
+ [case(false)];
+ } security_ace_object_ctr;
+
+ typedef [public,nodiscriminant,gensize] union {
+ [case(SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK)] [flag(NDR_REMAINING)] DATA_BLOB conditions;
+ [case(SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK)] [flag(NDR_REMAINING)] DATA_BLOB conditions;
+ [case(SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT)] [flag(NDR_REMAINING)] DATA_BLOB conditions;
+ [case(SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT)] [flag(NDR_REMAINING)] DATA_BLOB conditions;
+ [case(SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK)] [flag(NDR_REMAINING)] DATA_BLOB conditions;
+ [case(SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK_OBJECT)] [flag(NDR_REMAINING)] DATA_BLOB conditions;
+
+ [case(SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE)] CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 claim;
+ [default][flag(NDR_REMAINING)] DATA_BLOB ignored;
+ } security_ace_coda;
+
+ typedef [public,gensize,nosize,nopush,nopull] struct {
+ security_ace_type type; /* SEC_ACE_TYPE_* */
+ security_ace_flags flags; /* SEC_ACE_FLAG_* */
+ [value(ndr_size_security_ace(r,ndr->flags))] uint16 size;
+ uint32 access_mask;
+ [switch_is(sec_ace_object(type))] security_ace_object_ctr object;
+ dom_sid trustee;
+ [switch_is(type), subcontext(0), subcontext_size(ndr_subcontext_size_of_ace_coda(r, size, ndr->flags))] security_ace_coda coda;
+ } security_ace;
+
+ typedef enum {
+ SECURITY_ACL_REVISION_NT4 = 2,
+ SECURITY_ACL_REVISION_ADS = 4
+ } security_acl_revision;
+
+ const uint NT4_ACL_REVISION = SECURITY_ACL_REVISION_NT4;
+
+ typedef [public,gensize,nosize] struct {
+ security_acl_revision revision;
+ [value(ndr_size_security_acl(r,ndr->flags))] uint16 size;
+ [range(0,2000)] uint32 num_aces;
+ security_ace aces[num_aces];
+ } security_acl;
+
+ /* default revision for new ACLs */
+ typedef [public,enum8bit] enum {
+ SECURITY_DESCRIPTOR_REVISION_1 = 1
+ } security_descriptor_revision;
+
+ const int SD_REVISION = SECURITY_DESCRIPTOR_REVISION_1;
+
+ /* security_descriptor->type bits */
+ typedef [public,bitmap16bit] bitmap {
+ SEC_DESC_OWNER_DEFAULTED = 0x0001,
+ SEC_DESC_GROUP_DEFAULTED = 0x0002,
+ SEC_DESC_DACL_PRESENT = 0x0004,
+ SEC_DESC_DACL_DEFAULTED = 0x0008,
+ SEC_DESC_SACL_PRESENT = 0x0010,
+ SEC_DESC_SACL_DEFAULTED = 0x0020,
+ SEC_DESC_DACL_TRUSTED = 0x0040,
+ SEC_DESC_SERVER_SECURITY = 0x0080,
+ SEC_DESC_DACL_AUTO_INHERIT_REQ = 0x0100,
+ SEC_DESC_SACL_AUTO_INHERIT_REQ = 0x0200,
+ SEC_DESC_DACL_AUTO_INHERITED = 0x0400,
+ SEC_DESC_SACL_AUTO_INHERITED = 0x0800,
+ SEC_DESC_DACL_PROTECTED = 0x1000,
+ SEC_DESC_SACL_PROTECTED = 0x2000,
+ SEC_DESC_RM_CONTROL_VALID = 0x4000,
+ SEC_DESC_SELF_RELATIVE = 0x8000
+ } security_descriptor_type;
+
+ typedef [gensize,nosize,public,flag(NDR_LITTLE_ENDIAN)] struct {
+ security_descriptor_revision revision;
+ security_descriptor_type type; /* SEC_DESC_xxxx flags */
+ [relative] dom_sid *owner_sid;
+ [relative] dom_sid *group_sid;
+ [relative] security_acl *sacl; /* system ACL */
+ [relative] security_acl *dacl; /* user (discretionary) ACL */
+ } security_descriptor;
+
+ typedef [public] struct {
+ [range(0,0x40000),value(ndr_size_security_descriptor(sd,ndr->flags))] uint32 sd_size;
+ [subcontext(4)] security_descriptor *sd;
+ } sec_desc_buf;
+
+ /* Group attributes, used to be samr_GroupAttrs */
+ typedef [public,bitmap32bit] bitmap {
+ SE_GROUP_MANDATORY = 0x00000001,
+ SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002,
+ SE_GROUP_ENABLED = 0x00000004,
+ SE_GROUP_OWNER = 0x00000008,
+ SE_GROUP_USE_FOR_DENY_ONLY = 0x00000010,
+ SE_GROUP_INTEGRITY = 0x00000020,
+ SE_GROUP_INTEGRITY_ENABLED = 0x00000040,
+ SE_GROUP_RESOURCE = 0x20000000,
+ SE_GROUP_LOGON_ID = 0xC0000000
+ } security_GroupAttrs;
+
+ const uint32 SE_GROUP_DEFAULT_FLAGS =
+ SE_GROUP_MANDATORY |
+ SE_GROUP_ENABLED_BY_DEFAULT |
+ SE_GROUP_ENABLED;
+
+ /*
+ * Should claims be evaluated on this token?
+ *
+ * 0 is invalid to catch a zeroed token
+ */
+ typedef enum {
+ CLAIMS_EVALUATION_INVALID_STATE=0,
+ CLAIMS_EVALUATION_NEVER = 1,
+ CLAIMS_EVALUATION_ALWAYS = 2
+ } claims_evaluation_control;
+
+ /*
+ * This is linearised to pass authentication over the NP proxy
+ * from smbd to RPC servers, but is not in public network protocols
+ */
+ typedef [public] struct {
+ uint32 num_sids;
+ [size_is(num_sids)] dom_sid sids[*];
+ se_privilege privilege_mask;
+ lsa_SystemAccessModeFlags rights_mask;
+ uint32 num_local_claims;
+ uint32 num_user_claims;
+ uint32 num_device_claims;
+ uint32 num_device_sids;
+ [size_is(num_local_claims)] CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 local_claims[*];
+ [size_is(num_user_claims)] CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 user_claims[*];
+ [size_is(num_device_claims)] CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 device_claims[*];
+ [size_is(num_device_sids)] dom_sid device_sids[*];
+
+ /*
+ * This allows us to disable claims evaluation on a
+ * per-token basis, allowing library code to remain
+ * distinct from configuration by passing this in as a
+ * flag here
+ */
+ claims_evaluation_control evaluate_claims;
+ } security_token;
+
+ typedef [public] struct {
+ security_token token;
+ security_descriptor sd;
+ uint32 access_desired;
+ } security_token_descriptor_fuzzing_pair;
+
+ /* This is not yet sent over the network, but is simply defined in IDL */
+ typedef [public] struct {
+ uid_t uid;
+ gid_t gid;
+ uint32 ngroups;
+ [size_is(ngroups)] gid_t groups[*];
+ } security_unix_token;
+
+ /* bits that determine which parts of a security descriptor
+ are being queried/set */
+ typedef [public,bitmap32bit] bitmap {
+ SECINFO_OWNER = 0x00000001,
+ SECINFO_GROUP = 0x00000002,
+ SECINFO_DACL = 0x00000004,
+ SECINFO_SACL = 0x00000008,
+ SECINFO_LABEL = 0x00000010,
+ SECINFO_ATTRIBUTE = 0x00000020,
+ SECINFO_SCOPE = 0x00000040,
+ SECINFO_BACKUP = 0x00010000,
+ SECINFO_UNPROTECTED_SACL = 0x10000000,
+ SECINFO_UNPROTECTED_DACL = 0x20000000,
+ SECINFO_PROTECTED_SACL = 0x40000000,
+ SECINFO_PROTECTED_DACL = 0x80000000
+ } security_secinfo;
+
+ /*
+ * a SMB server should only support the following flags
+ * and ignore all others.
+ *
+ * See AdditionalInformation in [MS-SMB2] 2.2.37 SMB2 QUERY_INFO Request
+ * and 2.2.39 SMB2 SET_INFO Request.
+ */
+ const int SMB_SUPPORTED_SECINFO_FLAGS = (
+ SECINFO_OWNER |
+ SECINFO_GROUP |
+ SECINFO_DACL |
+ SECINFO_SACL |
+ SECINFO_LABEL |
+ SECINFO_ATTRIBUTE |
+ SECINFO_SCOPE |
+ SECINFO_BACKUP |
+ 0);
+
+ /*
+ * See [MS-KILE] 2.2.5 LSAP_TOKEN_INFO_INTEGRITY
+ */
+ typedef [public,gensize,flag(NDR_PAHEX)] struct {
+ uint32 Flags;
+ uint32 TokenIL;
+ uint8 MachineId[32];
+ } LSAP_TOKEN_INFO_INTEGRITY;
+
+ /*
+ * See [MS-KILE] 2.2.6 Supported Encryption Types Bit Flags
+ */
+ typedef [public,bitmap32bit] bitmap {
+ KERB_ENCTYPE_DES_CBC_CRC = 0x00000001,
+ KERB_ENCTYPE_DES_CBC_MD5 = 0x00000002,
+ KERB_ENCTYPE_RC4_HMAC_MD5 = 0x00000004,
+ KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 = 0x00000008,
+ KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 = 0x00000010,
+ KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96_SK = 0x00000020,
+ KERB_ENCTYPE_FAST_SUPPORTED = 0x00010000,
+ KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED = 0x00020000,
+ KERB_ENCTYPE_CLAIMS_SUPPORTED = 0x00040000,
+ KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED = 0x00080000
+ } kerb_EncTypes;
+
+ typedef [public,bitmap32bit] bitmap {
+ SEC_DACL_AUTO_INHERIT = 0x00000001,
+ SEC_SACL_AUTO_INHERIT = 0x00000002,
+ SEC_DEFAULT_DESCRIPTOR = 0x00000004,
+ SEC_OWNER_FROM_PARENT = 0x00000008,
+ SEC_GROUP_FROM_PARENT = 0x00000010
+ } security_autoinherit;
+
+ /***************************************************************/
+ /* Extended right guids */
+
+ const string GUID_DRS_ALLOCATE_RIDS = "1abd7cf8-0a99-11d1-adbb-00c04fd8d5cd";
+ const string GUID_DRS_CHANGE_DOMAIN_MASTER = "014bf69c-7b3b-11d1-85f6-08002be74fab";
+ const string GUID_DRS_CHANGE_INFR_MASTER = "cc17b1fb-33d9-11d2-97d4-00c04fd8d5cd";
+ const string GUID_DRS_CHANGE_PDC = "bae50096-4752-11d1-9052-00c04fc2d4cf";
+ const string GUID_DRS_CHANGE_RID_MASTER = "d58d5f36-0a98-11d1-adbb-00c04fd8d5cd";
+ const string GUID_DRS_CHANGE_SCHEMA_MASTER = "e12b56b6-0a95-11d1-adbb-00c04fd8d5cd";
+ const string GUID_DRS_GET_CHANGES = "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2";
+ const string GUID_DRS_REPL_SYNCRONIZE = "1131f6ab-9c07-11d1-f79f-00c04fc2dcd2";
+ const string GUID_DRS_MANAGE_TOPOLOGY = "1131f6ac-9c07-11d1-f79f-00c04fc2dcd2";
+ const string GUID_DRS_GET_ALL_CHANGES = "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2";
+ const string GUID_DRS_RO_REPL_SECRET_SYNC = "1131f6ae-9c07-11d1-f79f-00c04fc2dcd2";
+ const string GUID_DRS_GET_FILTERED_ATTRIBUTES = "89e95b76-444d-4c62-991a-0facbeda640c";
+ const string GUID_DRS_MONITOR_TOPOLOGY = "f98340fb-7c5b-4cdb-a00b-2ebdfa115a96";
+ const string GUID_DRS_USER_CHANGE_PASSWORD = "ab721a53-1e2f-11d0-9819-00aa0040529b";
+ const string GUID_DRS_FORCE_CHANGE_PASSWORD = "00299570-246d-11d0-a768-00aa006e0529";
+ const string GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT
+ = "280f369c-67c7-438e-ae98-1d46f3c6f541";
+ const string GUID_DRS_UNEXPIRE_PASSWORD = "ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501";
+ const string GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD
+ = "05c74c5e-4deb-43b4-bd9f-86664c2a7fd5";
+ const string GUID_DRS_DS_INSTALL_REPLICA = "9923a32a-3607-11d2-b9be-0000f87a36b2";
+ const string GUID_DRS_REANIMATE_TOMBSTONE = "45ec5156-db7e-47bb-b53f-dbeb2d03c40f";
+ const string GUID_DRS_ALLOWED_TO_AUTHENTICATE = "68b1d179-0d15-4D4F-ab71-46152e79a7bc";
+
+ /***************************************************************/
+ /* validated writes guids */
+ const string GUID_DRS_VALIDATE_SPN = "f3a64788-5306-11d1-a9c5-0000f80367c1";
+ const string GUID_DRS_SELF_MEMBERSHIP = "bf9679c0-0de6-11d0-a285-00aa003049e2";
+ const string GUID_DRS_DNS_HOST_NAME = "72e39547-7b18-11d1-adef-00c04fd8d5cd";
+ const string GUID_DRS_ADD_DNS_HOST_NAME = "80863791-dbe9-4eb8-837e-7f0ab55d9ac7";
+ const string GUID_DRS_BEHAVIOR_VERSION = "d31a8757-2447-4545-8081-3bb610cacbf2";
+
+ /* A type to describe the mapping of generic access rights to object
+ specific access rights. */
+
+ typedef struct {
+ uint32 generic_read;
+ uint32 generic_write;
+ uint32 generic_execute;
+ uint32 generic_all;
+ } generic_mapping;
+
+ typedef struct {
+ uint32 std_read;
+ uint32 std_write;
+ uint32 std_execute;
+ uint32 std_all;
+ } standard_mapping;
+}
diff --git a/librpc/idl/server_id.idl b/librpc/idl/server_id.idl
new file mode 100644
index 0000000..8ebffc5
--- /dev/null
+++ b/librpc/idl/server_id.idl
@@ -0,0 +1,36 @@
+[
+ pointer_default(unique)
+]
+interface server_id
+{
+
+ /*
+ * Virtual Node Numbers are identifying a node within a cluster.
+ * Ctdbd sets this, we retrieve our vnn from it.
+ */
+
+ const uint32 NONCLUSTER_VNN = 0xFFFFFFFF;
+
+ /** Don't verify this unique id */
+ const hyper SERVERID_UNIQUE_ID_NOT_TO_VERIFY = 0xFFFFFFFFFFFFFFFFULL;
+
+ /* used to look like the following, note that unique_id was not
+ * marshalled at all...
+
+ struct server_id {
+ pid_t pid;
+ #ifdef CLUSTER_SUPPORT
+ uint32 vnn;
+ #endif
+ uint64_t unique_id;
+ };
+
+ */
+
+ typedef [public] struct {
+ hyper pid;
+ uint32 task_id;
+ uint32 vnn;
+ hyper unique_id;
+ } server_id;
+}
diff --git a/librpc/idl/smb2_lease_struct.idl b/librpc/idl/smb2_lease_struct.idl
new file mode 100644
index 0000000..5ccd8a3
--- /dev/null
+++ b/librpc/idl/smb2_lease_struct.idl
@@ -0,0 +1,34 @@
+#include "idl_types.h"
+
+/*
+ miscellaneous IDL structures
+*/
+
+[
+ pointer_default(unique)
+]
+interface smb2_lease_struct
+{
+ /*
+ * SMB2 lease structure (per MS-SMB2 2.2.13)
+ */
+ typedef [public] struct {
+ hyper data[2];
+ } smb2_lease_key;
+
+ typedef [public,bitmap32bit] bitmap {
+ SMB2_LEASE_READ = 0x01,
+ SMB2_LEASE_HANDLE = 0x02,
+ SMB2_LEASE_WRITE = 0x04
+ } smb2_lease_state;
+
+ typedef [public] struct {
+ smb2_lease_key lease_key;
+ smb2_lease_state lease_state;
+ uint32 lease_flags;
+ hyper lease_duration; /* should be 0 */
+ smb2_lease_key parent_lease_key;
+ uint16 lease_version;
+ uint16 lease_epoch;
+ } smb2_lease;
+}; \ No newline at end of file
diff --git a/librpc/idl/smb3posix.idl b/librpc/idl/smb3posix.idl
new file mode 100644
index 0000000..e759229
--- /dev/null
+++ b/librpc/idl/smb3posix.idl
@@ -0,0 +1,36 @@
+#include "idl_types.h"
+
+/*
+ IDL for smb311 unix structures
+*/
+
+import "security.idl";
+
+[
+ version(0.0),
+ pointer_default(unique)
+]
+interface smb3posix
+{
+ typedef [public,flag(NDR_NOALIGN)] struct {
+ uint32 nlinks;
+ uint32 reparse_tag;
+ uint32 posix_perms;
+ dom_sid owner;
+ dom_sid group;
+ } smb3_posix_cc_info;
+
+ typedef [public,flag(NDR_NOALIGN)] struct {
+ NTTIME creation_time;
+ NTTIME last_access_time;
+ NTTIME last_write_time;
+ NTTIME change_time;
+ hyper end_of_file;
+ hyper allocation_size;
+ uint32 file_attributes;
+ hyper inode;
+ uint32 device;
+ uint32 reserved;
+ smb3_posix_cc_info cc;
+ } smb3_file_posix_information;
+}
diff --git a/librpc/idl/smb_acl.idl b/librpc/idl/smb_acl.idl
new file mode 100644
index 0000000..a1532ac
--- /dev/null
+++ b/librpc/idl/smb_acl.idl
@@ -0,0 +1,96 @@
+/*
+ Unix SMB/CIFS implementation.
+ Portable SMB ACL interface
+ Copyright (C) Jeremy Allison 2000
+ 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/>.
+*/
+
+
+/*
+ * Allow the smb_acl interface to be pushed into an NDR blob and
+ * read/written in python.
+ *
+ * The exact layout of these structures is CRITICAL, as a SHA-256 hash is
+ * taken over these after they are pushed as NDR blobs, and stored in an
+ * xattr for ACL verification.
+ */
+[
+ pointer_default(unique)
+]
+interface smb_acl
+{
+
+ const int SMB_ACL_READ = 4;
+ const int SMB_ACL_WRITE = 2;
+ const int SMB_ACL_EXECUTE = 1;
+
+ /* Types of ACLs. */
+ typedef enum {
+ SMB_ACL_TAG_INVALID = 0,
+ SMB_ACL_USER = 1,
+ SMB_ACL_USER_OBJ = 2,
+ SMB_ACL_GROUP = 3,
+ SMB_ACL_GROUP_OBJ = 4,
+ SMB_ACL_OTHER = 5,
+ SMB_ACL_MASK = 6
+ } smb_acl_tag_t;
+
+ typedef struct {
+ uid_t uid;
+ } smb_acl_user;
+
+ typedef struct {
+ gid_t gid;
+ } smb_acl_group;
+
+ typedef [switch_type(uint16)] union {
+ [case (SMB_ACL_USER)] smb_acl_user user;
+ [case (SMB_ACL_USER_OBJ)];
+ [case (SMB_ACL_GROUP)] smb_acl_group group;
+ [case (SMB_ACL_GROUP_OBJ)];
+ [case (SMB_ACL_OTHER)];
+ [case (SMB_ACL_MASK)];
+ } smb_acl_entry_info;
+
+ typedef struct {
+ smb_acl_tag_t a_type;
+ [switch_is(a_type)] smb_acl_entry_info info;
+ mode_t a_perm;
+ } smb_acl_entry;
+
+ [public] typedef struct {
+ int count;
+ [value(0)] int next;
+ [size_is(count)] smb_acl_entry acl[*];
+ } smb_acl_t;
+
+ const int SMB_ACL_FIRST_ENTRY = 0;
+ const int SMB_ACL_NEXT_ENTRY = 1;
+
+ const int SMB_ACL_TYPE_ACCESS = 0;
+ const int SMB_ACL_TYPE_DEFAULT = 1;
+
+ /* A wrapper of all the information required to reproduce an
+ * ACL, so we can hash it for the acl_xattr and acl_tdb
+ * modules */
+ [public] typedef struct {
+ smb_acl_t *access_acl;
+ smb_acl_t *default_acl; /* NULL on files */
+ uid_t owner;
+ gid_t group;
+ mode_t mode;
+ } smb_acl_wrapper;
+}
diff --git a/librpc/idl/spoolss.idl b/librpc/idl/spoolss.idl
new file mode 100644
index 0000000..8160587
--- /dev/null
+++ b/librpc/idl/spoolss.idl
@@ -0,0 +1,3566 @@
+#include "idl_types.h"
+
+/*
+ spoolss interface definitions
+*/
+import "misc.idl", "security.idl", "winreg.idl";
+
+
+cpp_quote("#define spoolss_security_descriptor security_descriptor")
+
+[ uuid("12345678-1234-abcd-ef00-0123456789ab"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\spoolss]", "ncalrpc:"),
+ pointer_default(unique),
+ helpstring("Spooler SubSystem"),
+ helper("../librpc/ndr/ndr_spoolss_buf.h")
+] interface spoolss
+{
+ typedef [v1_enum] enum winreg_Type winreg_Type;
+ typedef [gensize,noprint] struct {
+ uint16 year;
+ uint16 month;
+ uint16 day_of_week;
+ uint16 day;
+ uint16 hour;
+ uint16 minute;
+ uint16 second;
+ uint16 millisecond;
+ } spoolss_Time;
+
+ typedef [public] struct {
+ [value(ndr_size_spoolss_Time(time, ndr->flags))] uint32 size;
+ [unique] spoolss_Time *time;
+ } spoolss_TimeCtr;
+
+ typedef enum {
+ PROCESSOR_ARCHITECTURE_INTEL = 0x0000,
+ PROCESSOR_ARCHITECTURE_MIPS = 0x0001,
+ PROCESSOR_ARCHITECTURE_ALPHA = 0x0002,
+ PROCESSOR_ARCHITECTURE_PPC = 0x0003,
+ PROCESSOR_ARCHITECTURE_SHX = 0x0004,
+ PROCESSOR_ARCHITECTURE_ARM = 0x0005,
+ PROCESSOR_ARCHITECTURE_IA64 = 0x0006,
+ PROCESSOR_ARCHITECTURE_ALPHA64 = 0x0007,
+ PROCESSOR_ARCHITECTURE_MSIL = 0x0008,
+ PROCESSOR_ARCHITECTURE_AMD64 = 0x0009,
+ PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 = 0x000A, /* 10 */
+ PROCESSOR_ARCHITECTURE_NEUTRAL = 0x000B, /* 11 */
+ PROCESSOR_ARCHITECTURE_ARM64 = 0x000C, /* 12 */
+ PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64 = 0x000D, /* 13 */
+ PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 = 0x000E, /* 14 */
+ PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF
+ } spoolss_ProcessorArchitecture;
+
+ typedef [v1_enum] enum {
+ PROCESSOR_INTEL_386 = 0x00000182, /* 386 */
+ PROCESSOR_INTEL_486 = 0x000001E6, /* 486 */
+ PROCESSOR_INTEL_PENTIUM = 0x0000024A, /* 586 */
+ PROCESSOR_INTEL_860 = 0x0000035C, /* 860 */
+ PROCESSOR_INTEL_IA64 = 0x00000898, /* 2200 */
+ PROCESSOR_AMD_X8664 = 0x000021D8, /* 8664 */
+ PROCESSOR_MIPS_R2000 = 0x000007D0, /* 2000 */
+ PROCESSOR_MIPS_R3000 = 0x00000BB8, /* 3000 */
+ PROCESSOR_ALPHA_21064 = 0x00005248, /* 21064 */
+ PROCESSOR_PPC_601 = 0x00000259, /* 601 */
+ PROCESSOR_PPC_603 = 0x0000025B, /* 603 */
+ PROCESSOR_PPC_604 = 0x0000025C, /* 604 */
+ PROCESSOR_PPC_620 = 0x0000026C, /* 620 */
+ PROCESSOR_HITACHI_SH3 = 0x00002713, /* 10003 */
+ PROCESSOR_HITACHI_SH3E = 0x00002714, /* 10004 */
+ PROCESSOR_HITACHI_SH4 = 0x00002715, /* 10005 */
+ PROCESSOR_MOTOROLA_821 = 0x00000335, /* 821 */
+ PROCESSOR_STRONGARM = 0x00000A11, /* 2577 */
+ PROCESSOR_ARM720 = 0x00000720, /* 1824 */
+ PROCESSOR_ARM820 = 0x00000820, /* 2080 */
+ PROCESSOR_ARM920 = 0x00000920, /* 2336 */
+ PROCESSOR_ARM_7TDMI = 0x00011171, /* 70001 */
+ PROCESSOR_OPTIL = 0x0000494F /* 18767 */
+ } spoolss_ProcessorType;
+
+ typedef [v1_enum] enum {
+ /* Windows 95, Windows 98, Windows Me, Windows NT4 */
+ SPOOLSS_MAJOR_VERSION_NT4_95_98_ME = 0x00000004,
+ /* Windows 2000, Windows 2003, Windows XP */
+ SPOOLSS_MAJOR_VERSION_2000_2003_XP = 0x00000005,
+ /* Windows Vista, Windows 2008 */
+ SPOOLSS_MAJOR_VERSION_2008_VISTA = 0x00000006
+ } spoolss_MajorVersion;
+
+ typedef [v1_enum] enum {
+ /* Windows 2008, Windows Vista, Windows 2000, Windows NT4, Windows 95 */
+ SPOOLSS_MINOR_VERSION_0 = 0x00000000,
+ /* Windows XP */
+ SPOOLSS_MINOR_VERSION_XP = 0x00000001,
+ /* Windows 2003, Windows XP x64 */
+ SPOOLSS_MINOR_VERSION_2003_XP64 = 0x00000002,
+ /* Windows 98 */
+ SPOOLSS_MINOR_VERSION_98 = 0x0000000a,
+ /* Windows Me */
+ SPOOLSS_MINOR_VERSION_ME = 0x0000005a
+ } spoolss_MinorVersion;
+
+ const int PRINTER_STATUS_OK = 0x00000000;
+
+ typedef [public] bitmap {
+ PRINTER_STATUS_PAUSED = 0x00000001,
+ PRINTER_STATUS_ERROR = 0x00000002,
+ PRINTER_STATUS_PENDING_DELETION = 0x00000004,
+ PRINTER_STATUS_PAPER_JAM = 0x00000008,
+ PRINTER_STATUS_PAPER_OUT = 0x00000010,
+ PRINTER_STATUS_MANUAL_FEED = 0x00000020,
+ PRINTER_STATUS_PAPER_PROBLEM = 0x00000040,
+ PRINTER_STATUS_OFFLINE = 0x00000080,
+ PRINTER_STATUS_IO_ACTIVE = 0x00000100,
+ PRINTER_STATUS_BUSY = 0x00000200,
+ PRINTER_STATUS_PRINTING = 0x00000400,
+ PRINTER_STATUS_OUTPUT_BIN_FULL = 0x00000800,
+ PRINTER_STATUS_NOT_AVAILABLE = 0x00001000,
+ PRINTER_STATUS_WAITING = 0x00002000,
+ PRINTER_STATUS_PROCESSING = 0x00004000,
+ PRINTER_STATUS_INITIALIZING = 0x00008000,
+ PRINTER_STATUS_WARMING_UP = 0x00010000,
+ PRINTER_STATUS_TONER_LOW = 0x00020000,
+ PRINTER_STATUS_NO_TONER = 0x00040000,
+ PRINTER_STATUS_PAGE_PUNT = 0x00080000,
+ PRINTER_STATUS_USER_INTERVENTION= 0x00100000,
+ PRINTER_STATUS_OUT_OF_MEMORY = 0x00200000,
+ PRINTER_STATUS_DOOR_OPEN = 0x00400000,
+ PRINTER_STATUS_SERVER_UNKNOWN = 0x00800000,
+ PRINTER_STATUS_POWER_SAVE = 0x01000000
+ } spoolss_PrinterStatus;
+
+ /* JOB status codes. */
+
+ const int JOB_STATUS_QUEUED = 0x0000;
+
+ typedef [bitmap32bit] bitmap {
+ JOB_STATUS_PAUSED = 0x00000001,
+ JOB_STATUS_ERROR = 0x00000002,
+ JOB_STATUS_DELETING = 0x00000004,
+ JOB_STATUS_SPOOLING = 0x00000008,
+ JOB_STATUS_PRINTING = 0x00000010,
+ JOB_STATUS_OFFLINE = 0x00000020,
+ JOB_STATUS_PAPEROUT = 0x00000040,
+ JOB_STATUS_PRINTED = 0x00000080,
+ JOB_STATUS_DELETED = 0x00000100,
+ JOB_STATUS_BLOCKED_DEVQ = 0x00000200,
+ JOB_STATUS_USER_INTERVENTION = 0x00000400,
+ JOB_STATUS_RESTART = 0x00000800,
+ JOB_STATUS_COMPLETE = 0x00001000
+ } spoolss_JobStatus;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DEBUGGING_BUILD = 0x00000000,
+ SPOOLSS_RELEASE_BUILD = 0x00000001
+ } spoolss_Build;
+
+ typedef [public,gensize] struct {
+ [relative] nstring *printername;
+ [relative] nstring *servername;
+ uint32 cjobs;
+ uint32 total_jobs;
+ uint32 total_bytes;
+ spoolss_Time time;
+ uint32 global_counter;
+ uint32 total_pages;
+ uint32 version;
+ spoolss_Build free_build;
+ uint32 spooling;
+ uint32 max_spooling;
+ uint32 session_counter;
+ uint32 num_error_out_of_paper;
+ uint32 num_error_not_ready;
+ spoolss_JobStatus job_error;
+ uint32 number_of_processors;
+ spoolss_ProcessorType processor_type;
+ uint32 high_part_total_bytes;
+ uint32 change_id;
+ WERROR last_error;
+ spoolss_PrinterStatus status;
+ uint32 enumerate_network_printers;
+ uint32 c_setprinter;
+ spoolss_ProcessorArchitecture processor_architecture;
+ uint16 processor_level;
+ uint32 ref_ic;
+ uint32 reserved2;
+ uint32 reserved3;
+ } spoolss_PrinterInfo0;
+
+ /* Device Mode Extra Data */
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DM_SIGNATURE_UNIDRVEXTRA = 0x554e4944, /* 0x44494e55 */
+ SPOOLSS_DM_SIGNATURE_JTEXP = 0x4a544d53, /* 0x534d544a */
+ SPOOLSS_DM_SIGNATURE_PSEXTRA = 0x50524956 /* 0x56495250 */
+ } spoolss_DM_Signature;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DM_LAYOUT_NUP_DISABLED = 0x00000000,
+ SPOOLSS_DM_LAYOUT_NUP_2 = 0x00000001,
+ SPOOLSS_DM_LAYOUT_NUP_4 = 0x00000002,
+ SPOOLSS_DM_LAYOUT_NUP_6 = 0x00000003,
+ SPOOLSS_DM_LAYOUT_NUP_9 = 0x00000004,
+ SPOOLSS_DM_LAYOUT_NUP_16 = 0x00000005,
+ SPOOLSS_DM_LAYOUT_BOOKLET = 0x00000006
+ } spoolss_DM_Layout;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DM_NUP_DIRECTION_L2R_T2B = 0x00000001,
+ SPOOLSS_DM_NUP_DIRECTION_T2B_L2R = 0x00000002,
+ SPOOLSS_DM_NUP_DIRECTION_R2L_T2B = 0x00000004,
+ SPOOLSS_DM_NUP_DIRECTION_T2B_R2L = 0x00000008
+ } spoolss_DM_NupDirection;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DM_NUP_BORDER_PRINT = 0x00000000,
+ SPOOLSS_DM_NUP_BORDER_NONE = 0x00000001
+ } spoolss_DM_NupBorderFlags;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DM_BOOKLET_LEFT_FLIP = 0x00000000,
+ SPOOLSS_DM_BOOKLET_RIGHT_FLIP = 0x00000001
+ } spoolss_DM_BookletFlags;
+
+ /* Device Mode Extra Data: PostScript */
+
+ /* NT 3.51 */
+
+ typedef [bitmap32bit] bitmap {
+ SPOOLSS_DM_PS_FLAGS_DRV_ERROR_HANDLER = 0x00000002,
+ SPOOLSS_DM_PS_FLAGS_PRINT_MIRROR = 0x00000004,
+ SPOOLSS_DM_PS_FLAGS_PRINT_NEGATIVE = 0x00000010,
+ SPOOLSS_DM_PS_FLAGS_COMPRESS_BITMAP = 0x00000040,
+ SPOOLSS_DM_PS_FLAGS_ROTATE_180 = 0x00000200,
+ SPOOLSS_DM_PS_FLAGS_GDI_METAFILE_SPOOL = 0x00002000
+ } spoolss_DMPS_Flags;
+
+ typedef struct {
+ [value(SPOOLSS_DM_SIGNATURE_PSEXTRA)] spoolss_DM_Signature dwSignature;
+ spoolss_DMPS_Flags dwFlags;
+ uint32 wchEPSFile[12];
+ [value(24)] uint16 caSize;
+ uint16 caFlags;
+ uint16 caIlluminantIndex;
+ uint16 caRedGamma;
+ uint16 caGreenGamma;
+ uint16 caBlueGamma;
+ uint16 caReferenceBlack;
+ uint16 caReferenceWhite;
+ uint16 caContrast;
+ uint16 caBrightness;
+ uint16 caColorfulness;
+ uint16 caRedGreenTint;
+ } spoolss_PSDRVEXTRA351;
+
+ /* NT 4.0 */
+
+ typedef struct {
+ [value(SPOOLSS_DM_SIGNATURE_PSEXTRA)] spoolss_DM_Signature dwSignature;
+ spoolss_DMPS_Flags dwFlags;
+ uint32 wchEPSFile[12];
+ [value(24)] uint16 caSize;
+ uint16 caFlags;
+ uint16 caIlluminantIndex;
+ uint16 caRedGamma;
+ uint16 caGreenGamma;
+ uint16 caBlueGamma;
+ uint16 caReferenceBlack;
+ uint16 caReferenceWhite;
+ uint16 caContrast;
+ uint16 caBrightness;
+ uint16 caColorfulness;
+ uint16 caRedGreenTint;
+ uint16 wChecksum;
+ uint16 wOptions;
+ uint32 aubOptions[8];
+ } spoolss_PSDRVEXTRA400;
+
+ /* 2000 & XP */
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DM_PS_OPTIMIZE_SPEED = 0x00000000,
+ SPOOLSS_DM_PS_OPTIMIZE_PORTABILITY = 0x00000001,
+ SPOOLSS_DM_PS_OPTIMIZE_EPS = 0x00000002,
+ SPOOLSS_DM_PS_OPTIMIZE_ARCHIVAL = 0x00000003
+ } spoolss_DMPS_Dialect;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DM_PS_TTDLFMT_DEFAULT = 0x00000000,
+ SPOOLSS_DM_PS_TTDLFMT_TYPE_1 = 0x00000001,
+ SPOOLSS_DM_PS_TTDLFMT_TYPE_3 = 0x00000002,
+ SPOOLSS_DM_PS_TTDLFMT_TYPE_42 = 0x00000003
+ } spoolss_DMPS_TTDLFmt;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DM_PS_PSLEVEL_1 = 0x00000001,
+ SPOOLSS_DM_PS_PSLEVEL_2 = 0x00000002,
+ SPOOLSS_DM_PS_PSLEVEL_3 = 0x00000003
+ } spoolss_DMPS_PSLevel;
+
+ typedef enum {
+ SPOOLSS_DM_PS_FEED_DIRECTION_LONG_EDGE_FIRST = 0x0000,
+ SPOOLSS_DM_PS_FEED_DIRECTION_SHORT_EDGE_FIRST = 0x0001,
+ SPOOLSS_DM_PS_FEED_DIRECTION_LONG_EDGE_FIRST_UPSIDEDOWN = 0x0002,
+ SPOOLSS_DM_PS_FEED_DIRECTION_SHORT_EDGE_FIRST_UPSIDEDOWN= 0x0003
+ } spoolss_DMPS_FeedDirection;
+
+ typedef struct {
+ [value(SPOOLSS_DM_SIGNATURE_PSEXTRA)] spoolss_DM_Signature dwSignature;
+ spoolss_DMPS_Flags dwFlags;
+ uint32 wchEPSFile[12];
+ [value(24)] uint16 caSize;
+ uint16 caFlags;
+ uint16 caIlluminantIndex;
+ uint16 caRedGamma;
+ uint16 caGreenGamma;
+ uint16 caBlueGamma;
+ uint16 caReferenceBlack;
+ uint16 caReferenceWhite;
+ uint16 caContrast;
+ uint16 caBrightness;
+ uint16 caColorfulness;
+ uint16 caRedGreenTint;
+ uint16 wReserved1;
+ uint16 wSize;
+ uint32 fxScrFreq;
+ uint32 fxScrAngle;
+ spoolss_DMPS_Dialect iDialect;
+ spoolss_DMPS_TTDLFmt iTTDLFmt;
+ boolean32 bReversePrint;
+ spoolss_DM_Layout iLayout;
+ spoolss_DMPS_PSLevel iPSLevel;
+ uint32 dwReserved2;
+ uint16 wOEMExtra;
+ [value(0x0010)] uint16 wVer;
+ uint32 dwX;
+ uint32 dwY;
+ uint32 dwWidthOffset;
+ uint32 dwHeightOffset;
+ spoolss_DMPS_FeedDirection wFeedDirection;
+ uint16 wCutSheet;
+ uint32 dwReserved3[4];
+ uint32 dwChecksum32;
+ uint32 dwOptions;
+ uint32 aOptions[128];
+ } spoolss_PSDRVEXTRA500;
+
+ /* Vista, 2008, 7 */
+
+ typedef struct {
+ [value(SPOOLSS_DM_SIGNATURE_PSEXTRA)] spoolss_DM_Signature dwSignature;
+ spoolss_DMPS_Flags dwFlags;
+ uint32 wchEPSFile[12];
+ [value(24)] uint16 caSize;
+ uint16 caFlags;
+ uint16 caIlluminantIndex;
+ uint16 caRedGamma;
+ uint16 caGreenGamma;
+ uint16 caBlueGamma;
+ uint16 caReferenceBlack;
+ uint16 caReferenceWhite;
+ uint16 caContrast;
+ uint16 caBrightness;
+ uint16 caColorfulness;
+ uint16 caRedGreenTint;
+ uint16 wCoreJTExpSize;
+ [value(ndr_size_spoolss_PSDRVEXTRA(r, ndr->flags) + wCoreJTExpSize)] uint16 wCoreFullSize;
+ uint32 fxScrFreq;
+ uint32 fxScrAngle;
+ spoolss_DMPS_Dialect iDialect;
+ spoolss_DMPS_TTDLFmt iTTDLFmt;
+ boolean32 bReversePrint;
+ spoolss_DM_Layout iLayout;
+ spoolss_DMPS_PSLevel iPSLevel;
+ uint32 dwReserved2;
+ uint16 wOEMExtra;
+ [value(0x0010)] uint16 wVer;
+ uint32 dwX;
+ uint32 dwY;
+ uint32 dwWidthOffset;
+ uint32 dwHeightOffset;
+ spoolss_DMPS_FeedDirection wFeedDirection;
+ uint16 wCutSheet;
+ uint32 dwReserved3[4];
+ uint32 dwChecksum32;
+ uint32 dwOptions;
+ uint32 aOptions[128];
+ spoolss_DM_NupDirection dwNupDirection;
+ spoolss_DM_NupBorderFlags dwNupBorderFlags;
+ spoolss_DM_BookletFlags dwBookletFlags;
+ uint32 dwPadding;
+ } spoolss_PSDRVEXTRA;
+
+ /* Device Mode Extra Data: UniDriver */
+
+ /* NT 3.5, NT 4.0 */
+
+ typedef struct {
+ uint16 wReserved[56];
+ } spoolss_UNIDRVEXTRA3_4;
+
+ /* 2000, XP */
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DM_UNI_QUALITY_BEST = 0x00000000,
+ SPOOLSS_DM_UNI_QUALITY_MEDIUM = 0x00000001,
+ SPOOLSS_DM_UNI_QUALITY_DRAFT = 0x00000002
+ } spoolss_DMUNI_Quality;
+
+ typedef [bitmap32bit] bitmap {
+ SPOOLSS_DM_UNI_FLAGS_PRINT_TEXT_AS_GRAPHICS = 0x00000002,
+ SPOOLSS_DM_UNI_FLAGS_AVOID_EMFSPOOL = 0x00000010,
+ SPOOLSS_DM_UNI_FLAGS_CUSTOM_HALFTONING = 0x00000080
+ } spoolss_DMUNI_Flags;
+
+ typedef struct {
+ [value(SPOOLSS_DM_SIGNATURE_UNIDRVEXTRA)] spoolss_DM_Signature dwSignature;
+ [value(0x0022)] uint16 wVer;
+ uint16 sPadding;
+ uint16 wSize;
+ uint16 wOEMExtra;
+ uint32 dwChecksum32;
+ spoolss_DMUNI_Flags dwFlags;
+ boolean32 bReversePrint;
+ spoolss_DM_Layout iLayout;
+ spoolss_DMUNI_Quality iQuality;
+ uint16 wReserved[6];
+ uint32 dwOptions;
+ uint32 aOptions[128];
+ } spoolss_UNIDRVEXTRA500;
+
+ /* Vista, 2008, 7 */
+
+ typedef [public,gensize] struct {
+ [value(SPOOLSS_DM_SIGNATURE_UNIDRVEXTRA)] spoolss_DM_Signature dwSignature;
+ [value(0x0022)] uint16 wVer;
+ uint16 wCoreJTExpSize;
+ [value(ndr_size_spoolss_UNIDRVEXTRA(r, ndr->flags) + wCoreJTExpSize)] uint16 wCoreFullSize;
+ uint16 wOEMExtra;
+ uint32 dwChecksum32;
+ spoolss_DMUNI_Flags dwFlags;
+ boolean32 bReversePrint;
+ spoolss_DM_Layout iLayout;
+ spoolss_DMUNI_Quality iQuality;
+ uint16 wReserved[6];
+ uint32 dwOptions;
+ uint32 aOptions[128];
+ spoolss_DM_NupDirection dwNupDirection;
+ spoolss_DM_NupBorderFlags dwNupBorderFlags;
+ spoolss_DM_BookletFlags dwBookletFlags;
+ } spoolss_UNIDRVEXTRA;
+
+ /* Device Mode Extra Data: JTEXP */
+
+ typedef struct {
+ uint32 dwSize;
+ [value(SPOOLSS_DM_SIGNATURE_JTEXP)] spoolss_DM_Signature dwSignature;
+ [value(0)] uint32 dwVersion;
+ [value(16)] uint16 wJTHdrSize;
+ uint16 wCoreMFOSize; /* must be sizeof the two following elements, must be dwSize - 16*/
+ nstring ModelName;
+ [flag(STR_UTF8|STR_NULLTERM|NDR_REMAINING)] string_array FeatureOptionPairs;
+ } spoolss_JTEXP;
+
+ /* Device Mode Extra Data: OEM_DMEXTRA */
+
+ typedef struct {
+ uint32 dwSize;
+ spoolss_DM_Signature dwSignature;
+ uint32 dwVersion;
+ [flag(NDR_REMAINING)] DATA_BLOB Data;
+ } spoolss_OEM_DMEXTRA;
+
+ typedef [nodiscriminant] union {
+ [case(0x0350)] spoolss_PSDRVEXTRA351 psdrvextra351;
+ [case(0x0400)] spoolss_PSDRVEXTRA400 psdrvextra400;
+ [case(0x0501)] spoolss_PSDRVEXTRA500 psdrvextra500;
+ [case(0x0600)] spoolss_PSDRVEXTRA psdrvextra;
+ [default] [flag(NDR_REMAINING)] DATA_BLOB psblob;
+ } spoolss_DeviceModeExtraDataPostScript;
+
+ typedef [nodiscriminant] union {
+ [case(0x0301)] spoolss_UNIDRVEXTRA3_4 unidrvextra3_4;
+ [case(0x0500)] spoolss_UNIDRVEXTRA500 unidrvextra500;
+ [case(0x0600)] spoolss_UNIDRVEXTRA unidrvextra;
+ [default] [flag(NDR_REMAINING)] DATA_BLOB uniblob;
+ } spoolss_DeviceModeExtraDataUniDriver;
+
+ typedef [bitmap32bit] bitmap {
+ DEVMODE_ORIENTATION = 0x00000001,
+ DEVMODE_PAPERSIZE = 0x00000002,
+ DEVMODE_PAPERLENGTH = 0x00000004,
+ DEVMODE_PAPERWIDTH = 0x00000008,
+ DEVMODE_SCALE = 0x00000010,
+ DEVMODE_POSITION = 0x00000020,
+ DEVMODE_NUP = 0x00000040,
+ DEVMODE_COPIES = 0x00000100,
+ DEVMODE_DEFAULTSOURCE = 0x00000200,
+ DEVMODE_PRINTQUALITY = 0x00000400,
+ DEVMODE_COLOR = 0x00000800,
+ DEVMODE_DUPLEX = 0x00001000,
+ DEVMODE_YRESOLUTION = 0x00002000,
+ DEVMODE_TTOPTION = 0x00004000,
+ DEVMODE_COLLATE = 0x00008000,
+ DEVMODE_FORMNAME = 0x00010000,
+ DEVMODE_LOGPIXELS = 0x00020000,
+ DEVMODE_BITSPERPEL = 0x00040000,
+ DEVMODE_PELSWIDTH = 0x00080000,
+ DEVMODE_PELSHEIGHT = 0x00100000,
+ DEVMODE_DISPLAYFLAGS = 0x00200000,
+ DEVMODE_DISPLAYFREQUENCY = 0x00400000,
+ DEVMODE_ICMMETHOD = 0x00800000,
+ DEVMODE_ICMINTENT = 0x01000000,
+ DEVMODE_MEDIATYPE = 0x02000000,
+ DEVMODE_DITHERTYPE = 0x04000000,
+ DEVMODE_PANNINGWIDTH = 0x08000000,
+ DEVMODE_PANNINGHEIGHT = 0x10000000
+ } spoolss_DeviceModeFields;
+
+ typedef [enum16bit] enum {
+ DMSPEC_NT3 = 0x320,
+ DMSPEC_WIN95_98_ME = 0x400,
+ DMSPEC_NT4_AND_ABOVE = 0x401
+ } spoolss_DeviceModeSpecVersion;
+
+ typedef [enum16bit] enum {
+ DMORIENT_PORTRAIT = 0x0001,
+ DMORIENT_LANDSCAPE = 0x0002
+ } spoolss_DeviceModeOrientation;
+
+ typedef [enum16bit] enum {
+ DMPAPER_LETTER = 0x0001, /* Letter, 8 1/2 x 11 inches */
+ DMPAPER_LETTERSMALL = 0x0002, /* Letter Small, 8 1/2 x 11 inches */
+ DMPAPER_TABLOID = 0x0003, /* Tabloid, 11 x 17 inches */
+ DMPAPER_LEDGER = 0x0004, /* Ledger, 17 x 11 inches */
+ DMPAPER_LEGAL = 0x0005, /* Legal, 8 1/2 x 14 inches */
+ DMPAPER_STATEMENT = 0x0006, /* Statement, 5 1/2 x 8 1/2 inches */
+ DMPAPER_EXECUTIVE = 0x0007, /* Executive, 7 1/4 x 10 1/2 inches */
+ DMPAPER_A3 = 0x0008, /* A3 sheet, 297 x 420 millimeters */
+ DMPAPER_A4 = 0x0009, /* A4 sheet, 210 x 297 millimeters */
+ DMPAPER_A4SMALL = 0x000A, /* A4 small sheet, 210 x 297 millimeters */
+ DMPAPER_A5 = 0x000B, /* A5 sheet, 148 x 210 millimeters */
+ DMPAPER_B4 = 0x000C, /* B4 sheet, 250 x 354 millimeters */
+ DMPAPER_B5 = 0x000D, /* B5 sheet, 182 x 257-millimeter paper */
+ DMPAPER_FOLIO = 0x000E, /* Folio, 8 1/2 x 13-inch paper */
+ DMPAPER_QUARTO = 0x000F, /* Quarto, 215 x 275 millimeter paper */
+ DMPAPER_10X14 = 0x0010, /* 10 x 14-inch sheet */
+ DMPAPER_11X17 = 0x0011, /* 11 x 17-inch sheet */
+ DMPAPER_NOTE = 0x0012, /* Note, 8 1/2 x 11-inches */
+ DMPAPER_ENV_9 = 0x0013, /* #9 Envelope, 3 7/8 x 8 7/8 inches */
+ DMPAPER_ENV_10 = 0x0014, /* #10 Envelope, 4 1/8 x 9 1/2 inches */
+ DMPAPER_ENV_11 = 0x0015, /* #11 Envelope, 4 1/2 x 10 3/8 inches */
+ DMPAPER_ENV_12 = 0x0016, /* #12 Envelope, 4 3/4 x 11 inches */
+ DMPAPER_ENV_14 = 0x0017, /* #14 Envelope, 5 x 11 1/2 inches */
+ DMPAPER_CSHEET = 0x0018, /* C Sheet, 17 x 22 inches */
+ DMPAPER_DSHEET = 0x0019, /* D Sheet, 22 x 34 inches */
+ DMPAPER_ESHEET = 0x001A, /* E Sheet, 34 x 44 inches */
+ DMPAPER_ENV_DL = 0x001B, /* DL Envelope, 110 x 220 millimeters */
+ DMPAPER_ENV_C5 = 0x001C, /* C5 Envelope, 162 x 229 millimeters */
+ DMPAPER_ENV_C3 = 0x001D, /* C3 Envelope, 324 x 458 millimeters */
+ DMPAPER_ENV_C4 = 0x001E, /* C4 Envelope, 229 x 324 millimeters */
+ DMPAPER_ENV_C6 = 0x001F, /* C6 Envelope, 114 x 162 millimeters */
+ DMPAPER_ENV_C65 = 0x0020, /* C65 Envelope, 114 x 229 millimeters */
+ DMPAPER_ENV_B4 = 0x0021, /* B4 Envelope, 250 x 353 millimeters */
+ DMPAPER_ENV_B5 = 0x0022, /* B5 Envelope, 176 x 250 millimeters */
+ DMPAPER_ENV_B6 = 0x0023, /* B6 Envelope, 176 x 125 millimeters */
+ DMPAPER_ENV_ITALY = 0x0024, /* Italy Envelope, 110 x 230 millimeters */
+ DMPAPER_ENV_MONARCH = 0x0025, /* Monarch Envelope, 3 7/8 x 7 1/2 inches */
+ DMPAPER_ENV_PERSONAL = 0x0026, /* 6 3/4 Envelope, 3 5/8 x 6 1/2 inches */
+ DMPAPER_FANFOLD_US = 0x0027, /* US Std Fanfold, 14 7/8 x 11 inches */
+ DMPAPER_FANFOLD_STD_GERMAN = 0x0028, /* German Std Fanfold, 8 1/2 x 12 inches */
+ DMPAPER_FANFOLD_LGL_GERMAN = 0x0029, /* German Legal Fanfold, 8 x 13 inches */
+ DMPAPER_DBL_JAPANESE_POSTCARD = 0x0045, /* Double Japanese Postcard, 200 x 148 millimeters */
+ DMPAPER_A6 = 0x0046, /* A6 sheet, 105 x 148 millimeters */
+ DMPAPER_JENV_KAKU2 = 0x0047, /* Japanese Envelope Kaku #2 */
+ DMPAPER_JENV_KAKU3 = 0x0048, /* Japanese Envelope Kaku #3 */
+ DMPAPER_JENV_CHOU3 = 0x0049, /* Japanese Envelope Chou #3 */
+ DMPAPER_JENV_CHOU4 = 0x004A, /* Japanese Envelope Chou #4 */
+ DMPAPER_LETTER_ROTATED = 0x004B, /* Letter Rotated, 11 by 8 1/2 inches */
+ DMPAPER_A3_ROTATED = 0x004C, /* A3 rotated sheet, 420 x 297 millimeters */
+ DMPAPER_A4_ROTATED = 0x004D, /* A4 rotated sheet, 297 x 210 millimeters */
+ DMPAPER_A5_ROTATED = 0x004E, /* A5 rotated sheet, 210 x 148 millimeters */
+ DMPAPER_B4_JIS_ROTATED = 0x004F, /* B4 (JIS) rotated sheet, 364 x 257 millimeters */
+ DMPAPER_B5_JIS_ROTATED = 0x0050, /* B5 (JIS) rotated sheet, 257 x 182 millimeters */
+ DMPAPER_JAPANESE_POSTCARD_ROTATED = 0x0051, /* Japanese Postcard Rotated, 148 x 100 millimeters */
+ DMPAPER_DBL_JAPANESE_POSTCARD_ROTATED = 0x0052, /* Double Japanese Postcard Rotated, 148 x 200 millimeters */
+ DMPAPER_A6_ROTATED = 0x0053, /* A6 rotated sheet, 148 x 105 millimeters */
+ DMPAPER_JENV_KAKU2_ROTATED = 0x0054, /* Japanese Envelope Kaku #2 Rotated */
+ DMPAPER_JENV_KAKU3_ROTATED = 0x0055, /* Japanese Envelope Kaku #3 Rotated */
+ DMPAPER_JENV_CHOU3_ROTATED = 0x0056, /* Japanese Envelope Chou #3 Rotated */
+ DMPAPER_JENV_CHOU4_ROTATED = 0x0057, /* Japanese Envelope Chou #4 Rotated */
+ DMPAPER_B6_JIS = 0x0058, /* B6 (JIS) sheet, 128 x 182 millimeters */
+ DMPAPER_B6_JIS_ROTATED = 0x0059, /* B6 (JIS) rotated sheet, 182 x 128 millimeters */
+ DMPAPER_12X11 = 0x005A, /* 12 x 11-inch sheet */
+ DMPAPER_JENV_YOU4 = 0x005B, /* Japanese Envelope You #4 */
+ DMPAPER_JENV_YOU4_ROTATED = 0x005C, /* Japanese Envelope You #4 */
+ DMPAPER_P16K = 0x005D, /* PRC 16K, 146 x 215 millimeters */
+ DMPAPER_P32K = 0x005E, /* PRC 32K, 97 x 151 millimeters */
+ DMPAPER_P32KBIG = 0x005F, /* PRC 32K(Big) 97 x 151 millimeters */
+ DMPAPER_PENV_1 = 0x0060, /* PRC Envelope #1, 102 by 165 millimeters */
+ DMPAPER_PENV_2 = 0x0061, /* PRC Envelope #2, 102 x 176 millimeters */
+ DMPAPER_PENV_3 = 0x0062, /* PRC Envelope #3, 125 x 176 millimeters */
+ DMPAPER_PENV_4 = 0x0063, /* PRC Envelope #4, 110 x 208 millimeters */
+ DMPAPER_PENV_5 = 0x0064, /* PRC Envelope #5, 110 x 220 millimeters */
+ DMPAPER_PENV_6 = 0x0065, /* PRC Envelope #6, 120 x 230 millimeters */
+ DMPAPER_PENV_7 = 0x0066, /* PRC Envelope #7, 160 x 230 millimeters */
+ DMPAPER_PENV_8 = 0x0067, /* PRC Envelope #8, 120 x 309 millimeters */
+ DMPAPER_PENV_9 = 0x0068, /* PRC Envelope #9, 229 x 324 millimeters */
+ DMPAPER_PENV_10 = 0x0069, /* PRC Envelope #10, 324 x 458 millimeters */
+ DMPAPER_P16K_ROTATED = 0x006A, /* PRC 16K Rotated, 215 x 146 millimeters */
+ DMPAPER_P32K_ROTATED = 0x006B, /* PRC 32K Rotated, 151 x 97 millimeters */
+ DMPAPER_P32KBIG_ROTATED = 0x006C, /* PRC 32K(Big) Rotated, 151 x 97 millimeters */
+ DMPAPER_PENV_1_ROTATED = 0x006D, /* PRC Envelope #1 Rotated, 165 x 102 millimeters */
+ DMPAPER_PENV_2_ROTATED = 0x006E, /* PRC Envelope #2 Rotated, 176 x 102 millimeters */
+ DMPAPER_PENV_3_ROTATED = 0x006F, /* PRC Envelope #3 Rotated, 176 x 125 millimeters */
+ DMPAPER_PENV_4_ROTATED = 0x0070, /* PRC Envelope #4 Rotated, 208 x 110 millimeters */
+ DMPAPER_PENV_5_ROTATED = 0x0071, /* PRC Envelope #5 Rotated, 220 x 110 millimeters */
+ DMPAPER_PENV_6_ROTATED = 0x0072, /* PRC Envelope #6 Rotated, 230 x 120 millimeters */
+ DMPAPER_PENV_7_ROTATED = 0x0073, /* PRC Envelope #7 Rotated, 230 x 160 millimeters */
+ DMPAPER_PENV_8_ROTATED = 0x0074, /* PRC Envelope #8 Rotated, 309 x 120 millimeters */
+ DMPAPER_PENV_9_ROTATED = 0x0075, /* PRC Envelope #9 Rotated, 324 x 229 millimeters */
+ DMPAPER_PENV_10_ROTATED = 0x0076 /* PRC Envelope #10 Rotated, 458 x 324 millimeters */
+ } spoolss_DeviceModePaperSize;
+
+ typedef [enum16bit] enum {
+ DMBIN_UPPER = 0x0001,
+ DMBIN_LOWER = 0x0002,
+ DMBIN_MIDDLE = 0x0003,
+ DMBIN_MANUAL = 0x0004,
+ DMBIN_ENVELOPE = 0x0005,
+ DMBIN_ENVMANUAL = 0x0006,
+ DMBIN_AUTO = 0x0007,
+ DMBIN_TRACTOR = 0x0008,
+ DMBIN_SMALLFMT = 0x0009,
+ DMBIN_LARGEFMT = 0x000a,
+ DMBIN_LARGECAPACITY = 0x000b,
+ DMBIN_CASSETTE = 0x000e,
+ DMBIN_FORMSOURCE = 0x000f
+ } spoolss_DeviceModeDefaultSource;
+
+ typedef [enum16bit] enum {
+ DMRES_HIGH = 0xfffc,
+ DMRES_MEDIUM = 0xfffd,
+ DMRES_LOW = 0xfffe,
+ DMRES_DRAFT = 0xffff
+ } spoolss_DeviceModePrintQuality;
+
+ typedef [enum16bit] enum {
+ DMRES_MONOCHROME = 0x0001,
+ DMRES_COLOR = 0x0002
+ } spoolss_DeviceModeColor;
+
+ typedef [enum16bit] enum {
+ DMDUP_SIMPLEX = 0x0001,
+ DMDUP_VERTICAL = 0x0002,
+ DMDUP_HORIZONTAL = 0x0003
+ } spoolss_DeviceModeDuplex;
+
+ typedef [enum16bit] enum {
+ DMTT_BITMAP = 0x0001,
+ DMTT_DOWNLOAD = 0x0002,
+ DMTT_SUBDEV = 0x0003,
+ DMTT_DOWNLOAD_OUTLINE = 0x0004
+ } spoolss_DeviceModeTTOption;
+
+ typedef [enum16bit] enum {
+ DMCOLLATE_FALSE = 0x0000,
+ DMCOLLATE_TRUE = 0x0001
+ } spoolss_DeviceModeCollate;
+
+ typedef [v1_enum] enum {
+ DMNUP_SYSTEM = 0x00000001,
+ DMNUP_ONEUP = 0x00000002
+ } spoolss_DeviceModeNUp;
+
+ typedef [v1_enum] enum {
+ DMICMMETHOD_NONE = 0x00000001,
+ DMICMMETHOD_SYSTEM = 0x00000002,
+ DMICMMETHOD_DRIVER = 0x00000003,
+ DMICMMETHOD_DEVICE = 0x00000004
+ } spoolss_DeviceModeICMMethod;
+
+ typedef [v1_enum] enum {
+ DMICM_SATURATE = 0x00000001,
+ DMICM_CONTRAST = 0x00000002,
+ DMICM_COLORIMETRIC = 0x00000003,
+ DMICM_ABS_COLORIMETRIC = 0x00000004
+ } spoolss_DeviceModeICMIntent;
+
+ typedef [v1_enum] enum {
+ DMMEDIA_STANDARD = 0x00000001,
+ DMMEDIA_TRANSPARENCY = 0x00000002,
+ DMMEDIA_GLOSSY = 0x00000003
+ } spoolss_DeviceModeMediaType;
+
+ typedef [v1_enum] enum {
+ DMDITHER_NONE = 0x00000001,
+ DMDITHER_COARSE = 0x00000002,
+ DMDITHER_FINE = 0x00000003,
+ DMDITHER_LINEART = 0x00000004,
+ DMDITHER_ERRORDIFFUSION = 0x00000005,
+ DMDITHER_RESERVED6 = 0x00000006,
+ DMDITHER_RESERVED7 = 0x00000007,
+ DMDITHER_RESERVED8 = 0x00000008,
+ DMDITHER_RESERVED9 = 0x00000009,
+ DMDITHER_GRAYSCALE = 0x0000000A
+ } spoolss_DeviceModeDitherType;
+
+ const int MAXDEVICENAME = 32;
+
+ typedef [public,gensize] struct {
+ [charset(UTF16),to_null] uint16 devicename[MAXDEVICENAME];
+ spoolss_DeviceModeSpecVersion specversion;
+ uint16 driverversion;
+ uint16 size;
+ [value(r->driverextra_data.length)] uint16 __driverextra_length;
+ spoolss_DeviceModeFields fields;
+ spoolss_DeviceModeOrientation orientation;
+ spoolss_DeviceModePaperSize papersize;
+ uint16 paperlength;
+ uint16 paperwidth;
+ uint16 scale;
+ uint16 copies;
+ spoolss_DeviceModeDefaultSource defaultsource;
+ spoolss_DeviceModePrintQuality printquality;
+ spoolss_DeviceModeColor color;
+ spoolss_DeviceModeDuplex duplex;
+ uint16 yresolution;
+ spoolss_DeviceModeTTOption ttoption;
+ spoolss_DeviceModeCollate collate;
+ [charset(UTF16),to_null] uint16 formname[MAXDEVICENAME];
+ uint16 logpixels; /* reserved */
+ uint32 bitsperpel; /* reserved */
+ uint32 pelswidth; /* reserved */
+ uint32 pelsheight; /* reserved */
+ spoolss_DeviceModeNUp displayflags;
+ uint32 displayfrequency; /* reserved */
+ spoolss_DeviceModeICMMethod icmmethod;
+ spoolss_DeviceModeICMIntent icmintent;
+ spoolss_DeviceModeMediaType mediatype;
+ spoolss_DeviceModeDitherType dithertype;
+ uint32 reserved1;
+ uint32 reserved2;
+ uint32 panningwidth; /* reserved */
+ uint32 panningheight; /* reserved */
+ [subcontext_size(__driverextra_length),subcontext(0),flag(NDR_REMAINING)] DATA_BLOB driverextra_data;
+ } spoolss_DeviceMode;
+
+ typedef [public] bitmap {
+ PRINTER_ENUM_DEFAULT = 0x00000001,
+ PRINTER_ENUM_LOCAL = 0x00000002,
+ PRINTER_ENUM_CONNECTIONS = 0x00000004,
+ PRINTER_ENUM_FAVORITE = 0x00000004,
+ PRINTER_ENUM_NAME = 0x00000008,
+ PRINTER_ENUM_REMOTE = 0x00000010,
+ PRINTER_ENUM_SHARED = 0x00000020,
+ PRINTER_ENUM_NETWORK = 0x00000040,
+ PRINTER_ENUM_EXPAND = 0x00004000,
+ PRINTER_ENUM_CONTAINER = 0x00008000,
+ PRINTER_ENUM_ICON1 = 0x00010000,
+ PRINTER_ENUM_ICON2 = 0x00020000,
+ PRINTER_ENUM_ICON3 = 0x00040000,
+ PRINTER_ENUM_ICON4 = 0x00080000,
+ PRINTER_ENUM_ICON5 = 0x00100000,
+ PRINTER_ENUM_ICON6 = 0x00200000,
+ PRINTER_ENUM_ICON7 = 0x00400000,
+ PRINTER_ENUM_ICON8 = 0x00800000,
+ PRINTER_ENUM_HIDE = 0x01000000
+ } spoolss_EnumPrinterFlags;
+
+ const int PRINTER_ENUM_ICONMASK = (PRINTER_ENUM_ICON1 |
+ PRINTER_ENUM_ICON2 |
+ PRINTER_ENUM_ICON3 |
+ PRINTER_ENUM_ICON4 |
+ PRINTER_ENUM_ICON5 |
+ PRINTER_ENUM_ICON6 |
+ PRINTER_ENUM_ICON7 |
+ PRINTER_ENUM_ICON8); /* 0x00ff0000 */
+
+ typedef [public] bitmap {
+ PRINTER_ATTRIBUTE_QUEUED = 0x00000001,
+ PRINTER_ATTRIBUTE_DIRECT = 0x00000002,
+ PRINTER_ATTRIBUTE_DEFAULT = 0x00000004,
+ PRINTER_ATTRIBUTE_SHARED = 0x00000008,
+ PRINTER_ATTRIBUTE_NETWORK = 0x00000010,
+ PRINTER_ATTRIBUTE_HIDDEN = 0x00000020,
+ PRINTER_ATTRIBUTE_LOCAL = 0x00000040,
+ PRINTER_ATTRIBUTE_ENABLE_DEVQ = 0x00000080,
+ PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS = 0x00000100,
+ PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST = 0x00000200,
+ PRINTER_ATTRIBUTE_WORK_OFFLINE = 0x00000400,
+ PRINTER_ATTRIBUTE_ENABLE_BIDI = 0x00000800,
+ PRINTER_ATTRIBUTE_RAW_ONLY = 0x00001000,
+ PRINTER_ATTRIBUTE_PUBLISHED = 0x00002000,
+ PRINTER_ATTRIBUTE_FAX = 0x00004000,
+ PRINTER_ATTRIBUTE_TS = 0x00008000
+ } spoolss_PrinterAttributes;
+
+ typedef [public,gensize] struct {
+ spoolss_EnumPrinterFlags flags;
+ [relative] nstring *description;
+ [relative] nstring *name;
+ [relative] nstring *comment;
+ } spoolss_PrinterInfo1;
+
+ typedef [public,gensize,nopush] struct {
+ [relative] nstring *servername;
+ [relative] nstring *printername;
+ [relative] nstring *sharename;
+ [relative] nstring *portname;
+ [relative] nstring *drivername;
+ [relative] nstring *comment;
+ [relative] nstring *location;
+ [relative,subcontext(0),flag(NDR_ALIGN4)] spoolss_DeviceMode *devmode;
+ [relative] nstring *sepfile;
+ [relative] nstring *printprocessor;
+ [relative] nstring *datatype;
+ [relative] nstring *parameters;
+ [relative,subcontext(0),flag(NDR_ALIGN4)] spoolss_security_descriptor *secdesc;
+ spoolss_PrinterAttributes attributes;
+ [range(0,99)] uint32 priority;
+ uint32 defaultpriority;
+ uint32 starttime;
+ uint32 untiltime;
+ spoolss_PrinterStatus status;
+ uint32 cjobs;
+ uint32 averageppm;
+ } spoolss_PrinterInfo2;
+
+ typedef [public,gensize] struct {
+ [relative,subcontext(0),flag(NDR_ALIGN4)] spoolss_security_descriptor *secdesc;
+ } spoolss_PrinterInfo3;
+
+ typedef [public,gensize] struct {
+ [relative] nstring *printername;
+ [relative] nstring *servername;
+ spoolss_PrinterAttributes attributes;
+ } spoolss_PrinterInfo4;
+
+ typedef [public,gensize] struct {
+ [relative] nstring *printername;
+ [relative] nstring *portname;
+ spoolss_PrinterAttributes attributes;
+ uint32 device_not_selected_timeout;
+ uint32 transmission_retry_timeout;
+ } spoolss_PrinterInfo5;
+
+ typedef [public,gensize] struct {
+ spoolss_PrinterStatus status;
+ } spoolss_PrinterInfo6;
+
+ typedef bitmap {
+ DSPRINT_PUBLISH = 0x00000001,
+ DSPRINT_UPDATE = 0x00000002,
+ DSPRINT_UNPUBLISH = 0x00000004,
+ DSPRINT_REPUBLISH = 0x00000008,
+ DSPRINT_PENDING = 0x80000000
+ } spoolss_DsPrintAction;
+
+ typedef [public,gensize] struct {
+ [relative] nstring *guid; /* text form of printer guid */
+ spoolss_DsPrintAction action;
+ } spoolss_PrinterInfo7;
+
+ typedef struct {
+ [relative,subcontext(0),flag(NDR_ALIGN4)] spoolss_DeviceMode *devmode;
+ } spoolss_DeviceModeInfo;
+
+ typedef [nodiscriminant,relative_base,public,gensize,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(0)] spoolss_PrinterInfo0 info0;
+ [case(1)] spoolss_PrinterInfo1 info1;
+ [case(2)] spoolss_PrinterInfo2 info2;
+ [case(3)] spoolss_PrinterInfo3 info3;
+ [case(4)] spoolss_PrinterInfo4 info4;
+ [case(5)] spoolss_PrinterInfo5 info5;
+ [case(6)] spoolss_PrinterInfo6 info6;
+ [case(7)] spoolss_PrinterInfo7 info7;
+ [case(8)] spoolss_DeviceModeInfo info8;
+ [case(9)] spoolss_DeviceModeInfo info9;
+ [default];
+ } spoolss_PrinterInfo;
+
+ /******************/
+ /* Function: 0x00 */
+ /* we are using this as internal parsing code */
+ [public,noopnum,noprint] WERROR _spoolss_EnumPrinters(
+ [in] spoolss_EnumPrinterFlags flags,
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPrinters(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_PrinterInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPrinters(
+ [in] spoolss_EnumPrinterFlags flags,
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ /* what we have here is a subcontext containing an array of no discriminant unions
+ * and the array has no size in front
+ */
+ [out,ref] uint32 *count,
+ [out,ref,switch_is(level),size_is(,*count)] spoolss_PrinterInfo **info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ typedef [public] struct {
+ [value(_ndr_size_spoolss_DeviceMode(devmode, ndr->flags))] uint32 _ndr_size;
+ [subcontext(4),subcontext_size(_ndr_size)] spoolss_DeviceMode *devmode;
+ } spoolss_DevmodeContainer;
+
+ [public] WERROR spoolss_OpenPrinter(
+ [in,unique] [string,charset(UTF16)] uint16 *printername,
+ [in,unique] [string,charset(UTF16)] uint16 *datatype,
+ [in] spoolss_DevmodeContainer devmode_ctr,
+ [in] spoolss_AccessRights access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x02 */
+
+ typedef [public,gensize] struct {
+ uint32 job_id;
+ [relative] nstring *printer_name;
+ [relative] nstring *server_name;
+ [relative] nstring *user_name;
+ [relative] nstring *document_name;
+ [relative] nstring *data_type;
+ [relative] nstring *text_status;
+ spoolss_JobStatus status;
+ [range(0,99)] uint32 priority;
+ uint32 position;
+ uint32 total_pages;
+ uint32 pages_printed;
+ spoolss_Time submitted;
+ } spoolss_JobInfo1;
+
+ typedef [public,gensize] struct {
+ uint32 job_id;
+ [relative] nstring *printer_name;
+ [relative] nstring *server_name;
+ [relative] nstring *user_name;
+ [relative] nstring *document_name;
+ [relative] nstring *notify_name;
+ [relative] nstring *data_type;
+ [relative] nstring *print_processor;
+ [relative] nstring *parameters;
+ [relative] nstring *driver_name;
+ [relative,subcontext(0),flag(NDR_ALIGN4)] spoolss_DeviceMode *devmode;
+ [relative] nstring *text_status;
+ [relative,subcontext(0),flag(NDR_ALIGN4)] spoolss_security_descriptor *secdesc;
+ spoolss_JobStatus status;
+ [range(0,99)] uint32 priority;
+ uint32 position;
+ uint32 start_time;
+ uint32 until_time;
+ uint32 total_pages;
+ uint32 size;
+ spoolss_Time submitted;
+ uint32 time;
+ uint32 pages_printed;
+ } spoolss_JobInfo2;
+
+ typedef [public,gensize] struct {
+ uint32 job_id;
+ uint32 next_job_id;
+ uint32 reserved;
+ } spoolss_JobInfo3;
+
+ typedef [public,gensize] struct {
+ uint32 job_id;
+ [relative] nstring *printer_name;
+ [relative] nstring *server_name;
+ [relative] nstring *user_name;
+ [relative] nstring *document_name;
+ [relative] nstring *notify_name;
+ [relative] nstring *data_type;
+ [relative] nstring *print_processor;
+ [relative] nstring *parameters;
+ [relative] nstring *driver_name;
+ [relative,subcontext(0),flag(NDR_ALIGN4)] spoolss_DeviceMode *devmode;
+ [relative] nstring *text_status;
+ [relative,subcontext(0),flag(NDR_ALIGN4)] spoolss_security_descriptor *secdesc;
+ spoolss_JobStatus status;
+ [range(0,99)] uint32 priority;
+ uint32 position;
+ uint32 start_time;
+ uint32 until_time;
+ uint32 total_pages;
+ uint32 size;
+ spoolss_Time submitted;
+ uint32 time;
+ uint32 pages_printed;
+ uint32 size_high;
+ } spoolss_JobInfo4;
+
+ typedef [nodiscriminant,relative_base,public,gensize,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(1)] spoolss_JobInfo1 info1;
+ [case(2)] spoolss_JobInfo2 info2;
+ [case(3)] spoolss_JobInfo3 info3;
+ [case(4)] spoolss_JobInfo4 info4;
+ [default];
+ } spoolss_JobInfo;
+
+ typedef struct {
+ uint32 job_id;
+ [string,charset(UTF16)] uint16 *printer_name;
+ [string,charset(UTF16)] uint16 *server_name;
+ [string,charset(UTF16)] uint16 *user_name;
+ [string,charset(UTF16)] uint16 *document_name;
+ [string,charset(UTF16)] uint16 *data_type;
+ [string,charset(UTF16)] uint16 *text_status;
+ spoolss_JobStatus status;
+ [range(0,99)] uint32 priority;
+ uint32 position;
+ uint32 total_pages;
+ uint32 pages_printed;
+ spoolss_Time submitted;
+ } spoolss_SetJobInfo1;
+
+ typedef struct {
+ uint32 job_id;
+ [string,charset(UTF16)] uint16 *printer_name;
+ [string,charset(UTF16)] uint16 *server_name;
+ [string,charset(UTF16)] uint16 *user_name;
+ [string,charset(UTF16)] uint16 *document_name;
+ [string,charset(UTF16)] uint16 *notify_name;
+ [string,charset(UTF16)] uint16 *data_type;
+ [string,charset(UTF16)] uint16 *print_processor;
+ [string,charset(UTF16)] uint16 *parameters;
+ [string,charset(UTF16)] uint16 *driver_name;
+ uint3264 _devmode_ptr; /* ULONG_PTR */
+ [string,charset(UTF16)] uint16 *text_status;
+ uint3264 _secdesc_ptr; /* ULONG_PTR */
+ spoolss_JobStatus status;
+ [range(0,99)] uint32 priority;
+ uint32 position;
+ uint32 start_time;
+ uint32 until_time;
+ uint32 total_pages;
+ uint32 size;
+ spoolss_Time submitted;
+ uint32 time;
+ uint32 pages_printed;
+ } spoolss_SetJobInfo2;
+
+ typedef struct {
+ uint32 job_id;
+ [string,charset(UTF16)] uint16 *printer_name;
+ [string,charset(UTF16)] uint16 *server_name;
+ [string,charset(UTF16)] uint16 *user_name;
+ [string,charset(UTF16)] uint16 *document_name;
+ [string,charset(UTF16)] uint16 *notify_name;
+ [string,charset(UTF16)] uint16 *data_type;
+ [string,charset(UTF16)] uint16 *print_processor;
+ [string,charset(UTF16)] uint16 *parameters;
+ [string,charset(UTF16)] uint16 *driver_name;
+ uint3264 _devmode_ptr; /* ULONG_PTR */
+ [string,charset(UTF16)] uint16 *text_status;
+ uint3264 _secdesc_ptr; /* ULONG_PTR */
+ spoolss_JobStatus status;
+ [range(0,99)] uint32 priority;
+ uint32 position;
+ uint32 start_time;
+ uint32 until_time;
+ uint32 total_pages;
+ uint32 size;
+ spoolss_Time submitted;
+ uint32 time;
+ uint32 pages_printed;
+ uint32 size_high;
+ } spoolss_SetJobInfo4;
+
+ typedef [ms_union,public] union {
+ [case(1)] spoolss_SetJobInfo1 *info1;
+ [case(2)] spoolss_SetJobInfo2 *info2;
+ [case(3)] spoolss_JobInfo3 *info3;
+ [case(4)] spoolss_SetJobInfo4 *info4;
+ [default];
+ } spoolss_SetJobInfo;
+
+ typedef [public] struct {
+ uint32 level;
+ [switch_is(level)] spoolss_SetJobInfo info;
+ } spoolss_JobInfoContainer;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_JOB_CONTROL_NOOP = 0,
+ SPOOLSS_JOB_CONTROL_PAUSE = 1,
+ SPOOLSS_JOB_CONTROL_RESUME = 2,
+ SPOOLSS_JOB_CONTROL_CANCEL = 3,
+ SPOOLSS_JOB_CONTROL_RESTART = 4,
+ SPOOLSS_JOB_CONTROL_DELETE = 5,
+ SPOOLSS_JOB_CONTROL_SEND_TO_PRINTER = 6,
+ SPOOLSS_JOB_CONTROL_LAST_PAGE_EJECTED = 7,
+ SPOOLSS_JOB_CONTROL_RETAIN = 8,
+ SPOOLSS_JOB_CONTROL_RELEASE = 9
+ } spoolss_JobControl;
+
+ WERROR spoolss_SetJob(
+ [in,ref] policy_handle *handle,
+ [in] uint32 job_id,
+ [in,unique] spoolss_JobInfoContainer *ctr,
+ [in] spoolss_JobControl command
+ );
+
+ /******************/
+ /* Function: 0x03 */
+ WERROR spoolss_GetJob(
+ [in,ref] policy_handle *handle,
+ [in] uint32 job_id,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_JobInfo *info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ [public,noopnum,noprint] WERROR _spoolss_EnumJobs(
+ [in,ref] policy_handle *handle,
+ [in] uint32 firstjob,
+ [in] uint32 numjobs,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumJobs(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_JobInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumJobs(
+ [in,ref] policy_handle *handle,
+ [in] uint32 firstjob,
+ [in] uint32 numjobs,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *count,
+ [out,ref,switch_is(level),size_is(,*count)] spoolss_JobInfo **info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ WERROR spoolss_AddPrinter(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,ref] spoolss_SetPrinterInfoCtr *info_ctr,
+ [in,ref] spoolss_DevmodeContainer *devmode_ctr,
+ [in,ref] sec_desc_buf *secdesc_ctr,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x06 */
+ WERROR spoolss_DeletePrinter(
+ [in] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x07 */
+ typedef [v1_enum] enum {
+ SPOOLSS_PRINTER_CONTROL_UNPAUSE = 0,
+ SPOOLSS_PRINTER_CONTROL_PAUSE = 1,
+ SPOOLSS_PRINTER_CONTROL_RESUME = 2,
+ SPOOLSS_PRINTER_CONTROL_PURGE = 3,
+ SPOOLSS_PRINTER_CONTROL_SET_STATUS = 4
+ } spoolss_PrinterControl;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *servername;
+ [string,charset(UTF16)] uint16 *printername;
+ uint32 cjobs;
+ uint32 total_jobs;
+ uint32 total_bytes;
+ spoolss_Time time;
+ uint32 global_counter;
+ uint32 total_pages;
+ uint32 version;
+ spoolss_Build free_build;
+ uint32 spooling;
+ uint32 max_spooling;
+ uint32 session_counter;
+ uint32 num_error_out_of_paper;
+ uint32 num_error_not_ready;
+ spoolss_JobStatus job_error;
+ uint32 number_of_processors;
+ spoolss_ProcessorType processor_type;
+ uint32 high_part_total_bytes;
+ uint32 change_id;
+ WERROR last_error;
+ spoolss_PrinterStatus status;
+ uint32 enumerate_network_printers;
+ uint32 c_setprinter;
+ spoolss_ProcessorArchitecture processor_architecture;
+ uint16 processor_level;
+ uint32 ref_ic;
+ uint32 reserved2;
+ uint32 reserved3;
+ } spoolss_SetPrinterInfo0;
+
+ typedef struct {
+ spoolss_PrinterAttributes flags;
+ [string,charset(UTF16)] uint16 *description;
+ [string,charset(UTF16)] uint16 *name;
+ [string,charset(UTF16)] uint16 *comment;
+ } spoolss_SetPrinterInfo1;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *servername;
+ [string,charset(UTF16)] uint16 *printername;
+ [string,charset(UTF16)] uint16 *sharename;
+ [string,charset(UTF16)] uint16 *portname;
+ [string,charset(UTF16)] uint16 *drivername;
+ [string,charset(UTF16)] uint16 *comment;
+ [string,charset(UTF16)] uint16 *location;
+ uint3264 devmode_ptr; /* ULONG_PTR */
+ [string,charset(UTF16)] uint16 *sepfile;
+ [string,charset(UTF16)] uint16 *printprocessor;
+ [string,charset(UTF16)] uint16 *datatype;
+ [string,charset(UTF16)] uint16 *parameters;
+ uint3264 secdesc_ptr; /* ULONG_PTR */
+ spoolss_PrinterAttributes attributes;
+ [range(0,99)] uint32 priority;
+ uint32 defaultpriority;
+ uint32 starttime;
+ uint32 untiltime;
+ spoolss_PrinterStatus status;
+ uint32 cjobs;
+ uint32 averageppm;
+ } spoolss_SetPrinterInfo2;
+
+ typedef struct {
+ uint3264 sec_desc_ptr; /* ULONG_PTR */
+ } spoolss_SetPrinterInfo3;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *printername;
+ [string,charset(UTF16)] uint16 *servername;
+ spoolss_PrinterAttributes attributes;
+ } spoolss_SetPrinterInfo4;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *printername;
+ [string,charset(UTF16)] uint16 *portname;
+ spoolss_PrinterAttributes attributes;
+ uint32 device_not_selected_timeout;
+ uint32 transmission_retry_timeout;
+ } spoolss_SetPrinterInfo5;
+
+ typedef struct {
+ spoolss_PrinterStatus status;
+ } spoolss_SetPrinterInfo6;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *guid; /* text form of printer guid */
+ spoolss_DsPrintAction action;
+ } spoolss_SetPrinterInfo7;
+
+ typedef struct {
+ uint3264 devmode_ptr; /* ULONG_PTR */
+ } spoolss_SetPrinterInfo8;
+
+ typedef struct {
+ uint3264 devmode_ptr; /* ULONG_PTR */
+ } spoolss_SetPrinterInfo9;
+
+ typedef [ms_union,switch_type(uint32)] union {
+ [case(0)] spoolss_SetPrinterInfo0 *info0;
+ [case(1)] spoolss_SetPrinterInfo1 *info1;
+ [case(2)] spoolss_SetPrinterInfo2 *info2;
+ [case(3)] spoolss_SetPrinterInfo3 *info3;
+ [case(4)] spoolss_SetPrinterInfo4 *info4;
+ [case(5)] spoolss_SetPrinterInfo5 *info5;
+ [case(6)] spoolss_SetPrinterInfo6 *info6;
+ [case(7)] spoolss_SetPrinterInfo7 *info7;
+ [case(8)] spoolss_SetPrinterInfo8 *info8;
+ [case(9)] spoolss_SetPrinterInfo9 *info9;
+ [default];
+ } spoolss_SetPrinterInfo;
+
+ typedef [public] struct {
+ uint32 level;
+ [switch_is(level)] spoolss_SetPrinterInfo info;
+ } spoolss_SetPrinterInfoCtr;
+
+ [public] WERROR spoolss_SetPrinter(
+ [in,ref] policy_handle *handle,
+ [in,ref] spoolss_SetPrinterInfoCtr *info_ctr,
+ [in,ref] spoolss_DevmodeContainer *devmode_ctr,
+ [in,ref] sec_desc_buf *secdesc_ctr,
+ [in] spoolss_PrinterControl command
+ );
+
+ /******************/
+ /* Function: 0x08 */
+ [public] WERROR spoolss_GetPrinter(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_PrinterInfo *info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x09 */
+
+ typedef [public] struct {
+ [value((ndr_size_spoolss_StringArray(r, ndr->flags)-4)/2)] uint32 _ndr_size;
+ /*[subcontext(0),subcontext_size(_ndr_size*2)]*/ nstring_array string;
+ } spoolss_StringArray;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *driver_name;
+ } spoolss_AddDriverInfo1;
+
+ typedef [v1_enum,public] enum {
+ SPOOLSS_DRIVER_VERSION_9X = 0,
+ SPOOLSS_DRIVER_VERSION_NT35 = 1,
+ SPOOLSS_DRIVER_VERSION_NT4 = 2,
+ SPOOLSS_DRIVER_VERSION_200X = 3,
+ SPOOLSS_DRIVER_VERSION_2012 = 4
+ } spoolss_DriverOSVersion;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [string,charset(UTF16)] uint16 *driver_name;
+ [string,charset(UTF16)] uint16 *architecture;
+ [string,charset(UTF16)] uint16 *driver_path;
+ [string,charset(UTF16)] uint16 *data_file;
+ [string,charset(UTF16)] uint16 *config_file;
+ } spoolss_AddDriverInfo2;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [string,charset(UTF16)] uint16 *driver_name;
+ [string,charset(UTF16)] uint16 *architecture;
+ [string,charset(UTF16)] uint16 *driver_path;
+ [string,charset(UTF16)] uint16 *data_file;
+ [string,charset(UTF16)] uint16 *config_file;
+ [string,charset(UTF16)] uint16 *help_file;
+ [string,charset(UTF16)] uint16 *monitor_name;
+ [string,charset(UTF16)] uint16 *default_datatype;
+ [value(((ndr_size_spoolss_StringArray(dependent_files, ndr->flags)-4)/2))] uint32 _ndr_size_dependent_files;
+ spoolss_StringArray *dependent_files;
+ } spoolss_AddDriverInfo3;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [string,charset(UTF16)] uint16 *driver_name;
+ [string,charset(UTF16)] uint16 *architecture;
+ [string,charset(UTF16)] uint16 *driver_path;
+ [string,charset(UTF16)] uint16 *data_file;
+ [string,charset(UTF16)] uint16 *config_file;
+ [string,charset(UTF16)] uint16 *help_file;
+ [string,charset(UTF16)] uint16 *monitor_name;
+ [string,charset(UTF16)] uint16 *default_datatype;
+ [value(((ndr_size_spoolss_StringArray(dependent_files, ndr->flags)-4)/2))] uint32 _ndr_size_dependent_files;
+ spoolss_StringArray *dependent_files;
+ [value(((ndr_size_spoolss_StringArray(previous_names, ndr->flags)-4)/2))] uint32 _ndr_size_previous_names;
+ spoolss_StringArray *previous_names;
+ } spoolss_AddDriverInfo4;
+
+ typedef [bitmap32bit] bitmap {
+ PRINTER_DRIVER_PACKAGE_AWARE = 0x00000001,
+ PRINTER_DRIVER_XPS = 0x00000002,
+ PRINTER_DRIVER_SANDBOX_ENABLED = 0x00000004,
+ PRINTER_DRIVER_CLASS = 0x00000008,
+ PRINTER_DRIVER_DERIVED = 0x00000010,
+ PRINTER_DRIVER_NOT_SHAREABLE = 0x00000020,
+ PRINTER_DRIVER_CATEGORY_FAX = 0x00000040,
+ PRINTER_DRIVER_CATEGORY_FILE = 0x00000080,
+ PRINTER_DRIVER_CATEGORY_VIRTUAL = 0x00000100,
+ PRINTER_DRIVER_CATEGORY_SERVICE = 0x00000200,
+ PRINTER_DRIVER_SOFT_RESET_REQUIRED = 0x00000400,
+ PRINTER_DRIVER_CATEGORY_3D = 0x00001000
+ } spoolss_DriverAttributes;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [string,charset(UTF16)] uint16 *driver_name;
+ [string,charset(UTF16)] uint16 *architecture;
+ [string,charset(UTF16)] uint16 *driver_path;
+ [string,charset(UTF16)] uint16 *data_file;
+ [string,charset(UTF16)] uint16 *config_file;
+ spoolss_DriverAttributes driver_attributes;
+ uint32 config_version;
+ uint32 driver_version;
+ } spoolss_AddDriverInfo5;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [string,charset(UTF16)] uint16 *driver_name;
+ [string,charset(UTF16)] uint16 *architecture;
+ [string,charset(UTF16)] uint16 *driver_path;
+ [string,charset(UTF16)] uint16 *data_file;
+ [string,charset(UTF16)] uint16 *config_file;
+ [string,charset(UTF16)] uint16 *help_file;
+ [string,charset(UTF16)] uint16 *monitor_name;
+ [string,charset(UTF16)] uint16 *default_datatype;
+ [value(((ndr_size_spoolss_StringArray(dependent_files, ndr->flags)-4)/2))] uint32 _ndr_size_dependent_files;
+ spoolss_StringArray *dependent_files;
+ [value(((ndr_size_spoolss_StringArray(previous_names, ndr->flags)-4)/2))] uint32 _ndr_size_previous_names;
+ spoolss_StringArray *previous_names;
+ NTTIME driver_date;
+ hyper driver_version;
+ [string,charset(UTF16)] uint16 *manufacturer_name;
+ [string,charset(UTF16)] uint16 *manufacturer_url;
+ [string,charset(UTF16)] uint16 *hardware_id;
+ [string,charset(UTF16)] uint16 *provider;
+ } spoolss_AddDriverInfo6;
+
+ typedef struct {
+ spoolss_DriverOSVersion version;
+ [string,charset(UTF16)] uint16 *driver_name;
+ [string,charset(UTF16)] uint16 *architecture;
+ [string,charset(UTF16)] uint16 *driver_path;
+ [string,charset(UTF16)] uint16 *data_file;
+ [string,charset(UTF16)] uint16 *config_file;
+ [string,charset(UTF16)] uint16 *help_file;
+ [string,charset(UTF16)] uint16 *monitor_name;
+ [string,charset(UTF16)] uint16 *default_datatype;
+ [value(((ndr_size_spoolss_StringArray(dependent_files, ndr->flags)-4)/2))] uint32 _ndr_size_dependent_files;
+ spoolss_StringArray *dependent_files;
+ [value(((ndr_size_spoolss_StringArray(previous_names, ndr->flags)-4)/2))] uint32 _ndr_size_previous_names;
+ spoolss_StringArray *previous_names;
+ NTTIME driver_date;
+ hyper driver_version;
+ [string,charset(UTF16)] uint16 *manufacturer_name;
+ [string,charset(UTF16)] uint16 *manufacturer_url;
+ [string,charset(UTF16)] uint16 *hardware_id;
+ [string,charset(UTF16)] uint16 *provider;
+ [string,charset(UTF16)] uint16 *print_processor;
+ [string,charset(UTF16)] uint16 *vendor_setup;
+ [value(((ndr_size_spoolss_StringArray(color_profiles, ndr->flags)-4)/2))] uint32 _ndr_size_color_profiles;
+ spoolss_StringArray *color_profiles;
+ [string,charset(UTF16)] uint16 *inf_path;
+ spoolss_DriverAttributes printer_driver_attributes;
+ [value(((ndr_size_spoolss_StringArray(core_driver_dependencies, ndr->flags)-4)/2))] uint32 _ndr_size_core_driver_dependencies;
+ spoolss_StringArray *core_driver_dependencies;
+ NTTIME min_inbox_driver_ver_date;
+ hyper min_inbox_driver_ver_version;
+ } spoolss_AddDriverInfo8;
+
+ typedef [ms_union,switch_type(uint32)] union {
+ [case(1)] spoolss_AddDriverInfo1 *info1;
+ [case(2)] spoolss_AddDriverInfo2 *info2;
+ [case(3)] spoolss_AddDriverInfo3 *info3;
+ [case(4)] spoolss_AddDriverInfo4 *info4;
+ [case(6)] spoolss_AddDriverInfo6 *info6;
+ [case(8)] spoolss_AddDriverInfo8 *info8;
+ } spoolss_AddDriverInfo;
+
+ typedef [public] struct {
+ uint32 level;
+ [switch_is(level)] spoolss_AddDriverInfo info;
+ } spoolss_AddDriverInfoCtr;
+
+ WERROR spoolss_AddPrinterDriver(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,ref] spoolss_AddDriverInfoCtr *info_ctr
+ );
+
+ typedef [public,gensize] struct {
+ [relative] nstring *driver_name;
+ } spoolss_DriverInfo1;
+
+ typedef [public,gensize] struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ } spoolss_DriverInfo2;
+
+ typedef [public,gensize] struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ [relative] nstring *help_file;
+ [relative] nstring_array *dependent_files;
+ [relative] nstring *monitor_name;
+ [relative] nstring *default_datatype;
+ } spoolss_DriverInfo3;
+
+ typedef [public,gensize] struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ [relative] nstring *help_file;
+ [relative] nstring_array *dependent_files;
+ [relative] nstring *monitor_name;
+ [relative] nstring *default_datatype;
+ [relative] nstring_array *previous_names;
+ } spoolss_DriverInfo4;
+
+ typedef [public,gensize] struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ spoolss_DriverAttributes driver_attributes;
+ uint32 config_version;
+ uint32 driver_version;
+ } spoolss_DriverInfo5;
+
+ typedef [public,gensize] struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ [relative] nstring *help_file;
+ [relative] nstring_array *dependent_files;
+ [relative] nstring *monitor_name;
+ [relative] nstring *default_datatype;
+ [relative] nstring_array *previous_names;
+ NTTIME driver_date;
+ hyper driver_version;
+ [relative] nstring *manufacturer_name;
+ [relative] nstring *manufacturer_url;
+ [relative] nstring *hardware_id;
+ [relative] nstring *provider;
+ } spoolss_DriverInfo6;
+
+ typedef [public,gensize] struct {
+ uint32 size;
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *inf_name;
+ [relative] nstring *install_source_root;
+ } spoolss_DriverInfo7;
+
+ typedef [public,gensize] struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative] nstring *driver_path;
+ [relative] nstring *data_file;
+ [relative] nstring *config_file;
+ [relative] nstring *help_file;
+ [relative] nstring_array *dependent_files;
+ [relative] nstring *monitor_name;
+ [relative] nstring *default_datatype;
+ [relative] nstring_array *previous_names;
+ NTTIME driver_date;
+ hyper driver_version;
+ [relative] nstring *manufacturer_name;
+ [relative] nstring *manufacturer_url;
+ [relative] nstring *hardware_id;
+ [relative] nstring *provider;
+ [relative] nstring *print_processor;
+ [relative] nstring *vendor_setup;
+ [relative] nstring_array *color_profiles;
+ [relative] nstring *inf_path;
+ spoolss_DriverAttributes printer_driver_attributes;
+ [relative] nstring_array *core_driver_dependencies;
+ NTTIME min_inbox_driver_ver_date;
+ hyper min_inbox_driver_ver_version;
+ } spoolss_DriverInfo8;
+
+ typedef [v1_enum] enum {
+ SPOOLSS_DRIVER_FILE_TYPE_RENDERING = 0x00000000,
+ SPOOLSS_DRIVER_FILE_TYPE_CONFIGURATION = 0x00000001,
+ SPOOLSS_DRIVER_FILE_TYPE_DATA = 0x00000002,
+ SPOOLSS_DRIVER_FILE_TYPE_HELP = 0x00000003,
+ SPOOLSS_DRIVER_FILE_TYPE_OTHER = 0x00000004
+ } spoolss_DriverFileType;
+
+ typedef [public] struct {
+ [relative] nstring *file_name;
+ spoolss_DriverFileType file_type;
+ uint32 file_version;
+ } spoolss_DriverFileInfo;
+
+ typedef [public,gensize,nopush,nopull] struct {
+ spoolss_DriverOSVersion version;
+ [relative] nstring *driver_name;
+ [relative] nstring *architecture;
+ [relative,size_is(file_count),flag(NDR_ALIGN4)] spoolss_DriverFileInfo *file_info;
+ uint32 file_count;
+ [relative] nstring *monitor_name;
+ [relative] nstring *default_datatype;
+ [relative] nstring_array *previous_names;
+ NTTIME driver_date;
+ hyper driver_version;
+ [relative] nstring *manufacturer_name;
+ [relative] nstring *manufacturer_url;
+ [relative] nstring *hardware_id;
+ [relative] nstring *provider;
+ } spoolss_DriverInfo101;
+
+ typedef [nodiscriminant,relative_base,public,gensize,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(1)] spoolss_DriverInfo1 info1;
+ [case(2)] spoolss_DriverInfo2 info2;
+ [case(3)] spoolss_DriverInfo3 info3;
+ [case(4)] spoolss_DriverInfo4 info4;
+ [case(5)] spoolss_DriverInfo5 info5;
+ [case(6)] spoolss_DriverInfo6 info6;
+ [case(7)] spoolss_DriverInfo7 info7;
+ [case(8)] spoolss_DriverInfo8 info8;
+ [case(101)] spoolss_DriverInfo101 info101;
+ [default];
+ } spoolss_DriverInfo;
+
+ /******************/
+ /* Function: 0x0a */
+ [public,noopnum,noprint] WERROR _spoolss_EnumPrinterDrivers(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPrinterDrivers(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_DriverInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPrinterDrivers(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *count,
+ [out,ref,switch_is(level),size_is(,*count)] spoolss_DriverInfo **info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x0b */
+ WERROR spoolss_GetPrinterDriver(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *architecture,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_DriverInfo *info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x0c */
+ typedef [public,gensize] struct {
+ nstring directory_name;
+ } spoolss_DriverDirectoryInfo1;
+
+ /* NOTE: It seems that w2k3 completely ignores the level
+ in its server code
+ */
+ typedef [nodiscriminant,relative_base,public,gensize,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(1)] spoolss_DriverDirectoryInfo1 info1;
+ [default] spoolss_DriverDirectoryInfo1 info1;
+ } spoolss_DriverDirectoryInfo;
+
+ [public] WERROR spoolss_GetPrinterDriverDirectory(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_DriverDirectoryInfo *info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x0d */
+ WERROR spoolss_DeletePrinterDriver(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in] [string,charset(UTF16)] uint16 architecture[],
+ [in] [string,charset(UTF16)] uint16 driver[]
+ );
+
+ /******************/
+ /* Function: 0x0e */
+ WERROR spoolss_AddPrintProcessor(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in] [string,charset(UTF16)] uint16 architecture[],
+ [in] [string,charset(UTF16)] uint16 path_name[],
+ [in] [string,charset(UTF16)] uint16 print_processor_name[]
+ );
+
+ /******************/
+ /* Function: 0x0f */
+ typedef [public,gensize] struct {
+ [relative] nstring *print_processor_name;
+ } spoolss_PrintProcessorInfo1;
+
+ typedef [nodiscriminant,relative_base,public,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(1)] spoolss_PrintProcessorInfo1 info1;
+ [default];
+ } spoolss_PrintProcessorInfo;
+
+ [public,noopnum,noprint] WERROR _spoolss_EnumPrintProcessors(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPrintProcessors(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_PrintProcessorInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPrintProcessors(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *count,
+ [out,ref,switch_is(level),size_is(,*count)] spoolss_PrintProcessorInfo **info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x10 */
+ typedef [public,gensize] struct {
+ nstring directory_name;
+ } spoolss_PrintProcessorDirectoryInfo1;
+
+ typedef [nodiscriminant,relative_base,public,gensize,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(1)] spoolss_PrintProcessorDirectoryInfo1 info1;
+ [default] spoolss_PrintProcessorDirectoryInfo1 info1;
+ } spoolss_PrintProcessorDirectoryInfo;
+
+ WERROR spoolss_GetPrintProcessorDirectory(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *environment,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_PrintProcessorDirectoryInfo *info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x11 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *document_name;
+ [string,charset(UTF16)] uint16 *output_file;
+ [string,charset(UTF16)] uint16 *datatype;
+ } spoolss_DocumentInfo1;
+
+ typedef [ms_union,switch_type(uint32)] union {
+ [case(1)] spoolss_DocumentInfo1 *info1;
+ [case(2)]; /* TODO */
+ [case(3)]; /* TODO */
+ [default];
+ } spoolss_DocumentInfo;
+
+ typedef [public] struct {
+ uint32 level;
+ [switch_is(level)] spoolss_DocumentInfo info;
+ } spoolss_DocumentInfoCtr;
+
+ WERROR spoolss_StartDocPrinter(
+ [in,ref] policy_handle *handle,
+ [in,ref] spoolss_DocumentInfoCtr *info_ctr,
+ [out,ref] uint32 *job_id
+ );
+
+ /******************/
+ /* Function: 0x12 */
+ WERROR spoolss_StartPagePrinter(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x13 */
+ WERROR spoolss_WritePrinter(
+ [in,ref] policy_handle *handle,
+ [in] DATA_BLOB data,
+ [in,value(r->in.data.length)] uint32 _data_size,
+ [out,ref] uint32 *num_written
+ );
+
+ /******************/
+ /* Function: 0x14 */
+ WERROR spoolss_EndPagePrinter(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x15 */
+ WERROR spoolss_AbortPrinter(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x16 */
+ WERROR spoolss_ReadPrinter(
+ [in,ref] policy_handle *handle,
+ [out,ref] [size_is(data_size)] uint8 *data,
+ [in] uint32 data_size,
+ [out,ref] uint32 *_data_size
+ );
+
+ /******************/
+ /* Function: 0x17 */
+ WERROR spoolss_EndDocPrinter(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x18 */
+ WERROR spoolss_AddJob(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,out,unique] [size_is(offered)] uint8 *buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x19 */
+ WERROR spoolss_ScheduleJob(
+ [in,ref] policy_handle *handle,
+ [in] uint32 jobid
+ );
+
+ /******************/
+ /* Function: 0x1a */
+
+ const string SPL_ARCH_WIN40 = "WIN40";
+ const string SPL_ARCH_W32X86 = "W32X86";
+ const string SPL_ARCH_W32MIPS = "W32MIPS";
+ const string SPL_ARCH_W32ALPHA = "W32ALPHA";
+ const string SPL_ARCH_W32PPC = "W32PPC";
+ const string SPL_ARCH_IA64 = "IA64";
+ const string SPL_ARCH_X64 = "x64";
+ const string SPL_ARCH_ARM = "ARM";
+ const string SPL_ARCH_ARM64 = "ARM64";
+
+ const string SPOOLSS_ARCHITECTURE_ALL = "All";
+ const string SPOOLSS_ARCHITECTURE_ALL_CLUSTER = "AllCluster";
+ const string SPOOLSS_ARCHITECTURE_NT_X86 = "Windows NT x86";
+ const string SPOOLSS_ARCHITECTURE_IA_64 = "Windows IA64";
+ const string SPOOLSS_ARCHITECTURE_x64 = "Windows x64";
+ const string SPOOLSS_ARCHITECTURE_4_0 = "Windows 4.0";
+ const string SPOOLSS_ARCHITECTURE_W32MIPS = "Windows NT R4000";
+ const string SPOOLSS_ARCHITECTURE_W32PPC = "Windows NT PowerPC";
+ const string SPOOLSS_ARCHITECTURE_W32ALPHA = "Windows NT Alpha AXP";
+ const string SPOOLSS_ARCHITECTURE_ARM = "Windows ARM";
+ const string SPOOLSS_ARCHITECTURE_ARM64 = "Windows ARM64";
+ const string SPOOLSS_DEFAULT_SERVER_PATH = "C:\\WINDOWS\\system32\\spool";
+
+ typedef [public,gensize] struct {
+ [value(ndr_size_spoolss_OSVersion(r,ndr->flags))] uint32 _ndr_size;
+ uint32 major;
+ uint32 minor;
+ uint32 build;
+ [value(2)] uint32 platform_id;
+ [subcontext(0),subcontext_size(256)] nstring extra_string;
+ } spoolss_OSVersion;
+
+ typedef [public,gensize] struct {
+ [value(ndr_size_spoolss_OSVersionEx(r,ndr->flags))] uint32 _ndr_size;
+ uint32 major;
+ uint32 minor;
+ uint32 build;
+ [value(2)] uint32 platform_id;
+ [subcontext(0),subcontext_size(256)] nstring extra_string;
+ uint16 service_pack_major;
+ uint16 service_pack_minor;
+ uint16 suite_mask;
+ uint8 product_type;
+ uint8 reserved;
+ } spoolss_OSVersionEx;
+
+ typedef [nodiscriminant,public] union {
+ [case(REG_NONE)];
+ [case(REG_SZ)] nstring string;
+ [case(REG_BINARY),flag(NDR_REMAINING)] DATA_BLOB binary;
+ [case(REG_DWORD)] uint32 value;
+ [case(REG_MULTI_SZ)] nstring_array string_array;
+ [default,flag(NDR_REMAINING)] DATA_BLOB data;
+ } spoolss_PrinterData;
+
+ /* predefined registry key names for printer data */
+
+ const string SPOOL_PRINTERDATA_KEY = "PrinterDriverData";
+ const string SPOOL_DSSPOOLER_KEY = "DsSpooler";
+ const string SPOOL_DSDRIVER_KEY = "DsDriver";
+ const string SPOOL_DSUSER_KEY = "DsUser";
+ const string SPOOL_PNPDATA_KEY = "PnPData";
+ const string SPOOL_OID_KEY = "OID";
+
+ /* predefined value names for printer data */
+
+ const string SPOOL_REG_ASSETNUMBER = "assetNumber";
+ const string SPOOL_REG_BYTESPERMINUTE = "bytesPerMinute";
+ const string SPOOL_REG_DEFAULTPRIORITY = "defaultPriority";
+ const string SPOOL_REG_DESCRIPTION = "description";
+ const string SPOOL_REG_DRIVERNAME = "driverName";
+ const string SPOOL_REG_DRIVERVERSION = "driverVersion";
+ const string SPOOL_REG_FLAGS = "flags";
+ const string SPOOL_REG_LOCATION = "location";
+ const string SPOOL_REG_OPERATINGSYSTEM = "operatingSystem";
+ const string SPOOL_REG_OPERATINGSYSTEMHOTFIX = "operatingSystemHotfix";
+ const string SPOOL_REG_OPERATINGSYSTEMSERVICEPACK = "operatingSystemServicePack";
+ const string SPOOL_REG_OPERATINGSYSTEMVERSION = "operatingSystemVersion";
+ const string SPOOL_REG_PORTNAME = "portName";
+ const string SPOOL_REG_PRINTATTRIBUTES = "printAttributes";
+ const string SPOOL_REG_PRINTBINNAMES = "printBinNames";
+ const string SPOOL_REG_PRINTCOLLATE = "printCollate";
+ const string SPOOL_REG_PRINTCOLOR = "printColor";
+ const string SPOOL_REG_PRINTDUPLEXSUPPORTED = "printDuplexSupported";
+ const string SPOOL_REG_PRINTENDTIME = "printEndTime";
+ const string SPOOL_REG_PRINTERNAME = "printerName";
+ const string SPOOL_REG_PRINTFORMNAME = "printFormName";
+ const string SPOOL_REG_PRINTKEEPPRINTEDJOBS = "printKeepPrintedJobs";
+ const string SPOOL_REG_PRINTLANGUAGE = "printLanguage";
+ const string SPOOL_REG_PRINTMACADDRESS = "printMACAddress";
+ const string SPOOL_REG_PRINTMAXCOPIES = "printMaxCopies";
+ const string SPOOL_REG_PRINTMAXRESOLUTIONSUPPORTED = "printMaxResolutionSupported";
+ const string SPOOL_REG_PRINTMAXXEXTENT = "printMaxXExtent";
+ const string SPOOL_REG_PRINTMAXYEXTENT = "printMaxYExtent";
+ const string SPOOL_REG_PRINTMEDIAREADY = "printMediaReady";
+ const string SPOOL_REG_PRINTMEDIASUPPORTED = "printMediaSupported";
+ const string SPOOL_REG_PRINTMEMORY = "printMemory";
+ const string SPOOL_REG_PRINTMINXEXTENT = "printMinXExtent";
+ const string SPOOL_REG_PRINTMINYEXTENT = "printMinYExtent";
+ const string SPOOL_REG_PRINTNETWORKADDRESS = "printNetworkAddress";
+ const string SPOOL_REG_PRINTNOTIFY = "printNotify";
+ const string SPOOL_REG_PRINTNUMBERUP = "printNumberUp";
+ const string SPOOL_REG_PRINTORIENTATIONSSUPPORTED = "printOrientationsSupported";
+ const string SPOOL_REG_PRINTOWNER = "printOwner";
+ const string SPOOL_REG_PRINTPAGESPERMINUTE = "printPagesPerMinute";
+ const string SPOOL_REG_PRINTRATE = "printRate";
+ const string SPOOL_REG_PRINTRATEUNIT = "printRateUnit";
+ const string SPOOL_REG_PRINTSEPARATORFILE = "printSeparatorFile";
+ const string SPOOL_REG_PRINTSHARENAME = "printShareName";
+ const string SPOOL_REG_PRINTSPOOLING = "printSpooling";
+ const string SPOOL_REGVAL_PRINTWHILESPOOLING = "PrintWhileSpooling";
+ const string SPOOL_REGVAL_PRINTAFTERSPOOLED = "PrintAfterSpooled";
+ const string SPOOL_REGVAL_PRINTDIRECT = "PrintDirect";
+ const string SPOOL_REG_PRINTSTAPLINGSUPPORTED = "printStaplingSupported";
+ const string SPOOL_REG_PRINTSTARTTIME = "printStartTime";
+ const string SPOOL_REG_PRINTSTATUS = "printStatus";
+ const string SPOOL_REG_PRIORITY = "priority";
+ const string SPOOL_REG_SERVERNAME = "serverName";
+ const string SPOOL_REG_SHORTSERVERNAME = "shortServerName";
+ const string SPOOL_REG_UNCNAME = "uNCName";
+ const string SPOOL_REG_URL = "url";
+ const string SPOOL_REG_VERSIONNUMBER = "versionNumber";
+
+ [public] WERROR spoolss_GetPrinterData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [out,ref] winreg_Type *type,
+ [out,ref,size_is(offered)] uint8 *data,
+ [in] uint32 offered,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x1b */
+ WERROR spoolss_SetPrinterData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [in] winreg_Type type,
+ [in,ref] [size_is(offered)] uint8 *data,
+ [in] uint32 offered
+ );
+
+ /******************/
+ /* Function: 0x1c */
+ [todo] WERROR spoolss_WaitForPrinterChange(
+ );
+
+ /******************/
+ /* Function: 0x1d */
+ [public] WERROR spoolss_ClosePrinter(
+ [in,out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x1e */
+ typedef [v1_enum] enum {
+ SPOOLSS_FORM_USER = 0,
+ SPOOLSS_FORM_BUILTIN = 1,
+ SPOOLSS_FORM_PRINTER = 2
+ } spoolss_FormFlags;
+
+ typedef struct {
+ uint32 width;
+ uint32 height;
+ } spoolss_FormSize;
+
+ typedef struct {
+ uint32 left;
+ uint32 top;
+ uint32 right;
+ uint32 bottom;
+ } spoolss_FormArea;
+
+ typedef [public,gensize] struct {
+ spoolss_FormFlags flags;
+ [relative] nstring *form_name;
+ spoolss_FormSize size;
+ spoolss_FormArea area;
+ } spoolss_FormInfo1;
+
+ typedef [bitmap32bit] bitmap {
+ SPOOLSS_FORM_STRING_TYPE_NONE = 0x00000001,
+ SPOOLSS_FORM_STRING_TYPE_MUI_DLL = 0x00000002,
+ SPOOLSS_FORM_STRING_TYPE_LANG_PAIR = 0x00000004
+ } spoolss_FormStringType;
+
+ typedef [public,gensize] struct {
+ spoolss_FormFlags flags;
+ [relative] nstring *form_name;
+ spoolss_FormSize size;
+ spoolss_FormArea area;
+ [relative] astring *keyword;
+ spoolss_FormStringType string_type;
+ [relative] nstring *mui_dll;
+ uint32 ressource_id;
+ [relative] nstring *display_name;
+ uint16 lang_id;
+ uint16 unused;
+ } spoolss_FormInfo2;
+
+ typedef [nodiscriminant,relative_base,public,gensize,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(1)] spoolss_FormInfo1 info1;
+ [case(2)] spoolss_FormInfo2 info2;
+ [default];
+ } spoolss_FormInfo;
+
+ typedef struct {
+ spoolss_FormFlags flags;
+ [string,charset(UTF16)] uint16 *form_name;
+ spoolss_FormSize size;
+ spoolss_FormArea area;
+ } spoolss_AddFormInfo1;
+
+ typedef struct {
+ spoolss_FormFlags flags;
+ [string,charset(UTF16)] uint16 *form_name;
+ spoolss_FormSize size;
+ spoolss_FormArea area;
+ [string,charset(DOS)] uint8 *keyword;
+ spoolss_FormStringType string_type;
+ [string,charset(UTF16)] uint16 *mui_dll;
+ uint32 ressource_id;
+ [string,charset(UTF16)] uint16 *display_name;
+ uint32 lang_id;
+ } spoolss_AddFormInfo2;
+
+ typedef [ms_union,switch_type(uint32)] union {
+ [case(1)] spoolss_AddFormInfo1 *info1;
+ [case(2)] spoolss_AddFormInfo2 *info2;
+ } spoolss_AddFormInfo;
+
+ typedef [public] struct {
+ uint32 level;
+ [switch_is(level)] spoolss_AddFormInfo info;
+ } spoolss_AddFormInfoCtr;
+
+ WERROR spoolss_AddForm(
+ [in,ref] policy_handle *handle,
+ [in,ref] spoolss_AddFormInfoCtr *info_ctr
+ );
+
+ /******************/
+ /* Function: 0x1f */
+ WERROR spoolss_DeleteForm(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 form_name[]
+ );
+
+ /******************/
+ /* Function: 0x20 */
+ WERROR spoolss_GetForm(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 form_name[],
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_FormInfo *info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x21 */
+ WERROR spoolss_SetForm(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 form_name[],
+ [in,ref] spoolss_AddFormInfoCtr *info_ctr
+ );
+
+ /******************/
+ /* Function: 0x22 */
+ [public,noopnum,noprint] WERROR _spoolss_EnumForms(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumForms(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_FormInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumForms(
+ [in,ref] policy_handle *handle,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *count,
+ [out,ref,switch_is(level),size_is(,*count)] spoolss_FormInfo **info,
+ [out,ref] uint32 *needed
+ );
+
+ /*
+ * Special strings for the OpenPrinter() call. See the MSDN DDK
+ * docs on the XcvDataPort() for more details.
+ */
+
+ const string SPL_LOCAL_PORT = "Local Port";
+ const string SPL_TCPIP_PORT = "Standard TCP/IP Port";
+ const string SPL_XCV_MONITOR_LOCALMON = ",XcvMonitor Local Port";
+ const string SPL_XCV_MONITOR_TCPMON = ",XcvMonitor Standard TCP/IP Port";
+
+ typedef [public,gensize] struct {
+ [relative] nstring *port_name;
+ } spoolss_PortInfo1;
+
+ typedef bitmap {
+ SPOOLSS_PORT_TYPE_WRITE = 0x00000001,
+ SPOOLSS_PORT_TYPE_READ = 0x00000002,
+ SPOOLSS_PORT_TYPE_REDIRECTED = 0x00000004,
+ SPOOLSS_PORT_TYPE_NET_ATTACHED = 0x00000008
+ } spoolss_PortType;
+
+ typedef [public,gensize] struct {
+ [relative] nstring *port_name;
+ [relative] nstring *monitor_name;
+ [relative] nstring *description;
+ spoolss_PortType port_type;
+ uint32 reserved;
+ } spoolss_PortInfo2;
+
+ typedef [v1_enum] enum {
+ PORT_STATUS_CLEAR = 0x00000000,
+ PORT_STATUS_OFFLINE = 0x00000001,
+ PORT_STATUS_PAPER_JAM = 0x00000002,
+ PORT_STATUS_PAPER_OUT = 0x00000003,
+ PORT_STATUS_OUTPUT_BIN_FULL = 0x00000004,
+ PORT_STATUS_PAPER_PROBLEM = 0x00000005,
+ PORT_STATUS_NO_TONER = 0x00000006,
+ PORT_STATUS_DOOR_OPEN = 0x00000007,
+ PORT_STATUS_USER_INTERVENTION = 0x00000008,
+ PORT_STATUS_OUT_OF_MEMORY = 0x00000009,
+ PORT_STATUS_TONER_LOW = 0x0000000A,
+ PORT_STATUS_WARMING_UP = 0x0000000B,
+ PORT_STATUS_POWER_SAVE = 0x0000000C
+ } spoolss_PortStatus;
+
+ typedef [v1_enum] enum {
+ PORT_STATUS_TYPE_ERROR = 0x00000001,
+ PORT_STATUS_TYPE_WARNING = 0x00000002,
+ PORT_STATUS_TYPE_INFO = 0x00000003
+ } spoolss_PortSeverity;
+
+ typedef [public,gensize] struct {
+ spoolss_PortStatus status;
+ [relative] nstring *status_string;
+ spoolss_PortSeverity severity;
+ } spoolss_PortInfo3;
+
+ typedef [public,gensize] struct {
+ [relative] nstring *port_name;
+ DATA_BLOB monitor_data; /* relative ?? */
+ } spoolss_PortInfoFF;
+
+ typedef [nodiscriminant,relative_base,public,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(1)] spoolss_PortInfo1 info1;
+ [case(2)] spoolss_PortInfo2 info2;
+ [case(3)] spoolss_PortInfo3 info3;
+ [case(0xff)] spoolss_PortInfoFF infoFF;
+ [default];
+ } spoolss_PortInfo;
+
+ /******************/
+ /* Function: 0x23 */
+ [public,noopnum,noprint] WERROR _spoolss_EnumPorts(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPorts(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_PortInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPorts(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *count,
+ [out,ref,switch_is(level),size_is(,*count)] spoolss_PortInfo **info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x24 */
+ typedef [public,gensize] struct {
+ [relative] nstring *monitor_name;
+ } spoolss_MonitorInfo1;
+
+ typedef [public,gensize] struct {
+ [relative] nstring *monitor_name;
+ [relative] nstring *environment;
+ [relative] nstring *dll_name;
+ } spoolss_MonitorInfo2;
+
+ typedef [nodiscriminant,relative_base,public,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(1)] spoolss_MonitorInfo1 info1;
+ [case(2)] spoolss_MonitorInfo2 info2;
+ [default];
+ } spoolss_MonitorInfo;
+
+ [public,noopnum,noprint] WERROR _spoolss_EnumMonitors(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumMonitors(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_MonitorInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumMonitors(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *count,
+ [out,ref,switch_is(level),size_is(,*count)] spoolss_MonitorInfo **info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x25 */
+
+ typedef [public,gensize] struct {
+ [string,charset(UTF16)] uint16 *port_name;
+ } spoolss_SetPortInfo1;
+
+ typedef [public,gensize] struct {
+ [string,charset(UTF16)] uint16 *port_name;
+ [string,charset(UTF16)] uint16 *monitor_name;
+ [string,charset(UTF16)] uint16 *description;
+ spoolss_PortType port_type;
+ uint32 reserved;
+ } spoolss_SetPortInfo2;
+
+ typedef [public,gensize] struct {
+ spoolss_PortStatus status;
+ [string,charset(UTF16)] uint16 *status_string;
+ spoolss_PortSeverity severity;
+ } spoolss_SetPortInfo3;
+
+ typedef [public,gensize] struct {
+ [string,charset(UTF16)] uint16 *port_name;
+ DATA_BLOB monitor_data; /* relative ?? */
+ } spoolss_SetPortInfoFF;
+
+ typedef [ms_union,switch_type(uint32)] union {
+ [case(1)] spoolss_SetPortInfo1 *info1;
+ [case(2)] spoolss_SetPortInfo2 *info2;
+ [case(3)] spoolss_SetPortInfo3 *info3;
+ [case(0xff)] spoolss_SetPortInfoFF *infoFF;
+ } spoolss_SetPortInfo;
+
+ typedef [public] struct {
+ uint32 level;
+ [switch_is(level)] spoolss_SetPrinterInfo info;
+ } spoolss_SetPortInfoContainer;
+
+ WERROR spoolss_AddPort(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 unknown,
+ [in] [string,charset(UTF16)] uint16 monitor_name[]
+ );
+
+ /******************/
+ /* Function: 0x26 */
+ [todo] WERROR spoolss_ConfigurePort(
+ );
+
+ /******************/
+ /* Function: 0x27 */
+ WERROR spoolss_DeletePort(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint3264 ptr, /* ULONG_PTR */
+ [in,ref] [string,charset(UTF16)] uint16 *port_name
+ );
+
+ /******************/
+ /* Function: 0x28 */
+ WERROR spoolss_CreatePrinterIC(
+ [in,ref] policy_handle *handle,
+ [out,ref] policy_handle *gdi_handle,
+ [in,ref] spoolss_DevmodeContainer *devmode_ctr
+ );
+
+ /******************/
+ /* Function: 0x29 */
+
+ typedef struct {
+ uint32 Checksum;
+ uint32 Index;
+ } UNIVERSAL_FONT_ID;
+
+ typedef [public] struct {
+ uint32 count;
+ UNIVERSAL_FONT_ID fonts[count];
+ } UNIVERSAL_FONT_ID_ctr;
+
+ WERROR spoolss_PlayGDIScriptOnPrinterIC(
+ [in,ref] policy_handle *gdi_handle,
+ [in,ref] [size_is(cIn)] uint8 *pIn,
+ [in] uint32 cIn,
+ [out,ref] [size_is(cOut)] uint8 *pOut,
+ [in] uint32 cOut,
+ [in] uint32 ul
+ );
+
+ /******************/
+ /* Function: 0x2a */
+ WERROR spoolss_DeletePrinterIC(
+ [in,out,ref] policy_handle *gdi_handle
+ );
+
+ /******************/
+ /* Function: 0x2b */
+ [todo] WERROR spoolss_AddPrinterConnection(
+ );
+
+ /******************/
+ /* Function: 0x2c */
+ [todo] WERROR spoolss_DeletePrinterConnection(
+ );
+
+ /******************/
+ /* Function: 0x2d */
+ [todo] WERROR spoolss_PrinterMessageBox(
+ /* Marked as obsolete in MSDN. "Not necessary and has
+ no effect". */
+ );
+
+ /******************/
+ /* Function: 0x2e */
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *monitor_name;
+ } spoolss_AddMonitorInfo1;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *monitor_name;
+ [string,charset(UTF16)] uint16 *environment;
+ [string,charset(UTF16)] uint16 *dll_name;
+ } spoolss_AddMonitorInfo2;
+
+ typedef [ms_union,switch_type(uint32)] union {
+ [case(1)] spoolss_AddMonitorInfo1 *info1;
+ [case(2)] spoolss_AddMonitorInfo2 *info2;
+ } spoolss_AddMonitorInfo;
+
+ typedef [public] struct {
+ uint32 level;
+ [switch_is(level)] spoolss_MonitorInfo info;
+ } spoolss_MonitorContainer;
+
+ [todo] WERROR spoolss_AddMonitor(
+ );
+
+ /******************/
+ /* Function: 0x2f */
+ [todo] WERROR spoolss_DeleteMonitor(
+ );
+
+ /******************/
+ /* Function: 0x30 */
+ WERROR spoolss_DeletePrintProcessor(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] [string,charset(UTF16)] uint16 *architecture,
+ [in] [string,charset(UTF16)] uint16 print_processor_name[]
+ );
+
+ /******************/
+ /* Function: 0x31 */
+ [todo] WERROR spoolss_AddPrintProvidor(
+ );
+
+ /******************/
+ /* Function: 0x32 */
+ [todo] WERROR spoolss_DeletePrintProvidor(
+ );
+
+ /******************/
+ /* Function: 0x33 */
+
+ typedef [public,gensize] struct {
+ [relative] nstring *name_array;
+ } spoolss_PrintProcDataTypesInfo1;
+
+ typedef [nodiscriminant,relative_base,public,flag(NDR_RELATIVE_REVERSE)] union {
+ [case(1)] spoolss_PrintProcDataTypesInfo1 info1;
+ [default];
+ } spoolss_PrintProcDataTypesInfo;
+
+ [public,noopnum,noprint] WERROR _spoolss_EnumPrintProcessorDataTypes(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *print_processor_name,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPrintProcessorDataTypes(
+ [in] uint32 level,
+ [in] uint32 count,
+ [out,switch_is(level)] spoolss_PrintProcDataTypesInfo info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPrintProcessorDataTypes(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *print_processor_name,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *count,
+ [out,ref,switch_is(level),size_is(,*count)] spoolss_PrintProcDataTypesInfo **info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x34 */
+ WERROR spoolss_ResetPrinter(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *data_type,
+ [in,ref] spoolss_DevmodeContainer *devmode_ctr
+ );
+
+ /******************/
+ /* Function: 0x35 */
+ [public] WERROR spoolss_GetPrinterDriver2(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *architecture,
+ [in] uint32 level,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [in] uint32 client_major_version,
+ [in] uint32 client_minor_version,
+ [out,unique,subcontext(4),subcontext_size(offered),switch_is(level)] spoolss_DriverInfo *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *server_major_version,
+ [out,ref] uint32 *server_minor_version
+ );
+
+ /******************/
+ /* Function: 0x36 */
+ [todo] WERROR spoolss_FindFirstPrinterChangeNotification(
+ );
+
+ /******************/
+ /* Function: 0x37 */
+ [todo] WERROR spoolss_FindNextPrinterChangeNotification(
+ );
+
+ /******************/
+ /* Function: 0x38 */
+ [public] WERROR spoolss_FindClosePrinterNotify(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x39 */
+ [todo] WERROR spoolss_RouterFindFirstPrinterChangeNotificationOld(
+ );
+
+ /******************/
+ /* Function: 0x3a */
+ [public] WERROR spoolss_ReplyOpenPrinter(
+ [in,string,charset(UTF16)] uint16 server_name[],
+ [in] uint32 printer_local,
+ [in] winreg_Type type,
+ [in,range(0,512)] uint32 bufsize,
+ [in,unique,size_is(bufsize)] uint8 *buffer,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x3b */
+
+ typedef [bitmap32bit] bitmap {
+ PRINTER_CHANGE_ADD_PRINTER = 0x00000001,
+ PRINTER_CHANGE_SET_PRINTER = 0x00000002,
+ PRINTER_CHANGE_DELETE_PRINTER = 0x00000004,
+ PRINTER_CHANGE_FAILED_CONNECTION_PRINTER = 0x00000008,
+ PRINTER_CHANGE_ADD_JOB = 0x00000100,
+ PRINTER_CHANGE_SET_JOB = 0x00000200,
+ PRINTER_CHANGE_DELETE_JOB = 0x00000400,
+ PRINTER_CHANGE_WRITE_JOB = 0x00000800,
+ PRINTER_CHANGE_ADD_FORM = 0x00010000,
+ PRINTER_CHANGE_SET_FORM = 0x00020000,
+ PRINTER_CHANGE_DELETE_FORM = 0x00040000,
+ PRINTER_CHANGE_ADD_PORT = 0x00100000,
+ PRINTER_CHANGE_CONFIGURE_PORT = 0x00200000,
+ PRINTER_CHANGE_DELETE_PORT = 0x00400000,
+ PRINTER_CHANGE_ADD_PRINT_PROCESSOR = 0x01000000,
+ PRINTER_CHANGE_DELETE_PRINT_PROCESSOR = 0x04000000,
+ PRINTER_CHANGE_SERVER = 0x08000000,
+ PRINTER_CHANGE_ADD_PRINTER_DRIVER = 0x10000000,
+ PRINTER_CHANGE_SET_PRINTER_DRIVER = 0x20000000,
+ PRINTER_CHANGE_DELETE_PRINTER_DRIVER = 0x40000000,
+ PRINTER_CHANGE_TIMEOUT = 0x80000000
+ } spoolss_PrinterChangeFlags;
+
+ const int PRINTER_CHANGE_PRINTER = 0x000000FF;
+
+ const int PRINTER_CHANGE_JOB = 0x0000FF00;
+
+ const int PRINTER_CHANGE_FORM = (PRINTER_CHANGE_ADD_FORM |
+ PRINTER_CHANGE_SET_FORM |
+ PRINTER_CHANGE_DELETE_FORM); /* 0x00070000 */
+
+ const int PRINTER_CHANGE_PORT = (PRINTER_CHANGE_ADD_PORT |
+ PRINTER_CHANGE_CONFIGURE_PORT |
+ PRINTER_CHANGE_DELETE_PORT); /* 0x00700000 */
+
+ const int PRINTER_CHANGE_PRINT_PROCESSOR = 0x07000000;
+
+ const int PRINTER_CHANGE_PRINTER_DRIVER = (PRINTER_CHANGE_ADD_PRINTER_DRIVER |
+ PRINTER_CHANGE_SET_PRINTER_DRIVER |
+ PRINTER_CHANGE_DELETE_PRINTER_DRIVER); /* 0x70000000 */
+
+ const int PRINTER_CHANGE_ALL = (PRINTER_CHANGE_PRINTER |
+ PRINTER_CHANGE_JOB |
+ PRINTER_CHANGE_FORM |
+ PRINTER_CHANGE_PORT |
+ PRINTER_CHANGE_PRINT_PROCESSOR |
+ PRINTER_CHANGE_PRINTER_DRIVER); /* 0x7777FFFF */
+ WERROR spoolss_RouterReplyPrinter(
+ [in,ref] policy_handle *handle,
+ [in] spoolss_PrinterChangeFlags flags,
+ [in,range(0,512)] uint32 bufsize,
+ [in,unique,size_is(bufsize)] uint8 *buffer
+ );
+
+ /******************/
+ /* Function: 0x3c */
+ [public] WERROR spoolss_ReplyClosePrinter(
+ [in,out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x3d */
+
+ typedef [public] struct {
+ uint32 monitor_data_size;
+ [size_is(monitor_data_size),unique] uint8 *monitor_data;
+ } spoolss_PortVarContainer;
+
+ WERROR spoolss_AddPortEx(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,ref] spoolss_SetPortInfoContainer *port_ctr,
+ [in,ref] spoolss_PortVarContainer *port_var_ctr,
+ [in,unique] [string,charset(UTF16)] uint16 *monitor_name
+ );
+
+ /******************/
+ /* Function: 0x3e */
+ [todo] WERROR spoolss_RouterFindFirstPrinterChangeNotification(
+ );
+
+ /******************/
+ /* Function: 0x3f */
+ [todo] WERROR spoolss_SpoolerInit(
+ );
+
+ /******************/
+ /* Function: 0x40 */
+ [todo] WERROR spoolss_ResetPrinterEx(
+ );
+
+ typedef [enum16bit,public] enum {
+ JOB_NOTIFY_FIELD_PRINTER_NAME = 0x00,
+ JOB_NOTIFY_FIELD_MACHINE_NAME = 0x01,
+ JOB_NOTIFY_FIELD_PORT_NAME = 0x02,
+ JOB_NOTIFY_FIELD_USER_NAME = 0x03,
+ JOB_NOTIFY_FIELD_NOTIFY_NAME = 0x04,
+ JOB_NOTIFY_FIELD_DATATYPE = 0x05,
+ JOB_NOTIFY_FIELD_PRINT_PROCESSOR = 0x06,
+ JOB_NOTIFY_FIELD_PARAMETERS = 0x07,
+ JOB_NOTIFY_FIELD_DRIVER_NAME = 0x08,
+ JOB_NOTIFY_FIELD_DEVMODE = 0x09,
+ JOB_NOTIFY_FIELD_STATUS = 0x0a,
+ JOB_NOTIFY_FIELD_STATUS_STRING = 0x0b,
+ JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR = 0x0c,
+ JOB_NOTIFY_FIELD_DOCUMENT = 0x0d,
+ JOB_NOTIFY_FIELD_PRIORITY = 0x0e,
+ JOB_NOTIFY_FIELD_POSITION = 0x0f,
+ JOB_NOTIFY_FIELD_SUBMITTED = 0x10,
+ JOB_NOTIFY_FIELD_START_TIME = 0x11,
+ JOB_NOTIFY_FIELD_UNTIL_TIME = 0x12,
+ JOB_NOTIFY_FIELD_TIME = 0x13,
+ JOB_NOTIFY_FIELD_TOTAL_PAGES = 0x14,
+ JOB_NOTIFY_FIELD_PAGES_PRINTED = 0x15,
+ JOB_NOTIFY_FIELD_TOTAL_BYTES = 0x16,
+ JOB_NOTIFY_FIELD_BYTES_PRINTED = 0x17
+ } spoolss_JobNotifyField;
+
+ typedef [enum16bit,public] enum {
+ PRINTER_NOTIFY_FIELD_SERVER_NAME = 0x00,
+ PRINTER_NOTIFY_FIELD_PRINTER_NAME = 0x01,
+ PRINTER_NOTIFY_FIELD_SHARE_NAME = 0x02,
+ PRINTER_NOTIFY_FIELD_PORT_NAME = 0x03,
+ PRINTER_NOTIFY_FIELD_DRIVER_NAME = 0x04,
+ PRINTER_NOTIFY_FIELD_COMMENT = 0x05,
+ PRINTER_NOTIFY_FIELD_LOCATION = 0x06,
+ PRINTER_NOTIFY_FIELD_DEVMODE = 0x07,
+ PRINTER_NOTIFY_FIELD_SEPFILE = 0x08,
+ PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR = 0x09,
+ PRINTER_NOTIFY_FIELD_PARAMETERS = 0x0a,
+ PRINTER_NOTIFY_FIELD_DATATYPE = 0x0b,
+ PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR = 0x0c,
+ PRINTER_NOTIFY_FIELD_ATTRIBUTES = 0x0d,
+ PRINTER_NOTIFY_FIELD_PRIORITY = 0x0e,
+ PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY = 0x0f,
+ PRINTER_NOTIFY_FIELD_START_TIME = 0x10,
+ PRINTER_NOTIFY_FIELD_UNTIL_TIME = 0x11,
+ PRINTER_NOTIFY_FIELD_STATUS = 0x12,
+ PRINTER_NOTIFY_FIELD_STATUS_STRING = 0x13,
+ PRINTER_NOTIFY_FIELD_CJOBS = 0x14,
+ PRINTER_NOTIFY_FIELD_AVERAGE_PPM = 0x15,
+ PRINTER_NOTIFY_FIELD_TOTAL_PAGES = 0x16,
+ PRINTER_NOTIFY_FIELD_PAGES_PRINTED = 0x17,
+ PRINTER_NOTIFY_FIELD_TOTAL_BYTES = 0x18,
+ PRINTER_NOTIFY_FIELD_BYTES_PRINTED = 0x19,
+ PRINTER_NOTIFY_FIELD_OBJECT_GUID = 0x1a,
+ PRINTER_NOTIFY_FIELD_FRIENDLY_NAME = 0x1b
+ } spoolss_PrintNotifyField;
+
+ typedef [enum16bit] enum {
+ PRINTER_NOTIFY_TYPE = 0x00,
+ JOB_NOTIFY_TYPE = 0x01
+ } spoolss_NotifyType;
+
+ typedef [nodiscriminant,noprint] union {
+ [case(PRINTER_NOTIFY_TYPE)] uint16 field;
+ [case(JOB_NOTIFY_TYPE)] uint16 field;
+ [default] uint16 field;
+ } spoolss_Field;
+
+ /******************/
+ /* Function: 0x41 */
+ typedef struct {
+ spoolss_NotifyType type;
+ uint16 u1;
+ uint32 u2;
+ uint32 u3;
+ uint32 count;
+ [size_is(count),switch_is(type)] spoolss_Field *fields;
+ } spoolss_NotifyOptionType;
+
+ typedef [bitmap32bit] bitmap {
+ PRINTER_NOTIFY_OPTIONS_REFRESH = 0x00000001
+ } spoolssNotifyOptionFlags;
+
+ typedef [public] struct {
+ [value(2)] uint32 version;
+ spoolssNotifyOptionFlags flags;
+ uint32 count;
+ [size_is(count)] spoolss_NotifyOptionType *types;
+ } spoolss_NotifyOption;
+
+ [public] WERROR spoolss_RemoteFindFirstPrinterChangeNotifyEx(
+ [in,ref] policy_handle *handle,
+ [in] spoolss_PrinterChangeFlags flags,
+ [in] uint32 options,
+ [in,unique] [string,charset(UTF16)] uint16 *local_machine,
+ [in] uint32 printer_local,
+ [in,unique] spoolss_NotifyOption *notify_options
+ );
+
+ /******************/
+ /* Function: 0x42 */
+
+ typedef struct {
+ uint32 size;
+ [size_is(size/2),unique,charset(UTF16)] uint16 *string;
+ } spoolss_NotifyString;
+
+ typedef [v1_enum] enum {
+ NOTIFY_TABLE_DWORD = 0x0001,
+ NOTIFY_TABLE_STRING = 0x0002,
+ NOTIFY_TABLE_DEVMODE = 0x0003,
+ NOTIFY_TABLE_TIME = 0x0004,
+ NOTIFY_TABLE_SECURITYDESCRIPTOR = 0x0005
+ } spoolss_NotifyTable;
+
+ typedef [ms_union, switch_type(uint32)] union {
+ [case(1)] uint32 integer[2];
+ [case(2)] spoolss_NotifyString string;
+ [case(3)] spoolss_DevmodeContainer devmode;
+ [case(4)] spoolss_TimeCtr time;
+ [case(5)] sec_desc_buf sd;
+ } spoolss_NotifyData;
+
+ typedef struct {
+ spoolss_NotifyType type;
+ [switch_is(type)] spoolss_Field field;
+ spoolss_NotifyTable variable_type;
+ uint32 job_id;
+ [switch_is(variable_type)] spoolss_NotifyData data;
+ } spoolss_Notify;
+
+ typedef [public] struct {
+ [value(2)] uint32 version;
+ uint32 flags;
+ uint32 count;
+ [size_is(count)] spoolss_Notify notifies[];
+ } spoolss_NotifyInfo;
+
+ typedef [ms_union,switch_type(uint32)] union {
+ [case(0)] spoolss_NotifyInfo *info0;
+ } spoolss_ReplyPrinterInfo;
+
+ typedef [bitmap32bit] bitmap {
+ PRINTER_NOTIFY_INFO_DISCARDED = 0x00000001,
+ PRINTER_NOTIFY_INFO_DISCARDNOTED = 0x00010000,
+ PRINTER_NOTIFY_INFO_COLOR_MISMATCH = 0x00080000
+ } spoolss_PrinterNotifyFlags;
+
+ WERROR spoolss_RouterReplyPrinterEx(
+ [in,ref] policy_handle *handle,
+ [in] uint32 color,
+ [in] spoolss_PrinterChangeFlags flags,
+ [out,ref] spoolss_PrinterNotifyFlags *reply_result,
+ [in] uint32 reply_type,
+ [in,switch_is(reply_type)] spoolss_ReplyPrinterInfo info
+ );
+
+ /******************/
+ /* Function: 0x43 */
+ [public] WERROR spoolss_RouterRefreshPrinterChangeNotify(
+ [in,ref] policy_handle *handle,
+ [in] uint32 change_low,
+ [in,unique] spoolss_NotifyOption *options,
+ [out,ref] spoolss_NotifyInfo **info
+ );
+
+ /******************/
+ /* Function: 0x44 */
+ [todo] WERROR spoolss_44(
+ );
+
+ typedef struct {
+ uint32 size;
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 build;
+ spoolss_MajorVersion major;
+ spoolss_MinorVersion minor;
+ spoolss_ProcessorArchitecture processor;
+ } spoolss_UserLevel1;
+
+ typedef struct {
+ uint32 not_used;
+ } spoolss_UserLevel2;
+
+ typedef struct {
+ uint32 size;
+ uint32 flags;
+ uint32 size2;
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 build;
+ spoolss_MajorVersion major;
+ spoolss_MinorVersion minor;
+ spoolss_ProcessorArchitecture processor;
+ udlong reserved;
+ } spoolss_UserLevel3;
+
+ typedef [ms_union,switch_type(uint32)] union {
+ [case(1)] spoolss_UserLevel1 *level1;
+ [case(2)] spoolss_UserLevel2 *level2;
+ [case(3)] spoolss_UserLevel3 *level3;
+ } spoolss_UserLevel;
+
+ typedef [public] struct {
+ uint32 level;
+ [switch_is(level)] spoolss_UserLevel user_info;
+ } spoolss_UserLevelCtr;
+
+ typedef bitmap {
+ SERVER_ACCESS_ADMINISTER = 0x00000001,
+ SERVER_ACCESS_ENUMERATE = 0x00000002,
+ PRINTER_ACCESS_ADMINISTER = 0x00000004,
+ PRINTER_ACCESS_USE = 0x00000008,
+ JOB_ACCESS_ADMINISTER = 0x00000010,
+ JOB_ACCESS_READ = 0x00000020
+ } spoolss_AccessRights;
+
+ /* Access rights for print servers */
+ const int SERVER_ALL_ACCESS = SEC_STD_REQUIRED |
+ SERVER_ACCESS_ADMINISTER |
+ SERVER_ACCESS_ENUMERATE;
+
+ const int SERVER_READ = SEC_STD_READ_CONTROL |
+ SERVER_ACCESS_ENUMERATE;
+
+ const int SERVER_WRITE = STANDARD_RIGHTS_WRITE_ACCESS |
+ SERVER_ACCESS_ADMINISTER |
+ SERVER_ACCESS_ENUMERATE;
+
+ const int SERVER_EXECUTE = SEC_STD_READ_CONTROL |
+ SERVER_ACCESS_ENUMERATE;
+
+ /* Access rights for printers */
+ const int PRINTER_ALL_ACCESS = SEC_STD_REQUIRED |
+ PRINTER_ACCESS_ADMINISTER |
+ PRINTER_ACCESS_USE;
+
+ const int PRINTER_READ = SEC_STD_READ_CONTROL |
+ PRINTER_ACCESS_USE;
+
+ const int PRINTER_WRITE = STANDARD_RIGHTS_WRITE_ACCESS |
+ PRINTER_ACCESS_USE;
+
+ const int PRINTER_EXECUTE = SEC_STD_READ_CONTROL |
+ PRINTER_ACCESS_USE;
+
+ /* Access rights for jobs */
+ const int JOB_ALL_ACCESS = SEC_STD_REQUIRED |
+ JOB_ACCESS_ADMINISTER;
+
+ const int JOB_READ = SEC_STD_READ_CONTROL |
+ JOB_ACCESS_ADMINISTER;
+
+ const int JOB_WRITE = STANDARD_RIGHTS_WRITE_ACCESS |
+ JOB_ACCESS_ADMINISTER;
+
+ const int JOB_EXECUTE = SEC_STD_READ_CONTROL |
+ JOB_ACCESS_ADMINISTER;
+
+ /* ACE masks for various print permissions */
+ const int PRINTER_ACE_FULL_CONTROL = SEC_GENERIC_ALL |
+ PRINTER_ALL_ACCESS;
+
+ const int PRINTER_ACE_MANAGE_DOCUMENTS = SEC_GENERIC_ALL |
+ SEC_STD_READ_CONTROL;
+
+ const int PRINTER_ACE_PRINT = SEC_GENERIC_EXECUTE |
+ SEC_STD_READ_CONTROL |
+ PRINTER_ACCESS_USE;
+
+ /******************/
+ /* Function: 0x45 */
+ [public] WERROR spoolss_OpenPrinterEx(
+ [in,unique] [string,charset(UTF16)] uint16 *printername,
+ [in,unique] [string,charset(UTF16)] uint16 *datatype,
+ [in] spoolss_DevmodeContainer devmode_ctr,
+ [in] spoolss_AccessRights access_mask,
+ [in] spoolss_UserLevelCtr userlevel_ctr,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x46 */
+ WERROR spoolss_AddPrinterEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,ref] spoolss_SetPrinterInfoCtr *info_ctr,
+ [in,ref] spoolss_DevmodeContainer *devmode_ctr,
+ [in,ref] sec_desc_buf *secdesc_ctr,
+ [in,ref] spoolss_UserLevelCtr *userlevel_ctr,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x47 */
+ WERROR spoolss_SetPort(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,unique] [string,charset(UTF16)] uint16 *port_name,
+ [in,ref] spoolss_SetPortInfoContainer *port_ctr
+ );
+
+ /******************/
+ /* Function: 0x48 */
+ WERROR spoolss_EnumPrinterData(
+ [in,ref] policy_handle *handle,
+ [in] uint32 enum_index,
+ [out,size_is(value_offered/2),charset(UTF16)] uint16 value_name[],
+ [in] uint32 value_offered,
+ [out,ref] uint32 *value_needed,
+ [out,ref] winreg_Type *type,
+ [out,ref,size_is(data_offered),flag(LIBNDR_PRINT_ARRAY_HEX)] uint8 *data,
+ [in] uint32 data_offered,
+ [out,ref] uint32 *data_needed
+ );
+
+ /******************/
+ /* Function: 0x49 */
+ WERROR spoolss_DeletePrinterData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 value_name[]
+ );
+
+ /******************/
+ /* Function: 0x4a */
+ [todo] WERROR spoolss_4a(
+ );
+
+ /******************/
+ /* Function: 0x4b */
+ [todo] WERROR spoolss_4b(
+ );
+
+ /******************/
+ /* Function: 0x4c */
+ [todo] WERROR spoolss_4c(
+ );
+
+ /******************/
+ /* Function: 0x4d */
+ WERROR spoolss_SetPrinterDataEx(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [in] winreg_Type type,
+ [in,ref] [size_is(offered)] uint8 *data,
+ [in] uint32 offered
+ );
+
+ /******************/
+ /* Function: 0x4e */
+ WERROR spoolss_GetPrinterDataEx(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [in] [string,charset(UTF16)] uint16 value_name[],
+ [out,ref] winreg_Type *type,
+ [out,ref,size_is(offered)] uint8 *data,
+ [in] uint32 offered,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x4f */
+
+ typedef [relative_base,public,gensize] struct {
+ [relative] nstring *value_name;
+ [value(2*strlen_m_term(value_name))] uint32 value_name_len;
+ winreg_Type type;
+ [relative,subcontext(0),subcontext_size(data_length),flag(NDR_REMAINING|ndr_spoolss_PrinterEnumValues_align(r->type))] DATA_BLOB *data;
+ [value(data ? data->length : 0)] uint32 data_length;
+ } spoolss_PrinterEnumValues;
+
+ [public,noopnum,noprint] WERROR _spoolss_EnumPrinterDataEx(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [out] DATA_BLOB info,
+ [in] uint32 offered,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPrinterDataEx(
+ [in] uint32 count,
+ [out] spoolss_PrinterEnumValues info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPrinterDataEx(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [in] uint32 offered,
+ [out,ref] uint32 *count,
+ [out,ref,size_is(,*count)] spoolss_PrinterEnumValues **info,
+ [out,ref] uint32 *needed
+ );
+
+ typedef [nodiscriminant] union {
+ [case(0)];
+ [case(1)];
+ [default] nstring_array string_array;
+ } spoolss_KeyNames;
+
+ /******************/
+ /* Function: 0x50 */
+ [public] WERROR spoolss_EnumPrinterKey(
+ [in, ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [out,ref] uint32 *_ndr_size,
+ [out,ref,subcontext(0),subcontext_size(*_ndr_size*2),switch_is(*_ndr_size)] spoolss_KeyNames *key_buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x51 */
+ WERROR spoolss_DeletePrinterDataEx(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[],
+ [in] [string,charset(UTF16)] uint16 value_name[]
+ );
+
+ /******************/
+ /* Function: 0x52 */
+ WERROR spoolss_DeletePrinterKey(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 key_name[]
+ );
+
+ /******************/
+ /* Function: 0x53 */
+ [todo] WERROR spoolss_53(
+ );
+
+ /******************/
+ /* Function: 0x54 */
+ typedef [public,bitmap32bit] bitmap {
+ DPD_DELETE_UNUSED_FILES = 0x00000001,
+ DPD_DELETE_SPECIFIC_VERSION = 0x00000002,
+ DPD_DELETE_ALL_FILES = 0x00000004
+ } spoolss_DeleteDriverFlags;
+
+ WERROR spoolss_DeletePrinterDriverEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in] [string,charset(UTF16)] uint16 architecture[],
+ [in] [string,charset(UTF16)] uint16 driver[],
+ [in] spoolss_DeleteDriverFlags delete_flags,
+ [in] uint32 version
+ );
+
+ /******************/
+ /* Function: 0x55 */
+ WERROR spoolss_AddPerMachineConnection(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,ref] [string,charset(UTF16)] uint16 *printername,
+ [in,ref] [string,charset(UTF16)] uint16 *printserver,
+ [in,ref] [string,charset(UTF16)] uint16 *provider
+ );
+
+ /******************/
+ /* Function: 0x56 */
+ WERROR spoolss_DeletePerMachineConnection(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,ref] [string,charset(UTF16)] uint16 *printername
+ );
+
+ /******************/
+ /* Function: 0x57 */
+ [public,noopnum,noprint] WERROR _spoolss_EnumPerMachineConnections(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,unique] DATA_BLOB *info,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *count
+ );
+ [public,noopnum,noprint] void __spoolss_EnumPerMachineConnections(
+ [in] uint32 count,
+ [out] spoolss_PrinterInfo4 info[count]
+ );
+ [nopull,nopush] WERROR spoolss_EnumPerMachineConnections(
+ [in,unique] [string,charset(UTF16)] uint16 *server,
+ [in,unique] DATA_BLOB *buffer,
+ [in] uint32 offered,
+ [out,ref] uint32 *count,
+ [out,ref,size_is(,*count)] spoolss_PrinterInfo4 **info,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x58 */
+
+ typedef [v1_enum] enum {
+ PROTOCOL_RAWTCP_TYPE = 1,
+ PROTOCOL_LPR_TYPE = 2
+ } spoolss_PortProtocol;
+
+ typedef [public,gensize] struct {
+ [charset(UTF16)] uint16 portname[64];
+ [value(0x00000001)] uint32 version;
+ spoolss_PortProtocol protocol;
+ [value(ndr_size_spoolss_PortData1(r, ndr->flags))] uint32 size;
+ uint32 reserved;
+ [charset(UTF16)] uint16 hostaddress[49];
+ [charset(UTF16)] uint16 snmpcommunity[33];
+ uint32 dblspool;
+ [charset(UTF16)] uint16 queue[33];
+ [charset(UTF16)] uint16 ip_address[16]; /* s3 had 17 */
+ [charset(UTF16)] uint16 hardware_address[13];
+ [charset(UTF16)] uint16 device_type[257];
+ uint32 port_number;
+ boolean32 snmp_enabled;
+ uint32 snmp_dev_index;
+ } spoolss_PortData1;
+
+ typedef [public,gensize] struct {
+ [charset(UTF16)] uint16 portname[64];
+ [value(0x00000002)] uint32 version;
+ spoolss_PortProtocol protocol;
+ [value(ndr_size_spoolss_PortData2(r, ndr->flags))] uint32 size;
+ uint32 reserved;
+ [charset(UTF16)] uint16 hostaddress[128];
+ [charset(UTF16)] uint16 snmpcommunity[33];
+ uint32 dblspool;
+ [charset(UTF16)] uint16 queue[33];
+ [charset(UTF16)] uint16 device_type[257];
+ uint32 port_number;
+ boolean32 snmp_enabled;
+ uint32 snmp_dev_index;
+ uint32 port_monitor_mib_index;
+ } spoolss_PortData2;
+
+ typedef [public] struct {
+ nstring dll_name;
+ } spoolss_MonitorUi;
+
+ WERROR spoolss_XcvData(
+ [in,ref] policy_handle *handle,
+ [in] [string,charset(UTF16)] uint16 function_name[],
+ [in] DATA_BLOB in_data,
+ [in,value(r->in.in_data.length)] uint32 _in_data_length,
+ [out,ref] [size_is(out_data_size)] uint8 *out_data,
+ [in] uint32 out_data_size,
+ [out,ref] uint32 *needed,
+ [in,out,ref] uint32 *status_code
+ );
+
+ /******************/
+ /* Function: 0x59 */
+
+ typedef [bitmap32bit] bitmap {
+ APD_STRICT_UPGRADE = 0x00000001,
+ APD_STRICT_DOWNGRADE = 0x00000002,
+ APD_COPY_ALL_FILES = 0x00000004,
+ APD_COPY_NEW_FILES = 0x00000008,
+ APD_COPY_FROM_DIRECTORY = 0x00000010,
+ APD_DONT_COPY_FILES_TO_CLUSTER = 0x00001000,
+ APD_COPY_TO_ALL_SPOOLERS = 0x00002000,
+ APD_RETURN_BLOCKING_STATUS_CODE = 0x00010000
+ } spoolss_AddPrinterDriverExFlags;
+
+ [public] WERROR spoolss_AddPrinterDriverEx(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,ref] spoolss_AddDriverInfoCtr *info_ctr,
+ [in] spoolss_AddPrinterDriverExFlags flags
+ );
+
+ /******************/
+ /* Function: 0x5a */
+ [todo] WERROR spoolss_5a(
+ );
+
+ /******************/
+ /* Function: 0x5b */
+ [todo] WERROR spoolss_5b(
+ );
+
+ /******************/
+ /* Function: 0x5c */
+ [todo] WERROR spoolss_5c(
+ );
+
+ /******************/
+ /* Function: 0x5d */
+ [todo] WERROR spoolss_5d(
+ );
+
+ /******************/
+ /* Function: 0x5e */
+ [todo] WERROR spoolss_5e(
+ );
+
+ /******************/
+ /* Function: 0x5f */
+ [todo] WERROR spoolss_5f(
+ );
+
+ /******************/
+ /* Function: 0x60 */
+ [todo] WERROR spoolss_60(
+ );
+
+ /******************/
+ /* Function: 0x61 */
+
+ const string BIDI_ACTION_ENUM_SCHEMA = "EnumSchema";
+ const string BIDI_ACTION_GET = "Get";
+ const string BIDI_ACTION_SET = "Set";
+ const string BIDI_ACTION_GET_ALL = "GetAll";
+
+ typedef enum {
+ BIDI_NULL = 0x00000000,
+ BIDI_INT = 0x00000001,
+ BIDI_FLOAT = 0x00000002,
+ BIDI_BOOL = 0x00000003,
+ BIDI_STRING = 0x00000004,
+ BIDI_TEXT = 0x00000005,
+ BIDI_ENUM = 0x00000006,
+ BIDI_BLOB = 0x00000007
+ } BIDI_TYPE;
+
+ typedef struct {
+ uint32 cbBuf;
+ [size_is(cbBuf), unique] uint8 *pszString;
+ } RPC_BINARY_CONTAINER;
+
+ typedef [ms_union,switch_type(uint32)] union {
+ [case(BIDI_NULL)] uint32 bData;
+ [case(BIDI_BOOL)] uint32 bData;
+ [case(BIDI_INT)] uint32 iData;
+ [case(BIDI_STRING)] [unique] [string,charset(UTF16)] uint16 *sData;
+ [case(BIDI_TEXT)] [unique] [string,charset(UTF16)] uint16 *sData;
+ [case(BIDI_ENUM)] [unique] [string,charset(UTF16)] uint16 *sData;
+ /*[case(BIDI_FLOAT)] float fData;*/
+ [case(BIDI_BLOB)] RPC_BINARY_CONTAINER biData;
+ } RPC_BIDI_DATA_u;
+
+ typedef struct {
+ uint32 dwBidiType;
+ [switch_is(dwBidiType)] RPC_BIDI_DATA_u u;
+ } RPC_BIDI_DATA;
+
+ typedef struct {
+ uint32 dwReqNumber;
+ [unique] [string,charset(UTF16)] uint16 *pSchema;
+ RPC_BIDI_DATA data;
+ } RPC_BIDI_REQUEST_DATA;
+
+ typedef [public] struct {
+ [value(1)] uint32 Version;
+ uint32 Flags;
+ uint32 Count;
+ [size_is(Count), unique] RPC_BIDI_REQUEST_DATA *aData[];
+ } RPC_BIDI_REQUEST_CONTAINER;
+
+ typedef struct {
+ uint32 dwResult;
+ uint32 dwReqNumber;
+ [unique] [string,charset(UTF16)] uint16 *pSchema;
+ RPC_BIDI_DATA data;
+ } RPC_BIDI_RESPONSE_DATA;
+
+ typedef [public] struct {
+ [value(1)] uint32 Version;
+ uint32 Flags;
+ uint32 Count;
+ [size_is(Count), unique] RPC_BIDI_RESPONSE_DATA *aData[];
+ } RPC_BIDI_RESPONSE_CONTAINER;
+
+ WERROR spoolss_SendRecvBidiData(
+ [in] policy_handle hPrinter,
+ [in,unique] [string,charset(UTF16)] uint16 *pAction,
+ [in] RPC_BIDI_REQUEST_CONTAINER *pReqData,
+ [out] RPC_BIDI_RESPONSE_CONTAINER **ppRespData
+ );
+
+ /******************/
+ /* Function: 0x62 */
+ [todo] WERROR spoolss_62(
+ );
+
+ /******************/
+ /* Function: 0x63 */
+ [todo] WERROR spoolss_63(
+ );
+
+ /******************/
+ /* Function: 0x64 */
+ [todo] WERROR spoolss_64(
+ );
+
+ /******************/
+ /* Function: 0x65 */
+ [todo] WERROR spoolss_65(
+ );
+
+ /******************/
+ /* Function: 0x66 */
+
+ const string SPOOLSS_CORE_PRINT_PACKAGE_FILES_UNIDRV = "{D20EA372-DD35-4950-9ED8-A6335AFE79F0}";
+ const string SPOOLSS_CORE_PRINT_PACKAGE_FILES_PSCRIPT = "{D20EA372-DD35-4950-9ED8-A6335AFE79F1}";
+ const string SPOOLSS_CORE_PRINT_PACKAGE_FILES_PCLXL = "{D20EA372-DD35-4950-9ED8-A6335AFE79F2}";
+ const string SPOOLSS_CORE_PRINT_PACKAGE_FILES_PLOTTER = "{D20EA372-DD35-4950-9ED8-A6335AFE79F4}";
+ const string SPOOLSS_CORE_PRINT_PACKAGE_FILES_XPSDRV = "{D20EA372-DD35-4950-9ED8-A6335AFE79F5}";
+
+ typedef [public] struct {
+ GUID core_driver_guid;
+ NTTIME driver_date;
+ hyper driver_version;
+ [charset(UTF16),to_null] uint16 szPackageID[260];
+ } spoolss_CorePrinterDriver;
+
+ [public] HRESULT spoolss_GetCorePrinterDrivers(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,ref] [string,charset(UTF16)] uint16 *architecture,
+ [in] uint32 core_driver_size,
+ [in,size_is(core_driver_size)] uint16 *core_driver_dependencies,
+ [in] uint32 core_printer_driver_count,
+ [out,size_is(core_printer_driver_count)] spoolss_CorePrinterDriver *core_printer_drivers
+ );
+
+ /******************/
+ /* Function: 0x67 */
+ [todo] WERROR spoolss_67(
+ );
+
+ /******************/
+ /* Function: 0x68 */
+ HRESULT spoolss_GetPrinterDriverPackagePath(
+ [in,unique] [string,charset(UTF16)] uint16 *servername,
+ [in,ref] [string,charset(UTF16)] uint16 *architecture,
+ [in,unique] [string,charset(UTF16)] uint16 *language,
+ [in,ref] [string,charset(UTF16)] uint16 *package_id,
+ [in,out,unique,size_is(driver_package_cab_size)] [charset(UTF16)] uint16 *driver_package_cab,
+ [in] uint32 driver_package_cab_size,
+ [out,ref] uint32 *required
+ );
+
+ /******************/
+ /* Function: 0x69 */
+ [todo] WERROR spoolss_69(
+ );
+
+ /******************/
+ /* Function: 0x6a */
+ [todo] WERROR spoolss_6a(
+ );
+
+ /******************/
+ /* Function: 0x6b */
+ [todo] WERROR spoolss_6b(
+ );
+
+ /******************/
+ /* Function: 0x6c */
+ [todo] WERROR spoolss_6c(
+ );
+
+ /******************/
+ /* Function: 0x6d */
+ [todo] WERROR spoolss_6d(
+ );
+
+ /******************/
+ /* Function: 0x6e */
+
+ const string SPLFILE_CONTENT_TYPE_PROP_NAME = "Spool File Contents";
+ const string SPLFILE_CONTENT_TYPE_XPS_MS = "TYPE_XPS_MS";
+ const string SPLFILE_CONTENT_TYPE_XPS_OPEN = "TYPE_XPS_OPEN";
+ const string SPLFILE_CONTENT_TYPE_PDL_POSTSCRIPT = "TYPE_PDL_POSTSCRIPT";
+ const string SPLFILE_CONTENT_TYPE_PDL_UNKNOWN = "TYPE_PDL_UNKNOWN";
+
+ typedef enum {
+ kRpcPropertyTypeString = 1,
+ kRpcPropertyTypeInt32 = 2,
+ kRpcPropertyTypeInt64 = 3,
+ kRpcPropertyTypeByte = 4,
+ kRpcPropertyTypeBuffer = 5
+ } spoolss_EPrintPropertyType;
+
+ typedef struct {
+ uint32 cbBuf;
+ [size_is(cbBuf)] uint8 *pBuf;
+ } propertyBlob;
+
+ typedef [ms_union,switch_type(spoolss_EPrintPropertyType)] union {
+ [case(kRpcPropertyTypeString)] [string,charset(UTF16)] uint16 *propertyString;
+ [case(kRpcPropertyTypeInt32)] uint32 propertyInt32;
+ [case(kRpcPropertyTypeInt64)] hyper propertyInt64;
+ [case(kRpcPropertyTypeByte)] uint8 propertyByte;
+ [case(kRpcPropertyTypeBuffer)] propertyBlob propertyBlob;
+ } spoolss_PrintPropertyValueUnion;
+
+ typedef [public] struct {
+ spoolss_EPrintPropertyType ePropertyType;
+ [switch_is(ePropertyType)] spoolss_PrintPropertyValueUnion value;
+ } spoolss_PrintPropertyValue;
+
+ typedef [public] struct {
+ [string,charset(UTF16)] uint16 *propertyName;
+ spoolss_PrintPropertyValue propertyValue;
+ } spoolss_PrintNamedProperty;
+
+ WERROR spoolss_GetJobNamedPropertyValue(
+ [in,ref] policy_handle *hPrinter,
+ [in] uint32 JobId,
+ [in] [string,charset(UTF16)] uint16 *pszName,
+ [out,ref] spoolss_PrintPropertyValue *pValue
+ );
+
+ /******************/
+ /* Function: 0x6f */
+ [public] WERROR spoolss_SetJobNamedProperty(
+ [in,ref] policy_handle *hPrinter,
+ [in] uint32 JobId,
+ [in,ref] spoolss_PrintNamedProperty *pProperty
+ );
+
+ /******************/
+ /* Function: 0x70 */
+ WERROR spoolss_DeleteJobNamedProperty(
+ [in,ref] policy_handle *hPrinter,
+ [in] uint32 JobId,
+ [in] [string,charset(UTF16)] uint16 *pszName
+ );
+
+ /******************/
+ /* Function: 0x71 */
+ WERROR spoolss_EnumJobNamedProperties(
+ [in,ref] policy_handle *hPrinter,
+ [in] uint32 JobId,
+ [out,ref] uint32 *pcProperties,
+ [out,ref,size_is(,*pcProperties)] spoolss_PrintNamedProperty **ppProperties
+ );
+
+ /******************/
+ /* Function: 0x72 */
+ [todo] WERROR spoolss_72(
+ );
+
+ /******************/
+ /* Function: 0x73 */
+ [todo] WERROR spoolss_73(
+ );
+
+ /******************/
+ /* Function: 0x71 */
+ typedef enum {
+ kInvalidJobState = 0,
+ kLogJobPrinted = 1,
+ kLogJobRendered = 2,
+ kLogJobError = 3,
+ kLogJobPipelineError = 4,
+ kLogOfflineFileFull = 5
+ } EBranchOfficeJobEventType;
+
+ typedef struct {
+ DWORD Status;
+ [string,charset(UTF16)] uint16 *pDocumentName;
+ [string,charset(UTF16)] uint16 *pUserName;
+ [string,charset(UTF16)] uint16 *pMachineName;
+ [string,charset(UTF16)] uint16 *pPrinterName;
+ [string,charset(UTF16)] uint16 *pPortName;
+ hyper Size;
+ DWORD TotalPages;
+ } spoolss_BranchOfficeJobDataPrinted;
+
+ typedef struct {
+ hyper Size;
+ DWORD ICMMethod;
+ short Color;
+ short PrintQuality;
+ short YResolution;
+ short Copies;
+ short TTOption;
+ } spoolss_BranchOfficeJobDataRendered;
+
+ typedef struct {
+ WERROR LastError;
+ [string,charset(UTF16)] uint16 *pDocumentName;
+ [string,charset(UTF16)] uint16 *pUserName;
+ [string,charset(UTF16)] uint16 *pPrinterName;
+ [string,charset(UTF16)] uint16 *pDataType;
+ hyper TotalSize;
+ hyper PrintedSize;
+ DWORD TotalPages;
+ DWORD PrintedPages;
+ [string,charset(UTF16)] uint16 *pMachineName;
+ [string,charset(UTF16)] uint16 *pJobError;
+ [string,charset(UTF16)] uint16 *pErrorDescription;
+ } spoolss_BranchOfficeJobDataError;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *pDocumentName;
+ [string,charset(UTF16)] uint16 *pPrinterName;
+ [string,charset(UTF16)] uint16 *pExtraErrorInfo;
+ } spoolss_BranchOfficeJobDataPipelineFailed;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *pMachineName;
+ } spoolss_BranchOfficeLogOfflineFileFull;
+
+ typedef [ms_union,switch_type(EBranchOfficeJobEventType)] union {
+ [case(kLogJobPrinted)]
+ spoolss_BranchOfficeJobDataPrinted LogJobPrinted;
+ [case(kLogJobRendered)]
+ spoolss_BranchOfficeJobDataRendered LogJobRendered;
+ [case(kLogJobError)]
+ spoolss_BranchOfficeJobDataError LogJobError;
+ [case(kLogJobPipelineError)]
+ spoolss_BranchOfficeJobDataPipelineFailed LogPipelineFailed;
+ [case(kLogOfflineFileFull)]
+ spoolss_BranchOfficeLogOfflineFileFull LogOfflineFileFull;
+ } spoolss_BranchOfficeJobInfo;
+
+ typedef struct {
+ EBranchOfficeJobEventType eEventType;
+ DWORD JobId;
+ [switch_is(eEventType)] spoolss_BranchOfficeJobInfo JobInfo;
+ } spoolss_BranchOfficeJobData;
+
+ typedef [public] struct {
+ DWORD cJobDataEntries;
+ [size_is(cJobDataEntries)] spoolss_BranchOfficeJobData JobData[];
+ } spoolss_BranchOfficeJobDataContainer;
+
+ WERROR spoolss_LogJobInfoForBranchOffice(
+ [in,ref] policy_handle *hPrinter,
+ [in,ref] spoolss_BranchOfficeJobDataContainer *pBranchOfficeJobDataContainer
+ );
+
+}
diff --git a/librpc/idl/srvsvc.idl b/librpc/idl/srvsvc.idl
new file mode 100644
index 0000000..db804e5
--- /dev/null
+++ b/librpc/idl/srvsvc.idl
@@ -0,0 +1,1569 @@
+#include "idl_types.h"
+
+/*
+ srvsvc interface definitions
+*/
+import "misc.idl", "security.idl", "svcctl.idl";
+
+[ uuid("4b324fc8-1670-01d3-1278-5a47bf6ee188"),
+ version(3.0),
+ endpoint("ncacn_np:[\\pipe\\srvsvc]", "ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique),
+ helpstring("Server Service")
+] interface srvsvc
+{
+ typedef bitmap svcctl_ServerType svcctl_ServerType;
+ typedef bitmap security_secinfo security_secinfo;
+
+/**************************/
+/* srvsvc_NetCharDev */
+/**************************/
+ typedef struct {
+ [string,charset(UTF16)] uint16 *device;
+ } srvsvc_NetCharDevInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetCharDevInfo0 *array;
+ } srvsvc_NetCharDevCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *device;
+ uint32 status;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 time;
+ } srvsvc_NetCharDevInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetCharDevInfo1 *array;
+ } srvsvc_NetCharDevCtr1;
+
+ typedef union {
+ [case(0)] srvsvc_NetCharDevInfo0 *info0;
+ [case(1)] srvsvc_NetCharDevInfo1 *info1;
+ [default] ;
+ } srvsvc_NetCharDevInfo;
+
+ typedef union {
+ [case(0)] srvsvc_NetCharDevCtr0 *ctr0;
+ [case(1)] srvsvc_NetCharDevCtr1 *ctr1;
+ [default] ;
+ } srvsvc_NetCharDevCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetCharDevCtr ctr;
+ } srvsvc_NetCharDevInfoCtr;
+
+ /******************/
+ /* Function: 0x00 */
+ WERROR srvsvc_NetCharDevEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,out,ref] srvsvc_NetCharDevInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ WERROR srvsvc_NetCharDevGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 device_name[],
+ [in] uint32 level,
+ [out,ref,switch_is(level)] srvsvc_NetCharDevInfo *info
+ );
+
+ /******************/
+ /* Function: 0x02 */
+ WERROR srvsvc_NetCharDevControl(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 device_name[],
+ [in] uint32 opcode
+ );
+
+/**************************/
+/* srvsvc_NetCharDevQ */
+/**************************/
+ typedef struct {
+ [string,charset(UTF16)] uint16 *device;
+ } srvsvc_NetCharDevQInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetCharDevQInfo0 *array;
+ } srvsvc_NetCharDevQCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *device;
+ uint32 priority;
+ [string,charset(UTF16)] uint16 *devices;
+ uint32 users;
+ uint32 num_ahead;
+ } srvsvc_NetCharDevQInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetCharDevQInfo1 *array;
+ } srvsvc_NetCharDevQCtr1;
+
+ typedef union {
+ [case(0)] srvsvc_NetCharDevQInfo0 *info0;
+ [case(1)] srvsvc_NetCharDevQInfo1 *info1;
+ [default] ;
+ } srvsvc_NetCharDevQInfo;
+
+ typedef union {
+ [case(0)] srvsvc_NetCharDevQCtr0 *ctr0;
+ [case(1)] srvsvc_NetCharDevQCtr1 *ctr1;
+ [default] ;
+ } srvsvc_NetCharDevQCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetCharDevQCtr ctr;
+ } srvsvc_NetCharDevQInfoCtr;
+
+ /******************/
+ /* Function: 0x03 */
+ WERROR srvsvc_NetCharDevQEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *user,
+ [in,out,ref] srvsvc_NetCharDevQInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ WERROR srvsvc_NetCharDevQGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 queue_name[],
+ [in] [string,charset(UTF16)] uint16 user[],
+ [in] uint32 level,
+ [out,switch_is(level),ref] srvsvc_NetCharDevQInfo *info
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ WERROR srvsvc_NetCharDevQSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 queue_name[],
+ [in] uint32 level,
+ [in,switch_is(level)] srvsvc_NetCharDevQInfo info,
+ [in,out,unique] uint32 *parm_error
+ );
+
+ /******************/
+ /* Function: 0x06 */
+ WERROR srvsvc_NetCharDevQPurge(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 queue_name[]
+ );
+
+ /******************/
+ /* Function: 0x07 */
+ WERROR srvsvc_NetCharDevQPurgeSelf(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 queue_name[],
+ [in] [string,charset(UTF16)] uint16 computer_name[]
+ );
+
+/**************************/
+/* srvsvc_NetConn */
+/**************************/
+ typedef struct {
+ uint32 conn_id;
+ } srvsvc_NetConnInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetConnInfo0 *array;
+ } srvsvc_NetConnCtr0;
+
+ typedef struct {
+ uint32 conn_id;
+ uint32 conn_type;
+ uint32 num_open;
+ uint32 num_users;
+ uint32 conn_time;
+ [string,charset(UTF16)] uint16 *user;
+ [string,charset(UTF16)] uint16 *share;
+ } srvsvc_NetConnInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetConnInfo1 *array;
+ } srvsvc_NetConnCtr1;
+
+ typedef union {
+ [case(0)] srvsvc_NetConnCtr0 *ctr0;
+ [case(1)] srvsvc_NetConnCtr1 *ctr1;
+ [default] ;
+ } srvsvc_NetConnCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetConnCtr ctr;
+ } srvsvc_NetConnInfoCtr;
+
+ /******************/
+ /* Function: 0x08 */
+ WERROR srvsvc_NetConnEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *path,
+ [in,out,ref] srvsvc_NetConnInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+/**************************/
+/* srvsvc_NetFile */
+/**************************/
+ typedef struct {
+ uint32 fid;
+ } srvsvc_NetFileInfo2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetFileInfo2 *array;
+ } srvsvc_NetFileCtr2;
+
+ typedef struct {
+ uint32 fid;
+ uint32 permissions;
+ uint32 num_locks;
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *user;
+ } srvsvc_NetFileInfo3;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetFileInfo3 *array;
+ } srvsvc_NetFileCtr3;
+
+ typedef union {
+ [case(2)] srvsvc_NetFileInfo2 *info2;
+ [case(3)] srvsvc_NetFileInfo3 *info3;
+ [default] ;
+ } srvsvc_NetFileInfo;
+
+ typedef union {
+ [case(2)] srvsvc_NetFileCtr2 *ctr2;
+ [case(3)] srvsvc_NetFileCtr3 *ctr3;
+ [default] ;
+ } srvsvc_NetFileCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetFileCtr ctr;
+ } srvsvc_NetFileInfoCtr;
+
+ /******************/
+ /* Function: 0x09 */
+ WERROR srvsvc_NetFileEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *path,
+ [in,unique] [string,charset(UTF16)] uint16 *user,
+ [in,out,ref] srvsvc_NetFileInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x0a */
+ WERROR srvsvc_NetFileGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 fid,
+ [in] uint32 level,
+ [out,switch_is(level),ref] srvsvc_NetFileInfo *info
+ );
+
+ /******************/
+ /* Function: 0x0b */
+ WERROR srvsvc_NetFileClose(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 fid
+ );
+
+/**************************/
+/* srvsvc_NetSess */
+/**************************/
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ } srvsvc_NetSessInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo0 *array;
+ } srvsvc_NetSessCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 num_open;
+ uint32 time;
+ uint32 idle_time;
+ uint32 user_flags;
+ } srvsvc_NetSessInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo1 *array;
+ } srvsvc_NetSessCtr1;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 num_open;
+ uint32 time;
+ uint32 idle_time;
+ uint32 user_flags;
+ [string,charset(UTF16)] uint16 *client_type;
+ } srvsvc_NetSessInfo2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo2 *array;
+ } srvsvc_NetSessCtr2;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 time;
+ uint32 idle_time;
+ } srvsvc_NetSessInfo10;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo10 *array;
+ } srvsvc_NetSessCtr10;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *client;
+ [string,charset(UTF16)] uint16 *user;
+ uint32 num_open;
+ uint32 time;
+ uint32 idle_time;
+ uint32 user_flags;
+ [string,charset(UTF16)] uint16 *client_type;
+ [string,charset(UTF16)] uint16 *transport;
+ } srvsvc_NetSessInfo502;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetSessInfo502 *array;
+ } srvsvc_NetSessCtr502;
+
+ typedef union {
+ [case(0)] srvsvc_NetSessCtr0 *ctr0;
+ [case(1)] srvsvc_NetSessCtr1 *ctr1;
+ [case(2)] srvsvc_NetSessCtr2 *ctr2;
+ [case(10)] srvsvc_NetSessCtr10 *ctr10;
+ [case(502)] srvsvc_NetSessCtr502 *ctr502;
+ [default] ;
+ } srvsvc_NetSessCtr;
+
+ /******************/
+ /* Function: 0x0c */
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetSessCtr ctr;
+ } srvsvc_NetSessInfoCtr;
+
+ WERROR srvsvc_NetSessEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *client,
+ [in,unique] [string,charset(UTF16)] uint16 *user,
+ [in,out,ref] srvsvc_NetSessInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x0d */
+ WERROR srvsvc_NetSessDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *client,
+ [in,unique] [string,charset(UTF16)] uint16 *user
+ );
+
+/**************************/
+/* srvsvc_NetShare */
+/**************************/
+
+ /* share types */
+ const uint32 STYPE_TEMPORARY = 0x40000000; /* share is a temporary one */
+ const uint32 STYPE_HIDDEN = 0x80000000; /* share is a hidden one */
+
+ typedef [v1_enum, flag(NDR_PAHEX)] enum {
+ STYPE_DISKTREE = 0,
+ STYPE_DISKTREE_TEMPORARY = STYPE_DISKTREE|STYPE_TEMPORARY,
+ STYPE_DISKTREE_HIDDEN = STYPE_DISKTREE|STYPE_HIDDEN,
+ STYPE_PRINTQ = 1,
+ STYPE_PRINTQ_TEMPORARY = STYPE_PRINTQ|STYPE_TEMPORARY,
+ STYPE_PRINTQ_HIDDEN = STYPE_PRINTQ|STYPE_HIDDEN,
+ STYPE_DEVICE = 2, /* Serial device */
+ STYPE_DEVICE_TEMPORARY = STYPE_DEVICE|STYPE_TEMPORARY,
+ STYPE_DEVICE_HIDDEN = STYPE_DEVICE|STYPE_HIDDEN,
+ STYPE_IPC = 3, /* Interprocess communication (IPC) */
+ STYPE_IPC_TEMPORARY = STYPE_IPC|STYPE_TEMPORARY,
+ STYPE_IPC_HIDDEN = STYPE_IPC|STYPE_HIDDEN,
+ STYPE_CLUSTER_FS = 0x02000000, /* A cluster share */
+ STYPE_CLUSTER_FS_TEMPORARY = STYPE_CLUSTER_FS|STYPE_TEMPORARY,
+ STYPE_CLUSTER_FS_HIDDEN = STYPE_CLUSTER_FS|STYPE_HIDDEN,
+ STYPE_CLUSTER_SOFS = 0x04000000, /* A Scale-Out cluster share */
+ STYPE_CLUSTER_SOFS_TEMPORARY = STYPE_CLUSTER_SOFS|STYPE_TEMPORARY,
+ STYPE_CLUSTER_SOFS_HIDDEN = STYPE_CLUSTER_SOFS|STYPE_HIDDEN,
+ STYPE_CLUSTER_DFS = 0x08000000, /* A DFS share in a cluster */
+ STYPE_CLUSTER_DFS_TEMPORARY = STYPE_CLUSTER_DFS|STYPE_TEMPORARY,
+ STYPE_CLUSTER_DFS_HIDDEN = STYPE_CLUSTER_DFS|STYPE_HIDDEN
+ } srvsvc_ShareType;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ } srvsvc_NetShareInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo0 *array;
+ } srvsvc_NetShareCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ srvsvc_ShareType type;
+ [string,charset(UTF16)] uint16 *comment;
+ } srvsvc_NetShareInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1 *array;
+ } srvsvc_NetShareCtr1;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ srvsvc_ShareType type;
+ [string,charset(UTF16)] uint16 *comment;
+ uint32 permissions;
+ uint32 max_users;
+ uint32 current_users;
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *password;
+ } srvsvc_NetShareInfo2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo2 *array;
+ } srvsvc_NetShareCtr2;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ srvsvc_ShareType type;
+ [string,charset(UTF16)] uint16 *comment;
+ uint32 csc_policy;
+ } srvsvc_NetShareInfo501;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo501 *array;
+ } srvsvc_NetShareCtr501;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *name;
+ srvsvc_ShareType type;
+ [string,charset(UTF16)] uint16 *comment;
+ uint32 permissions;
+ uint32 max_users;
+ uint32 current_users;
+ [string,charset(UTF16)] uint16 *path;
+ [string,charset(UTF16)] uint16 *password;
+ sec_desc_buf sd_buf;
+ } srvsvc_NetShareInfo502;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo502 *array;
+ } srvsvc_NetShareCtr502;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *comment;
+ } srvsvc_NetShareInfo1004;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1004 *array;
+ } srvsvc_NetShareCtr1004;
+
+ const uint32 SHARE_1005_CSC_CACHE_MANUAL_REINT = 0x00000000;
+
+ typedef bitmap {
+ SHARE_1005_IN_DFS = 0x00000001,
+ SHARE_1005_DFS_ROOT = 0x00000002,
+ SHARE_1005_CSC_CACHE_AUTO_REINT = 0x00000010,
+ SHARE_1005_CSC_CACHE_VDO = 0x00000020,
+ SHARE_1005_CSC_CACHE_NONE = 0x00000030,
+ SHARE_1005_RESTRICT_EXCLUSIVE_OPENS = 0x00000100,
+ SHARE_1005_FORCE_SHARED_DELETE = 0x00000200,
+ SHARE_1005_ALLOW_NAMESPACE_CACHING = 0x00000400,
+ SHARE_1005_ACCESS_BASED_DIRECTORY_ENUM = 0x00000800,
+ SHARE_1005_FORCE_LEVELII_OPLOCK = 0x00001000,
+ SHARE_1005_ENABLE_HASH = 0x00002000,
+ SHARE_1005_ENABLE_CA = 0x00004000,
+ SHARE_1005_ENCRYPT_DATA = 0x00008000
+ } NetShareInfo1005Flags;
+
+ const uint32 SHARE_1005_CSC_POLICY_MASK = 0x00000030;
+ const uint32 SHARE_1005_CSC_POLICY_SHIFT = 4;
+
+ typedef struct {
+ NetShareInfo1005Flags dfs_flags;
+ } srvsvc_NetShareInfo1005;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1005 *array;
+ } srvsvc_NetShareCtr1005;
+
+ typedef struct {
+ uint32 max_users;
+ } srvsvc_NetShareInfo1006;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1006 *array;
+ } srvsvc_NetShareCtr1006;
+
+ typedef struct {
+ uint32 flags;
+ [string,charset(UTF16)] uint16 *alternate_directory_name;
+ } srvsvc_NetShareInfo1007;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetShareInfo1007 *array;
+ } srvsvc_NetShareCtr1007;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] sec_desc_buf *array;
+ } srvsvc_NetShareCtr1501;
+
+ typedef union {
+ [case(0)] srvsvc_NetShareInfo0 *info0;
+ [case(1)] srvsvc_NetShareInfo1 *info1;
+ [case(2)] srvsvc_NetShareInfo2 *info2;
+ [case(501)] srvsvc_NetShareInfo501 *info501;
+ [case(502)] srvsvc_NetShareInfo502 *info502;
+ [case(1004)] srvsvc_NetShareInfo1004 *info1004;
+ [case(1005)] srvsvc_NetShareInfo1005 *info1005;
+ [case(1006)] srvsvc_NetShareInfo1006 *info1006;
+ [case(1007)] srvsvc_NetShareInfo1007 *info1007;
+ [case(1501)] sec_desc_buf *info1501;
+ [default] ;
+ } srvsvc_NetShareInfo;
+
+ typedef union {
+ [case(0)] srvsvc_NetShareCtr0 *ctr0;
+ [case(1)] srvsvc_NetShareCtr1 *ctr1;
+ [case(2)] srvsvc_NetShareCtr2 *ctr2;
+ [case(501)] srvsvc_NetShareCtr501 *ctr501;
+ [case(502)] srvsvc_NetShareCtr502 *ctr502;
+ [case(1004)] srvsvc_NetShareCtr1004 *ctr1004;
+ [case(1005)] srvsvc_NetShareCtr1005 *ctr1005;
+ [case(1006)] srvsvc_NetShareCtr1006 *ctr1006;
+ [case(1007)] srvsvc_NetShareCtr1007 *ctr1007;
+ [case(1501)] srvsvc_NetShareCtr1501 *ctr1501;
+ [default] ;
+ } srvsvc_NetShareCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetShareCtr ctr;
+ } srvsvc_NetShareInfoCtr;
+
+ /******************/
+ /* Function: 0x0e */
+ WERROR srvsvc_NetShareAdd(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] srvsvc_NetShareInfo *info,
+ [in,out,unique] uint32 *parm_error
+ );
+
+ /******************/
+ /* Function: 0x0f */
+ WERROR srvsvc_NetShareEnumAll (
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,out,ref] srvsvc_NetShareInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x10 */
+ WERROR srvsvc_NetShareGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share_name[],
+ [in] uint32 level,
+ [out,ref,switch_is(level)] srvsvc_NetShareInfo *info
+ );
+
+ /******************/
+ /* Function: 0x11 */
+ WERROR srvsvc_NetShareSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share_name[],
+ [in] uint32 level,
+ [in,ref,switch_is(level)] srvsvc_NetShareInfo *info,
+ [in,out,unique] uint32 *parm_error
+ );
+
+ /******************/
+ /* Function: 0x12 */
+ WERROR srvsvc_NetShareDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share_name[],
+ [in] uint32 reserved
+ );
+
+ /******************/
+ /* Function: 0x13 */
+ WERROR srvsvc_NetShareDelSticky(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share_name[],
+ [in] uint32 reserved
+ );
+
+ /******************/
+ /* Function: 0x14 */
+ WERROR srvsvc_NetShareCheck(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 device_name[],
+ [out,ref] srvsvc_ShareType *type
+ );
+
+/**************************/
+/* srvsvc_NetSrv */
+/**************************/
+ typedef [public,v1_enum] enum {
+ PLATFORM_ID_DOS = 300,
+ PLATFORM_ID_OS2 = 400,
+ PLATFORM_ID_NT = 500,
+ PLATFORM_ID_OSF = 600,
+ PLATFORM_ID_VMS = 700
+ } srvsvc_PlatformId;
+
+ typedef [public] struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ } srvsvc_NetSrvInfo100;
+
+ typedef [public] struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ uint32 version_major;
+ uint32 version_minor;
+ svcctl_ServerType server_type;
+ [string,charset(UTF16)] uint16 *comment;
+ } srvsvc_NetSrvInfo101;
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ uint32 version_major;
+ uint32 version_minor;
+ svcctl_ServerType server_type;
+ [string,charset(UTF16)] uint16 *comment;
+ uint32 users;
+ uint32 disc;
+ uint32 hidden;
+ uint32 announce;
+ uint32 anndelta;
+ uint32 licenses;
+ [string,charset(UTF16)] uint16 *userpath;
+ } srvsvc_NetSrvInfo102;
+
+ typedef struct {
+ uint32 ulist_mtime;
+ uint32 glist_mtime;
+ uint32 alist_mtime;
+ [string,charset(UTF16)] uint16 *alerts;
+ uint32 security;
+ uint32 numadmin;
+ uint32 lanmask;
+ [string,charset(UTF16)] uint16 *guestaccount;
+ uint32 chdevs;
+ uint32 chdevqs;
+ uint32 chdevjobs;
+ uint32 connections;
+ uint32 shares;
+ uint32 openfiles;
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 sessreqs;
+ uint32 opensearch;
+ uint32 activelocks;
+ uint32 numreqbufs;
+ uint32 sizereqbufs;
+ uint32 numbigbufs;
+ uint32 numfiletasks;
+ uint32 alertsched;
+ uint32 erroralert;
+ uint32 logonalert;
+ uint32 accessalert;
+ uint32 diskalert;
+ uint32 netioalert;
+ uint32 maxaudits;
+ [string,charset(UTF16)] uint16 *srvheuristics;
+ } srvsvc_NetSrvInfo402;
+
+ typedef struct {
+ uint32 ulist_mtime;
+ uint32 glist_mtime;
+ uint32 alist_mtime;
+ [string,charset(UTF16)] uint16 *alerts;
+ uint32 security;
+ uint32 numadmin;
+ uint32 lanmask;
+ [string,charset(UTF16)] uint16 *guestaccount;
+ uint32 chdevs;
+ uint32 chdevqs;
+ uint32 chdevjobs;
+ uint32 connections;
+ uint32 shares;
+ uint32 openfiles;
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 sessreqs;
+ uint32 opensearch;
+ uint32 activelocks;
+ uint32 numreqbufs;
+ uint32 sizereqbufs;
+ uint32 numbigbufs;
+ uint32 numfiletasks;
+ uint32 alertsched;
+ uint32 erroralert;
+ uint32 logonalert;
+ uint32 accessalert;
+ uint32 diskalert;
+ uint32 netioalert;
+ uint32 maxaudits;
+ [string,charset(UTF16)] uint16 *srvheuristics;
+ uint32 auditedevents;
+ uint32 auditprofile;
+ [string,charset(UTF16)] uint16 *autopath;
+ } srvsvc_NetSrvInfo403;
+
+ typedef struct {
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 opensearch;
+ uint32 sizereqbufs;
+ uint32 initworkitems;
+ uint32 maxworkitems;
+ uint32 rawworkitems;
+ uint32 irpstacksize;
+ uint32 maxrawbuflen;
+ uint32 sessusers;
+ uint32 sessconns;
+ uint32 maxpagedmemoryusage;
+ uint32 maxnonpagedmemoryusage;
+ uint32 enablesoftcompat;
+ uint32 enableforcedlogoff;
+ uint32 timesource;
+ uint32 acceptdownlevelapis;
+ uint32 lmannounce;
+ } srvsvc_NetSrvInfo502;
+
+ typedef struct{
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 opensearch;
+ uint32 sizereqbufs;
+ uint32 initworkitems;
+ uint32 maxworkitems;
+ uint32 rawworkitems;
+ uint32 irpstacksize;
+ uint32 maxrawbuflen;
+ uint32 sessusers;
+ uint32 sessconns;
+ uint32 maxpagedmemoryusage;
+ uint32 maxnonpagedmemoryusage;
+ uint32 enablesoftcompat;
+ uint32 enableforcedlogoff;
+ uint32 timesource;
+ uint32 acceptdownlevelapis;
+ uint32 lmannounce;
+ [string,charset(UTF16)] uint16 *domain;
+ uint32 maxcopyreadlen;
+ uint32 maxcopywritelen;
+ uint32 minkeepsearch;
+ uint32 maxkeepsearch;
+ uint32 minkeepcomplsearch;
+ uint32 maxkeepcomplsearch;
+ uint32 threadcountadd;
+ uint32 numlockthreads;
+ uint32 scavtimeout;
+ uint32 minrcvqueue;
+ uint32 minfreeworkitems;
+ uint32 xactmemsize;
+ uint32 threadpriority;
+ uint32 maxmpxct;
+ uint32 oplockbreakwait;
+ uint32 oplockbreakresponsewait;
+ uint32 enableoplocks;
+ uint32 enableoplockforceclose;
+ uint32 enablefcbopens;
+ uint32 enableraw;
+ uint32 enablesharednetdrives;
+ uint32 minfreeconnections;
+ uint32 maxfreeconnections;
+ } srvsvc_NetSrvInfo503;
+
+ typedef struct{
+ uint32 sessopen;
+ uint32 sesssvc;
+ uint32 opensearch;
+ uint32 sizereqbufs;
+ uint32 initworkitems;
+ uint32 maxworkitems;
+ uint32 rawworkitems;
+ uint32 irpstacksize;
+ uint32 maxrawbuflen;
+ uint32 sessusers;
+ uint32 sessconns;
+ uint32 maxpagedmemoryusage;
+ uint32 maxnonpagedmemoryusage;
+ uint32 enablesoftcompat;
+ uint32 enableforcedlogoff;
+ uint32 timesource;
+ uint32 acceptdownlevelapis;
+ uint32 lmannounce;
+ [string,charset(UTF16)] uint16 *domain;
+ uint32 maxcopyreadlen;
+ uint32 maxcopywritelen;
+ uint32 minkeepsearch;
+ uint32 minkeepcomplsearch;
+ uint32 maxkeepcomplsearch;
+ uint32 threadcountadd;
+ uint32 numlockthreads;
+ uint32 scavtimeout;
+ uint32 minrcvqueue;
+ uint32 minfreeworkitems;
+ uint32 xactmemsize;
+ uint32 threadpriority;
+ uint32 maxmpxct;
+ uint32 oplockbreakwait;
+ uint32 oplockbreakresponsewait;
+ uint32 enableoplocks;
+ uint32 enableoplockforceclose;
+ uint32 enablefcbopens;
+ uint32 enableraw;
+ uint32 enablesharednetdrives;
+ uint32 minfreeconnections;
+ uint32 maxfreeconnections;
+ uint32 initsesstable;
+ uint32 initconntable;
+ uint32 initfiletable;
+ uint32 initsearchtable;
+ uint32 alertsched;
+ uint32 errortreshold;
+ uint32 networkerrortreshold;
+ uint32 diskspacetreshold;
+ uint32 reserved;
+ uint32 maxlinkdelay;
+ uint32 minlinkthroughput;
+ uint32 linkinfovalidtime;
+ uint32 scavqosinfoupdatetime;
+ uint32 maxworkitemidletime;
+ } srvsvc_NetSrvInfo599;
+
+ typedef struct{
+ [string,charset(UTF16)] uint16 *comment;
+ } srvsvc_NetSrvInfo1005;
+
+ typedef struct{
+ uint32 disc;
+ } srvsvc_NetSrvInfo1010;
+
+ typedef struct{
+ uint32 hidden;
+ } srvsvc_NetSrvInfo1016;
+
+ typedef struct{
+ uint32 announce;
+ } srvsvc_NetSrvInfo1017;
+
+ typedef struct{
+ uint32 anndelta;
+ } srvsvc_NetSrvInfo1018;
+
+ typedef struct{
+ uint32 users;
+ } srvsvc_NetSrvInfo1107;
+
+ typedef struct{
+ uint32 sessopens;
+ } srvsvc_NetSrvInfo1501;
+
+ typedef struct{
+ uint32 sessvcs;
+ } srvsvc_NetSrvInfo1502;
+
+ typedef struct{
+ uint32 opensearch;
+ } srvsvc_NetSrvInfo1503;
+
+ typedef struct{
+ uint32 maxworkitems;
+ } srvsvc_NetSrvInfo1506;
+
+ typedef struct{
+ uint32 maxrawbuflen;
+ } srvsvc_NetSrvInfo1509;
+
+ typedef struct{
+ uint32 sessusers;
+ } srvsvc_NetSrvInfo1510;
+
+ typedef struct{
+ uint32 sesscons;
+ } srvsvc_NetSrvInfo1511;
+
+ typedef struct{
+ uint32 maxnonpagedmemoryusage;
+ } srvsvc_NetSrvInfo1512;
+
+ typedef struct{
+ uint32 maxpagedmemoryusage;
+ } srvsvc_NetSrvInfo1513;
+
+ typedef struct{
+ uint32 enablesoftcompat;
+ } srvsvc_NetSrvInfo1514;
+
+ typedef struct{
+ uint32 enableforcedlogoff;
+ } srvsvc_NetSrvInfo1515;
+
+ typedef struct{
+ uint32 timesource;
+ } srvsvc_NetSrvInfo1516;
+
+ typedef struct{
+ uint32 lmannounce;
+ } srvsvc_NetSrvInfo1518;
+
+ typedef struct{
+ uint32 maxcopyreadlen;
+ } srvsvc_NetSrvInfo1520;
+
+ typedef struct{
+ uint32 maxcopywritelen;
+ } srvsvc_NetSrvInfo1521;
+
+ typedef struct{
+ uint32 minkeepsearch;
+ } srvsvc_NetSrvInfo1522;
+
+ typedef struct{
+ uint32 maxkeepsearch;
+ } srvsvc_NetSrvInfo1523;
+
+ typedef struct{
+ uint32 minkeepcomplsearch;
+ } srvsvc_NetSrvInfo1524;
+
+ typedef struct{
+ uint32 maxkeepcomplsearch;
+ } srvsvc_NetSrvInfo1525;
+
+ typedef struct{
+ uint32 scavtimeout;
+ } srvsvc_NetSrvInfo1528;
+
+ typedef struct{
+ uint32 minrcvqueue;
+ } srvsvc_NetSrvInfo1529;
+
+ typedef struct{
+ uint32 minfreeworkitems;
+ } srvsvc_NetSrvInfo1530;
+
+ typedef struct{
+ uint32 maxmpxct;
+ } srvsvc_NetSrvInfo1533;
+
+ typedef struct{
+ uint32 oplockbreakwait;
+ } srvsvc_NetSrvInfo1534;
+
+ typedef struct{
+ uint32 oplockbreakresponsewait;
+ } srvsvc_NetSrvInfo1535;
+
+ typedef struct{
+ uint32 enableoplocks;
+ } srvsvc_NetSrvInfo1536;
+
+ typedef struct{
+ uint32 enableoplockforceclose;
+ } srvsvc_NetSrvInfo1537;
+
+ typedef struct{
+ uint32 enablefcbopens;
+ } srvsvc_NetSrvInfo1538;
+
+ typedef struct{
+ uint32 enableraw;
+ } srvsvc_NetSrvInfo1539;
+
+ typedef struct{
+ uint32 enablesharednetdrives;
+ } srvsvc_NetSrvInfo1540;
+
+ typedef struct{
+ uint32 minfreeconnections;
+ } srvsvc_NetSrvInfo1541;
+
+ typedef struct{
+ uint32 maxfreeconnections;
+ } srvsvc_NetSrvInfo1542;
+
+ typedef struct{
+ uint32 initsesstable;
+ } srvsvc_NetSrvInfo1543;
+
+ typedef struct{
+ uint32 initconntable;
+ } srvsvc_NetSrvInfo1544;
+
+ typedef struct{
+ uint32 initfiletable;
+ } srvsvc_NetSrvInfo1545;
+
+ typedef struct{
+ uint32 initsearchtable;
+ } srvsvc_NetSrvInfo1546;
+
+ typedef struct{
+ uint32 alertsched;
+ } srvsvc_NetSrvInfo1547;
+
+ typedef struct{
+ uint32 errortreshold;
+ } srvsvc_NetSrvInfo1548;
+
+ typedef struct{
+ uint32 networkerrortreshold;
+ } srvsvc_NetSrvInfo1549;
+
+ typedef struct{
+ uint32 diskspacetreshold;
+ } srvsvc_NetSrvInfo1550;
+
+ typedef struct{
+ uint32 maxlinkdelay;
+ } srvsvc_NetSrvInfo1552;
+
+ typedef struct{
+ uint32 minlinkthroughput;
+ } srvsvc_NetSrvInfo1553;
+
+ typedef struct{
+ uint32 linkinfovalidtime;
+ } srvsvc_NetSrvInfo1554;
+
+ typedef struct{
+ uint32 scavqosinfoupdatetime;
+ } srvsvc_NetSrvInfo1555;
+
+ typedef struct{
+ uint32 maxworkitemidletime;
+ } srvsvc_NetSrvInfo1556;
+
+
+ typedef union{
+ [case(100)] srvsvc_NetSrvInfo100 *info100;
+ [case(101)] srvsvc_NetSrvInfo101 *info101;
+ [case(102)] srvsvc_NetSrvInfo102 *info102;
+ [case(402)] srvsvc_NetSrvInfo402 *info402;
+ [case(403)] srvsvc_NetSrvInfo403 *info403;
+ [case(502)] srvsvc_NetSrvInfo502 *info502;
+ [case(503)] srvsvc_NetSrvInfo503 *info503;
+ [case(599)] srvsvc_NetSrvInfo599 *info599;
+ [case(1005)] srvsvc_NetSrvInfo1005 *info1005;
+ [case(1010)] srvsvc_NetSrvInfo1010 *info1010;
+ [case(1016)] srvsvc_NetSrvInfo1016 *info1016;
+ [case(1017)] srvsvc_NetSrvInfo1017 *info1017;
+ [case(1018)] srvsvc_NetSrvInfo1018 *info1018;
+ [case(1107)] srvsvc_NetSrvInfo1107 *info1107;
+ [case(1501)] srvsvc_NetSrvInfo1501 *info1501;
+ [case(1502)] srvsvc_NetSrvInfo1502 *info1502;
+ [case(1503)] srvsvc_NetSrvInfo1503 *info1503;
+ [case(1506)] srvsvc_NetSrvInfo1506 *info1506;
+ [case(1509)] srvsvc_NetSrvInfo1509 *info1509;
+ [case(1510)] srvsvc_NetSrvInfo1510 *info1510;
+ [case(1511)] srvsvc_NetSrvInfo1511 *info1511;
+ [case(1512)] srvsvc_NetSrvInfo1512 *info1512;
+ [case(1513)] srvsvc_NetSrvInfo1513 *info1513;
+ [case(1514)] srvsvc_NetSrvInfo1514 *info1514;
+ [case(1515)] srvsvc_NetSrvInfo1515 *info1515;
+ [case(1516)] srvsvc_NetSrvInfo1516 *info1516;
+ [case(1518)] srvsvc_NetSrvInfo1518 *info1518;
+ [case(1520)] srvsvc_NetSrvInfo1520 *info1520;
+ [case(1521)] srvsvc_NetSrvInfo1521 *info1521;
+ [case(1522)] srvsvc_NetSrvInfo1522 *info1522;
+ [case(1523)] srvsvc_NetSrvInfo1523 *info1523;
+ [case(1524)] srvsvc_NetSrvInfo1524 *info1524;
+ [case(1525)] srvsvc_NetSrvInfo1525 *info1525;
+ [case(1528)] srvsvc_NetSrvInfo1528 *info1528;
+ [case(1529)] srvsvc_NetSrvInfo1529 *info1529;
+ [case(1530)] srvsvc_NetSrvInfo1530 *info1530;
+ [case(1533)] srvsvc_NetSrvInfo1533 *info1533;
+ [case(1534)] srvsvc_NetSrvInfo1534 *info1534;
+ [case(1535)] srvsvc_NetSrvInfo1535 *info1535;
+ [case(1536)] srvsvc_NetSrvInfo1536 *info1536;
+ [case(1537)] srvsvc_NetSrvInfo1537 *info1537;
+ [case(1538)] srvsvc_NetSrvInfo1538 *info1538;
+ [case(1539)] srvsvc_NetSrvInfo1539 *info1539;
+ [case(1540)] srvsvc_NetSrvInfo1540 *info1540;
+ [case(1541)] srvsvc_NetSrvInfo1541 *info1541;
+ [case(1542)] srvsvc_NetSrvInfo1542 *info1542;
+ [case(1543)] srvsvc_NetSrvInfo1543 *info1543;
+ [case(1544)] srvsvc_NetSrvInfo1544 *info1544;
+ [case(1545)] srvsvc_NetSrvInfo1545 *info1545;
+ [case(1546)] srvsvc_NetSrvInfo1546 *info1546;
+ [case(1547)] srvsvc_NetSrvInfo1547 *info1547;
+ [case(1548)] srvsvc_NetSrvInfo1548 *info1548;
+ [case(1549)] srvsvc_NetSrvInfo1549 *info1549;
+ [case(1550)] srvsvc_NetSrvInfo1550 *info1550;
+ [case(1552)] srvsvc_NetSrvInfo1552 *info1552;
+ [case(1553)] srvsvc_NetSrvInfo1553 *info1553;
+ [case(1554)] srvsvc_NetSrvInfo1554 *info1554;
+ [case(1555)] srvsvc_NetSrvInfo1555 *info1555;
+ [case(1556)] srvsvc_NetSrvInfo1556 *info1556;
+ [default];
+ } srvsvc_NetSrvInfo;
+
+ /******************/
+ /* Function: 0x15 */
+ WERROR srvsvc_NetSrvGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [out,ref,switch_is(level)] srvsvc_NetSrvInfo *info
+ );
+
+ /******************/
+ /* Function: 0x16 */
+ WERROR srvsvc_NetSrvSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,ref,switch_is(level)] srvsvc_NetSrvInfo *info,
+ [in,out,unique] uint32 *parm_error
+ );
+
+/**************************/
+/* srvsvc_NetDisk */
+/**************************/
+ typedef struct {
+ /*
+ * In theory this should be:
+ * [charset(UTF16),string] uint16 annotation[3]
+ * But midl treats this as:
+ * [charset(UTF16),string] uint16 annotation[]
+ * and pidl doesn't support this yet
+ */
+ [value(0)] uint32 __disk_offset;
+ [value(strlen(disk)+1)] uint32 __disk_length;
+ [charset(UTF16)] uint16 disk[__disk_length];
+ } srvsvc_NetDiskInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count), length_is(count)] srvsvc_NetDiskInfo0 *disks;
+ } srvsvc_NetDiskInfo;
+
+ /******************/
+ /* Function: 0x17 */
+ WERROR srvsvc_NetDiskEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,out,ref] srvsvc_NetDiskInfo *info,
+ [in] uint32 maxlen,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+/**************************/
+/* srvsvc_NetStatistics */
+/**************************/
+ typedef struct {
+ uint32 start;
+ uint32 fopens;
+ uint32 devopens;
+ uint32 jobsqueued;
+ uint32 sopens;
+ uint32 stimeouts;
+ uint32 serrorout;
+ uint32 pwerrors;
+ uint32 permerrors;
+ uint32 syserrors;
+ uint32 bytessent_low;
+ uint32 bytessent_high;
+ uint32 bytesrcvd_low;
+ uint32 bytesrcvd_high;
+ uint32 avresponse;
+ uint32 reqbufneed;
+ uint32 bigbufneed;
+ } srvsvc_Statistics;
+
+ /******************/
+ /* Function: 0x18 */
+ WERROR srvsvc_NetServerStatisticsGet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *service,
+ [in] uint32 level,
+ [in] uint32 options,
+ [out,ref] srvsvc_Statistics **stats
+ );
+
+/**************************/
+/* srvsvc_NetTransport */
+/**************************/
+ typedef struct {
+ uint32 vcs;
+ [string,charset(UTF16)] uint16 *name;
+ [size_is(addr_len)] uint8 *addr;
+ uint32 addr_len;
+ [string,charset(UTF16)] uint16 *net_addr;
+ } srvsvc_NetTransportInfo0;
+
+ /******************/
+ /* Function: 0x19 */
+ WERROR srvsvc_NetTransportAdd(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,switch_is(level)] srvsvc_NetTransportInfo info
+ );
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetTransportInfo0 *array;
+ } srvsvc_NetTransportCtr0;
+
+ typedef struct {
+ uint32 vcs;
+ [string,charset(UTF16)] uint16 *name;
+ [size_is(addr_len)] uint8 *addr;
+ uint32 addr_len;
+ [string,charset(UTF16)] uint16 *net_addr;
+ [string,charset(UTF16)] uint16 *domain;
+ } srvsvc_NetTransportInfo1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetTransportInfo1 *array;
+ } srvsvc_NetTransportCtr1;
+
+ typedef struct {
+ uint32 vcs;
+ [string,charset(UTF16)] uint16 *name;
+ [size_is(addr_len)] uint8 *addr;
+ uint32 addr_len;
+ [string,charset(UTF16)] uint16 *net_addr;
+ [string,charset(UTF16)] uint16 *domain;
+ uint32 unknown;
+ } srvsvc_NetTransportInfo2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetTransportInfo2 *array;
+ } srvsvc_NetTransportCtr2;
+
+ typedef struct {
+ uint32 vcs;
+ [string,charset(UTF16)] uint16 *name;
+ [size_is(addr_len)] uint8 *addr;
+ uint32 addr_len;
+ [string,charset(UTF16)] uint16 *net_addr;
+ [string,charset(UTF16)] uint16 *domain;
+ uint32 unknown1;
+ uint32 unknown2;
+ uint8 unknown3[256];
+ } srvsvc_NetTransportInfo3;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] srvsvc_NetTransportInfo3 *array;
+ } srvsvc_NetTransportCtr3;
+
+ typedef union {
+ [case(0)] srvsvc_NetTransportCtr0 *ctr0;
+ [case(1)] srvsvc_NetTransportCtr1 *ctr1;
+ [case(2)] srvsvc_NetTransportCtr2 *ctr2;
+ [case(3)] srvsvc_NetTransportCtr3 *ctr3;
+ [default];
+ } srvsvc_NetTransportCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] srvsvc_NetTransportCtr ctr;
+ } srvsvc_NetTransportInfoCtr;
+
+ /******************/
+ /* Function: 0x1a */
+ WERROR srvsvc_NetTransportEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,out,ref] srvsvc_NetTransportInfoCtr *transports,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x1b */
+ WERROR srvsvc_NetTransportDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in] srvsvc_NetTransportInfo0 *info0
+ );
+
+/**************************/
+/* srvsvc_NetRemoteTOD */
+/**************************/
+ typedef struct {
+ uint32 elapsed; /* time(NULL) */
+ uint32 msecs; /* milliseconds till system reboot (uptime) */
+ uint32 hours;
+ uint32 mins;
+ uint32 secs;
+ uint32 hunds;
+ int32 timezone; /* in minutes */
+ uint32 tinterval; /* clock tick interval in 0.0001 second units; 310 on windows */
+ uint32 day;
+ uint32 month;
+ uint32 year;
+ uint32 weekday;
+ } srvsvc_NetRemoteTODInfo;
+
+ /******************/
+ /* Function: 0x1c */
+ WERROR srvsvc_NetRemoteTOD(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [out,ref] srvsvc_NetRemoteTODInfo **info
+ );
+
+/**************************/
+/* srvsvc_NetServiceBits */
+/**************************/
+ /******************/
+ /* Function: 0x1d */
+ WERROR srvsvc_NetSetServiceBits(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *transport,
+ [in] uint32 servicebits,
+ [in] uint32 updateimmediately
+ );
+
+/**************************/
+/* srvsvc_NetPath */
+/**************************/
+ /******************/
+ /* Function: 0x1e */
+ WERROR srvsvc_NetPathType(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 path[],
+ [in] uint32 pathflags,
+ [out,ref] uint32 *pathtype
+ );
+
+ /******************/
+ /* Function: 0x1f */
+ WERROR srvsvc_NetPathCanonicalize(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 path[],
+ [out] [size_is(maxbuf)] uint8 can_path[],
+ [in] uint32 maxbuf,
+ [in] [string,charset(UTF16)] uint16 prefix[],
+ [in,out,ref] uint32 *pathtype,
+ [in] uint32 pathflags
+ );
+
+ /******************/
+ /* Function: 0x20 */
+ WERROR srvsvc_NetPathCompare(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 path1[],
+ [in] [string,charset(UTF16)] uint16 path2[],
+ [in] uint32 pathtype,
+ [in] uint32 pathflags
+ );
+
+/**************************/
+/* srvsvc_NetName */
+/**************************/
+ /******************/
+ /* Function: 0x21 */
+ WERROR srvsvc_NetNameValidate(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 name[],
+ [in] uint32 name_type,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x22 */
+ [todo] WERROR srvsvc_NETRPRNAMECANONICALIZE(
+ );
+
+ /******************/
+ /* Function: 0x23 */
+ WERROR srvsvc_NetPRNameCompare(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 name1[],
+ [in] [string,charset(UTF16)] uint16 name2[],
+ [in] uint32 name_type,
+ [in] uint32 flags
+ );
+
+/**************************/
+/* srvsvc_NetShare ... */
+/**************************/
+ /******************/
+ /* Function: 0x24 */
+ /* Note, there must be some way to return entries read vs
+ total entries ... */
+ WERROR srvsvc_NetShareEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,out,ref] srvsvc_NetShareInfoCtr *info_ctr,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *totalentries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /******************/
+ /* Function: 0x25 */
+ WERROR srvsvc_NetShareDelStart(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] [string,charset(UTF16)] uint16 share[],
+ [in] uint32 reserved,
+ [out,unique] policy_handle *hnd
+ );
+
+ /******************/
+ /* Function: 0x26 */
+ WERROR srvsvc_NetShareDelCommit(
+ [in, out,unique] policy_handle *hnd
+ );
+
+ /******************/
+ /* Function: 0x27 */
+ WERROR srvsvc_NetGetFileSecurity(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *share,
+ [in] [string,charset(UTF16)] uint16 file[],
+ [in] security_secinfo securityinformation,
+ [out,ref] sec_desc_buf **sd_buf
+ );
+
+ /******************/
+ /* Function: 0x28 */
+ WERROR srvsvc_NetSetFileSecurity(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *share,
+ [in] [string,charset(UTF16)] uint16 file[],
+ [in] security_secinfo securityinformation,
+ [in,ref] sec_desc_buf *sd_buf
+ );
+
+
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] srvsvc_NetTransportInfo0 info0;
+ [case(1)] srvsvc_NetTransportInfo1 info1;
+ [case(2)] srvsvc_NetTransportInfo2 info2;
+ [case(3)] srvsvc_NetTransportInfo3 info3;
+ } srvsvc_NetTransportInfo;
+
+ /******************/
+ /* Function: 0x29 */
+ WERROR srvsvc_NetServerTransportAddEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in] uint32 level,
+ [in,switch_is(level)] srvsvc_NetTransportInfo info
+ );
+
+ /******************/
+ /* Function: 0x2a */
+ WERROR srvsvc_NetServerSetServiceBitsEx(
+ [in,unique] [string,charset(UTF16)] uint16 *server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *emulated_server_unc,
+ [in,unique] [string,charset(UTF16)] uint16 *transport,
+ [in] uint32 servicebitsofinterest,
+ [in] uint32 servicebits,
+ [in] uint32 updateimmediately
+ );
+
+ /******************/
+ /* Function: 0x2b */
+ [todo] WERROR srvsvc_NETRDFSGETVERSION(
+ );
+
+ /******************/
+ /* Function: 0x2c */
+ [todo] WERROR srvsvc_NETRDFSCREATELOCALPARTITION(
+ );
+
+ /******************/
+ /* Function: 0x2d */
+ [todo] WERROR srvsvc_NETRDFSDELETELOCALPARTITION(
+ );
+
+ /******************/
+ /* Function: 0x2e */
+ [todo] WERROR srvsvc_NETRDFSSETLOCALVOLUMESTATE(
+ );
+
+ /******************/
+ /* Function: 0x2f */
+ [todo] WERROR srvsvc_NETRDFSSETSERVERINFO(
+ );
+
+ /******************/
+ /* Function: 0x30 */
+ [todo] WERROR srvsvc_NETRDFSCREATEEXITPOINT(
+ );
+
+ /******************/
+ /* Function: 0x31 */
+ [todo] WERROR srvsvc_NETRDFSDELETEEXITPOINT(
+ );
+
+ /******************/
+ /* Function: 0x32 */
+ [todo] WERROR srvsvc_NETRDFSMODIFYPREFIX(
+ );
+
+ /******************/
+ /* Function: 0x33 */
+ [todo] WERROR srvsvc_NETRDFSFIXLOCALVOLUME(
+ );
+
+ /******************/
+ /* Function: 0x34 */
+ [todo] WERROR srvsvc_NETRDFSMANAGERREPORTSITEINFO(
+ );
+
+ /******************/
+ /* Function: 0x35 */
+ [todo] WERROR srvsvc_NETRSERVERTRANSPORTDELEX(
+ );
+}
diff --git a/librpc/idl/svcctl.idl b/librpc/idl/svcctl.idl
new file mode 100644
index 0000000..c8db99b
--- /dev/null
+++ b/librpc/idl/svcctl.idl
@@ -0,0 +1,1040 @@
+#include "idl_types.h"
+
+/*
+ svcctl interface definitions
+
+ The below was initially obtained from MS-SCMR which is
+ Copyright © 2022 Microsoft Corporation as permitted
+ by the Open Specifications terms reproduced in IDL_LICENCE.txt
+*/
+
+import "misc.idl", "security.idl";
+[ uuid("367abb81-9844-35f1-ad32-98f038001003"),
+ version(2.0),
+ pointer_default(unique),
+ ms_union,
+ endpoint("ncacn_np:[\\pipe\\svcctl]", "ncalrpc:"),
+ helper("../librpc/ndr/ndr_svcctl.h"),
+ helpstring("Service Control")
+] interface svcctl
+{
+ const int MAX_SERVICE_NAME_LENGTH = 256;
+ const short SC_MAX_DEPEND_SIZE = 4 * 1024;
+ const short SC_MAX_NAME_LENGTH = MAX_SERVICE_NAME_LENGTH + 1;
+ const short SC_MAX_PATH_LENGTH = 32 * 1024;
+ const short SC_MAX_PWD_SIZE = 514;
+ const short SC_MAX_COMPUTER_NAME_LENGTH = 1024;
+ const short SC_MAX_ACCOUNT_NAME_LENGTH = 2 * 1024;
+ const short SC_MAX_COMMENT_LENGTH = 128;
+ const short SC_MAX_ARGUMENT_LENGTH = 1024;
+ const short SC_MAX_ARGUMENTS = 1024;
+
+#define BOUNDED_DWORD_4K [range(0, 1024 * 4)] uint32
+#define BOUNDED_DWORD_8K [range(0, 1024 * 8)] uint32
+#define BOUNDED_DWORD_256K [range(0, 1024 * 256)] uint32
+
+#if 0
+ /*
+ * pidl does not yet have a real [context_handle] implementation, so we
+ * just use some defines here.
+ */
+
+ typedef [context_handle] void *SC_RPC_HANDLE;
+ typedef [context_handle] void *SC_NOTIFY_RPC_HANDLE;
+#else
+#define SC_RPC_HANDLE policy_handle
+#define SC_NOTIFY_RPC_HANDLE policy_handle
+#define handle_t policy_handle
+#endif
+ typedef struct {
+ uint32 is_locked;
+ [string,charset(UTF16)] uint16 *lock_owner;
+ uint32 lock_duration;
+ } SERVICE_LOCK_STATUS;
+
+ typedef [v1_enum] enum {
+ SVCCTL_STATE_UNKNOWN = 0x00000000, /* only used internally to smbd */
+ SVCCTL_STOPPED = 0x00000001,
+ SVCCTL_START_PENDING = 0x00000002,
+ SVCCTL_STOP_PENDING = 0x00000003,
+ SVCCTL_RUNNING = 0x00000004,
+ SVCCTL_CONTINUE_PENDING = 0x00000005,
+ SVCCTL_PAUSE_PENDING = 0x00000006,
+ SVCCTL_PAUSED = 0x00000007
+ } svcctl_ServiceStatus;
+
+ const int SVCCTL_ACCEPT_NONE = 0x00000000;
+
+ typedef [bitmap32bit] bitmap {
+ SVCCTL_ACCEPT_STOP = 0x00000001,
+ SVCCTL_ACCEPT_PAUSE_CONTINUE = 0x00000002,
+ SVCCTL_ACCEPT_SHUTDOWN = 0x00000004,
+ SVCCTL_ACCEPT_PARAMCHANGE = 0x00000008,
+ SVCCTL_ACCEPT_NETBINDCHANGE = 0x00000010,
+ SVCCTL_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020,
+ SVCCTL_ACCEPT_POWEREVENT = 0x00000040
+ } svcctl_ControlsAccepted;
+
+ typedef struct {
+ uint32 type;
+ svcctl_ServiceStatus state;
+ svcctl_ControlsAccepted controls_accepted;
+ WERROR win32_exit_code;
+ uint32 service_exit_code;
+ uint32 check_point;
+ uint32 wait_hint;
+ } SERVICE_STATUS;
+
+ typedef [public] struct {
+ SERVICE_STATUS status;
+ uint32 process_id;
+ uint32 service_flags;
+ } SERVICE_STATUS_PROCESS;
+
+ typedef [public,gensize] struct {
+ [relative] nstring *service_name;
+ [relative] nstring *display_name;
+ SERVICE_STATUS status;
+ } ENUM_SERVICE_STATUSW;
+
+ typedef [public,gensize] struct {
+ [relative] astring *service_name;
+ [relative] astring *display_name;
+ SERVICE_STATUS status;
+ } ENUM_SERVICE_STATUSA;
+
+ const int SERVICE_TYPE_KERNEL_DRIVER = 0x01;
+ const int SERVICE_TYPE_FS_DRIVER = 0x02;
+ const int SERVICE_TYPE_ADAPTER = 0x04;
+ const int SERVICE_TYPE_RECOGNIZER_DRIVER = 0x08;
+ const int SERVICE_TYPE_DRIVER=SERVICE_TYPE_KERNEL_DRIVER|SERVICE_TYPE_FS_DRIVER|SERVICE_TYPE_RECOGNIZER_DRIVER;
+ const int SERVICE_TYPE_WIN32_OWN_PROCESS = 0x10;
+ const int SERVICE_TYPE_WIN32_SHARE_PROCESS = 0x20;
+ const int SERVICE_TYPE_WIN32=SERVICE_TYPE_WIN32_OWN_PROCESS|SERVICE_TYPE_WIN32_SHARE_PROCESS;
+ const int SERVICE_TYPE_INTERACTIVE_PROCESS = 0x100;
+
+ /*****************/
+ /* Function 0x00 */
+ WERROR svcctl_CloseServiceHandle(
+ [in,out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x01 */
+
+ /* Service Controls */
+
+ typedef [v1_enum] enum {
+ SVCCTL_CONTROL_STOP = 0x00000001,
+ SVCCTL_CONTROL_PAUSE = 0x00000002,
+ SVCCTL_CONTROL_CONTINUE = 0x00000003,
+ SVCCTL_CONTROL_INTERROGATE = 0x00000004,
+ SVCCTL_CONTROL_SHUTDOWN = 0x00000005,
+ SVCCTL_CONTROL_PARAMCHANGE = 0x00000006,
+ SVCCTL_CONTROL_NETBINDADD = 0x00000007,
+ SVCCTL_CONTROL_NETBINDREMOVE = 0x00000008,
+ SVCCTL_CONTROL_NETBINDENABLE = 0x00000009,
+ SVCCTL_CONTROL_NETBINDDISABLE = 0x0000000A
+ } SERVICE_CONTROL;
+
+ WERROR svcctl_ControlService(
+ [in,ref] policy_handle *handle,
+ [in] SERVICE_CONTROL control,
+ [out,ref] SERVICE_STATUS *service_status
+ );
+
+ /*****************/
+ /* Function 0x02 */
+ WERROR svcctl_DeleteService(
+ [in,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x03 */
+
+ WERROR svcctl_LockServiceDatabase(
+ [in,ref] policy_handle *handle,
+ [out,ref] policy_handle *lock
+ );
+
+ /*****************/
+ /* Function 0x04 */
+ WERROR svcctl_QueryServiceObjectSecurity(
+ [in] policy_handle *handle,
+ [in] security_secinfo security_flags,
+ [out,ref,size_is(offered)] uint8 *buffer,
+ [in,range(0,0x40000)] uint32 offered,
+ [out,ref,range(0,0x40000)] uint32 *needed
+ );
+
+ /*****************/
+ /* Function 0x05 */
+ WERROR svcctl_SetServiceObjectSecurity(
+ [in] policy_handle *handle,
+ [in] security_secinfo security_flags,
+ [in,ref,size_is(offered)] uint8 *buffer,
+ [in] uint32 offered
+ );
+
+ /*****************/
+ /* Function 0x06 */
+ WERROR svcctl_QueryServiceStatus(
+ [in,ref] policy_handle *handle,
+ [out,ref] SERVICE_STATUS *service_status
+ );
+
+ /*****************/
+ /* Function 0x07 */
+ [todo] WERROR svcctl_SetServiceStatus(
+ );
+
+ /*****************/
+ /* Function 0x08 */
+ WERROR svcctl_UnlockServiceDatabase(
+ [in,out,ref] policy_handle *lock
+ );
+
+ /*****************/
+ /* Function 0x09 */
+ [todo] WERROR svcctl_NotifyBootConfigStatus(
+ );
+
+ /*****************/
+ /* Function 0x0a */
+ WERROR svcctl_SCSetServiceBitsW(
+ [in,ref] policy_handle *handle,
+ [in] uint32 bits,
+ [in] boolean32 bitson,
+ [in] boolean32 immediate
+ );
+
+ /*****************/
+ /* Function 0x0b */
+
+ typedef [v1_enum] enum {
+ SVCCTL_SVC_ERROR_IGNORE = 0x00000000,
+ SVCCTL_SVC_ERROR_NORMAL = 0x00000001,
+ SVCCTL_SVC_ERROR_CRITICAL = 0x00000002,
+ SVCCTL_SVC_ERROR_SEVERE = 0x00000003
+ } svcctl_ErrorControl;
+
+ typedef [v1_enum] enum {
+ SVCCTL_BOOT_START = 0x00000000,
+ SVCCTL_SYSTEM_START = 0x00000001,
+ SVCCTL_AUTO_START = 0x00000002,
+ SVCCTL_DEMAND_START = 0x00000003,
+ SVCCTL_DISABLED = 0x00000004
+ } svcctl_StartType;
+
+ [public] WERROR svcctl_ChangeServiceConfigW(
+ [in,ref] policy_handle *handle,
+ [in] uint32 type,
+ [in] svcctl_StartType start_type,
+ [in] svcctl_ErrorControl error_control,
+ [in,unique] [string,charset(UTF16)] uint16 *binary_path,
+ [in,unique] [string,charset(UTF16)] uint16 *load_order_group,
+ [in,out,unique] uint32 *tag_id,
+ [in,unique,size_is(dwDependSize)] [string,charset(UTF16)] uint16 *dependencies,
+ [in,range(0, SC_MAX_DEPEND_SIZE)] uint32 dwDependSize,
+ [in,unique,range(0, SC_MAX_ACCOUNT_NAME_LENGTH)] [string,charset(UTF16)] uint16 *service_start_name,
+ [in,unique,size_is(dwPwSize)] [string,charset(UTF16)] uint16 *password,
+ [in,range(0, SC_MAX_PWD_SIZE)] uint32 dwPwSize,
+ [in,unique,range(0, SC_MAX_NAME_LENGTH)] [string,charset(UTF16)] uint16 *display_name
+ );
+
+ /*****************/
+ /* Function 0x0c */
+ WERROR svcctl_CreateServiceW(
+ [in,ref] policy_handle *scmanager_handle,
+ [in] [string,charset(UTF16)] uint16 ServiceName[],
+ [in,unique] [string,charset(UTF16)] uint16 *DisplayName,
+ [in] uint32 desired_access,
+ [in] uint32 type,
+ [in] svcctl_StartType start_type,
+ [in] svcctl_ErrorControl error_control,
+ [in] [string,charset(UTF16)] uint16 binary_path[],
+ [in,unique] [string,charset(UTF16)] uint16 *LoadOrderGroupKey,
+ [in,out,unique] uint32 *TagId,
+ [in,unique,size_is(dependencies_size)] uint8 *dependencies,
+ [in] uint32 dependencies_size,
+ [in,unique] [string,charset(UTF16)] uint16 *service_start_name,
+ [in,unique,size_is(password_size)] uint8 *password,
+ [in] uint32 password_size,
+ [out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x0d */
+ WERROR svcctl_EnumDependentServicesW(
+ [in,ref] policy_handle *service,
+ [in] svcctl_ServiceState state,
+ [out,ref,size_is(offered)] uint8 *service_status,
+ [in,range(0,0x40000)] uint32 offered,
+ [out,ref,range(0,0x40000)] uint32 *needed,
+ [out,ref,range(0,0x40000)] uint32 *services_returned
+ );
+
+ /*****************/
+ /* Function 0x0e */
+
+ typedef [v1_enum] enum {
+ SERVICE_STATE_ACTIVE = 0x00000001,
+ SERVICE_STATE_INACTIVE = 0x00000002,
+ SERVICE_STATE_ALL = ( SERVICE_STATE_ACTIVE | SERVICE_STATE_INACTIVE )
+ } svcctl_ServiceState;
+
+ WERROR svcctl_EnumServicesStatusW(
+ [in,ref] policy_handle *handle,
+ [in] uint32 type,
+ [in] svcctl_ServiceState state,
+ [out,ref,size_is(offered)] uint8 *service,
+ [in] [range(0,0x40000)] uint32 offered,
+ [out,ref] [range(0,0x40000)] uint32 *needed,
+ [out,ref] [range(0,0x40000)] uint32 *services_returned,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************/
+ /* Function 0x0f */
+
+ /* Service Control Manager Bits */
+
+ typedef [bitmap32bit] bitmap {
+ SC_RIGHT_MGR_CONNECT = 0x0001,
+ SC_RIGHT_MGR_CREATE_SERVICE = 0x0002,
+ SC_RIGHT_MGR_ENUMERATE_SERVICE = 0x0004,
+ SC_RIGHT_MGR_LOCK = 0x0008,
+ SC_RIGHT_MGR_QUERY_LOCK_STATUS = 0x0010,
+ SC_RIGHT_MGR_MODIFY_BOOT_CONFIG = 0x0020
+ } svcctl_MgrAccessMask;
+
+ const int SC_MANAGER_READ_ACCESS =
+ (SEC_STD_READ_CONTROL |
+ SC_RIGHT_MGR_CONNECT |
+ SC_RIGHT_MGR_ENUMERATE_SERVICE |
+ SC_RIGHT_MGR_QUERY_LOCK_STATUS);
+
+ const int SC_MANAGER_EXECUTE_ACCESS = SC_MANAGER_READ_ACCESS;
+
+ const int SC_MANAGER_WRITE_ACCESS =
+ (SEC_STD_REQUIRED |
+ SC_MANAGER_READ_ACCESS |
+ SC_RIGHT_MGR_CREATE_SERVICE |
+ SC_RIGHT_MGR_LOCK |
+ SC_RIGHT_MGR_MODIFY_BOOT_CONFIG);
+
+ const int SC_MANAGER_ALL_ACCESS = SC_MANAGER_WRITE_ACCESS;
+
+ WERROR svcctl_OpenSCManagerW(
+ [in,unique] [string,charset(UTF16)] uint16 *MachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *DatabaseName,
+ [in] svcctl_MgrAccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x10 */
+
+ /* Service Object Bits */
+
+ typedef [bitmap32bit] bitmap {
+ SC_RIGHT_SVC_QUERY_CONFIG = 0x0001,
+ SC_RIGHT_SVC_CHANGE_CONFIG = 0x0002,
+ SC_RIGHT_SVC_QUERY_STATUS = 0x0004,
+ SC_RIGHT_SVC_ENUMERATE_DEPENDENTS = 0x0008,
+ SC_RIGHT_SVC_START = 0x0010,
+ SC_RIGHT_SVC_STOP = 0x0020,
+ SC_RIGHT_SVC_PAUSE_CONTINUE = 0x0040,
+ SC_RIGHT_SVC_INTERROGATE = 0x0080,
+ SC_RIGHT_SVC_USER_DEFINED_CONTROL = 0x0100
+ } svcctl_ServiceAccessMask;
+
+ const int SERVICE_READ_ACCESS =
+ (SEC_STD_READ_CONTROL |
+ SC_RIGHT_SVC_ENUMERATE_DEPENDENTS |
+ SC_RIGHT_SVC_INTERROGATE |
+ SC_RIGHT_SVC_QUERY_CONFIG |
+ SC_RIGHT_SVC_QUERY_STATUS |
+ SC_RIGHT_SVC_USER_DEFINED_CONTROL);
+
+ const int SERVICE_EXECUTE_ACCESS =
+ (SERVICE_READ_ACCESS |
+ SC_RIGHT_SVC_START |
+ SC_RIGHT_SVC_STOP |
+ SC_RIGHT_SVC_PAUSE_CONTINUE);
+
+ const int SERVICE_WRITE_ACCESS =
+ (SEC_STD_REQUIRED |
+ SERVICE_READ_ACCESS |
+ SERVICE_EXECUTE_ACCESS |
+ SC_RIGHT_SVC_CHANGE_CONFIG);
+
+ const int SERVICE_ALL_ACCESS = SERVICE_WRITE_ACCESS;
+
+ WERROR svcctl_OpenServiceW(
+ [in,ref] policy_handle *scmanager_handle,
+ [in] [string,charset(UTF16)] uint16 ServiceName[],
+ [in] svcctl_ServiceAccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x11 */
+
+ typedef [public,gensize] struct {
+ uint32 service_type;
+ svcctl_StartType start_type;
+ svcctl_ErrorControl error_control;
+ [string,charset(UTF16)] [range(0,8192)] uint16 *executablepath;
+ [string,charset(UTF16)] [range(0,8192)] uint16 *loadordergroup;
+ uint32 tag_id;
+ [string,charset(UTF16)] [range(0,8192)] uint16 *dependencies;
+ [string,charset(UTF16)] [range(0,8192)] uint16 *startname;
+ [string,charset(UTF16)] [range(0,8192)] uint16 *displayname;
+ } QUERY_SERVICE_CONFIG;
+
+ WERROR svcctl_QueryServiceConfigW(
+ [in,ref] policy_handle *handle,
+ [out] QUERY_SERVICE_CONFIG *query,
+ [in] [range(0,8192)] uint32 offered,
+ [out,ref] [range(0,8192)] uint32 *needed
+ );
+
+ /*****************/
+ /* Function 0x12 */
+ WERROR svcctl_QueryServiceLockStatusW(
+ [in,ref] policy_handle *handle,
+ [in] uint32 offered,
+ [out,ref] SERVICE_LOCK_STATUS *lock_status,
+ [out,ref] uint32 *needed
+ );
+
+ /*****************/
+ /* Function 0x13 */
+
+ const int SC_MAX_ARGUMENT_LENGTH = 1024;
+ const int SC_MAX_ARGUMENTS = 1024;
+
+ typedef struct {
+ [string,charset(UTF16),range(0,SC_MAX_ARGUMENT_LENGTH)] uint16 *string;
+ } svcctl_ArgumentString;
+
+ WERROR svcctl_StartServiceW(
+ [in,ref] policy_handle *handle,
+ [in,range(0,SC_MAX_ARGUMENTS)] uint32 NumArgs,
+ [in,unique,size_is(NumArgs)] svcctl_ArgumentString *Arguments
+ );
+
+ /*****************/
+ /* Function 0x14 */
+ WERROR svcctl_GetServiceDisplayNameW(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *service_name,
+ [out,ref] [string,charset(UTF16)] uint16 **display_name,
+ [in,out,unique] uint32 *display_name_length
+ );
+
+ /*****************/
+ /* Function 0x15 */
+ WERROR svcctl_GetServiceKeyNameW(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *service_name,
+ [out,ref] [string,charset(UTF16)] uint16 **key_name,
+ [in,out,unique] uint32 *display_name_length
+ );
+
+ /*****************/
+ /* Function 0x16 */
+ WERROR svcctl_SCSetServiceBitsA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 bits,
+ [in] boolean32 bitson,
+ [in] boolean32 immediate
+ );
+
+ /*****************/
+ /* Function 0x17 */
+ WERROR svcctl_ChangeServiceConfigA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 type,
+ [in] svcctl_StartType start_type,
+ [in] svcctl_ErrorControl error_control,
+ [in,unique] [string,charset(UTF16)] uint16 *binary_path,
+ [in,unique] [string,charset(UTF16)] uint16 *load_order_group,
+ [out,ref] uint32 *tag_id,
+ [in,unique] [string,charset(UTF16)] uint16 *dependencies,
+ [in,unique] [string,charset(UTF16)] uint16 *service_start_name,
+ [in,unique] [string,charset(UTF16)] uint16 *password,
+ [in,unique] [string,charset(UTF16)] uint16 *display_name
+ );
+
+ /*****************/
+ /* Function 0x18 */
+ WERROR svcctl_CreateServiceA(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *ServiceName,
+ [in,unique] [string,charset(UTF16)] uint16 *DisplayName,
+ [in] uint32 desired_access,
+ [in] uint32 type,
+ [in] svcctl_StartType start_type,
+ [in] svcctl_ErrorControl error_control,
+ [in,unique] [string,charset(UTF16)] uint16 *binary_path,
+ [in,unique] [string,charset(UTF16)] uint16 *LoadOrderGroupKey,
+ [out,unique] uint32 *TagId,
+ [in,unique] [string,charset(UTF16)] uint16 *dependencies,
+ [in,unique] [string,charset(UTF16)] uint16 *service_start_name,
+ [in,unique] [string,charset(UTF16)] uint16 *password
+ );
+
+ /*****************/
+ /* Function 0x19 */
+ WERROR svcctl_EnumDependentServicesA(
+ [in,ref] policy_handle *service,
+ [in] svcctl_ServiceState state,
+ [out,unique] ENUM_SERVICE_STATUSA *service_status,
+ [in] uint32 offered,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *services_returned
+ );
+
+ /*****************/
+ /* Function 0x1a */
+ WERROR svcctl_EnumServicesStatusA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 type,
+ [in] svcctl_ServiceState state,
+ [in] uint32 offered,
+ [out,size_is(offered)] uint8 service[*],
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *services_returned,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************/
+ /* Function 0x1b */
+ WERROR svcctl_OpenSCManagerA(
+ [in,unique] [string,charset(UTF16)] uint16 *MachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *DatabaseName,
+ [in] uint32 access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x1c */
+ WERROR svcctl_OpenServiceA(
+ [in,ref] policy_handle *scmanager_handle,
+ [in,unique] [string,charset(UTF16)] uint16 *ServiceName,
+ [in] uint32 access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /*****************/
+ /* Function 0x1d */
+ WERROR svcctl_QueryServiceConfigA(
+ [in,ref] policy_handle *handle,
+ [out] uint8 query[offered], /*QUERYU_SERVICE_CONFIG */
+ [in] uint32 offered,
+ [out,ref] uint32 *needed
+ );
+
+ /*****************/
+ /* Function 0x1e */
+ WERROR svcctl_QueryServiceLockStatusA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 offered,
+ [out,ref] SERVICE_LOCK_STATUS *lock_status,
+ [out,ref] uint32 *needed
+ );
+
+ /*****************/
+ /* Function 0x1f */
+ WERROR svcctl_StartServiceA(
+ [in,ref] policy_handle *handle,
+ [in] uint32 NumArgs,
+ [in,unique/*FIXME:,length_is(NumArgs)*/] [string,charset(UTF16)] uint16 *Arguments
+ );
+
+ /*****************/
+ /* Function 0x20 */
+ WERROR svcctl_GetServiceDisplayNameA(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *service_name,
+ [out,ref] [string,charset(UTF16)] uint16 **display_name,
+ [in,out,unique] uint32 *display_name_length
+ );
+
+ /*****************/
+ /* Function 0x21 */
+ WERROR svcctl_GetServiceKeyNameA(
+ [in,ref] policy_handle *handle,
+ [in,unique] [string,charset(UTF16)] uint16 *service_name,
+ [out,ref] [string,charset(UTF16)] uint16 **key_name,
+ [in,out,unique] uint32 *display_name_length
+ );
+
+ /*****************/
+ /* Function 0x22 */
+ [todo] WERROR svcctl_GetCurrentGroupeStateW(
+ );
+
+ /*****************/
+ /* Function 0x23 */
+ [todo] WERROR svcctl_EnumServiceGroupW(
+ );
+
+ /*****************/
+ /* Function 0x24 */
+ WERROR svcctl_ChangeServiceConfig2A(
+ [in,ref] policy_handle *handle,
+ [in] uint32 info_level,
+ [in,unique] uint8 *info
+ );
+
+ /*****************/
+ /* Function 0x25 */
+ WERROR svcctl_ChangeServiceConfig2W(
+ [in,ref] policy_handle *handle,
+ [in] uint32 info_level,
+ [in,unique] uint8 *info
+ );
+
+ /*****************/
+ /* Function 0x26 */
+
+ typedef [v1_enum] enum {
+ SERVICE_CONFIG_DESCRIPTION = 0x00000001,
+ SERVICE_CONFIG_FAILURE_ACTIONS = 0x00000002
+ } svcctl_ConfigLevel;
+
+ typedef [gensize,public] struct {
+ [relative] nstring *description;
+ } SERVICE_DESCRIPTION;
+
+ typedef [v1_enum] enum {
+ SC_ACTION_NONE = 0,
+ SC_ACTION_RESTART = 1,
+ SC_ACTION_REBOOT = 2,
+ SC_ACTION_RUN_COMMAND = 3
+ } SC_ACTION_TYPE;
+
+ typedef struct {
+ SC_ACTION_TYPE type;
+ uint32 delay;
+ } SC_ACTION;
+
+ typedef [public,gensize] struct {
+ uint32 reset_period;
+ [relative] nstring *rebootmsg;
+ [relative] nstring *command;
+ [range(0,1024)] uint32 num_actions;
+ [relative] [size_is(num_actions)] SC_ACTION *actions;
+ } SERVICE_FAILURE_ACTIONSW;
+
+ WERROR svcctl_QueryServiceConfig2A(
+ [in,ref] policy_handle *handle,
+ [in] svcctl_ConfigLevel info_level,
+ [out] uint8 buffer[offered],
+ [in] uint32 offered,
+ [out,ref] uint32 *needed
+ );
+
+ /*****************/
+ /* Function 0x27 */
+ WERROR svcctl_QueryServiceConfig2W(
+ [in,ref] policy_handle *handle,
+ [in] svcctl_ConfigLevel info_level,
+ [out,ref,size_is(offered)] uint8 *buffer,
+ [in] [range(0,8192)] uint32 offered,
+ [out,ref] [range(0,8192)] uint32 *needed
+ );
+
+ /*****************/
+ /* Function 0x28 */
+
+ typedef [v1_enum] enum {
+ SVC_STATUS_PROCESS_INFO = 0x00000000
+ } svcctl_StatusLevel;
+
+ WERROR svcctl_QueryServiceStatusEx(
+ [in,ref] policy_handle *handle,
+ [in] svcctl_StatusLevel info_level,
+ [out,ref,size_is(offered)] uint8 *buffer,
+ [in] [range(0,8192)] uint32 offered,
+ [out,ref] [range(0,8192)] uint32 *needed
+ );
+
+ /*****************/
+ /* Function 0x29 */
+ WERROR svcctl_EnumServicesStatusExA(
+ [in,ref] policy_handle *scmanager,
+ [in] uint32 info_level,
+ [in] uint32 type,
+ [in] svcctl_ServiceState state,
+ [out] uint8 services[offered],
+ [in] uint32 offered,
+ [out,ref] uint32 *needed,
+ [out,ref] uint32 *service_returned,
+ [in,out,unique] uint32 *resume_handle,
+ [out,ref] [string,charset(UTF16)] uint16 **group_name
+ );
+
+ /*****************/
+ /* Function 0x2a */
+ WERROR svcctl_EnumServicesStatusExW(
+ [in,ref] policy_handle *scmanager,
+ [in] uint32 info_level,
+ [in] uint32 type,
+ [in] svcctl_ServiceState state,
+ [out,ref,size_is(offered)] uint8 *services,
+ [in] [range(0,0x40000)] uint32 offered,
+ [out,ref] [range(0,0x40000)] uint32 *needed,
+ [out,ref] [range(0,0x40000)] uint32 *service_returned,
+ [in,out,unique] [range(0,0x40000)] uint32 *resume_handle,
+ [in,unique] [string,charset(UTF16)] uint16 *group_name
+ );
+
+ /*****************/
+ /* Function 0x2b */
+ [todo] WERROR svcctl_SCSendTSMessage(
+ );
+
+ /*****************/
+ /* Function 0x2c */
+ WERROR svcctl_CreateServiceWOW64A(
+ [in] SC_RPC_HANDLE hSCManager,
+ [in,string,range(0, SC_MAX_NAME_LENGTH),charset(DOS)] char *lpServiceName,
+ [in,string,unique,range(0, SC_MAX_NAME_LENGTH),charset(DOS)] char *lpDisplayName,
+ [in] uint32 dwDesiredAccess,
+ [in] uint32 dwServiceType,
+ [in] uint32 dwStartType,
+ [in] uint32 dwErrorControl,
+ [in,string, range(0, SC_MAX_PATH_LENGTH),charset(DOS)] char *lpBinaryPathName,
+ [in,string,unique,range(0, SC_MAX_NAME_LENGTH),charset(DOS)] char *lpLoadOrderGroup,
+ [in,out,unique] uint32 *lpdwTagId,
+ [in,unique,size_is(dwDependSize)] uint8 *lpDependencies,
+ [in, range (0, SC_MAX_DEPEND_SIZE)] uint32 dwDependSize,
+ [in,string,unique,range(0, SC_MAX_ACCOUNT_NAME_LENGTH),charset(DOS)] char *lpServiceStartName,
+ [in,unique,size_is(dwPwSize)] uint8 *lpPassword,
+ [in, range(0, SC_MAX_PWD_SIZE)] uint32 dwPwSize,
+ [out] SC_RPC_HANDLE *lpServiceHandle
+ );
+
+ /*****************/
+ /* Function 0x2d */
+ WERROR svcctl_CreateServiceWOW64W(
+ [in] SC_RPC_HANDLE hSCManager,
+ [in,string,range(0, SC_MAX_NAME_LENGTH),charset(UTF16)] uint16 *lpServiceName,
+ [in,string,unique,range(0, SC_MAX_NAME_LENGTH),charset(UTF16)] uint16 *lpDisplayName,
+ [in] uint32 dwDesiredAccess,
+ [in] uint32 dwServiceType,
+ [in] uint32 dwStartType,
+ [in] uint32 dwErrorControl,
+ [in,string,range(0, SC_MAX_PATH_LENGTH),charset(UTF16)] uint16 *lpBinaryPathName,
+ [in,string,unique,range(0, SC_MAX_NAME_LENGTH),charset(UTF16)] uint16 *lpLoadOrderGroup,
+ [in,out,unique] uint32 *lpdwTagId,
+ [in,unique,size_is(dwDependSize)] uint8 *lpDependencies,
+ [in, range (0, SC_MAX_DEPEND_SIZE)] uint32 dwDependSize,
+ [in,string,unique,range(0, SC_MAX_ACCOUNT_NAME_LENGTH),charset(UTF16)] uint16 *lpServiceStartName,
+ [in,unique,size_is(dwPwSize)] uint8 *lpPassword,
+ [in, range(0, SC_MAX_PWD_SIZE)] uint32 dwPwSize,
+ [out] SC_RPC_HANDLE *lpServiceHandle
+ );
+
+ /*****************/
+ /* Function 0x2e */
+ void Opnum46NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x2f */
+
+ typedef struct {
+ hyper ullThreadId;
+ uint32 dwNotifyMask;
+ char CallbackAddressArray[16];
+ char CallbackParamAddressArray[16];
+ SERVICE_STATUS_PROCESS ServiceStatus;
+ uint32 dwNotificationStatus;
+ uint32 dwSequence;
+ } SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_1;
+
+ typedef struct {
+ hyper ullThreadId;
+ uint32 dwNotifyMask;
+ char CallbackAddressArray[16];
+ char CallbackParamAddressArray[16];
+ SERVICE_STATUS_PROCESS ServiceStatus;
+ uint32 dwNotificationStatus;
+ uint32 dwSequence;
+ uint32 dwNotificationTriggered;
+ [string, range(0, 64*1024), charset(UTF16)] uint16 *pszServiceNames;
+ } SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2;
+
+ typedef SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2
+ SERVICE_NOTIFY_STATUS_CHANGE_PARAMS;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_1 *pStatusChangeParam1;
+ [case(2)] SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *pStatusChangeParams;
+ } SC_RPC_NOTIFY_PARAMS_u;
+
+ typedef struct {
+ uint32 dwInfoLevel;
+ [switch_is(dwInfoLevel)] SC_RPC_NOTIFY_PARAMS_u u;
+ } SC_RPC_NOTIFY_PARAMS;
+
+ typedef struct {
+ BOUNDED_DWORD_4K cElements;
+ [size_is(cElements)] SC_RPC_NOTIFY_PARAMS NotifyParamsArray[*];
+ } SC_RPC_NOTIFY_PARAMS_LIST;
+
+ WERROR svcctl_NotifyServiceStatusChange(
+ [in] SC_RPC_HANDLE hService,
+ [in] SC_RPC_NOTIFY_PARAMS NotifyParams,
+ [in] GUID *pClientProcessGuid,
+ [out] GUID *pSCMProcessGuid,
+ [out] boolean32 *pfCreateRemoteQueue,
+ [out] SC_NOTIFY_RPC_HANDLE *phNotify
+ );
+
+ /*****************/
+ /* Function 0x30 */
+ WERROR svcctl_GetNotifyResults(
+ [in] SC_NOTIFY_RPC_HANDLE hNotify,
+ [out,ref] SC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams
+ );
+
+ /*****************/
+ /* Function 0x31 */
+ WERROR svcctl_CloseNotifyHandle(
+ [in, out] SC_NOTIFY_RPC_HANDLE *phNotify,
+ [out] boolean32 *pfApcFired
+ );
+
+ /*****************/
+ /* Function 0x32 */
+
+ typedef [v1_enum] enum {
+ SERVICE_STOP_UNPLANNED = 0x10000000,
+ SERVICE_STOP_CUSTOM = 0x20000000,
+ SERVICE_STOP_PLANNED = 0x40000000
+ } svcctl_ServiceStopReasonMain;
+
+ typedef [v1_enum] enum {
+ SERVICE_STOP_REASON_MAJOR_OTHER = 0x00010000,
+ SERVICE_STOP_REASON_MAJOR_HARDWARE = 0x00020000,
+ SERVICE_STOP_REASON_MAJOR_OPERATINGSYSTEM = 0x00030000,
+ SERVICE_STOP_REASON_MAJOR_SOFTWARE = 0x00040000,
+ SERVICE_STOP_REASON_MAJOR_APPLICATION = 0x00050000,
+ SERVICE_STOP_REASON_MAJOR_NONE = 0x00060000
+ } svcctl_ServiceStopReasonMajor;
+
+ typedef [v1_enum] enum {
+ SERVICE_STOP_REASON_MINOR_OTHER = 0x00000001,
+ SERVICE_STOP_REASON_MINOR_MAINTENANCE = 0x00000002,
+ SERVICE_STOP_REASON_MINOR_INSTALLATION = 0x00000003,
+ SERVICE_STOP_REASON_MINOR_UPGRADE = 0x00000004,
+ SERVICE_STOP_REASON_MINOR_RECONFIG = 0x00000005,
+ SERVICE_STOP_REASON_MINOR_HUNG = 0x00000006,
+ SERVICE_STOP_REASON_MINOR_UNSTABLE = 0x00000007,
+ SERVICE_STOP_REASON_MINOR_DISK = 0x00000008,
+ SERVICE_STOP_REASON_MINOR_NETWORKCARD = 0x00000009,
+ SERVICE_STOP_REASON_MINOR_ENVIRONMENT = 0x0000000a,
+ SERVICE_STOP_REASON_MINOR_HARDWARE_DRIVER = 0x0000000b,
+ SERVICE_STOP_REASON_MINOR_OTHERDRIVER = 0x0000000c,
+ SERVICE_STOP_REASON_MINOR_SERVICEPACK = 0x0000000d,
+ SERVICE_STOP_REASON_MINOR_SOFTWARE_UPDATE = 0x0000000e,
+ SERVICE_STOP_REASON_MINOR_SECURITYFIX = 0x0000000f,
+ SERVICE_STOP_REASON_MINOR_SECURITY = 0x00000010,
+ SERVICE_STOP_REASON_MINOR_NETWORK_CONNECTIVITY = 0x00000011,
+ SERVICE_STOP_REASON_MINOR_WMI = 0x00000012,
+ SERVICE_STOP_REASON_MINOR_SERVICEPACK_UNINSTALL = 0x00000013,
+ SERVICE_STOP_REASON_MINOR_SOFTWARE_UPDATE_UNINSTALL = 0x00000014,
+ SERVICE_STOP_REASON_MINOR_SECURITYFIX_UNINSTALL = 0x00000015,
+ SERVICE_STOP_REASON_MINOR_MMC = 0x00000016,
+ SERVICE_STOP_REASON_MINOR_NONE = 0x00000017
+ } svcctl_ServiceStopReasonMinor;
+
+ typedef struct {
+ uint32 dwReason;
+ [string,range(0, SC_MAX_COMMENT_LENGTH),charset(DOS)] char *szComment;
+ } SERVICE_CONTROL_STATUS_REASON_IN_PARAMSA;
+
+ typedef struct {
+ SERVICE_STATUS_PROCESS ServiceStatus;
+ } SERVICE_CONTROL_STATUS_REASON_OUT_PARAMS;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] SERVICE_CONTROL_STATUS_REASON_IN_PARAMSA *psrInParams;
+ } SC_RPC_SERVICE_CONTROL_IN_PARAMSA;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] SERVICE_CONTROL_STATUS_REASON_OUT_PARAMS *psrOutParams;
+ } SC_RPC_SERVICE_CONTROL_OUT_PARAMSA;
+
+ WERROR svcctl_ControlServiceExA (
+ [in] SC_RPC_HANDLE hService,
+ [in] SERVICE_CONTROL dwControl,
+ [in] uint32 dwInfoLevel,
+ [in, switch_is(dwInfoLevel)] SC_RPC_SERVICE_CONTROL_IN_PARAMSA *pControlInParams,
+ [out, switch_is(dwInfoLevel)] SC_RPC_SERVICE_CONTROL_OUT_PARAMSA *pControlOutParams
+ );
+
+ /*****************/
+ /* Function 0x33 */
+
+ typedef struct {
+ uint32 dwReason;
+ [string,range(0, SC_MAX_COMMENT_LENGTH),charset(UTF16)] uint16 *pszComment;
+ } SERVICE_CONTROL_STATUS_REASON_IN_PARAMSW;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] SERVICE_CONTROL_STATUS_REASON_IN_PARAMSW *psrInParams;
+ } SC_RPC_SERVICE_CONTROL_IN_PARAMSW;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] SERVICE_CONTROL_STATUS_REASON_OUT_PARAMS *psrOutParams;
+ } SC_RPC_SERVICE_CONTROL_OUT_PARAMSW;
+
+ WERROR svcctl_ControlServiceExW (
+ [in] SC_RPC_HANDLE hService,
+ [in] SERVICE_CONTROL dwControl,
+ [in] uint32 dwInfoLevel,
+ [in, ref, switch_is(dwInfoLevel)] SC_RPC_SERVICE_CONTROL_IN_PARAMSW *pControlInParams,
+ [out,ref, switch_is(dwInfoLevel)] SC_RPC_SERVICE_CONTROL_OUT_PARAMSW *pControlOutParams
+ );
+
+ /*****************/
+ /* Function 0x34 */
+ void Opnum52NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x35 */
+ void Opnum53NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x36 */
+ void Opnum54NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x37 */
+ void Opnum55NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x38 */
+
+ typedef struct {
+ [string,range(0, 8 * 1024), charset(UTF16)] uint16 *lpDescription;
+ } SERVICE_DESCRIPTIONW;
+
+ typedef struct {
+ boolean32 fDelayedAutostart;
+ } SERVICE_DELAYED_AUTO_START_INFO;
+
+ typedef struct {
+ boolean32 fFailureActionsOnNonCrashFailures;
+ } SERVICE_FAILURE_ACTIONS_FLAG;
+
+ typedef struct {
+ uint32 dwServiceSidType;
+ } SERVICE_SID_INFO;
+
+ typedef struct {
+ [range(0, 1024 * 4)] uint32 cbRequiredPrivileges;
+ [size_is(cbRequiredPrivileges)] uint8 *pRequiredPrivileges;
+ } SERVICE_RPC_REQUIRED_PRIVILEGES_INFO;
+
+ typedef struct {
+ uint32 dwPreshutdownTimeout;
+ } SERVICE_PRESHUTDOWN_INFO;
+
+ typedef struct {
+ uint32 dwDataType;
+ [range(0, 1024)] uint32 cbData;
+ [size_is(cbData)] uint8 *pData;
+ } SERVICE_TRIGGER_SPECIFIC_DATA_ITEM;
+
+ typedef struct {
+ uint32 dwTriggerType;
+ uint32 dwAction;
+ GUID *pTriggerSubtype;
+ [range(0, 64)] uint32 cDataItems;
+ [size_is(cDataItems)] SERVICE_TRIGGER_SPECIFIC_DATA_ITEM *pDataItems;
+ } SERVICE_TRIGGER;
+
+ typedef struct {
+ [range(0, 64)] uint32 cTriggers;
+ [size_is(cTriggers)] SERVICE_TRIGGER *pTriggers;
+ uint8 *pReserved;
+ } SERVICE_TRIGGER_INFO;
+
+ typedef struct {
+ uint16 usPreferredNode;
+ boolean32 fDelete;
+ } SERVICE_PREFERRED_NODE_INFO;
+
+ typedef [switch_type(uint32)] union {
+ [case(1)] SERVICE_DESCRIPTIONW *psd;
+ [case(2)] SERVICE_FAILURE_ACTIONSW *psfa;
+ [case(3)] SERVICE_DELAYED_AUTO_START_INFO *psda;
+ [case(4)] SERVICE_FAILURE_ACTIONS_FLAG *psfaf;
+ [case(5)] SERVICE_SID_INFO *pssid;
+ [case(6)] SERVICE_RPC_REQUIRED_PRIVILEGES_INFO *psrp;
+ [case(7)] SERVICE_PRESHUTDOWN_INFO *psps;
+ [case(8)] SERVICE_TRIGGER_INFO *psti;
+ [case(9)] SERVICE_PREFERRED_NODE_INFO *pspn;
+ } SC_RPC_CONFIG_INFOW_u;
+
+ typedef struct {
+ uint32 dwInfoLevel;
+ [switch_is(dwInfoLevel)] SC_RPC_CONFIG_INFOW_u u;
+ } SC_RPC_CONFIG_INFOW;
+
+ WERROR svcctl_QueryServiceConfigEx (
+ [in] SC_RPC_HANDLE hService,
+ [in] uint32 dwInfoLevel,
+ [out,ref] SC_RPC_CONFIG_INFOW *pInfo
+ );
+
+ /*****************/
+ /* Function 0x39 */
+ void Opnum57NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x3a */
+ void Opnum58NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x3b */
+ void Opnum59NotUsedOnWire(void);
+
+ /*****************/
+ /* Function 0x3c */
+ WERROR svcctl_CreateWowService(
+ [in] SC_RPC_HANDLE hSCManager,
+ [in,string,range(0, SC_MAX_NAME_LENGTH),charset(UTF16)] uint16 *lpServiceName,
+ [in,string,unique,range(0, SC_MAX_NAME_LENGTH),charset(UTF16)] uint16 *lpDisplayName,
+ [in] uint32 dwDesiredAccess,
+ [in] uint32 dwServiceType,
+ [in] uint32 dwStartType,
+ [in] uint32 dwErrorControl,
+ [in,string,range(0, SC_MAX_PATH_LENGTH),charset(UTF16)] uint16 *lpBinaryPathName,
+ [in,string,unique,range(0, SC_MAX_NAME_LENGTH),charset(UTF16)] uint16 *lpLoadOrderGroup,
+ [in,out,unique] uint32 *lpdwTagId,
+ [in,unique,size_is(dwDependSize)] uint8 *lpDependencies,
+ [in, range (0, SC_MAX_DEPEND_SIZE)] uint32 dwDependSize,
+ [in,string,unique,range(0, SC_MAX_ACCOUNT_NAME_LENGTH),charset(UTF16)] uint16 *lpServiceStartName,
+ [in,unique,size_is(dwPwSize)] uint8 *lpPassword,
+ [in, range(0, SC_MAX_PWD_SIZE)] uint32 dwPwSize,
+ [in] uint16 dwServiceWowType,
+ [out,ref] SC_RPC_HANDLE *lpServiceHandle
+ );
+
+ /*****************/
+ /* Function 0x3d */
+ WERROR svcctl_OpenSCManager2(
+ [in] handle_t BindingHandle,
+ [in,string,unique,range(0, SC_MAX_NAME_LENGTH),charset(UTF16)] uint16 *DatabaseName,
+ [in] uint32 DesiredAccess,
+ [out,ref] SC_RPC_HANDLE *ScmHandle
+ );
+}
diff --git a/librpc/idl/trkwks.idl b/librpc/idl/trkwks.idl
new file mode 100644
index 0000000..7f11af1
--- /dev/null
+++ b/librpc/idl/trkwks.idl
@@ -0,0 +1,17 @@
+/*
+ distributed key tracking services
+*/
+
+[
+ uuid("300f3532-38cc-11d0-a3f0-0020af6b0add"),
+ version(1.2),
+ pointer_default(unique),
+ helpstring("Distributed Key Tracking Service")
+]
+interface trkwks
+{
+
+ /*****************/
+ /* Function 0x00 */
+ WERROR trkwks_Unknown0();
+}
diff --git a/librpc/idl/unixinfo.idl b/librpc/idl/unixinfo.idl
new file mode 100644
index 0000000..6929e86
--- /dev/null
+++ b/librpc/idl/unixinfo.idl
@@ -0,0 +1,56 @@
+#include "idl_types.h"
+/*
+ Unixinfo interface definition
+*/
+
+import "security.idl";
+
+[ uuid("9c54e310-a955-4885-bd31-78787147dfa6"),
+ version(0.0),
+ endpoint("ncacn_np:[\\pipe\\unixinfo]", "ncacn_ip_tcp:", "ncalrpc:"),
+ pointer_default(unique),
+ helpstring("Unixinfo specific stuff")
+] interface unixinfo
+{
+ /******************/
+ /* Function: 0x00 */
+ NTSTATUS unixinfo_SidToUid (
+ [in] dom_sid sid,
+ [out] hyper *uid
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ NTSTATUS unixinfo_UidToSid (
+ [in] hyper uid,
+ [out] dom_sid *sid
+ );
+
+ /******************/
+ /* Function: 0x02 */
+ NTSTATUS unixinfo_SidToGid (
+ [in] dom_sid sid,
+ [out] hyper *gid
+ );
+
+ /******************/
+ /* Function: 0x03 */
+ NTSTATUS unixinfo_GidToSid (
+ [in] hyper gid,
+ [out] dom_sid *sid
+ );
+
+ typedef struct {
+ NTSTATUS status;
+ [charset(UTF8),string] uint8 homedir[];
+ [charset(UTF8),string] uint8 shell[];
+ } unixinfo_GetPWUidInfo;
+
+ /******************/
+ /* Function: 0x04 */
+ NTSTATUS unixinfo_GetPWUid (
+ [in,out,ref,range(0,1023)] uint32 *count,
+ [in,size_is(*count)] hyper uids[],
+ [out,size_is(*count)] unixinfo_GetPWUidInfo infos[*]
+ );
+}
diff --git a/librpc/idl/w32time.idl b/librpc/idl/w32time.idl
new file mode 100644
index 0000000..4839899
--- /dev/null
+++ b/librpc/idl/w32time.idl
@@ -0,0 +1,21 @@
+/*
+ w32time interface definitions
+*/
+
+[
+ uuid("8fb6d884-2388-11d0-8c35-00c04fda2795"),
+ endpoint("ncacn_np:[\\pipe\\srvsvc]","ncacn_np:[\\pipe\\atsvc]","ncacn_np:[\\pipe\\browser]","ncacn_np:[\\pipe\\keysvc]","ncacn_np:[\\pipe\\wkssvc]"),
+ version(4.1),
+ pointer_default(unique),
+ helpstring("Win32 Time Server")
+]
+interface w32time
+{
+
+ /*****************/
+ /* Function 0x00 */
+ [todo] WERROR w32time_SyncTime();
+
+ [todo] WERROR w32time_GetNetLogonServiceBits();
+ [todo] WERROR w32time_QueryProviderStatus();
+}
diff --git a/librpc/idl/winbind.idl b/librpc/idl/winbind.idl
new file mode 100644
index 0000000..50e3688
--- /dev/null
+++ b/librpc/idl/winbind.idl
@@ -0,0 +1,323 @@
+#include "idl_types.h"
+import "lsa.idl", "netlogon.idl", "samr.idl", "misc.idl", "security.idl", "idmap.idl";
+
+[
+ uuid("bf09192c-ed60-4928-9dff-d0d7bcb03ed8"),
+ endpoint("ncalrpc:"),
+ pointer_default(unique),
+ version(1.0),
+ helpstring("winbind parent-child protocol"),
+ no_srv_register
+]
+interface winbind
+{
+ /* Private methods */
+
+ NTSTATUS wbint_Ping(
+ [in] uint32 in_data,
+ [out] uint32 *out_data
+ );
+
+ NTSTATUS wbint_LookupSid(
+ [in] dom_sid *sid,
+ [out] lsa_SidType *type,
+ [out,string,charset(UTF8)] char **domain,
+ [out,string,charset(UTF8)] char **name
+ );
+
+ NTSTATUS wbint_LookupSids(
+ [in] lsa_SidArray *sids,
+ [out,ref] lsa_RefDomainList *domains,
+ [out,ref] lsa_TransNameArray *names
+ );
+
+ NTSTATUS wbint_LookupName(
+ [in,string,charset(UTF8)] char *domain,
+ [in,string,charset(UTF8)] char *name,
+ [in] uint32 flags,
+ [out] lsa_SidType *type,
+ [out] dom_sid *sid
+ );
+
+ typedef struct {
+ id_type type_hint;
+ uint32 domain_index;
+ uint32 rid;
+ unixid xid;
+ } wbint_TransID;
+
+ typedef struct {
+ uint32 num_ids;
+ [size_is(num_ids)] wbint_TransID ids[];
+ } wbint_TransIDArray;
+
+ NTSTATUS wbint_Sids2UnixIDs(
+ [in] lsa_RefDomainList *domains,
+ [in,out] wbint_TransIDArray *ids
+ );
+
+ NTSTATUS wbint_UnixIDs2Sids(
+ [in,string,charset(UTF8)] char *domain_name,
+ [in] dom_sid domain_sid,
+ [in] uint32 num_ids,
+ [in,out] unixid xids[num_ids],
+ [out] dom_sid sids[num_ids]
+ );
+
+ NTSTATUS wbint_AllocateUid(
+ [out] hyper *uid
+ );
+
+ NTSTATUS wbint_AllocateGid(
+ [out] hyper *gid
+ );
+
+ typedef [public] struct {
+ [string,charset(UTF8)] char *domain_name;
+ [string,charset(UTF8)] char *acct_name;
+ [string,charset(UTF8)] char *full_name;
+ [string,charset(UTF8)] char *homedir;
+ [string,charset(UTF8)] char *shell;
+ hyper uid;
+ hyper primary_gid;
+ [string,charset(UTF8)] char *primary_group_name;
+ dom_sid user_sid;
+ dom_sid group_sid;
+ } wbint_userinfo;
+
+ NTSTATUS wbint_GetNssInfo(
+ [in,out] wbint_userinfo *info
+ );
+
+ typedef [public] struct {
+ uint32 num_sids;
+ [size_is(num_sids)] dom_sid sids[];
+ } wbint_SidArray;
+
+ typedef [public] struct {
+ uint32 num_rids;
+ [size_is(num_rids)] uint32 rids[];
+ } wbint_RidArray;
+
+ NTSTATUS wbint_LookupUserAliases(
+ [in] wbint_SidArray *sids,
+ [out] wbint_RidArray *rids
+ );
+
+ NTSTATUS wbint_LookupUserGroups(
+ [in] dom_sid *sid,
+ [out] wbint_SidArray *sids
+ );
+
+ NTSTATUS wbint_QuerySequenceNumber(
+ [out] uint32 *sequence
+ );
+
+ typedef [public] struct {
+ dom_sid sid;
+ lsa_SidType type;
+ [string,charset(UTF8)] char *name;
+ } wbint_Principal;
+
+ typedef [public] struct {
+ uint32 num_principals;
+ [size_is(num_principals)] wbint_Principal principals[];
+ } wbint_Principals;
+
+ NTSTATUS wbint_LookupGroupMembers(
+ [in] dom_sid *sid,
+ [in] lsa_SidType type,
+ [out] wbint_Principals *members
+ );
+
+ NTSTATUS wbint_LookupAliasMembers(
+ [in] dom_sid *sid,
+ [in] lsa_SidType type,
+ [out] wbint_SidArray *sids
+ );
+
+ typedef [public] struct {
+ uint32 num_userinfos;
+ [size_is(num_userinfos)] wbint_userinfo userinfos[];
+ } wbint_userinfos;
+
+ NTSTATUS wbint_QueryGroupList(
+ [out] wbint_Principals *groups
+ );
+
+ NTSTATUS wbint_QueryUserRidList(
+ [out] wbint_RidArray *rids
+ );
+
+ NTSTATUS wbint_DsGetDcName(
+ [in,string,charset(UTF8)] char *domain_name,
+ [in,unique] GUID *domain_guid,
+ [in,string,unique,charset(UTF8)] char *site_name,
+ [in] uint32 flags,
+ [out] netr_DsRGetDCNameInfo **dc_info
+ );
+
+ NTSTATUS wbint_LookupRids(
+ [in] dom_sid *domain_sid,
+ [in] wbint_RidArray *rids,
+ [out,string,charset(UTF8)] char **domain_name,
+ [out] wbint_Principals *names
+ );
+
+ NTSTATUS wbint_CheckMachineAccount(
+ );
+
+ NTSTATUS wbint_ChangeMachineAccount(
+ [in,unique,string,charset(UTF8)] char *dcname
+ );
+
+ NTSTATUS wbint_PingDc(
+ [out,string,charset(UTF8)] char **dcname
+ );
+
+ NTSTATUS wbint_ListTrustedDomains(
+ [in,string,charset(UTF8)] char *client_name,
+ [in] hyper client_pid,
+ [out,ref] netr_DomainTrustList *domains
+ );
+
+ typedef [public] struct {
+ uint16 level;
+ [switch_is(level)] netr_Validation *validation;
+ [string,charset(UTF8)] char *krb5ccname;
+ } wbint_Validation;
+
+ typedef [public] struct {
+ [string,charset(UTF8)] char *username;
+ [string,charset(UTF8),flag(NDR_SECRET)] char *password;
+ [string,charset(UTF8)] char *krb5_cc_type;
+ hyper uid;
+ } wbint_AuthUserInfo;
+
+ NTSTATUS wbint_PamAuth(
+ [in,string,charset(UTF8)] char *client_name,
+ [in] hyper client_pid,
+ [in] uint32 flags,
+ [in] wbint_AuthUserInfo *info,
+ [in] wbint_SidArray *require_membership_of_sid,
+ [out,ref] wbint_Validation *validation
+ );
+
+ typedef [public] struct {
+ uint16 level;
+ [switch_is(level)] netr_Validation *validation;
+ } wbint_PamAuthCrapValidation;
+
+ NTSTATUS wbint_PamAuthCrap(
+ [in,string,charset(UTF8)] char *client_name,
+ [in] hyper client_pid,
+ [in] uint32 flags,
+ [in, string,charset(UTF8)] char *user,
+ [in, string,charset(UTF8)] char *domain,
+ [in, string,charset(UTF8)] char *workstation,
+ [in,flag(NDR_SECRET)] DATA_BLOB lm_resp,
+ [in,flag(NDR_SECRET)] DATA_BLOB nt_resp,
+ [in,flag(NDR_SECRET)] DATA_BLOB chal,
+ [in] uint32 logon_parameters,
+ [in] wbint_SidArray *require_membership_of_sid,
+ [out,ref] uint8 *authoritative,
+ [out,ref] wbint_PamAuthCrapValidation *validation
+ );
+
+ NTSTATUS wbint_PamLogOff(
+ [in,string,charset(UTF8)] char *client_name,
+ [in] hyper client_pid,
+ [in] uint32 flags,
+ [in,string,charset(UTF8)] char *user,
+ [in,string,charset(UTF8)] char *krb5ccname,
+ [in] hyper uid
+ );
+
+ NTSTATUS wbint_PamAuthCrapChangePassword(
+ [in,string,charset(UTF8)] char *client_name,
+ [in] hyper client_pid,
+ [in,string,charset(UTF8)] char *user,
+ [in,string,charset(UTF8)] char *domain,
+ [in,flag(NDR_SECRET)] DATA_BLOB new_nt_pswd,
+ [in,flag(NDR_SECRET)] DATA_BLOB old_nt_hash_enc,
+ [in,flag(NDR_SECRET)] DATA_BLOB new_lm_pswd,
+ [in,flag(NDR_SECRET)] DATA_BLOB old_lm_hash_enc
+ );
+
+ NTSTATUS wbint_PamAuthChangePassword(
+ [in,string,charset(UTF8)] char *client_name,
+ [in] hyper client_pid,
+ [in] uint32 flags,
+ [in,string,charset(UTF8)] char *user,
+ [in,string,charset(UTF8),flag(NDR_SECRET)] char *old_password,
+ [in,string,charset(UTF8),flag(NDR_SECRET)] char *new_password,
+ [out,ref] samr_DomInfo1 **dominfo,
+ [out,ref] samPwdChangeReason *reject_reason
+ );
+
+ typedef [enum16bit] enum {
+ WB_DOMINFO_DOMAIN_UNKNOWN = 0x0000,
+ WB_DOMINFO_DOMAIN_NATIVE = 0x0001,
+ WB_DOMINFO_DOMAIN_AD = 0x0002,
+ WB_DOMINFO_DOMAIN_PRIMARY = 0x0004,
+ WB_DOMINFO_DOMAIN_OFFLINE = 0x0008
+ } DomainInfoFlags;
+
+ NTSTATUS wbint_InitConnection(
+ [in,string,charset(UTF8)] char *dcname,
+ [out,string,charset(UTF8)] char **name,
+ [out,string,charset(UTF8)] char **alt_name,
+ [out,ref] dom_sid *sid,
+ [out,ref] DomainInfoFlags *flags
+ );
+
+ /* Public methods available via IRPC */
+
+ typedef [switch_type(uint16)] union netr_LogonLevel netr_LogonLevel;
+ typedef [switch_type(uint16)] union netr_Validation netr_Validation;
+
+ /*
+ * do a netr_LogonSamLogon() against the right DC
+ */
+ NTSTATUS winbind_SamLogon(
+ [in] uint16 logon_level,
+ [in] [switch_is(logon_level)] netr_LogonLevel logon,
+ [in] uint16 validation_level,
+ [out] [switch_is(validation_level)] netr_Validation validation,
+ [out] uint8 authoritative
+ );
+
+ NTSTATUS winbind_DsrUpdateReadOnlyServerDnsRecords(
+ [in,unique] [string,charset(UTF16)] uint16 *site_name,
+ [in] uint32 dns_ttl,
+ [in,out,ref] NL_DNS_NAME_INFO_ARRAY *dns_names
+ );
+
+ /*
+ * do a netr_LogonControl2Ex() against the right DC
+ */
+ typedef [v1_enum] enum netr_LogonControlCode netr_LogonControlCode;
+ typedef [switch_type(netr_LogonControlCode)] union netr_CONTROL_DATA_INFORMATION netr_CONTROL_DATA_INFORMATION;
+ typedef [switch_type(uint32)] union netr_CONTROL_QUERY_INFORMATION netr_CONTROL_QUERY_INFORMATION;
+
+ WERROR winbind_LogonControl(
+ [in] netr_LogonControlCode function_code,
+ [in] uint32 level,
+ [in,ref][switch_is(function_code)] netr_CONTROL_DATA_INFORMATION *data,
+ [out,ref][switch_is(level)] netr_CONTROL_QUERY_INFORMATION *query
+ );
+
+ /*
+ * do a netr_GetForestTrustInformation() against the right DC
+ */
+ WERROR winbind_GetForestTrustInformation(
+ [in,unique] [string,charset(UTF16)] uint16 *trusted_domain_name,
+ [in] uint32 flags,
+ [out,ref] lsa_ForestTrustInformation **forest_trust_info
+ );
+
+ NTSTATUS winbind_SendToSam(
+ [in] netr_SendToSamBase message
+ );
+
+}
diff --git a/librpc/idl/windows_event_ids.idl b/librpc/idl/windows_event_ids.idl
new file mode 100644
index 0000000..f482800
--- /dev/null
+++ b/librpc/idl/windows_event_ids.idl
@@ -0,0 +1,52 @@
+/*
+ IDL constants for windows event codes.
+*/
+
+[
+ pointer_default(unique)
+]
+interface windows_events
+{
+
+ typedef [v1_enum,public] enum {
+ EVT_ID_NONE = 0,
+ EVT_ID_SUCCESSFUL_LOGON = 4624,
+ EVT_ID_UNSUCCESSFUL_LOGON = 4625,
+ EVT_ID_PASSWORD_CHANGE = 4723,
+ EVT_ID_PASSWORD_RESET = 4724,
+ EVT_ID_USER_ADDED_TO_GLOBAL_SEC_GROUP = 4728,
+ EVT_ID_USER_REMOVED_FROM_GLOBAL_SEC_GROUP = 4729,
+ EVT_ID_USER_ADDED_TO_LOCAL_SEC_GROUP = 4732,
+ EVT_ID_USER_REMOVED_FROM_LOCAL_SEC_GROUP = 4733,
+ EVT_ID_USER_ADDED_TO_LOCAL_GROUP = 4746,
+ EVT_ID_USER_REMOVED_FROM_LOCAL_GROUP = 4747,
+ EVT_ID_USER_ADDED_TO_GLOBAL_GROUP = 4751,
+ EVT_ID_USER_REMOVED_FROM_GLOBAL_GROUP = 4752,
+ EVT_ID_USER_ADDED_TO_UNIVERSAL_SEC_GROUP = 4756,
+ EVT_ID_USER_REMOVED_FROM_UNIVERSAL_SEC_GROUP = 4757,
+ EVT_ID_USER_ADDED_TO_UNIVERSAL_GROUP = 4761,
+ EVT_ID_USER_REMOVED_FROM_UNIVERSAL_GROUP = 4762
+ } event_id_type;
+
+ /* See https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/authentication-policies-and-authentication-policy-silos#BKMK_ErrorandEvents */
+ typedef [v1_enum,public] enum {
+ AUTH_EVT_ID_NONE = 0,
+ AUTH_EVT_ID_NTLM_DEVICE_RESTRICTION = 101,
+ AUTH_EVT_ID_KERBEROS_DEVICE_RESTRICTION = 105,
+ AUTH_EVT_ID_KERBEROS_DEVICE_RESTRICTION_AUDIT = 305,
+ AUTH_EVT_ID_KERBEROS_SERVER_RESTRICTION = 106,
+ AUTH_EVT_ID_KERBEROS_SERVER_RESTRICTION_AUDIT = 306
+ } auth_event_id_type;
+
+ typedef [v1_enum,public] enum {
+ EVT_LOGON_INTERACTIVE = 2,
+ EVT_LOGON_NETWORK = 3,
+ EVT_LOGON_BATCH = 4,
+ EVT_LOGON_SERVICE = 5,
+ EVT_LOGON_UNLOCK = 7,
+ EVT_LOGON_NETWORK_CLEAR_TEXT = 8,
+ EVT_LOGON_NEW_CREDENTIALS = 9,
+ EVT_LOGON_REMOTE_INTERACTIVE = 10,
+ EVT_LOGON_CACHED_INTERACTIVE = 11
+ } event_logon_type;
+}
diff --git a/librpc/idl/winreg.cnf b/librpc/idl/winreg.cnf
new file mode 100644
index 0000000..e5a146c
--- /dev/null
+++ b/librpc/idl/winreg.cnf
@@ -0,0 +1,52 @@
+IMPORT security_secinfo offset = dissect_ndr_uint32(tvb, offset, pinfo, tree, drep, hf_winreg_winreg_GetKeySecurity_sec_info, NULL);
+
+HF_FIELD hf_winreg_access_required "Access Required" "winreg.access_required" FT_UINT32 BASE_HEX NULL 0 "" "" ""
+
+HF_RENAME hf_winreg_winreg_OpenHKCR_access_required hf_winreg_access_required
+HF_RENAME hf_winreg_winreg_OpenHKLM_access_required hf_winreg_access_required
+HF_RENAME hf_winreg_winreg_OpenHKU_access_required hf_winreg_access_required
+HF_RENAME hf_winreg_winreg_CreateKey_access_required hf_winreg_access_required
+HF_RENAME hf_winreg_winreg_OpenHKCC_access_required hf_winreg_access_required
+HF_RENAME hf_winreg_winreg_OpenHKDD_access_required hf_winreg_access_required
+HF_RENAME hf_winreg_winreg_OpenHKPT_access_required hf_winreg_access_required
+HF_RENAME hf_winreg_winreg_OpenHKPN_access_required hf_winreg_access_required
+
+HF_FIELD hf_winreg_system_name "System Name" "winreg.system_name" FT_UINT16 BASE_DEC NULL 0 "" "" ""
+
+HF_RENAME hf_winreg_winreg_OpenHKCR_system_name hf_winreg_system_name
+HF_RENAME hf_winreg_winreg_OpenHKCU_system_name hf_winreg_system_name
+HF_RENAME hf_winreg_winreg_OpenHKLM_system_name hf_winreg_system_name
+HF_RENAME hf_winreg_winreg_OpenHKPD_system_name hf_winreg_system_name
+HF_RENAME hf_winreg_winreg_OpenHKU_system_name hf_winreg_system_name
+HF_RENAME hf_winreg_winreg_OpenHKCC_system_name hf_winreg_system_name
+HF_RENAME hf_winreg_winreg_OpenHKDD_system_name hf_winreg_system_name
+HF_RENAME hf_winreg_winreg_OpenHKPT_system_name hf_winreg_system_name
+HF_RENAME hf_winreg_winreg_OpenHKPN_system_name hf_winreg_system_name
+
+HF_FIELD hf_winreg_handle "Handle" "winreg.handle" FT_BYTES BASE_NONE NULL 0 "" "" ""
+
+HF_RENAME hf_winreg_winreg_OpenHKCR_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_OpenHKCU_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_OpenHKLM_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_OpenHKPD_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_OpenHKU_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_CloseKey_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_CreateKey_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_DeleteKey_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_DeleteValue_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_EnumKey_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_EnumValue_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_FlushKey_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_GetKeySecurity_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_LoadKey_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_NotifyChangeKeyValue_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_OpenKey_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_QueryInfoKey_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_QueryValue_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_SetKeySecurity_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_SetValue_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_GetVersion_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_OpenHKCC_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_OpenHKDD_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_OpenHKPT_handle hf_winreg_handle
+HF_RENAME hf_winreg_winreg_OpenHKPN_handle hf_winreg_handle
diff --git a/librpc/idl/winreg.idl b/librpc/idl/winreg.idl
new file mode 100644
index 0000000..edbcc30
--- /dev/null
+++ b/librpc/idl/winreg.idl
@@ -0,0 +1,459 @@
+/*
+ winreg interface definition
+*/
+
+import "lsa.idl", "security.idl", "misc.idl";
+
+[
+ uuid("338cd001-2244-31f1-aaaa-900038001003"),
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\winreg]","ncacn_ip_tcp:","ncalrpc:"),
+ pointer_default(unique),
+ helpstring("Remote Registry Service")
+] interface winreg
+{
+ typedef bitmap security_secinfo security_secinfo;
+
+ /*
+ * Access Bits for registry ACLS
+ */
+
+ typedef [public,bitmap32bit] bitmap {
+ KEY_QUERY_VALUE = 0x00001,
+ KEY_SET_VALUE = 0x00002,
+ KEY_CREATE_SUB_KEY = 0x00004,
+ KEY_ENUMERATE_SUB_KEYS = 0x00008,
+ KEY_NOTIFY = 0x00010,
+ KEY_CREATE_LINK = 0x00020,
+ KEY_WOW64_64KEY = 0x00100,
+ KEY_WOW64_32KEY = 0x00200
+ } winreg_AccessMask;
+
+ const int REG_KEY_READ = ( STANDARD_RIGHTS_READ_ACCESS |
+ KEY_QUERY_VALUE |
+ KEY_ENUMERATE_SUB_KEYS |
+ KEY_NOTIFY);
+
+ const int REG_KEY_EXECUTE = REG_KEY_READ;
+
+ const int REG_KEY_WRITE = ( STANDARD_RIGHTS_WRITE_ACCESS |
+ KEY_SET_VALUE |
+ KEY_CREATE_SUB_KEY);
+
+ const int REG_KEY_ALL = ( STANDARD_RIGHTS_REQUIRED_ACCESS |
+ REG_KEY_READ |
+ REG_KEY_WRITE |
+ KEY_CREATE_LINK);
+
+ typedef [public] struct {
+ [value(strlen_m_term(name)*2)] uint16 name_len;
+ [value(strlen_m_term(name)*2)] uint16 name_size;
+ [string,charset(UTF16)] uint16 *name;
+ } winreg_String;
+
+ /******************/
+ /* Function: 0x00 */
+ WERROR winreg_OpenHKCR(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x01 */
+ WERROR winreg_OpenHKCU(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x02 */
+ [public] WERROR winreg_OpenHKLM(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x03 */
+ WERROR winreg_OpenHKPD(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x04 */
+ WERROR winreg_OpenHKU(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x05 */
+ [public] WERROR winreg_CloseKey(
+ [in,out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x06 */
+
+ typedef struct {
+ [size_is(size),length_is(len)] uint8 *data;
+ uint32 size;
+ uint32 len;
+ } KeySecurityData;
+
+ typedef struct {
+ uint32 length;
+ KeySecurityData sd;
+ boolean8 inherit;
+ } winreg_SecBuf;
+
+ const int REG_OPTION_NON_VOLATILE = 0x00000000;
+
+ typedef [bitmap32bit] bitmap {
+ REG_OPTION_VOLATILE = 0x00000001,
+ REG_OPTION_CREATE_LINK = 0x00000002,
+ REG_OPTION_BACKUP_RESTORE = 0x00000004,
+ REG_OPTION_OPEN_LINK = 0x00000008
+ } winreg_KeyOptions;
+
+ typedef [v1_enum] enum {
+ REG_ACTION_NONE = 0, /* used by caller */
+ REG_CREATED_NEW_KEY = 1,
+ REG_OPENED_EXISTING_KEY = 2
+ } winreg_CreateAction;
+
+ [public] WERROR winreg_CreateKey(
+ [in,ref] policy_handle *handle,
+ [in] winreg_String name,
+ [in] winreg_String keyclass,
+ [in] winreg_KeyOptions options,
+ [in] winreg_AccessMask access_mask,
+ [in,unique] winreg_SecBuf *secdesc,
+ [out,ref] policy_handle *new_handle,
+ [in,out,unique] winreg_CreateAction *action_taken
+ );
+
+ /******************/
+ /* Function: 0x07 */
+ [public] WERROR winreg_DeleteKey(
+ [in,ref] policy_handle *handle,
+ [in] winreg_String key
+ );
+
+ /******************/
+ /* Function: 0x08 */
+ WERROR winreg_DeleteValue(
+ [in,ref] policy_handle *handle,
+ [in] winreg_String value
+ );
+
+ typedef struct {
+ [value(strlen_m_term_null(name)*2)] uint16 length;
+ /* size cannot be auto-set by value() as it is the
+ amount of space the server is allowed to use for this
+ string in the reply, not its current size */
+ uint16 size;
+ [size_is(size/2),length_is(length/2),charset(UTF16)] uint16 *name;
+ } winreg_StringBuf;
+
+ /******************/
+ /* Function: 0x09 */
+ [public] WERROR winreg_EnumKey(
+ [in,ref] policy_handle *handle,
+ [in] uint32 enum_index,
+ [in,out,ref] winreg_StringBuf *name,
+ [in,out,unique] winreg_StringBuf *keyclass,
+ [in,out,unique] NTTIME *last_changed_time
+ );
+
+ typedef struct {
+ [value(strlen_m_term(name)*2)] uint16 length;
+ /* size cannot be auto-set by value() as it is the
+ amount of space the server is allowed to use for this
+ string in the reply, not its current size */
+ uint16 size;
+ [size_is(size/2),length_is(length/2),charset(UTF16)] uint16 *name;
+ } winreg_ValNameBuf;
+
+ /******************/
+ /* Function: 0x0a */
+
+ [public] WERROR winreg_EnumValue(
+ [in,ref] policy_handle *handle,
+ [in] uint32 enum_index,
+ [in,out,ref] winreg_ValNameBuf *name,
+ [in,out,unique] winreg_Type *type,
+ [in,out,unique,size_is(size ? *size : 0),length_is(length ? *length : 0),range(0,0x4000000)] uint8 *value,
+ [in,out,unique] uint32 *size,
+ [in,out,unique] uint32 *length
+ );
+
+ /******************/
+ /* Function: 0x0b */
+ [public] WERROR winreg_FlushKey(
+ [in,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x0c */
+ [public] WERROR winreg_GetKeySecurity(
+ [in,ref] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [in,out,ref] KeySecurityData *sd
+ );
+
+ /******************/
+ /* Function: 0x0d */
+ WERROR winreg_LoadKey(
+ [in,ref] policy_handle *handle,
+ [in,unique] winreg_String *keyname,
+ [in,unique] winreg_String *filename
+ );
+
+ /******************/
+ /* Function: 0x0e */
+ typedef [public,bitmap32bit] bitmap {
+ REG_NOTIFY_CHANGE_NAME = 0x00000001,
+ REG_NOTIFY_CHANGE_ATTRIBUTES = 0x00000002,
+ REG_NOTIFY_CHANGE_LAST_SET = 0x00000004,
+ REG_NOTIFY_CHANGE_SECURITY = 0x00000008
+ } winreg_NotifyChangeType;
+
+ [public] WERROR winreg_NotifyChangeKeyValue(
+ [in,ref] policy_handle *handle,
+ [in] boolean8 watch_subtree,
+ [in] winreg_NotifyChangeType notify_filter,
+ [in] uint32 unknown,
+ [in] winreg_String string1,
+ [in] winreg_String string2,
+ [in] uint32 unknown2
+ );
+
+ /******************/
+ /* Function: 0x0f */
+ [public] WERROR winreg_OpenKey(
+ [in,ref] policy_handle *parent_handle,
+ [in] winreg_String keyname,
+ [in] winreg_KeyOptions options,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x10 */
+ [public] WERROR winreg_QueryInfoKey(
+ [in,ref] policy_handle *handle,
+ [in,out,ref] winreg_String *classname,
+ [out,ref] uint32 *num_subkeys,
+ [out,ref] uint32 *max_subkeylen,
+ [out,ref] uint32 *max_classlen,
+ [out,ref] uint32 *num_values,
+ [out,ref] uint32 *max_valnamelen,
+ [out,ref] uint32 *max_valbufsize,
+ [out,ref] uint32 *secdescsize,
+ [out,ref] NTTIME *last_changed_time
+ );
+
+ /******************/
+ /* Function: 0x11 */
+ [public] WERROR winreg_QueryValue(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *value_name,
+ [in,out,unique] winreg_Type *type,
+ [in,out,unique,size_is(data_size ? *data_size : 0),length_is(data_length ? *data_length : 0),range(0,0x4000000)] uint8 *data,
+ [in,out,unique] uint32 *data_size,
+ [in,out,unique] uint32 *data_length
+ );
+
+ /******************/
+ /* Function: 0x12 */
+ WERROR winreg_ReplaceKey(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *subkey,
+ [in,ref] winreg_String *new_file,
+ [in,ref] winreg_String *old_file
+ );
+
+ /******************/
+ /* Function: 0x13 */
+
+ typedef [public,bitmap32bit] bitmap {
+ REG_WHOLE_HIVE_VOLATILE = 0x00000001,
+ REG_REFRESH_HIVE = 0x00000002,
+ REG_NO_LAZY_FLUSH = 0x00000004,
+ REG_FORCE_RESTORE = 0x00000008
+ } winreg_RestoreKeyFlags;
+
+ WERROR winreg_RestoreKey(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *filename,
+ [in] winreg_RestoreKeyFlags flags
+ );
+
+ /******************/
+ /* Function: 0x14 */
+
+ typedef struct {
+ uint32 data_size;
+ KeySecurityData sec_data;
+ uint8 inherit;
+ } KeySecurityAttribute;
+
+ WERROR winreg_SaveKey(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *filename,
+ [in,unique] KeySecurityAttribute *sec_attrib
+ );
+
+ /******************/
+ /* Function: 0x15 */
+ WERROR winreg_SetKeySecurity(
+ [in,ref] policy_handle *handle,
+ [in] security_secinfo sec_info,
+ [in,ref] KeySecurityData *sd
+ );
+
+ /******************/
+ /* Function: 0x16 */
+ WERROR winreg_SetValue(
+ [in,ref] policy_handle *handle,
+ [in] winreg_String name,
+ [in] winreg_Type type,
+ [in,size_is(size),ref] uint8 *data,
+ [in] uint32 size
+ );
+
+ /******************/
+ /* Function: 0x17 */
+ WERROR winreg_UnLoadKey(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *subkey
+ );
+
+ /******************/
+ /* Function: 0x18 */
+ WERROR winreg_InitiateSystemShutdown(
+ [in,unique] uint16 *hostname,
+ /*
+ * Note: lsa_String and winreg_String both result
+ * in WERR_INVALID_PARAMETER
+ */
+ [in,unique] lsa_StringLarge *message,
+ [in] uint32 timeout,
+ [in] uint8 force_apps,
+ [in] uint8 do_reboot
+ );
+
+ /******************/
+ /* Function: 0x19 */
+ WERROR winreg_AbortSystemShutdown(
+ [in,unique] uint16 *server
+ );
+
+ /******************/
+ /* Function: 0x1a */
+ [public] WERROR winreg_GetVersion(
+ [in,ref] policy_handle *handle,
+ [out,ref] uint32 *version
+ );
+
+ /******************/
+ /* Function: 0x1b */
+ WERROR winreg_OpenHKCC(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x1c */
+ WERROR winreg_OpenHKDD(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ typedef struct {
+ winreg_ValNameBuf *ve_valuename;
+ uint32 ve_valuelen;
+ uint32 ve_valueptr;
+ winreg_Type ve_type;
+ } QueryMultipleValue;
+
+ /******************/
+ /* Function: 0x1d */
+ [public] WERROR winreg_QueryMultipleValues(
+ [in,ref] policy_handle *key_handle,
+ [in,ref,size_is(num_values),length_is(num_values)] QueryMultipleValue *values_in,
+ [out,ref,size_is(num_values),length_is(num_values)] QueryMultipleValue *values_out,
+ [in] uint32 num_values,
+ [in,out,unique,size_is(*buffer_size),length_is(*buffer_size)] uint8 *buffer,
+ [in,out,ref] uint32 *buffer_size
+ );
+
+ /******************/
+ /* Function: 0x1e */
+ WERROR winreg_InitiateSystemShutdownEx(
+ [in,unique] uint16 *hostname,
+ /*
+ * Note: lsa_String and winreg_String both result
+ * in WERR_INVALID_PARAMETER
+ */
+ [in,unique] lsa_StringLarge *message,
+ [in] uint32 timeout,
+ [in] uint8 force_apps,
+ [in] uint8 do_reboot,
+ [in] uint32 reason
+ );
+
+ /******************/
+ /* Function: 0x1f */
+ WERROR winreg_SaveKeyEx(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *filename,
+ [in,unique] KeySecurityAttribute *sec_attrib,
+ [in] uint32 flags
+ );
+
+ /******************/
+ /* Function: 0x20 */
+ WERROR winreg_OpenHKPT(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x21 */
+ WERROR winreg_OpenHKPN(
+ [in,unique] uint16 *system_name,
+ [in] winreg_AccessMask access_mask,
+ [out,ref] policy_handle *handle
+ );
+
+ /******************/
+ /* Function: 0x22 */
+ [public] WERROR winreg_QueryMultipleValues2(
+ [in,ref] policy_handle *key_handle,
+ [in,ref,size_is(num_values),length_is(num_values)] QueryMultipleValue *values_in,
+ [out,ref,size_is(num_values),length_is(num_values)] QueryMultipleValue *values_out,
+ [in] uint32 num_values,
+ [in,out,unique,size_is(*offered),length_is(*offered)] uint8 *buffer,
+ [in,ref] uint32 *offered,
+ [out,ref] uint32 *needed
+ );
+
+ /******************/
+ /* Function: 0x23 */
+ WERROR winreg_DeleteKeyEx(
+ [in,ref] policy_handle *handle,
+ [in,ref] winreg_String *key,
+ [in] winreg_AccessMask access_mask,
+ [in] uint32 reserved
+ );
+}
diff --git a/librpc/idl/winspool.idl b/librpc/idl/winspool.idl
new file mode 100644
index 0000000..5497a67
--- /dev/null
+++ b/librpc/idl/winspool.idl
@@ -0,0 +1,878 @@
+#include "idl_types.h"
+
+/*
+ * IRemoteWinspool interface definitions
+ *
+ * This IDL defines the "Print System Asynchronous Remote Protocol" MS-PAR
+ * interface.
+ *
+ * Currently only eight functions in this interface have no matching functions
+ * in the "spoolss" interface. All other functions have a 1-to-1 match but
+ * different opcodes than the spoolss interface.
+ *
+ * Every request on this interface requires a object uuid of
+ * "9940CA8E-512F-4C58-88A9-61098D6896BD" to be sent along with the DCE/RPC
+ * header.
+ *
+ * On Windows, this interface uses [ncacn_ip_tcp] transport and requires
+ * DCERPC_AUTH_TYPE_SPNEGO and at least DCERPC_AUTH_LEVEL_PACKET authentication.
+ *
+ *
+ */
+
+import "misc.idl", "security.idl", "winreg.idl", "spoolss.idl";
+
+[
+ uuid("76f03f96-cdfd-44fc-a22c-64950A001209"),
+ version(1.0),
+ endpoint("ncacn_ip_tcp:"),
+ pointer_default(unique),
+ helpstring("IRemoteWinspool SubSystem")
+]
+ interface iremotewinspool
+{
+#if 0
+ /*
+ * pidl does not yet have a real [context_handle] implementation, so we
+ * just use some defines here.
+ */
+
+ typedef [context_handle] void *GDI_HANDLE;
+ typedef [context_handle] void *PRINTER_HANDLE;
+ typedef [context_handle] void *RMTNTFY_HANDLE;
+#else
+#define GDI_HANDLE policy_handle
+#define PRINTER_HANDLE policy_handle
+#define RMTNTFY_HANDLE policy_handle
+#endif
+
+ const string IREMOTEWINSPOOL_OBJECT_GUID = "9940CA8E-512F-4C58-88A9-61098D6896BD";
+
+ /******************/
+ /* Function: 0x00 */
+
+ typedef struct {
+ spoolss_NotifyInfo *pInfo;
+ } winspool_NOTIFY_REPLY_CONTAINER;
+
+ typedef struct {
+ spoolss_NotifyOption *pOptions;
+ } winspool_NOTIFY_OPTIONS_CONTAINER;
+
+ [public] WERROR winspool_AsyncOpenPrinter(
+ [in,unique] [string,charset(UTF16)] uint16 *pPrinterName,
+ [out] PRINTER_HANDLE *pHandle,
+ [in,unique] [string,charset(UTF16)] uint16 *pDatatype,
+ [in] spoolss_DevmodeContainer *pDevModeContainer,
+ [in] uint32 AccessRequired,
+ [in] spoolss_UserLevelCtr *pClientInfo
+ );
+
+ /******************/
+ /* Function: 0x01 */
+
+ WERROR winspool_AsyncAddPrinter(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in] spoolss_SetPrinterInfoCtr *pPrinterContainer,
+ [in] spoolss_DevmodeContainer *pDevModeContainer,
+ [in] sec_desc_buf *pSecurityContainer,
+ [in] spoolss_UserLevelCtr *pClientInfo,
+ [out] PRINTER_HANDLE *pHandle
+ );
+
+ /******************/
+ /* Function: 0x02 */
+
+ WERROR winspool_AsyncSetJob(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 JobId,
+ [in, unique] spoolss_JobInfoContainer *pJobContainer,
+ [in] uint32 Command
+ );
+
+ /******************/
+ /* Function: 0x03 */
+
+ WERROR winspool_AsyncGetJob(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 JobId,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pJob,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded
+ );
+
+ /******************/
+ /* Function: 0x04 */
+
+ WERROR winspool_AsyncEnumJobs(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 FirstJob,
+ [in] uint32 NoJobs,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pJob,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [out] uint32 *pcReturned
+ );
+
+ /******************/
+ /* Function: 0x05 */
+
+ WERROR winspool_AsyncAddJob(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pAddJob,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded
+ );
+
+ /******************/
+ /* Function: 0x06 */
+
+ WERROR winspool_AsyncScheduleJob(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 JobId
+ );
+
+ /******************/
+ /* Function: 0x07 */
+
+ WERROR winspool_AsyncDeletePrinter(
+ [in] PRINTER_HANDLE hPrinter
+ );
+
+ /******************/
+ /* Function: 0x08 */
+
+ [public] WERROR winspool_AsyncSetPrinter(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] spoolss_SetPrinterInfoCtr *pPrinterContainer,
+ [in] spoolss_DevmodeContainer *pDevModeContainer,
+ [in] sec_desc_buf *pSecurityContainer,
+ [in] uint32 Command
+ );
+
+ /******************/
+ /* Function: 0x09 */
+
+ [public] WERROR winspool_AsyncGetPrinter(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pPrinter,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded
+ );
+
+ /******************/
+ /* Function: 0x0a */
+
+ WERROR winspool_AsyncStartDocPrinter(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] spoolss_DocumentInfoCtr *pDocInfoContainer,
+ [out] uint32 *pJobId
+ );
+
+ /******************/
+ /* Function: 0x0b */
+
+ WERROR winspool_AsyncStartPagePrinter(
+ [in] PRINTER_HANDLE hPrinter
+ );
+
+ /******************/
+ /* Function: 0x0c */
+
+ WERROR winspool_AsyncWritePrinter(
+ [in] PRINTER_HANDLE hPrinter,
+ [in, size_is(cbBuf)] uint8 *pBuf,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcWritten
+ );
+
+ /******************/
+ /* Function: 0x0d */
+
+ WERROR winspool_AsyncEndPagePrinter(
+ [in] PRINTER_HANDLE hPrinter
+ );
+
+ /******************/
+ /* Function: 0x0e */
+
+ WERROR winspool_AsyncEndDocPrinter(
+ [in] PRINTER_HANDLE hPrinter
+ );
+
+ /******************/
+ /* Function: 0x0f */
+
+ WERROR winspool_AsyncAbortPrinter(
+ [in] PRINTER_HANDLE hPrinter
+ );
+
+ /******************/
+ /* Function: 0x10 */
+
+ [public] WERROR winspool_AsyncGetPrinterData(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pValueName,
+ [out] uint32 *pType,
+ [out, size_is(nSize)] uint8 *pData,
+ [in] uint32 nSize,
+ [out] uint32 *pcbNeeded
+ );
+
+ /******************/
+ /* Function: 0x11 */
+
+ WERROR winspool_AsyncGetPrinterDataEx(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pKeyName,
+ [in] [string,charset(UTF16)] uint16 *pValueName,
+ [out] uint32 *pType,
+ [out, size_is(nSize)] uint8 *pData,
+ [in] uint32 nSize,
+ [out] uint32 *pcbNeeded
+ );
+
+ /******************/
+ /* Function: 0x12 */
+
+ WERROR winspool_AsyncSetPrinterData(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pValueName,
+ [in] uint32 Type,
+ [in, size_is(cbData)] uint8 *pData,
+ [in] uint32 cbData
+ );
+
+ /******************/
+ /* Function: 0x13 */
+
+ WERROR winspool_AsyncSetPrinterDataEx(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pKeyName,
+ [in] [string,charset(UTF16)] uint16 *pValueName,
+ [in] uint32 Type,
+ [in, size_is(cbData)] uint8 *pData,
+ [in] uint32 cbData
+ );
+
+ /******************/
+ /* Function: 0x14 */
+
+ [public] WERROR winspool_AsyncClosePrinter(
+ [in, out] PRINTER_HANDLE *phPrinter
+ );
+
+ /******************/
+ /* Function: 0x15 */
+
+ WERROR winspool_AsyncAddForm(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] spoolss_AddFormInfoCtr *pFormInfoContainer
+ );
+
+ /******************/
+ /* Function: 0x16 */
+
+ WERROR winspool_AsyncDeleteForm(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pFormName
+ );
+
+ /******************/
+ /* Function: 0x17 */
+
+ WERROR winspool_AsyncGetForm(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pFormName,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pForm,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded
+ );
+
+ /******************/
+ /* Function: 0x18 */
+
+ WERROR winspool_AsyncSetForm(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pFormName,
+ [in] spoolss_AddFormInfoCtr *pFormInfoContainer
+ );
+
+ /******************/
+ /* Function: 0x19 */
+
+ [public] WERROR winspool_AsyncEnumForms(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pForm,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [out] uint32 *pcReturned
+ );
+
+ /******************/
+ /* Function: 0x1a */
+
+ [public] WERROR winspool_AsyncGetPrinterDriver(
+ [in] PRINTER_HANDLE hPrinter,
+ [in,unique] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pDriver,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [in] uint32 dwClientMajorVersion,
+ [in] uint32 dwClientMinorVersion,
+ [out] uint32 *pdwServerMaxVersion,
+ [out] uint32 *pdwServerMinVersion
+ );
+
+ /******************/
+ /* Function: 0x1b */
+
+ WERROR winspool_AsyncEnumPrinterData(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 dwIndex,
+ [out, size_is(cbValueName/2)] uint16 *pValueName,
+ [in] uint32 cbValueName,
+ [out] uint32 *pcbValueName,
+ [out] uint32 *pType,
+ [out, size_is(cbData)] uint8 *pData,
+ [in] uint32 cbData,
+ [out] uint32 *pcbData
+ );
+
+ /******************/
+ /* Function: 0x1c */
+
+ [public] WERROR winspool_AsyncEnumPrinterDataEx(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pKeyName,
+ [out, size_is(cbEnumValues)] uint8 *pEnumValues,
+ [in] uint32 cbEnumValues,
+ [out] uint32 *pcbEnumValues,
+ [out] uint32 *pnEnumValues
+ );
+
+ /******************/
+ /* Function: 0x1d */
+
+ [public] WERROR winspool_AsyncEnumPrinterKey(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pKeyName,
+ [out, size_is(cbSubkey/2)] uint16 *pSubkey,
+ [in] uint32 cbSubkey,
+ [out] uint32 *pcbSubkey
+ );
+
+ /******************/
+ /* Function: 0x1e */
+
+ WERROR winspool_AsyncDeletePrinterData(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pValueName
+ );
+
+ /******************/
+ /* Function: 0x1f */
+
+ WERROR winspool_AsyncDeletePrinterDataEx(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pKeyName,
+ [in] [string,charset(UTF16)] uint16 *pValueName
+ );
+
+ /******************/
+ /* Function: 0x20 */
+
+ WERROR winspool_AsyncDeletePrinterKey(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] [string,charset(UTF16)] uint16 *pKeyName
+ );
+
+ /******************/
+ /* Function: 0x21 */
+
+ WERROR winspool_AsyncXcvData(
+ [in] PRINTER_HANDLE hXcv,
+ [in] [string,charset(UTF16)] uint16 *pszDataName,
+ [in, size_is(cbInputData)] uint8 *pInputData,
+ [in] uint32 cbInputData,
+ [out, size_is(cbOutputData)] uint8 *pOutputData,
+ [in] uint32 cbOutputData,
+ [out] uint32 *pcbOutputNeeded,
+ [in, out] uint32 *pdwStatus
+ );
+
+ /******************/
+ /* Function: 0x22 */
+
+ WERROR winspool_AsyncSendRecvBidiData (
+ [in] PRINTER_HANDLE hPrinter,
+ [in,unique] [string,charset(UTF16)] uint16 *pAction,
+ [in] RPC_BIDI_REQUEST_CONTAINER* pReqData,
+ [out] RPC_BIDI_RESPONSE_CONTAINER** ppRespData
+ );
+
+ /******************/
+ /* Function: 0x23 */
+
+ WERROR winspool_AsyncCreatePrinterIC(
+ [in] PRINTER_HANDLE hPrinter,
+ [out] GDI_HANDLE *pHandle,
+ [in] spoolss_DevmodeContainer *pDevModeContainer
+ );
+
+ /******************/
+ /* Function: 0x24 */
+
+ WERROR winspool_AsyncPlayGdiScriptOnPrinterIC(
+ [in] GDI_HANDLE hPrinterIC,
+ [in, size_is(cIn)] uint8 *pIn,
+ [in] uint32 cIn,
+ [out, size_is(cOut)] uint8 *pOut,
+ [in] uint32 cOut,
+ [in] uint32 ul
+ );
+
+ /******************/
+ /* Function: 0x25 */
+
+ WERROR winspool_AsyncDeletePrinterIC(
+ [in, out] GDI_HANDLE *phPrinterIC
+ );
+
+ /******************/
+ /* Function: 0x26 */
+
+ WERROR winspool_AsyncEnumPrinters(
+ [in] uint32 Flags,
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pPrinterEnum,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [out] uint32 *pcReturned
+ );
+
+ /******************/
+ /* Function: 0x27 */
+
+ [public] WERROR winspool_AsyncAddPrinterDriver(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in] spoolss_AddDriverInfoCtr *pDriverContainer,
+ [in] uint32 dwFileCopyFlags
+ );
+
+ /******************/
+ /* Function: 0x28 */
+
+ WERROR winspool_AsyncEnumPrinterDrivers(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in,unique] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pDrivers,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [out] uint32 *pcReturned
+ );
+
+ /******************/
+ /* Function: 0x29 */
+
+ [public] WERROR winspool_AsyncGetPrinterDriverDirectory(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in,unique] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pDriverDirectory,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded
+ );
+
+ /******************/
+ /* Function: 0x2a */
+
+ WERROR winspool_AsyncDeletePrinterDriver(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] [string,charset(UTF16)] uint16 *pDriverName
+ );
+
+ /******************/
+ /* Function: 0x2b */
+
+ WERROR winspool_AsyncDeletePrinterDriverEx(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] [string,charset(UTF16)] uint16 *pDriverName,
+ [in] uint32 dwDeleteFlag,
+ [in] uint32 dwVersionNum
+ );
+
+ /******************/
+ /* Function: 0x2c */
+
+ WERROR winspool_AsyncAddPrintProcessor(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] [string,charset(UTF16)] uint16 *pPathName,
+ [in] [string,charset(UTF16)] uint16 *pPrintProcessorName
+ );
+
+ /******************/
+ /* Function: 0x2d */
+
+ WERROR winspool_AsyncEnumPrintProcessors(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in,unique] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pPrintProcessorInfo,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [out] uint32 *pcReturned
+ );
+
+ /******************/
+ /* Function: 0x2e */
+
+ WERROR winspool_AsyncGetPrintProcessorDirectory(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in,unique] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pPrintProcessorDirectory,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded
+ );
+
+ /******************/
+ /* Function: 0x2f */
+
+ WERROR winspool_AsyncEnumPorts(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pPort,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [out] uint32 *pcReturned
+ );
+
+ /******************/
+ /* Function: 0x30 */
+
+ WERROR winspool_AsyncEnumMonitors(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pMonitor,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [out] uint32 *pcReturned
+ );
+
+ /******************/
+ /* Function: 0x31 */
+
+ WERROR winspool_AsyncAddPort(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in] spoolss_SetPortInfoContainer *pPortContainer,
+ [in] spoolss_PortVarContainer *pPortVarContainer,
+ [in] [string,charset(UTF16)] uint16 *pMonitorName
+ );
+
+ /******************/
+ /* Function: 0x32 */
+
+ WERROR winspool_AsyncSetPort(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in,unique] [string,charset(UTF16)] uint16 *pPortName,
+ [in] spoolss_SetPortInfoContainer *pPortContainer
+ );
+
+ /******************/
+ /* Function: 0x33 */
+
+ WERROR winspool_AsyncAddMonitor(
+ [in,unique] [string,charset(UTF16)] uint16 *Name,
+ [in] spoolss_MonitorContainer *pMonitorContainer
+ );
+
+ /******************/
+ /* Function: 0x34 */
+
+ WERROR winspool_AsyncDeleteMonitor(
+ [in,unique] [string,charset(UTF16)] uint16 *Name,
+ [in,unique] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] [string,charset(UTF16)] uint16 *pMonitorName
+ );
+
+ /******************/
+ /* Function: 0x35 */
+
+ WERROR winspool_AsyncDeletePrintProcessor(
+ [in,unique] [string,charset(UTF16)] uint16 *Name,
+ [in,unique] [string,charset(UTF16)] uint16 *pEnvironment,
+ [in] [string,charset(UTF16)] uint16 *pPrintProcessorName
+ );
+
+ /******************/
+ /* Function: 0x36 */
+
+ WERROR winspool_AsyncEnumPrintProcessorDatatypes(
+ [in,unique] [string,charset(UTF16)] uint16 *pName,
+ [in,unique] [string,charset(UTF16)] uint16 *pPrintProcessorName,
+ [in] uint32 Level,
+ [in, out, unique, size_is(cbBuf)] uint8 *pDatatypes,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [out] uint32 *pcReturned
+ );
+
+ /******************/
+ /* Function: 0x37 */
+
+ WERROR winspool_AsyncAddPerMachineConnection(
+ [in,unique] [string,charset(UTF16)] uint16 *pServer,
+ [in] [string,charset(UTF16)] uint16 *pPrinterName,
+ [in] [string,charset(UTF16)] uint16 *pPrintServer,
+ [in] [string,charset(UTF16)] uint16 *pProvider
+ );
+
+ /******************/
+ /* Function: 0x38 */
+
+ WERROR winspool_AsyncDeletePerMachineConnection(
+ [in,unique] [string,charset(UTF16)] uint16 *pServer,
+ [in] [string,charset(UTF16)] uint16 *pPrinterName
+ );
+
+ /******************/
+ /* Function: 0x39 */
+
+ WERROR winspool_AsyncEnumPerMachineConnections(
+ [in,unique] [string,charset(UTF16)] uint16 *pServer,
+ [in, out, unique, size_is(cbBuf)] uint8 *pPrinterEnum,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcbNeeded,
+ [out] uint32 *pcReturned
+ );
+
+ /******************/
+ /* Function: 0x3a */
+
+ typedef enum {
+ winspool_PropertyTypeString = 1,
+ winspool_PropertyTypeInt32 = 2,
+ winspool_PropertyTypeInt64 = 3,
+ winspool_PropertyTypeByte = 4,
+ winspool_PropertyTypeTime = 5,
+ winspool_PropertyTypeDevMode = 6,
+ winspool_PropertyTypeSD = 7,
+ winspool_PropertyTypeNotificationReply = 8,
+ winspool_PropertyTypeNotificationOptions = 9
+ } winspool_PrintPropertyType;
+
+ typedef [ms_union,switch_type(winspool_PrintPropertyType)] union {
+ [case(winspool_PropertyTypeString)] [string,charset(UTF16)] uint16 *propertyString;
+ [case(winspool_PropertyTypeInt32)] uint32 propertyInt32;
+ [case(winspool_PropertyTypeInt64)] hyper propertyInt64;
+ [case(winspool_PropertyTypeByte)] uint8 propertyByte;
+ [case(winspool_PropertyTypeTime)] spoolss_TimeCtr propertyTimeContainer;
+ [case(winspool_PropertyTypeDevMode)] spoolss_DevmodeContainer propertyDevModeContainer;
+ [case(winspool_PropertyTypeSD)] sec_desc_buf propertySDContainer;
+ [case(winspool_PropertyTypeNotificationReply)] winspool_NOTIFY_REPLY_CONTAINER propertyReplyContainer;
+ [case(winspool_PropertyTypeNotificationOptions)] winspool_NOTIFY_OPTIONS_CONTAINER propertyOptionsContainer;
+ } winspool_PrintPropertyValueUnion;
+
+ typedef struct {
+ winspool_PrintPropertyType PropertyType;
+ [switch_is(PropertyType)] winspool_PrintPropertyValueUnion value;
+ } winspool_PrintPropertyValue;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *propertyName;
+ winspool_PrintPropertyValue propertyValue;
+ } winspool_PrintNamedProperty;
+
+ typedef struct {
+ [range(0,50)] uint32 numberOfProperties;
+ [size_is(numberOfProperties), unique] winspool_PrintNamedProperty *propertiesCollection;
+ } winspool_PrintPropertiesCollection;
+
+ [public] HRESULT winspool_SyncRegisterForRemoteNotifications(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] winspool_PrintPropertiesCollection *pNotifyFilter,
+ [out] RMTNTFY_HANDLE *phRpcHandle
+ );
+
+ /******************/
+ /* Function: 0x3b */
+
+ HRESULT winspool_SyncUnRegisterForRemoteNotifications(
+ [in, out] RMTNTFY_HANDLE *phRpcHandle
+ );
+
+ /******************/
+ /* Function: 0x3c */
+
+ HRESULT winspool_SyncRefreshRemoteNotifications(
+ [in] RMTNTFY_HANDLE hRpcHandle,
+ [in] winspool_PrintPropertiesCollection *pNotifyFilter,
+ [out] winspool_PrintPropertiesCollection **ppNotifyData
+ );
+
+ /******************/
+ /* Function: 0x3d */
+
+ HRESULT winspool_AsyncGetRemoteNotifications(
+ [in] RMTNTFY_HANDLE hRpcHandle,
+ [out] winspool_PrintPropertiesCollection **ppNotifyData
+ );
+
+ /******************/
+ /* Function: 0x3e */
+
+ typedef [bitmap32bit] bitmap {
+ IPDFP_FLAG_NONE = 0x00000000,
+ IPDFP_COPY_ALL_FILES = 0x00000001
+ } winspool_InstallPrinterDriverFromPackageFlags;
+
+ HRESULT winspool_AsyncInstallPrinterDriverFromPackage(
+ [in,unique] [string,charset(UTF16)] uint16 *pszServer,
+ [in,unique] [string,charset(UTF16)] uint16 *pszInfPath,
+ [in] [string,charset(UTF16)] uint16 *pszDriverName,
+ [in] [string,charset(UTF16)] uint16 *pszEnvironment,
+ [in] winspool_InstallPrinterDriverFromPackageFlags dwFlags
+ );
+
+ /******************/
+ /* Function: 0x3f */
+
+ typedef [bitmap32bit] bitmap {
+ UPDP_FLAG_NONE = 0x00000000,
+ UPDP_UPLOAD_ALWAYS = 0x00000002,
+ UPDP_CHECK_DRIVERSTORE = 0x00000004
+ } winspool_UploadPrinterDriverPackageFlags;
+
+ HRESULT winspool_AsyncUploadPrinterDriverPackage(
+ [in,unique] [string,charset(UTF16)] uint16 *pszServer,
+ [in] [string,charset(UTF16)] uint16 *pszInfPath,
+ [in] [string,charset(UTF16)] uint16 *pszEnvironment,
+ [in] winspool_UploadPrinterDriverPackageFlags dwFlags,
+ [in, out, unique, size_is(*pcchDestInfPath)] [charset(UTF16)] uint16 *pszDestInfPath,
+ [in, out] uint32 *pcchDestInfPath
+ );
+
+ /******************/
+ /* Function: 0x40 */
+
+ [public] HRESULT winspool_AsyncGetCorePrinterDrivers(
+ [in,unique] [string,charset(UTF16)] uint16 *pszServer,
+ [in] [string,charset(UTF16)] uint16 *pszEnvironment,
+ [in] uint32 cchCoreDrivers,
+ [in, size_is(cchCoreDrivers)] uint16 *pszzCoreDriverDependencies,
+ [in] uint32 cCorePrinterDrivers,
+ [out, size_is(cCorePrinterDrivers)] spoolss_CorePrinterDriver *pCorePrinterDrivers
+ );
+
+ /******************/
+ /* Function: 0x41 */
+
+ HRESULT winspool_AsyncCorePrinterDriverInstalled(
+ [in,unique] [string,charset(UTF16)] uint16 *pszServer,
+ [in] [string,charset(UTF16)] uint16 *pszEnvironment,
+ [in] GUID CoreDriverGUID,
+ [in] NTTIME ftDriverDate,
+ [in] hyper dwlDriverVersion,
+ [out] int *pbDriverInstalled
+ );
+
+ /******************/
+ /* Function: 0x42 */
+
+ HRESULT winspool_AsyncGetPrinterDriverPackagePath(
+ [in,unique] [string,charset(UTF16)] uint16 *pszServer,
+ [in] [string,charset(UTF16)] uint16 *pszEnvironment,
+ [in,unique] [string,charset(UTF16)] uint16 *pszLanguage,
+ [in] [string,charset(UTF16)] uint16 *pszPackageID,
+ [in, out, unique, size_is(cchDriverPackageCab)] uint16 *pszDriverPackageCab,
+ [in] uint32 cchDriverPackageCab,
+ [out] uint32 *pcchRequiredSize
+ );
+
+ /******************/
+ /* Function: 0x43 */
+
+ HRESULT winspool_AsyncDeletePrinterDriverPackage(
+ [in,unique] [string,charset(UTF16)] uint16 *pszServer,
+ [in] [string,charset(UTF16)] uint16 *pszInfPath,
+ [in] [string,charset(UTF16)] uint16 *pszEnvironment
+ );
+
+ /******************/
+ /* Function: 0x44 */
+
+ WERROR winspool_AsyncReadPrinter(
+ [in] PRINTER_HANDLE hPrinter,
+ [out, size_is(cbBuf)] uint8 *pBuf,
+ [in] uint32 cbBuf,
+ [out] uint32 *pcNoBytesRead
+ );
+
+ /******************/
+ /* Function: 0x45 */
+
+ WERROR winspool_AsyncResetPrinter(
+ [in] PRINTER_HANDLE hPrinter,
+ [in,unique] [string,charset(UTF16)] uint16 *pDatatype,
+ [in] spoolss_DevmodeContainer *pDevModeContainer
+ );
+
+ /******************/
+ /* Function: 0x46 */
+
+ WERROR winspool_AsyncGetJobNamedPropertyValue(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 JobId,
+ [in] [string,charset(UTF16)] uint16 *pszName,
+ [out] spoolss_PrintPropertyValue *pValue
+ );
+
+ /******************/
+ /* Function: 0x47 */
+
+ [public] WERROR winspool_AsyncSetJobNamedProperty(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 JobId,
+ [in] spoolss_PrintNamedProperty *pProperty
+ );
+
+ /******************/
+ /* Function: 0x48 */
+
+ WERROR winspool_AsyncDeleteJobNamedProperty(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 JobId,
+ [in] [string,charset(UTF16)] uint16 *pszName
+ );
+
+ /******************/
+ /* Function: 0x49 */
+
+ WERROR winspool_AsyncEnumJobNamedProperties(
+ [in] PRINTER_HANDLE hPrinter,
+ [in] uint32 JobId,
+ [out] uint32 *pcProperties,
+ [out, size_is(,*pcProperties)] spoolss_PrintNamedProperty **ppProperties
+ );
+
+ /******************/
+ /* Function: 0x4a */
+
+ WERROR winspool_AsyncLogJobInfoForBranchOffice(
+ [in] PRINTER_HANDLE hPrinter,
+ [in,ref] spoolss_BranchOfficeJobDataContainer *pBranchOfficeJobDataContainer
+ );
+}
diff --git a/librpc/idl/winstation.idl b/librpc/idl/winstation.idl
new file mode 100644
index 0000000..fb02fa7
--- /dev/null
+++ b/librpc/idl/winstation.idl
@@ -0,0 +1,13 @@
+/*
+ winstation interface definition
+*/
+
+#include "idl_types.h"
+
+[ uuid("5ca4a760-ebb1-11cf-8611-00a0245420ed"),
+ version(1.0),
+ helpstring("Terminal Services remote management")
+] interface winstation
+{
+ void winstation_foo();
+}
diff --git a/librpc/idl/witness.idl b/librpc/idl/witness.idl
new file mode 100644
index 0000000..dc3af4a
--- /dev/null
+++ b/librpc/idl/witness.idl
@@ -0,0 +1,153 @@
+#include "idl_types.h"
+
+import "misc.idl";
+
+[
+ uuid("ccd8c074-d0e5-4a40-92b4-d074faa6ba28"),
+ version(1.1),
+ pointer_default(unique),
+ helpstring("SMB Witness Service"),
+ helper("../librpc/ndr/ndr_witness.h"),
+ endpoint("ncacn_ip_tcp:"),
+ authservice("cifs")
+]
+interface witness
+{
+ typedef [flag(NDR_PAHEX),v1_enum,public] enum {
+ WITNESS_V1 = 0x00010001,
+ WITNESS_V2 = 0x00020000,
+ WITNESS_UNSPECIFIED_VERSION = 0xFFFFFFFF
+ } witness_version;
+
+ /*****************/
+ /* Function 0x00 */
+
+ typedef [flag(NDR_PAHEX),enum16bit] enum {
+ WITNESS_STATE_UNKNOWN = 0x00,
+ WITNESS_STATE_AVAILABLE = 0x01,
+ WITNESS_STATE_UNAVAILABLE = 0xff
+ } witness_interfaceInfo_state;
+
+ typedef [bitmap32bit] bitmap {
+ WITNESS_INFO_IPv4_VALID = 0x01,
+ WITNESS_INFO_IPv6_VALID = 0x02,
+ WITNESS_INFO_WITNESS_IF = 0x04
+ } witness_interfaceInfo_flags;
+
+ typedef struct {
+ [charset(UTF16),to_null] uint16 group_name[260];
+ witness_version version;
+ witness_interfaceInfo_state state;
+ [flag(NDR_BIG_ENDIAN)] ipv4address ipv4;
+ [flag(NDR_BIG_ENDIAN)] ipv6address ipv6;
+ witness_interfaceInfo_flags flags;
+ } witness_interfaceInfo;
+
+ typedef [public] struct {
+ uint32 num_interfaces;
+ [size_is(num_interfaces)] witness_interfaceInfo *interfaces;
+ } witness_interfaceList;
+
+ [public] WERROR witness_GetInterfaceList(
+ [out] witness_interfaceList **interface_list
+ );
+
+ /*****************/
+ /* Function 0x01 */
+
+ [public] WERROR witness_Register(
+ [out,ref] policy_handle *context_handle,
+ [in] witness_version version,
+ [in,unique,string,charset(UTF16)] uint16 *net_name,
+ [in,unique,string,charset(UTF16)] uint16 *ip_address,
+ [in,unique,string,charset(UTF16)] uint16 *client_computer_name
+ );
+
+ /*****************/
+ /* Function 0x02 */
+
+ [public] WERROR witness_UnRegister(
+ [in] policy_handle context_handle
+ );
+
+ /*****************/
+ /* Function 0x03 */
+
+ typedef [v1_enum,public] enum {
+ WITNESS_NOTIFY_RESOURCE_CHANGE = 1,
+ WITNESS_NOTIFY_CLIENT_MOVE = 2,
+ WITNESS_NOTIFY_SHARE_MOVE = 3,
+ WITNESS_NOTIFY_IP_CHANGE = 4
+ } witness_notifyResponse_type;
+
+ typedef [flag(NDR_PAHEX),v1_enum] enum {
+ WITNESS_RESOURCE_STATE_UNKNOWN = 0x00,
+ WITNESS_RESOURCE_STATE_AVAILABLE = 0x01,
+ WITNESS_RESOURCE_STATE_UNAVAILABLE = 0xff
+ } witness_ResourceChange_type;
+
+ typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN),gensize,public] struct {
+ [value(ndr_size_witness_ResourceChange(r,ndr->flags))] uint32 length;
+ witness_ResourceChange_type type;
+ nstring name;
+ } witness_ResourceChange;
+
+ typedef [bitmap32bit] bitmap {
+ WITNESS_IPADDR_V4 = 0x01,
+ WITNESS_IPADDR_V6 = 0x02,
+ WITNESS_IPADDR_ONLINE = 0x08,
+ WITNESS_IPADDR_OFFLINE = 0x10
+ } witness_IPaddrInfo_flags;
+
+ typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN)] struct {
+ witness_IPaddrInfo_flags flags;
+ [flag(NDR_BIG_ENDIAN)] ipv4address ipv4;
+ [flag(NDR_BIG_ENDIAN)] ipv6address ipv6;
+ } witness_IPaddrInfo;
+
+ typedef [public,flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN),gensize] struct {
+ [value(ndr_size_witness_IPaddrInfoList(r, ndr->flags))] uint32 length;
+ [value(0)] uint32 reserved;
+ uint32 num;
+ witness_IPaddrInfo addr[num];
+ } witness_IPaddrInfoList;
+
+ typedef [public,switch_type(witness_notifyResponse_type),nodiscriminant, flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN)] union {
+ [case(WITNESS_NOTIFY_RESOURCE_CHANGE)] witness_ResourceChange resource_change;
+ [case(WITNESS_NOTIFY_CLIENT_MOVE)] witness_IPaddrInfoList client_move;
+ [case(WITNESS_NOTIFY_SHARE_MOVE)] witness_IPaddrInfoList share_move;
+ [case(WITNESS_NOTIFY_IP_CHANGE)] witness_IPaddrInfoList ip_change;
+ [default,flag(NDR_REMAINING)] DATA_BLOB data;
+ } witness_notifyResponse_message;
+
+ typedef [flag(NDR_PAHEX),gensize,public,nopush,nopull] struct {
+ witness_notifyResponse_type type;
+ [value(ndr_size_witness_notifyResponse(r, ndr->flags)-20)] uint32 length;
+ uint32 num;
+ [subcontext(4), subcontext_size(length), flag(NDR_REMAINING), switch_is(type), size_is(num)] witness_notifyResponse_message *messages;
+ } witness_notifyResponse;
+
+ [public] WERROR witness_AsyncNotify(
+ [in] policy_handle context_handle,
+ [out] witness_notifyResponse **response
+ );
+
+ /*****************/
+ /* Function 0x04 */
+
+ typedef [bitmap32bit,public] bitmap {
+ WITNESS_REGISTER_NONE = 0x00,
+ WITNESS_REGISTER_IP_NOTIFICATION = 0x01
+ } witness_RegisterEx_flags;
+
+ WERROR witness_RegisterEx(
+ [out,ref] policy_handle *context_handle,
+ [in] witness_version version,
+ [in,unique,string,charset(UTF16)] uint16 *net_name,
+ [in,unique,string,charset(UTF16)] uint16 *share_name,
+ [in,unique,string,charset(UTF16)] uint16 *ip_address,
+ [in,unique,string,charset(UTF16)] uint16 *client_computer_name,
+ [in] witness_RegisterEx_flags flags,
+ [in] uint32 timeout
+ );
+}
diff --git a/librpc/idl/wkssvc.idl b/librpc/idl/wkssvc.idl
new file mode 100644
index 0000000..9e92ed7
--- /dev/null
+++ b/librpc/idl/wkssvc.idl
@@ -0,0 +1,796 @@
+#include "idl_types.h"
+
+/*
+ wkssvc interface definitions
+*/
+
+import "srvsvc.idl", "lsa.idl";
+
+[ uuid("6bffd098-a112-3610-9833-46c3f87e345a"),
+ version(1.0),
+ pointer_default(unique),
+ helpstring("Workstation Service"),
+ endpoint("ncacn_np:[\\pipe\\wkssvc]","ncacn_ip_tcp:","ncalrpc:")
+] interface wkssvc
+{
+ typedef [v1_enum] enum srvsvc_PlatformId srvsvc_PlatformId;
+
+#define BOOL uint32
+
+ /******************/
+ /* Function: 0x00 */
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ [string,charset(UTF16)] uint16 *domain_name;
+ uint32 version_major;
+ uint32 version_minor;
+ } wkssvc_NetWkstaInfo100;
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ [string,charset(UTF16)] uint16 *domain_name;
+ uint32 version_major;
+ uint32 version_minor;
+ [string,charset(UTF16)] uint16 *lan_root;
+ } wkssvc_NetWkstaInfo101;
+
+ typedef struct {
+ srvsvc_PlatformId platform_id;
+ [string,charset(UTF16)] uint16 *server_name;
+ [string,charset(UTF16)] uint16 *domain_name;
+ uint32 version_major;
+ uint32 version_minor;
+ [string,charset(UTF16)] uint16 *lan_root;
+ uint32 logged_on_users;
+ } wkssvc_NetWkstaInfo102;
+
+ /* FIXME: 302, 402 */
+
+ typedef struct {
+ uint32 char_wait;
+ uint32 collection_time;
+ uint32 maximum_collection_count;
+ uint32 keep_connection;
+ uint32 max_commands;
+ uint32 session_timeout;
+ uint32 size_char_buf;
+ uint32 max_threads;
+ uint32 lock_quota;
+ uint32 lock_increment;
+ uint32 lock_maximum;
+ uint32 pipe_increment;
+ uint32 pipe_maximum;
+ uint32 cache_file_timeout;
+ uint32 dormant_file_limit;
+ uint32 read_ahead_throughput;
+ uint32 num_mailslot_buffers;
+ uint32 num_srv_announce_buffers;
+ uint32 max_illegal_dgram_events;
+ uint32 dgram_event_reset_freq;
+ BOOL log_election_packets;
+ BOOL use_opportunistic_locking;
+ BOOL use_unlock_behind;
+ BOOL use_close_behind;
+ BOOL buf_named_pipes;
+ BOOL use_lock_read_unlock;
+ BOOL utilize_nt_caching;
+ BOOL use_raw_read;
+ BOOL use_raw_write;
+ BOOL use_write_raw_data;
+ BOOL use_encryption;
+ BOOL buf_files_deny_write;
+ BOOL buf_read_only_files;
+ BOOL force_core_create_mode;
+ BOOL use_512_byte_max_transfer;
+ } wkssvc_NetWkstaInfo502;
+
+ typedef struct {
+ uint32 char_wait;
+ } wkssvc_NetWkstaInfo1010;
+
+ typedef struct {
+ uint32 collection_time;
+ } wkssvc_NetWkstaInfo1011;
+
+ typedef struct {
+ uint32 maximum_collection_count;
+ } wkssvc_NetWkstaInfo1012;
+
+ typedef struct {
+ uint32 keep_connection;
+ } wkssvc_NetWkstaInfo1013;
+
+ typedef struct {
+ uint32 session_timeout;
+ } wkssvc_NetWkstaInfo1018;
+
+ typedef struct {
+ uint32 size_char_buf;
+ } wkssvc_NetWkstaInfo1023;
+
+ typedef struct {
+ uint32 errorlog_sz;
+ } wkssvc_NetWkstaInfo1027;
+
+ /* downlevel */
+ typedef struct {
+ uint32 print_buf_time;
+ } wkssvc_NetWkstaInfo1028;
+
+ /* downlevel */
+ typedef struct {
+ uint32 wrk_heuristics;
+ } wkssvc_NetWkstaInfo1032;
+
+ typedef struct {
+ uint32 max_threads;
+ } wkssvc_NetWkstaInfo1033;
+
+ typedef struct {
+ uint32 lock_quota;
+ } wkssvc_NetWkstaInfo1041;
+
+ typedef struct {
+ uint32 lock_increment;
+ } wkssvc_NetWkstaInfo1042;
+
+ typedef struct {
+ uint32 lock_maximum;
+ } wkssvc_NetWkstaInfo1043;
+
+ typedef struct {
+ uint32 pipe_increment;
+ } wkssvc_NetWkstaInfo1044;
+
+ typedef struct {
+ uint32 pipe_maximum;
+ } wkssvc_NetWkstaInfo1045;
+
+ typedef struct {
+ uint32 dormant_file_limit;
+ } wkssvc_NetWkstaInfo1046;
+
+ typedef struct {
+ uint32 cache_file_timeout;
+ } wkssvc_NetWkstaInfo1047;
+
+ typedef struct {
+ uint32 use_opportunistic_locking;
+ } wkssvc_NetWkstaInfo1048;
+
+ typedef struct {
+ uint32 use_unlock_behind;
+ } wkssvc_NetWkstaInfo1049;
+
+ typedef struct {
+ uint32 use_close_behind;
+ } wkssvc_NetWkstaInfo1050;
+
+ typedef struct {
+ uint32 buf_named_pipes;
+ } wkssvc_NetWkstaInfo1051;
+
+ typedef struct {
+ uint32 use_lock_read_unlock;
+ } wkssvc_NetWkstaInfo1052;
+
+ typedef struct {
+ uint32 utilize_nt_caching;
+ } wkssvc_NetWkstaInfo1053;
+
+ typedef struct {
+ uint32 use_raw_read;
+ } wkssvc_NetWkstaInfo1054;
+
+ typedef struct {
+ uint32 use_raw_write;
+ } wkssvc_NetWkstaInfo1055;
+
+ typedef struct {
+ uint32 use_write_raw_data;
+ } wkssvc_NetWkstaInfo1056;
+
+ typedef struct {
+ uint32 use_encryption;
+ } wkssvc_NetWkstaInfo1057;
+
+ typedef struct {
+ uint32 buf_files_deny_write;
+ } wkssvc_NetWkstaInfo1058;
+
+ typedef struct {
+ uint32 buf_read_only_files;
+ } wkssvc_NetWkstaInfo1059;
+
+ typedef struct {
+ uint32 force_core_create_mode;
+ } wkssvc_NetWkstaInfo1060;
+
+ typedef struct {
+ uint32 use_512_byte_max_transfer;
+ } wkssvc_NetWkstaInfo1061;
+
+ typedef struct {
+ uint32 read_ahead_throughput;
+ } wkssvc_NetWkstaInfo1062;
+
+ typedef union {
+ [case(100)] wkssvc_NetWkstaInfo100 *info100;
+ [case(101)] wkssvc_NetWkstaInfo101 *info101;
+ [case(102)] wkssvc_NetWkstaInfo102 *info102;
+ [case(502)] wkssvc_NetWkstaInfo502 *info502;
+ [case(1010)] wkssvc_NetWkstaInfo1010 *info1010;
+ [case(1011)] wkssvc_NetWkstaInfo1011 *info1011;
+ [case(1012)] wkssvc_NetWkstaInfo1012 *info1012;
+ [case(1013)] wkssvc_NetWkstaInfo1013 *info1013;
+ [case(1018)] wkssvc_NetWkstaInfo1018 *info1018;
+ [case(1023)] wkssvc_NetWkstaInfo1023 *info1023;
+ [case(1027)] wkssvc_NetWkstaInfo1027 *info1027;
+ [case(1028)] wkssvc_NetWkstaInfo1028 *info1028;
+ [case(1032)] wkssvc_NetWkstaInfo1032 *info1032;
+ [case(1033)] wkssvc_NetWkstaInfo1033 *info1033;
+ [case(1041)] wkssvc_NetWkstaInfo1041 *info1041;
+ [case(1042)] wkssvc_NetWkstaInfo1042 *info1042;
+ [case(1043)] wkssvc_NetWkstaInfo1043 *info1043;
+ [case(1044)] wkssvc_NetWkstaInfo1044 *info1044;
+ [case(1045)] wkssvc_NetWkstaInfo1045 *info1045;
+ [case(1046)] wkssvc_NetWkstaInfo1046 *info1046;
+ [case(1047)] wkssvc_NetWkstaInfo1047 *info1047;
+ [case(1048)] wkssvc_NetWkstaInfo1048 *info1048;
+ [case(1049)] wkssvc_NetWkstaInfo1049 *info1049;
+ [case(1050)] wkssvc_NetWkstaInfo1050 *info1050;
+ [case(1051)] wkssvc_NetWkstaInfo1051 *info1051;
+ [case(1052)] wkssvc_NetWkstaInfo1052 *info1052;
+ [case(1053)] wkssvc_NetWkstaInfo1053 *info1053;
+ [case(1054)] wkssvc_NetWkstaInfo1054 *info1054;
+ [case(1055)] wkssvc_NetWkstaInfo1055 *info1055;
+ [case(1056)] wkssvc_NetWkstaInfo1056 *info1056;
+ [case(1057)] wkssvc_NetWkstaInfo1057 *info1057;
+ [case(1058)] wkssvc_NetWkstaInfo1058 *info1058;
+ [case(1059)] wkssvc_NetWkstaInfo1059 *info1059;
+ [case(1060)] wkssvc_NetWkstaInfo1060 *info1060;
+ [case(1061)] wkssvc_NetWkstaInfo1061 *info1061;
+ [case(1062)] wkssvc_NetWkstaInfo1062 *info1062;
+ [default] ;
+ } wkssvc_NetWkstaInfo;
+
+ WERROR wkssvc_NetWkstaGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 level,
+ [out,switch_is(level),ref] wkssvc_NetWkstaInfo *info
+ );
+
+
+ /******************/
+ /* Function: 0x01 */
+ WERROR wkssvc_NetWkstaSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 level,
+ [in,switch_is(level),ref] wkssvc_NetWkstaInfo *info,
+ [in,out,ref] uint32 *parm_error
+ );
+
+
+ /*****************************/
+ /* Function 0x02 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *user_name;
+ } wkssvc_NetrWkstaUserInfo0;
+
+ typedef struct {
+ uint32 entries_read;
+ [size_is(entries_read)] wkssvc_NetrWkstaUserInfo0 *user0;
+ } wkssvc_NetWkstaEnumUsersCtr0;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *user_name;
+ [string,charset(UTF16)] uint16 *logon_domain;
+ [string,charset(UTF16)] uint16 *other_domains;
+ [string,charset(UTF16)] uint16 *logon_server;
+ } wkssvc_NetrWkstaUserInfo1;
+
+ typedef struct {
+ uint32 entries_read;
+ [size_is(entries_read)] wkssvc_NetrWkstaUserInfo1 *user1;
+ } wkssvc_NetWkstaEnumUsersCtr1;
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] wkssvc_NetWkstaEnumUsersCtr0 *user0;
+ [case(1)] wkssvc_NetWkstaEnumUsersCtr1 *user1;
+ } wkssvc_NetWkstaEnumUsersCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] wkssvc_NetWkstaEnumUsersCtr ctr;
+ } wkssvc_NetWkstaEnumUsersInfo;
+
+ WERROR wkssvc_NetWkstaEnumUsers(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,out,ref] wkssvc_NetWkstaEnumUsersInfo *info,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************************/
+ /* Function 0x03 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *other_domains;
+ } wkssvc_NetrWkstaUserInfo1101;
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] wkssvc_NetrWkstaUserInfo0 *info0;
+ [case(1)] wkssvc_NetrWkstaUserInfo1 *info1;
+ [case(1101)] wkssvc_NetrWkstaUserInfo1101 *info1101;
+ } wkssvc_NetrWkstaUserInfo;
+
+ WERROR wkssvc_NetrWkstaUserGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *unknown,
+ [in] uint32 level,
+ [out,ref] [switch_is(level)] wkssvc_NetrWkstaUserInfo *info
+ );
+
+ /*****************************/
+ /* Function 0x04 */
+ WERROR wkssvc_NetrWkstaUserSetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *unknown,
+ [in] uint32 level,
+ [in,ref] [switch_is(level)] wkssvc_NetrWkstaUserInfo *info,
+ [in,out,unique] uint32 *parm_err
+ );
+
+ /*****************************/
+ /* Function 0x05 */
+
+ typedef struct {
+ uint32 quality_of_service;
+ uint32 vc_count;
+ [string,charset(UTF16)] uint16 *name;
+ [string,charset(UTF16)] uint16 *address;
+ uint32 wan_link;
+ } wkssvc_NetWkstaTransportInfo0;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] wkssvc_NetWkstaTransportInfo0 *array;
+ } wkssvc_NetWkstaTransportCtr0;
+
+ typedef union {
+ [case(0)] wkssvc_NetWkstaTransportCtr0 *ctr0;
+ } wkssvc_NetWkstaTransportCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] wkssvc_NetWkstaTransportCtr ctr;
+ } wkssvc_NetWkstaTransportInfo;
+
+ WERROR wkssvc_NetWkstaTransportEnum (
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,out,ref] wkssvc_NetWkstaTransportInfo *info,
+ [in] uint32 max_buffer,
+ [out,ref] uint32 *total_entries,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************************/
+ /* Function 0x06 */
+ /* only supported on NT */
+ WERROR wkssvc_NetrWkstaTransportAdd(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 level, /* must be 0 */
+ [in,ref] wkssvc_NetWkstaTransportInfo0 *info0,
+ [in,out,unique] uint32 *parm_err
+ );
+
+ /*****************************/
+ /* Function 0x07 */
+ /* only supported on NT */
+ WERROR wkssvc_NetrWkstaTransportDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *transport_name,
+ [in] uint32 unknown3
+ );
+
+ /*****************************/
+ /* Function 0x08 */
+ typedef struct {
+ [string,charset(UTF16)] uint16 *unknown1;
+ [string,charset(UTF16)] uint16 *unknown2;
+ } wkssvc_NetrUseInfo3;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *local;
+ [string,charset(UTF16)] uint16 *remote;
+ [string,charset(UTF16)] uint16 *password;
+ uint32 status;
+ uint32 asg_type;
+ uint32 ref_count;
+ uint32 use_count;
+ [string,charset(UTF16)] uint16 *user_name;
+ [string,charset(UTF16)] uint16 *domain_name;
+ } wkssvc_NetrUseInfo2;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *local;
+ [string,charset(UTF16)] uint16 *remote;
+ [string,charset(UTF16)] uint16 *password;
+ uint32 status;
+ uint32 asg_type;
+ uint32 ref_count;
+ uint32 use_count;
+ } wkssvc_NetrUseInfo1;
+
+ typedef struct {
+ [string,charset(UTF16)] uint16 *local;
+ [string,charset(UTF16)] uint16 *remote;
+ } wkssvc_NetrUseInfo0;
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] wkssvc_NetrUseInfo0 *info0;
+ [case(1)] wkssvc_NetrUseInfo1 *info1;
+ [case(2)] wkssvc_NetrUseInfo2 *info2;
+ [case(3)] wkssvc_NetrUseInfo3 *info3;
+ } wkssvc_NetrUseGetInfoCtr;
+
+ WERROR wkssvc_NetrUseAdd(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] uint32 level,
+ [in,ref] [switch_is(level)] wkssvc_NetrUseGetInfoCtr *ctr,
+ [in,out,unique] uint32 *parm_err
+ );
+
+ /*****************************/
+ /* Function 0x09 */
+ WERROR wkssvc_NetrUseGetInfo(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *use_name,
+ [in] uint32 level,
+ [out,ref] [switch_is(level)] wkssvc_NetrUseGetInfoCtr *ctr
+ );
+
+ /*****************************/
+ /* Function 0x0a */
+ WERROR wkssvc_NetrUseDel(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *use_name,
+ [in] uint32 force_cond
+ );
+
+ /*****************************/
+ /* Function 0x0b */
+ typedef struct {
+ uint32 count;
+ [size_is(count)] wkssvc_NetrUseInfo2 *array;
+ } wkssvc_NetrUseEnumCtr2;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] wkssvc_NetrUseInfo1 *array;
+ } wkssvc_NetrUseEnumCtr1;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] wkssvc_NetrUseInfo0 *array;
+ } wkssvc_NetrUseEnumCtr0;
+
+ typedef [switch_type(uint32)] union {
+ [case(0)] wkssvc_NetrUseEnumCtr0 *ctr0;
+ [case(1)] wkssvc_NetrUseEnumCtr1 *ctr1;
+ [case(2)] wkssvc_NetrUseEnumCtr2 *ctr2;
+ } wkssvc_NetrUseEnumCtr;
+
+ typedef struct {
+ uint32 level;
+ [switch_is(level)] wkssvc_NetrUseEnumCtr ctr;
+ } wkssvc_NetrUseEnumInfo;
+
+ WERROR wkssvc_NetrUseEnum(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,out,ref] wkssvc_NetrUseEnumInfo *info,
+ [in] uint32 prefmaxlen,
+ [out,ref] uint32 *entries_read,
+ [in,out,unique] uint32 *resume_handle
+ );
+
+ /*****************************/
+ /* Function 0x0c */
+ WERROR wkssvc_NetrMessageBufferSend(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *message_name,
+ [in,unique] [string,charset(UTF16)] uint16 *message_sender_name,
+ [in,ref] [size_is(message_size)] uint8 *message_buffer,
+ [in] uint32 message_size
+ );
+
+ /*****************************/
+ /* Function 0x0d */
+ typedef struct {
+ hyper unknown1;
+ hyper unknown2;
+ hyper unknown3;
+ hyper unknown4;
+ hyper unknown5;
+ hyper unknown6;
+ hyper unknown7;
+ hyper unknown8;
+ hyper unknown9;
+ hyper unknown10;
+ hyper unknown11;
+ hyper unknown12;
+ hyper unknown13;
+ uint32 unknown14;
+ uint32 unknown15;
+ uint32 unknown16;
+ uint32 unknown17;
+ uint32 unknown18;
+ uint32 unknown19;
+ uint32 unknown20;
+ uint32 unknown21;
+ uint32 unknown22;
+ uint32 unknown23;
+ uint32 unknown24;
+ uint32 unknown25;
+ uint32 unknown26;
+ uint32 unknown27;
+ uint32 unknown28;
+ uint32 unknown29;
+ uint32 unknown30;
+ uint32 unknown31;
+ uint32 unknown32;
+ uint32 unknown33;
+ uint32 unknown34;
+ uint32 unknown35;
+ uint32 unknown36;
+ uint32 unknown37;
+ uint32 unknown38;
+ uint32 unknown39;
+ uint32 unknown40;
+ } wkssvc_NetrWorkstationStatistics;
+
+ WERROR wkssvc_NetrWorkstationStatisticsGet(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *unknown2,
+ [in] uint32 unknown3,
+ [in] uint32 unknown4,
+ [out,ref] wkssvc_NetrWorkstationStatistics **info
+ );
+
+ /*****************************/
+ /* Function 0x0e */
+ WERROR wkssvc_NetrLogonDomainNameAdd(
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name
+ );
+
+ /*****************************/
+ /* Function 0x0f */
+ WERROR wkssvc_NetrLogonDomainNameDel(
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name
+ );
+
+ /*****************************/
+ /* Function 0x10 */
+ WERROR wkssvc_NetrJoinDomain(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] [string,charset(UTF16)] uint16 *account_ou,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *password,
+ [in] wkssvc_joinflags join_flags
+ );
+
+ /*****************************/
+ /* Function 0x11 */
+ WERROR wkssvc_NetrUnjoinDomain(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *password,
+ [in] wkssvc_joinflags unjoin_flags
+ );
+
+ /*****************************/
+ /* Function 0x12 */
+ typedef [bitmap32bit] bitmap {
+ /* TRUE: create the account in the domain */
+ WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE = 0x00000002
+ } wkssvc_renameflags;
+
+ WERROR wkssvc_NetrRenameMachineInDomain(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *NewMachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *password,
+ [in] wkssvc_renameflags RenameOptions
+ );
+
+ /*****************************/
+ /* Function 0x13 */
+ typedef enum {
+ NetSetupUnknown = 0,
+ NetSetupMachine = 1,
+ NetSetupWorkgroup = 2,
+ NetSetupDomain = 3,
+ NetSetupNonExistentDomain = 4,
+ NetSetupDnsMachine = 5
+ } wkssvc_NetValidateNameType;
+
+ WERROR wkssvc_NetrValidateName(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *Password,
+ [in] wkssvc_NetValidateNameType name_type
+ );
+
+ /*****************************/
+ /* Function 0x14 */
+ typedef enum {
+ NET_SETUP_UNKNOWN_STATUS = 0,
+ NET_SETUP_UNJOINED = 1,
+ NET_SETUP_WORKGROUP_NAME = 2,
+ NET_SETUP_DOMAIN_NAME = 3
+ } wkssvc_NetJoinStatus;
+
+ WERROR wkssvc_NetrGetJoinInformation(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,out,ref] [string,charset(UTF16)] uint16 **name_buffer,
+ [out,ref] wkssvc_NetJoinStatus *name_type
+ );
+
+ /*****************************/
+ /* Function 0x15 */
+ WERROR wkssvc_NetrGetJoinableOus(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] [string,charset(UTF16)] uint16 *unknown,
+ [in,out,ref] uint32 *num_ous,
+ /*
+ * this is a [ref] pointer to a [unique] pointer to an
+ * array of [unique] pointers to a string array
+ */
+ [out,ref] [size_is(,*num_ous)] [string,charset(UTF16)] uint16 ***ous
+ );
+
+ typedef [flag(NDR_PAHEX)] struct {
+ uint8 data[524];
+ } wkssvc_PasswordBuffer;
+
+ typedef [bitmap32bit] bitmap {
+ WKSSVC_JOIN_FLAGS_IGNORE_UNSUPPORTED_FLAGS = 0x10000000,
+ WKSSVC_JOIN_FLAGS_JOIN_WITH_NEW_NAME = 0x00000400,
+ WKSSVC_JOIN_FLAGS_JOIN_DC_ACCOUNT = 0x00000200,
+ /* TRUE: defer setting the SPN and dNSHostName until a rename operation */
+ WKSSVC_JOIN_FLAGS_DEFER_SPN = 0x00000100,
+
+ /* TRUE: set the machine password to the provided one after the join completes */
+ WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED = 0x00000080,
+
+ /* TRUE: perform an unsecured join */
+ WKSSVC_JOIN_FLAGS_JOIN_UNSECURE = 0x00000040,
+
+ /* TRUE: allow the join to complete even if the account already exists */
+ WKSSVC_JOIN_FLAGS_DOMAIN_JOIN_IF_JOINED = 0x00000020,
+
+ /* TRUE: this join is part of a w9x upgrade */
+ WKSSVC_JOIN_FLAGS_WIN9X_UPGRADE = 0x00000010,
+
+ /* TRUE: delete the account when the domain is left */
+ WKSSVC_JOIN_FLAGS_ACCOUNT_DELETE = 0x00000004,
+
+ /* TRUE: create the account in the domain */
+ WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE = 0x00000002,
+
+ /* TRUE: join domain FALSE: join workgroup */
+ WKSSVC_JOIN_FLAGS_JOIN_TYPE = 0x00000001
+
+ } wkssvc_joinflags;
+
+ /*****************************/
+ /* Function 0x16 */
+ WERROR wkssvc_NetrJoinDomain2 (
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] [string,charset(UTF16)] uint16 *account_ou,
+ [in,unique] [string,charset(UTF16)] uint16 *admin_account,
+ [in,unique] wkssvc_PasswordBuffer *encrypted_password,
+ [in] wkssvc_joinflags join_flags
+ );
+
+ /*****************************/
+ /* Function 0x17 */
+ WERROR wkssvc_NetrUnjoinDomain2 (
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *account,
+ [in,unique] wkssvc_PasswordBuffer *encrypted_password,
+ [in] wkssvc_joinflags unjoin_flags
+ );
+
+ /*****************************/
+ /* Function 0x18 */
+ WERROR wkssvc_NetrRenameMachineInDomain2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *NewMachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] wkssvc_renameflags RenameOptions
+ );
+
+ /*****************************/
+ /* Function 0x19 */
+ WERROR wkssvc_NetrValidateName2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] wkssvc_NetValidateNameType name_type
+ );
+
+ /*****************************/
+ /* Function 0x1a */
+ WERROR wkssvc_NetrGetJoinableOus2(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,ref] [string,charset(UTF16)] uint16 *domain_name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in,out,ref] uint32 *num_ous,
+ /*
+ * this is a [ref] pointer to a [unique] pointer to an
+ * array of [unique] pointers to a string array
+ */
+ [out,ref] [size_is(,*num_ous)] [string,charset(UTF16)] uint16 ***ous
+ );
+
+ /*****************************/
+ /* Function 0x1b */
+ WERROR wkssvc_NetrAddAlternateComputerName(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *NewAlternateMachineName,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] uint32 Reserved
+ );
+
+ /*****************************/
+ /* Function 0x1c */
+ WERROR wkssvc_NetrRemoveAlternateComputerName(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *AlternateMachineNameToRemove,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] uint32 Reserved
+ );
+
+ /*****************************/
+ /* Function 0x1d */
+ WERROR wkssvc_NetrSetPrimaryComputername(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in,unique] [string,charset(UTF16)] uint16 *primary_name,
+ [in,unique] [string,charset(UTF16)] uint16 *Account,
+ [in,unique] wkssvc_PasswordBuffer *EncryptedPassword,
+ [in] uint32 Reserved
+ );
+
+ /*****************************/
+ /* Function 0x1e */
+ typedef enum {
+ NetPrimaryComputerName = 0,
+ NetAlternateComputerNames = 1,
+ NetAllComputerNames = 2,
+ NetComputerNameTypeMax = 3
+ } wkssvc_ComputerNameType;
+
+ typedef struct {
+ uint32 count;
+ [size_is(count)] lsa_String *computer_name;
+ } wkssvc_ComputerNamesCtr;
+
+ WERROR wkssvc_NetrEnumerateComputerNames(
+ [in,unique] [string,charset(UTF16)] uint16 *server_name,
+ [in] wkssvc_ComputerNameType name_type,
+ [in] uint32 Reserved,
+ [out,ref] wkssvc_ComputerNamesCtr **ctr
+ );
+}
diff --git a/librpc/idl/wscript_build b/librpc/idl/wscript_build
new file mode 100644
index 0000000..f3781fa
--- /dev/null
+++ b/librpc/idl/wscript_build
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''drsuapi.idl epmapper.idl
+ eventlog.idl
+ browser.idl dssetup.idl frsapi.idl
+ spoolss.idl
+ dnsserver.idl
+ samr.idl srvsvc.idl winreg.idl
+ mgmt.idl netlogon.idl
+ svcctl.idl wkssvc.idl eventlog6.idl backupkey.idl
+ witness.idl clusapi.idl
+ mdssvc.idl''',
+ options='--header --ndr-parser --server-compat --server --client --python',
+ output_dir='../gen_ndr')
+
+# The interface names here are not the same as the IDL name, so the
+# auto-generation of the fuzzer fails to link
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''echo.idl
+ fsrvp.idl
+ lsa.idl
+ winspool.idl''',
+ options='--header --ndr-parser --server-compat --server --client --python',
+ output_dir='../gen_ndr',
+ generate_fuzzers=False)
+
+# Services that we only have a client for
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''atsvc.idl gkdi.idl''',
+ options='--header --ndr-parser --client --python',
+ output_dir='../gen_ndr')
+
+# Services that we only have a server in the source3 style
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''initshutdown.idl ntsvcs.idl''',
+ options='--header --ndr-parser --client --python --server-compat',
+ output_dir='../gen_ndr')
+
+# The interface names here are not the same as the IDL name, so the
+# auto-generation of the fuzzer fails to link
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''dfs.idl''',
+ options='--header --ndr-parser --client --python --server-compat',
+ output_dir='../gen_ndr',
+ generate_fuzzers=False)
+
+# Services that we only have a server in the source4 style.
+
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''unixinfo.idl''',
+ options='--header --ndr-parser --client --python --server',
+ output_dir='../gen_ndr')
+
+# DCE/RPC protocols which Samba does not implement a client or server
+# for. We don't generate a fuzzer for these as they are unreachable
+#
+# Do not include IDL with public structures in this list as we want to
+# fuzz those
+
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''
+ audiosrv.idl
+ dbgidl.idl
+ dsbackup.idl
+ efs.idl
+ frstrans.idl
+ frsrpc.idl
+ keysvc.idl
+ msgsvc.idl
+ orpc.idl
+ policyagent.idl
+ rot.idl
+ scerpc.idl
+ trkwks.idl
+ w32time.idl
+ winstation.idl
+ wzcsvc.idl
+ ''',
+ options='--header --ndr-parser',
+ generate_fuzzers=False,
+ output_dir='../gen_ndr')
+
+# Non-DCE/RPC protocols encoded in IDL for Samba or helper IDLs for
+# DCE/RPC protocols (eg defining constants or structures but not
+# functions)
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''
+ bkupblobs.idl
+ cab.idl
+ file_id.idl
+ fscc.idl
+ fsrvp_state.idl
+ named_pipe_auth.idl
+ negoex.idl
+ notify.idl
+ ntprinting.idl
+ ODJ.idl
+ printcap.idl
+ rap.idl
+ schannel.idl
+ smb2_lease_struct.idl
+ ''',
+ options='--header --ndr-parser',
+ output_dir='../gen_ndr')
+
+# The interface names here are not the same as the IDL name, so the
+# auto-generation of the fuzzer fails to link
+
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''
+ ioctl.idl
+ nfs4acl.idl
+ quota.idl
+ wsp_data.idl
+ wsp.idl
+ ''',
+ options='--header --ndr-parser',
+ output_dir='../gen_ndr',
+ generate_fuzzers=False)
+
+# Non-DCE/RPC protocols with Python bindings
+# (for structures or constants)
+
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''
+ auth.idl
+ claims.idl
+ dcerpc.idl
+ dfsblobs.idl
+ dns.idl
+ dnsp.idl
+ drsblobs.idl
+ gmsa.idl
+ idmap.idl
+ krb5pac.idl
+ krb5ccache.idl
+ messaging.idl
+ misc.idl
+ nbt.idl
+ ntlmssp.idl
+ preg.idl
+ security.idl
+ server_id.idl
+ smb_acl.idl
+ xattr.idl
+ smb3posix.idl
+ ''',
+ options='--header --ndr-parser --python',
+ output_dir='../gen_ndr')
+
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''
+ windows_event_ids.idl
+ conditional_ace.idl
+ ''',
+ options='--header --ndr-parser --python',
+ output_dir='../gen_ndr',
+ generate_tables=False)
+
+bld.SAMBA_PIDL_LIST('PIDL',
+ 'winbind.idl',
+ options='--header --ndr-parser --server-compat --client --python',
+ output_dir='../gen_ndr')
diff --git a/librpc/idl/wsp.idl b/librpc/idl/wsp.idl
new file mode 100644
index 0000000..4ae81d7
--- /dev/null
+++ b/librpc/idl/wsp.idl
@@ -0,0 +1,1345 @@
+#include "idl_types.h"
+import "wsp_data.idl";
+import "misc.idl";
+
+[
+ version(1.0),
+ endpoint("ncacn_np:[\\pipe\\MsFteWds]"),
+ helpstring("Windows Search WSP Protocol"),
+ helper("../librpc/wsp/wsp_helper.h"),
+ pointer_default(unique)
+]
+
+interface msftewds
+{
+ typedef [public] struct {
+ /*
+ * hack to allow wsp_cbasestoragevariant to be used before
+ * it is defined
+ */
+ wsp_cbasestoragevariant variant[SINGLE_ITEM];
+ } vt_variant_wrap;
+
+ /* MS-WSP 2.2.1.1.1.1 DECIMAL */
+ typedef [public] struct {
+ uint32 hi32;
+ uint32 mid32;
+ uint32 lo32;
+ } vt_decimal;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_DECIMAL) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ vt_decimal vvector_data[vvector_elements];
+ } vt_decimal_vec;
+
+ /*
+ * variant elements in a vector (and presumably safearray also)
+ * must be aligned to 4-byte boundary, think this is automatic for
+ * elements which are structures
+ */
+
+ /* MS-WSP see vValue details in 2.2.1.1 (VT_BSTR) */
+ typedef [public] struct {
+ [value(strlen_m_term(value)*2)] uint32 nbytes;
+ [flag(STR_NULLTERM)] string value;
+ } vt_bstr;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_BSTR) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ vt_bstr vvector_data[vvector_elements];
+ } vt_bstr_vec;
+
+ /* MS-WSP see vValue details in 2.2.1.1 (VT_LPWSTR) */
+ typedef [public] struct {
+ [value(strlen_m_term(value))] uint32 nbytes;
+ [flag(STR_NULLTERM)] string value;
+ } vt_lpwstr;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_LPWSTR) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ vt_lpwstr vvector_data[vvector_elements];
+ } vt_lpwstr_vec;
+
+ /* MS-WSP see vValue details in 2.2.1.1 (VT_COMPRESSED_LPWSTR) */
+ typedef [public] struct {
+ uint32 cclen;
+ uint8 bytes[cclen];
+ } vt_compressed_lpwstr;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_COMPRESSED_LPWSTR) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ vt_compressed_lpwstr vvector_data[vvector_elements];
+ } vt_compressed_lpwstr_vec;
+
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_I1) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ int8 vvector_data[vvector_elements];
+ } vt_i1_vec;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_UI1) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ uint8 vvector_data[vvector_elements];
+ } vt_ui1_vec;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_I2) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ int16 vvector_data[vvector_elements];
+ } vt_i2_vec;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_UI2) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ uint16 vvector_data[vvector_elements];
+ } vt_ui2_vec;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_I4) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ int32 vvector_data[vvector_elements];
+ } vt_i4_vec;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_UI4) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ uint32 vvector_data[vvector_elements];
+ } vt_ui4_vec;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_I8) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ dlong vvector_data[vvector_elements];
+ } vt_dlong_vec;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_UI8) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ udlong vvector_data[vvector_elements];
+ } vt_udlong_vec;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_CLSID) */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ GUID vvector_data[vvector_elements];
+ } vt_clsid_vec;
+
+ /* MS-WSP 2.2.1.1.1.2 VT_VECTOR (VT_VARIANT) wrapped version */
+ typedef [public] struct {
+ uint32 vvector_elements;
+ vt_variant_wrap vvector_data[vvector_elements];
+ } vt_variant_wrap_vec;
+
+/*
+ * would be great if there some way to specify the above like below
+ * instead of having a vector
+ * for each element type e.g. see vt_lpwstr_vec, vt_bstr_vec & vt_i4_vec?
+ * typedef [public] struct {
+ * uint32 num;
+ * variant_types vec[num];
+ *} vt_vector;
+ */
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAYBOUND */
+ typedef [public] struct {
+ uint32 celements;
+ uint32 ilbound;
+ } safearraybound;
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAY (VT_I4) */
+ typedef [public] struct {
+ uint16 cdims;
+ uint16 ffeatures;
+ uint32 cbelements;
+ safearraybound rgsabound[cdims];
+ int32 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_i4_safe_array;
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAY (VT_UI4) */
+ typedef [public] struct {
+ uint16 cdims;
+ uint16 ffeatures;
+ uint32 cbelements;
+ safearraybound rgsabound[cdims];
+ uint32 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_ui4_safe_array;
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAY (VT_BSTR) */
+ typedef [public] struct {
+ uint16 cdims;
+ uint16 ffeatures;
+ uint32 cbelements;
+ safearraybound rgsabound[cdims];
+ vt_bstr vdata[calc_array_size(rgsabound, cdims)];
+ } vt_bstr_safe_array;
+
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAY (VT_I1) */
+ typedef [public] struct {
+ uint16 cdims;
+ uint16 ffeatures;
+ uint32 cbelements;
+ safearraybound rgsabound[cdims];
+ int8 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_i1_safe_array;
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAY (VT_UI1) */
+ typedef [public] struct {
+ uint16 cdims;
+ uint16 ffeatures;
+ uint32 cbelements;
+ safearraybound rgsabound[cdims];
+ uint8 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_ui1_safe_array;
+
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAY (VT_I2) */
+ typedef [public] struct {
+ uint16 cdims;
+ uint16 ffeatures;
+ uint32 cbelements;
+ safearraybound rgsabound[cdims];
+ int16 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_i2_safe_array;
+
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAY (VT_UI2) */
+ typedef [public] struct {
+ uint16 cdims;
+ uint16 ffeatures;
+ uint32 cbelements;
+ safearraybound rgsabound[cdims];
+ uint16 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_ui2_safe_array;
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAY (VT_I8) */
+ typedef [public] struct {
+ uint16 cdims;
+ uint16 ffeatures;
+ uint32 cbelements;
+ safearraybound rgsabound[cdims];
+ dlong vdata[calc_array_size(rgsabound, cdims)];
+ } vt_dlong_safe_array;
+
+ /* MS-WSP 2.2.1.1.1.4 SAFEARRAY (VT_VARIANT) */
+ typedef [public] struct {
+ uint16 cdims;
+ uint16 ffeatures;
+ uint32 cbelements;
+ safearraybound rgsabound[cdims];
+ vt_variant_wrap vdata[calc_array_size(rgsabound, cdims)];
+ } vt_variant_wrap_safearray;
+
+ typedef [public,nodiscriminant,switch_type(uint16)] union {
+ [case(VT_I1)] int8 vt_i1;
+ [case(VT_I1 | VT_ARRAY)] vt_i1_safe_array vt_i1_array;
+ [case(VT_I1 | VT_VECTOR)] vt_i1_vec vt_i1_vec;
+
+ [case(VT_UI1)] uint8 vt_ui1;
+ [case(VT_UI1 | VT_ARRAY)] vt_ui1_safe_array vt_ui1_array;
+ [case(VT_UI1 | VT_VECTOR)] vt_ui1_vec vt_ui1_vec;
+
+ [case(VT_I2)] int16 vt_i2;
+ [case(VT_I2 | VT_ARRAY)] vt_i2_safe_array vt_i2_array;
+ [case(VT_I2 | VT_VECTOR)] vt_i2_vec vt_i2_vec;
+
+ [case(VT_UI2)] uint16 vt_ui2;
+ [case(VT_UI2 | VT_ARRAY)] vt_ui2_safe_array vt_ui2_array;
+ [case(VT_UI2 | VT_VECTOR)] vt_ui2_vec vt_ui2_vec;
+
+ [case(VT_BOOL)] uint16 vt_bool;
+ [case(VT_BOOL | VT_ARRAY)] vt_ui2_safe_array vt_bool_array;
+ [case(VT_BOOL | VT_VECTOR)] vt_ui2_vec vt_bool_vec;
+
+ [case(VT_I4)] int32 vt_i4;
+ [case(VT_I4 | VT_VECTOR)] vt_i4_vec vt_i4_vec;
+ [case(VT_I4 | VT_ARRAY)] vt_i4_safe_array vt_i4_array;
+
+ [case(VT_UI4)] uint32 vt_ui4;
+ [case(VT_UI4 | VT_VECTOR)] vt_ui4_vec vt_ui4_vec;
+ [case(VT_UI4 | VT_ARRAY)] vt_ui4_safe_array vt_ui4_array;
+
+ [case(VT_R4)] uint32 vt_r4;
+ [case(VT_R4 | VT_VECTOR)] vt_i4_vec vt_r4_vec;
+ [case(VT_R4 | VT_ARRAY)] vt_i4_safe_array vt_r4_array;
+
+ [case(VT_INT)] int32 vt_int;
+ [case(VT_INT | VT_ARRAY)] vt_i4_safe_array vt_int_array;
+
+ [case(VT_UINT)] uint32 vt_uint;
+ [case(VT_UINT | VT_ARRAY)] vt_ui4_safe_array vt_uint_array;
+
+ [case(VT_ERROR)] uint32 vt_error;
+ [case(VT_ERROR | VT_VECTOR)] vt_ui4_vec vt_error_vec;
+ [case(VT_ERROR | VT_ARRAY)] vt_ui4_safe_array vt_error_array;
+
+ [case(VT_I8)] dlong vt_i8;
+ [case(VT_I8 | VT_VECTOR)] vt_dlong_vec vt_i8_vec;
+
+ [case(VT_UI8)] udlong vt_ui8;
+ [case(VT_UI8 | VT_VECTOR)] vt_udlong_vec vt_ui8_vec;
+
+ [case(VT_R8)] dlong vt_r8;
+ [case(VT_R8 | VT_VECTOR)] vt_dlong_vec vt_r8_vec;
+ [case(VT_R8 | VT_ARRAY)] vt_dlong_safe_array vt_r8_array;
+
+ [case(VT_CY)] dlong vt_cy;
+ [case(VT_CY | VT_VECTOR)] vt_dlong_vec vt_cy_vec;
+ [case(VT_CY | VT_ARRAY)] vt_dlong_safe_array vt_cy_array;
+
+ [case(VT_DATE)] dlong vt_date;
+ [case(VT_DATE | VT_VECTOR)] vt_dlong_vec vt_date_vec;
+ [case(VT_DATE| VT_ARRAY)] vt_dlong_safe_array vt_date_array;
+
+ [case(VT_FILETIME)] udlong vt_filetime;
+ [case(VT_FILETIME | VT_VECTOR)] vt_udlong_vec vt_filetime_vec;
+
+ [case(VT_BSTR)] vt_bstr vt_bstr;
+ [case(VT_BSTR | VT_VECTOR)] vt_bstr_vec vt_bstr_v;
+ [case(VT_BSTR | VT_ARRAY)] vt_bstr_safe_array vt_bstr_array;
+
+ [case(VT_LPWSTR)] vt_lpwstr vt_lpwstr;
+ [case(VT_LPWSTR | VT_VECTOR)] vt_lpwstr_vec vt_lpwstr_v;
+
+ [case(VT_COMPRESSED_LPWSTR)] vt_compressed_lpwstr vt_compressed_lpwstr;
+ [case(VT_COMPRESSED_LPWSTR | VT_VECTOR)] vt_compressed_lpwstr_vec vt_compresseed_lpwstr_v;
+
+ [case(VT_DECIMAL)] vt_decimal vt_decimal;
+ [case(VT_DECIMAL | VT_VECTOR)] vt_decimal_vec vt_decimal_v;
+
+ [case(VT_CLSID)] GUID vt_clid;
+ [case(VT_CLSID | VT_VECTOR)] vt_clsid_vec vt_clsid_v;
+
+ [case(VT_BLOB)] DATA_BLOB vt_blob;
+ [case(VT_BLOB_OBJECT)] DATA_BLOB vt_blob_object;
+
+ [case(VT_NULL)];
+ [case(VT_EMPTY)];
+ [case(VT_VARIANT)] vt_variant_wrap vt_variant_wrap;
+
+ [case(VT_VARIANT | VT_VECTOR)] vt_variant_wrap_vec vt_variant_wrap_vec;
+ [case(VT_VARIANT | VT_ARRAY)] vt_variant_wrap_safearray vt_variant_wrap_array;
+ } variant_types;
+
+ /*
+ * MS-WSP 2.2.1.1 CBaseStorageVariant
+ */
+ typedef [public] struct {
+ uint16 vtype;
+ uint8 vdata1;
+ uint8 vdata2;
+ [max_recursion(102), switch_is(vtype)] variant_types vvalue;
+ } wsp_cbasestoragevariant;
+
+ typedef [public, nodiscriminant, switch_type(uint32)] union {
+ [case(DBKIND_GUID_NAME)] string vstring;
+ [default];
+ } wsp_cdbcolid_opt_name;
+
+ /* MS-WSP 2.2.1.29 CDbColId */
+ typedef [public] struct {
+ uint32 ekind;
+ [flag(NDR_ALIGN8)] DATA_BLOB _pad1;
+ GUID guid;
+ uint32 uiid;
+ [switch_is(ekind)] wsp_cdbcolid_opt_name vstring;
+ } wsp_cdbcolid;
+
+
+ /* MS-WSP 2.2.2 Message Headers */
+ typedef [public] struct {
+ uint32 msg;
+ uint32 status;
+ uint32 checksum;
+ uint32 ulreserved2;
+ } wsp_header;
+
+ /* MS-WSP 2.2.1.30 CDbProp */
+ typedef [public,flag(NDR_ALIGN4)] struct {
+ uint32 dbpropid;
+ uint32 dbpropoptions;
+ uint32 dbpropstatus;
+ wsp_cdbcolid colid;
+ wsp_cbasestoragevariant vvalue;
+ } wsp_cdbprop;
+
+ /* MS-WSP 2.2.1.31 CDbPropSet */
+ typedef [flag(NDR_NOALIGN),public] struct {
+ GUID guidpropertyset;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad1;
+ uint32 cproperties;
+ wsp_cdbprop aprops[cproperties];
+ } wsp_cdbpropset;
+
+ /* MS-WSP 2.2.1.10 CSort */
+ typedef [public] struct {
+ uint32 pidcolimn;
+ uint32 dworder;
+ uint32 dwindividual;
+ uint32 locale;
+ } wsp_csort;
+
+ /* MS-WSP 2.2.1.42 CSortSet */
+ typedef [public] struct {
+ uint32 count;
+ wsp_csort sortarray[count];
+ } wsp_csortset;
+
+ /*
+ * cPropSets, PropterySet1 & PropertySet2 (parts of CPMConnectIn)
+ */
+ typedef [public] struct {
+ uint32 cpropsets;
+ wsp_cdbpropset propertyset1;
+ wsp_cdbpropset propertyset2;
+ } connectin_propsets;
+
+ /*
+ * cExtPropSet, aPropertySets (parts of CPMConnectIn)
+ */
+ typedef [public] struct {
+ uint32 cextpropset;
+ wsp_cdbpropset apropertysets[cextpropset];
+ } connectin_extpropsets;
+
+ /* MS-WSP 2.2.3.2 CPMConnectIn */
+ typedef [public] struct {
+ uint32 iclientversion;
+ uint32 fclientisremote;
+ uint32 cbblob1;
+ uint32 paddingcbblob2;
+ uint32 cbblob2;
+ uint8 padding[12];
+ [flag(STR_NULLTERM)] string machinename;
+ [flag(STR_NULLTERM)] string username;
+ [flag(NDR_ALIGN8)] DATA_BLOB _pad1;
+ uint8 propsets[cbblob1];
+ [flag(NDR_ALIGN8)] DATA_BLOB _pad2;
+ uint8 extpropsets[cbblob2];
+ } wsp_cpmconnectin;
+
+ typedef [public] struct {
+ uint32 reserved;
+ uint32 dwwinvermajor;
+ uint32 dwwinverminor;
+ uint32 dwnlsvermajor;
+ uint32 dwnlsverminor;
+ } version_info;
+
+ typedef [public, nodiscriminant, switch_type(uint32)] union {
+ [case(WINDOWS_7)] version_info version_info;
+ [case(WINDOWS_2008)] version_info version_info;
+ [default] uint32 reserved[4];
+ } version_dependant;
+
+ /* MS-WSP 2.2.3.3 CPMConnectOut */
+ typedef [public] struct {
+ uint32 server_version;
+ [switch_is(server_version)] version_dependant version_dependant;
+ } wsp_cpmconnectout;
+
+ /* MS-WSP 2.2.1.18 CColumnSet */
+ typedef [public] struct {
+ uint32 count;
+ uint32 indexes[count];
+ } wsp_ccolumnset;
+
+
+ /* MS-WSP 2.2.1.6 CNodeRestriction */
+ typedef [public] struct {
+ uint32 cnode;
+ [max_recursion(100)] wsp_crestriction panode[cnode];
+ } wsp_cnoderestriction;
+
+ typedef [public] struct {
+ uint32 len;
+ [charset(UTF16)] uint8 vstring[len*2];
+ } wsp_len_string_pair;
+
+ typedef [public, nodiscriminant, switch_type(uint32)] union {
+ [case(PRSPEC_LPWSTR)] wsp_len_string_pair propname;
+ [case(PRSPEC_PROPID)] uint32 prspec;
+ } wsp_propname_or_propid;
+
+ typedef [public] struct {
+ uint32 cclabel;
+ [charset(UTF16)] uint8 vstring[cclabel*2];
+ } wsp_labeldata;
+
+ typedef [public, nodiscriminant, switch_type(uint8)] union {
+ [case(0)];
+ [case(1)] wsp_labeldata data;
+ } opt_labeldata;
+
+ /* MS-WSP 2.2.1.23 RANGEBOUNDARY */
+ typedef [public] struct {
+ uint32 ultype;
+ wsp_cbasestoragevariant prval;
+ uint8 labelpresent;
+ [switch_is(labelpresent)] opt_labeldata opt_data;
+ } wsp_rangeboundary;
+
+ /* MS-WSP 2.2.1.22 CRangeCategSpec */
+ typedef [public] struct {
+ uint32 lcid;
+ uint32 crange;
+ wsp_rangeboundary arangebegin[crange + 1];
+ } wsp_crangecategspec;
+
+ typedef [public, nodiscriminant, switch_type(uint32)] union {
+ [case(0)];
+ [default] wsp_crangecategspec crangecategspec;
+ } opt_crangecatespec;
+
+ /* MS-WSP 2.2.1.21 CCategSpec */
+ typedef [public] struct {
+ uint32 ulcategtype;
+ wsp_csort sortkey;
+ [switch_is(ulcategtype)] opt_crangecatespec opt;
+ } wsp_ccategspec;
+
+ typedef [public] struct {
+ uint32 ulmaxnumtoret;
+ uint32 idrepresentitive;
+ } wsp_repofdata;
+
+ typedef [public,nodiscriminant,switch_type(uint8)] union {
+ [case(DBAGGTTYPE_FIRST)] uint32 firstmaxnumret;
+ [case(DBAGGTTYPE_BYFREQ)] uint32 firstbyfreq;
+ [case(DBAGGTTYPE_REPRESENTATIVEOF)] wsp_repofdata repofdata;
+ [default];
+ } opt_type_data;
+
+ /* MS-WSP 2.2.1.25 CAggregSpec */
+ typedef [public] struct {
+ uint8 type;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad1;
+ uint32 ccalias;
+ [charset(UTF16)] uint8 alias[ccalias*2];
+ uint32 idcolumn;
+ [switch_is(type)] opt_type_data opt_data;
+ } wsp_caggregspec;
+
+ /* MS-WSP 2.2.1.24 CAggregSet */
+ typedef [public] struct {
+ uint32 ccount;
+ wsp_caggregspec aggregspecs[ccount];
+ } wsp_caggregset;
+
+ /* MS-WSP 2.2.1.27 CAggregSortKey */
+ typedef [public] struct {
+ uint32 order;
+ wsp_caggregspec columnspec;
+ } wsp_caggregsortkey;
+
+ /* MS-WSP 2.2.1.26 CSortAggregSet */
+ typedef [public] struct {
+ uint32 ccount;
+ wsp_caggregsortkey sortkeys[ccount];
+ } wsp_csortaggregset;
+
+ typedef [public, nodiscriminant, switch_type(uint8)] union {
+ /*
+ * if type == GroupIdValue then wsp_cbasestoragevariant
+ * ingroupid is present
+ */
+ [case(0x03)] wsp_cbasestoragevariant ingroupid;
+ [default];
+ } wsp_opt_ingroupid;
+
+ typedef [public] struct {
+ uint8 type;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad1;
+ [switch_is(type)] wsp_opt_ingroupid opt_groupid;
+ wsp_csortset sortaggregset;
+ } wsp_cingroupsortaggregset;
+
+ /* MS-WSP 2.2.1.28 CInGroupSortAggregSets */
+ typedef [public] struct {
+ uint32 ccount;
+ wsp_cingroupsortaggregset sortsets[ccount];
+ } wsp_cingroupsortaggregsets;
+
+ /* MS-WSP 2.2.1.20 CCategorizationSpec */
+ typedef [public] struct {
+ wsp_ccolumnset cscolumns;
+ wsp_ccategspec spec;
+ wsp_caggregset aggregset;
+ wsp_csortaggregset sortaggregset;
+ wsp_cingroupsortaggregsets ingroupsortaggset;
+ uint32 cmaxresults;
+ } wsp_ccategorizationspec;
+
+ /* MS-WSP 2.2.1.19 CCategorizationSet */
+ typedef [public] struct {
+ uint32 size;
+ wsp_ccategorizationspec categories[size];
+ } wsp_ccategorizationset;
+
+ /* MS-WSP 2.2.1.2 CFullPropSpec */
+ typedef [flag(NDR_NOALIGN),public] struct {
+ [flag(NDR_ALIGN8)] DATA_BLOB _pad1;
+ GUID guidpropset;
+ uint32 ulkind;
+ [switch_is(ulkind)] wsp_propname_or_propid name_or_id;
+ } wsp_cfullpropspec;
+
+ /* MS-WSP 2.2.1.3 CContentRestriction */
+ typedef [public] struct {
+ wsp_cfullpropspec property;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad1;
+ uint32 cc;
+ [charset(UTF16)] uint8 pwcsphrase[cc*2];
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad2;
+ uint32 lcid;
+ uint32 ulgeneratemethod;
+ } wsp_ccontentrestriction;
+
+ /* MS-WSP 2.2.1.7 CPropertyRestriction */
+ typedef [public] struct {
+ uint32 relop;
+ wsp_cfullpropspec property;
+ wsp_cbasestoragevariant prval;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad1;
+ uint32 lcid;
+ } wsp_cpropertyrestriction;
+
+ /* MS-WSP 2.2.1.5 CNatLanguageRestriction */
+ typedef [public] struct {
+ wsp_cfullpropspec property;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad1;
+ uint32 cc;
+ [charset(UTF16)] uint8 pwcsphrase[cc*2];
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad2;
+ uint32 lcid;
+ } wsp_cnatlanguagerestriction;
+
+ typedef [public] struct {
+ wsp_crestriction restriction[SINGLE_ITEM];
+ } wsp_wrap_crestriction;
+
+
+ /* MS-WSP 2.2.1.12 CCoercionRestriction*/
+ typedef [public] struct {
+ /* no IEEE 754 implementation for float ?? */
+ /* float ffvalue; */
+ uint32 ffvalue;
+ wsp_crestriction childres[SINGLE_ITEM];
+ } wsp_ccoercionrestriction;
+
+ /* MS-WSP 2.2.1.11 CVectorRestriction */
+ typedef [public] struct {
+ uint32 pres;
+ [flag(NDR_ALIGN4)] DATA_BLOB padding;
+ uint32 uirankmethod;
+ } wsp_cvectorrestriction;
+
+ /* MS-WSP 2.2.1.9 CScopeRestriction */
+ typedef [public] struct {
+ uint32 cclowerpath;
+ [charset(UTF16)] uint8 lowerpath[cclowerpath*2];
+ [flag(NDR_ALIGN4)] DATA_BLOB padding;
+ uint32 length;
+ uint32 frecursive;
+ uint32 fvirtual;
+ } wsp_cscoperestriction;
+
+ /* MS-WSP 2.2.1.8 CReuseWhere */
+ typedef [public] struct {
+ uint32 whereid;
+ } wsp_creusewhere;
+
+ /* MS-WSP 2.2.1.4 CInternalPropertyRestriction */
+ typedef [public] struct {
+ uint32 relop;
+ uint32 pid;
+ wsp_cbasestoragevariant prval;
+ uint32 lcid;
+ uint8 restrictionpresent;
+ wsp_crestriction nextrestriction[SINGLE_ITEM];
+ } wsp_cinternalpropertyrestriction;
+
+
+ /* MS-WSP 2.2.1.14 CProbRestriction */
+ typedef [public] struct {
+ wsp_cfullpropspec property;
+ uint32 fik1;
+ uint32 fik2;
+ uint32 fik3;
+ uint32 flb;
+ uint32 cfeedbackdoc;
+ uint32 probquerypid;
+ } wsp_cprobrestriction;
+
+ /* MS-WSP 2.2.1.15 CFeedbackRestriction */
+ typedef [public] struct {
+ uint32 feedbackdoc;
+ wsp_cfullpropspec property;
+ } wsp_cfeedbackrestriction;
+
+ /* MS-WSP 2.2.1.13 CRelDocRestriction */
+ typedef [public] struct {
+ wsp_cbasestoragevariant vdocument;
+ } wsp_creldocrestriction;
+
+ typedef [public,nodiscriminant,switch_type(uint32)] union {
+ [case(RTNONE)];
+ [case(RTNOT)] wsp_wrap_crestriction restriction;
+ [case(RTAND)] wsp_cnoderestriction cnoderestriction;
+ [case(RTOR)] wsp_cnoderestriction orcnoderestriction;
+ [case(RTCONTENT)] wsp_ccontentrestriction ccontentrestriction;
+ [case(RTPROPERTY)] wsp_cpropertyrestriction cpropertyrestriction;
+ [case(RTPROXIMITY)] wsp_cnoderestriction proximityrestriction;
+ [case(RTVECTOR)] wsp_cvectorrestriction vectorrestriction;
+ [case(RTNATLANGUAGE)] wsp_cnatlanguagerestriction cnatlanguagerestriction;
+ [case(RTSCOPE)] wsp_cscoperestriction scoperestriction;
+ [case(RTREUSEWHERE)] wsp_creusewhere reusewhere;
+ [case(RTINTERNALPROP)] wsp_cinternalpropertyrestriction internalpropertyrestriction;
+ [case(RTPHRASE)] wsp_cnoderestriction phraserestriction;
+ [case(RTCOERCE_ABSOLUTE)] wsp_ccoercionrestriction ccoercionrestriction_abs;
+ [case(RTCOERCE_ADD)] wsp_ccoercionrestriction ccoercionrestriction_add;
+ [case(RTCOERCE_MULTIPLY)] wsp_ccoercionrestriction ccoercionrestriction_mul;
+ [case(RTPROB)] wsp_cprobrestriction probrestriction;
+ [case(RTFEEDBACK)] wsp_cfeedbackrestriction feedbackrestriction;
+ [case(RTRELDOC)] wsp_creldocrestriction reldocrestriction;
+
+ } wsp_crestrictions;
+
+
+ /* MS-WSP 2.2.1.17 CRestriction */
+ typedef [public] struct {
+ uint32 ultype;
+ uint32 weight;
+ [switch_is(ultype)] wsp_crestrictions restriction;
+ } wsp_crestriction;
+
+ /* MS-WSP 2.2.1.16 CRestrictionArray */
+ typedef [flag(NDR_NOALIGN),public] struct {
+ uint8 count;
+ uint8 ispresent;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad1;
+ wsp_crestriction restrictions[count];
+ } wsp_crestrictionarray;
+
+ /* MS-WSP 2.2.1.40 CRowsetProperties */
+ typedef [public] struct {
+ uint32 ubooleanoptions;
+ uint32 ulmaxopenrows;
+ uint32 ulmemoryusage;
+ uint32 cmaxresults;
+ uint32 ccmdtimeout;
+ } wsp_crowsetproperties;
+
+ /* MS-WSP 2.2.1.32 CPidMapper */
+ typedef [public] struct {
+ uint32 count;
+ [flag(NDR_ALIGN4)] DATA_BLOB _pad2;
+ wsp_cfullpropspec apropspec[count];
+ } wsp_cpidmapper;
+
+ /* MS-WSP 2.2.1.35 SProperty */
+ typedef [public] struct {
+ uint32 pid;
+ uint32 weight;
+ } wsp_sproperty;
+
+ /* MS-WSP 2.2.1.34 CColumnGroup */
+ typedef [public] struct {
+ uint32 count;
+ uint32 grouppid;
+ wsp_sproperty props[count];
+ } wsp_ccolumngroup;
+
+ /* MS-WSP 2.2.1.33 CColumnGroupArray */
+ typedef [public] struct {
+ uint32 count;
+ wsp_ccolumngroup agrouparray[count];
+ } wsp_ccolumngrouparray;
+
+ typedef [public,nodiscriminant,switch_type(uint8)] union {
+ [case(0)];
+ [default] wsp_cingroupsortaggregsets groupsortaggregsets;
+ }opt_wsp_cingroupsortaggregsets;
+
+ typedef [public,nodiscriminant,switch_type(uint8)] union {
+ [case(0)];
+ [default] wsp_crestrictionarray restrictionarray;
+ }opt_wsp_crestrictionarray;
+
+ typedef [public,nodiscriminant,switch_type(uint8)] union {
+ [case(0)];
+ [default] wsp_ccolumnset columnset;
+ }opt_wsp_ccolumnset;
+
+ typedef [public,nodiscriminant,switch_type(uint8)] union {
+ [case(0)];
+ [default] wsp_ccategorizationset ccategorizationset;
+ }opt_wsp_ccategorizationset;
+
+ typedef [public] struct {
+ uint32 size;
+ uint8 ccolumnsetpresent;
+ /* padding is not needed here (and below)
+ * as structures are default aligned to 4 byte
+ * boundaries.
+ * commented out valued left for documentation
+ * and to match the actual structure definition
+ */
+ /*[flag(NDR_ALIGN4)] DATA_BLOB paddingCColumnSetPresent;*/
+ [switch_is(ccolumnsetpresent)] opt_wsp_ccolumnset columnset;
+ uint8 crestrictionpresent;
+ [switch_is(crestrictionpresent)] opt_wsp_crestrictionarray restrictionarray;
+ uint8 csortsetpresent;
+ /*[flag(NDR_ALIGN4)] DATA_BLOB paddingCSortSetPresent;*/
+ [switch_is(csortsetpresent)] opt_wsp_cingroupsortaggregsets sortset;
+ uint8 ccategorizationsetpresent;
+ /*[flag(NDR_ALIGN4)] DATA_BLOB paddingCCategorizationSetPresent;*/
+ [switch_is(ccategorizationsetpresent)] opt_wsp_ccategorizationset ccategorizationset;
+ wsp_crowsetproperties rowsetproperties;
+ wsp_cpidmapper pidmapper;
+ wsp_ccolumngrouparray grouparray;
+ uint32 lcid;
+ } wsp_cpmcreatequeryin;
+
+ /* MS-WSP 2.2.3.5 CPMCreateQueryOut */
+ typedef [public] struct {
+ uint32 ftruesequential;
+ uint32 fWorkIdUnique;
+ /*
+ * uint32 acursors[SIZE];
+ *
+ * after fWorkIdUnique is an array of uint32 cursors,
+ * actually there is always at least 1 item in the array,
+ * SIZE is determined by the optional ccategorizationset field in
+ * the request
+ */
+ } wsp_cpmcreatequeryout;
+
+ typedef [public, nodiscriminant, switch_type(uint8)] union {
+ [case(1)] uint8 value;
+ [case(0)];
+ } aggregatetype;
+
+ typedef [public, nodiscriminant, switch_type(uint8)] union {
+ [case(1)] uint16 value;
+ [case(0)];
+ } valueoffset;
+
+ typedef [public, nodiscriminant, switch_type(uint8)] union {
+ [case(1)] uint16 value;
+ [case(0)];
+ } valuesize;
+
+ typedef [public, nodiscriminant, switch_type(uint8)] union {
+ [case(1)] uint16 value;
+ [case(0)];
+ } lengthoffset;
+
+ typedef [public, nodiscriminant, switch_type(uint8)] union {
+ [case(1)] uint16 value;
+ [case(0)];
+ } statusoffset;
+
+ /* MS-WSP 2.2.1.43 CTableColumn */
+ typedef [public] struct {
+ wsp_cfullpropspec propspec;
+ uint32 vtype;
+ uint8 aggregateused;
+ [switch_is(aggregateused)] aggregatetype aggregatetype;
+ uint8 valueused;
+ [switch_is(valueused)] valueoffset valueoffset; /* auto aligned to 2 byte boundary */
+ [switch_is(valueused)] valuesize valuesize; /* auto aligned to 2 byte boundary */
+ uint8 statusused;
+ [switch_is(statusused)] statusoffset statusoffset; /* auto aligned to 2 byte boundary */
+ uint8 lengthused;
+ [switch_is(lengthused)] lengthoffset lengthoffset; /* auto aligned to 2 byte boundary */
+ } wsp_ctablecolumn;
+
+ /*
+ * struct below is included for completeness but
+ * isn't currently referenced.
+ * MS-WSP 2.2.1.45 CCompletionCategSpec
+ */
+ typedef [public] struct {
+ uint32 type;
+ uint32 lcid;
+ uint32 ccomplstrings;
+ wsp_serializedpropertyvalue apszcomplstrings[ccomplstrings];
+ uint32 ccomplpids;
+ uint32 acomplpids[ccomplpids];
+ } wsp_ccompletioncategspec;
+
+ /* MS-WSP 2.2.3.10 CPMSetBindingsIn */
+ typedef [public] struct {
+ uint32 hcursor;
+ uint32 brow;
+ uint32 bbindingdesc;
+ uint32 dummy;
+ uint32 ccolumns;
+ wsp_ctablecolumn acolumns[ccolumns];
+ } wsp_cpmsetbindingsin;
+
+ /* MS-WSP 2.2.1.39 CRowSeekNext */
+ typedef [public] struct {
+ uint32 cskip;
+ } wsp_crowseeknext;
+
+ /* MS-WSP 2.2.1.36 CRowSeekAt */
+ typedef [public] struct {
+ uint32 bmkoffset;
+ uint32 cskip;
+ uint32 hregion;
+ } wsp_crowseekat;
+
+ /* MS-WSP 2.2.1.37 CRowSeekAtRatio */
+ typedef [public] struct {
+ uint32 ulnumerator;
+ uint32 uldenominator;
+ uint32 hregion;
+ } wsp_crowseekatratio;
+
+ /* MS-WSP 2.2.1.38 CRowSeekByBookmark */
+ typedef [public] struct {
+ uint32 cbookmarks;
+ uint32 abookmarks[cbookmarks];
+ uint32 maxret;
+ uint32 ascret[maxret];
+ } wsp_crowseekbybookmark;
+
+ typedef [public,nodiscriminant,switch_type(uint32)] union {
+ [case(EROWSEEKNONE)];
+ [case(EROWSEEKNEXT)] wsp_crowseeknext crowseeknext;
+ [case(EROWSEEKAT)] wsp_crowseekat crowseekat;
+ [case(EROWSEEKATRATIO)] wsp_crowseekatratio crowseekatratio;
+ [case(EROWSEEKBYBOOKMARK)] wsp_crowseekbybookmark crowseekbybookmark;
+ } wsp_seekdescription;
+
+ /* MS-WSP 2.2.3.11 CPMGetRowsIn */
+ typedef [public] struct {
+ uint32 hcursor;
+ uint32 crowstotransfer;
+ uint32 cbrowWidth;
+ uint32 cbseek;
+ uint32 cbreserved;
+ uint32 cbreadbuffer;
+ uint32 ulclientbase;
+ uint32 fbwdfetch;
+ uint32 etype;
+ uint32 chapt;
+ [switch_is(etype)] wsp_seekdescription seekdescription;
+ } wsp_cpmgetrowsin;
+
+ /* MS-WSP 2.2.1.42 */
+ typedef [public] struct {
+ uint16 vtype;
+ uint16 reserved1;
+ uint32 reserved2;
+ /* followed by offset either 4 or 8 byte count (if VT_VECTOR) */
+ /* followed by offset either 4 or 8 byte offset (if variable size value)*/
+ /* followed by fixed value (if fixed size value) */
+ } wsp_ctablevariant;
+
+ /* MS-WSP 2.2.3.12 CPMGetRowsOut */
+ typedef [public] struct {
+ uint32 rowsreturned;
+ uint32 etype;
+ uint32 chapt;
+ [switch_is(etype)] wsp_seekdescription seekdescription;
+ /*
+ * following rows data is not defined here, size is unknown
+ * in the context of this structure but is the size of
+ * breadbuffer defined in cpmgetrowsin.
+ */
+ } wsp_cpmgetrowsout;
+
+ /* MS-WSP 2.2.3.24 CPMFreeCursorIn */
+ typedef [public] struct {
+ uint32 hcursor;
+ } wsp_cpmfreecursorin;
+
+ /* MS-WSP 2.2.3.25 CPMFreeCursorOut */
+ typedef [public] struct {
+ uint32 ccursorsremaining;
+ } wsp_cpmfreecursorout;
+
+ /* MS-WSP 2.2.3.6 CPMGetQueryStatusIn */
+ typedef [public] struct {
+ uint32 hcursor;
+ } wsp_cpmgetquerystatusin;
+
+ /* MS-WSP 2.2.3.7 CPMGetQueryStatusOut */
+ typedef [public] struct {
+ uint32 qstatus;
+ } wsp_cpmgetquerystatusout;
+
+ /* MS-WSP 2.2.3.8 CPMGetQueryStatusExIn */
+ typedef [public] struct {
+ uint32 hcursor;
+ uint32 bmk;
+ } wsp_cpmgetquerystatusexin;
+
+ /* MS-WSP 2.2.3.9 CPMGetQueryStatusExOut */
+ typedef [public] struct {
+ uint32 qstatus;
+ uint32 cfiltereddocuments;
+ uint32 cdocumentstofilter;
+ uint32 dwratiofinisheddenominator;
+ uint32 dwratiofinishednumerator;
+ uint32 irowbmk;
+ uint32 crowstotal;
+ uint32 maxrank;
+ uint32 resultsfound;
+ uint32 whereid;
+ } wsp_cpmgetquerystatusexout;
+
+ /* MS-WSP 2.2.3.23 CPMRestartPositionIn */
+ typedef [public] struct {
+ uint32 hcursor;
+ uint32 chapter;
+ } wsp_cpmrestartpositionin;
+
+ /* MS-WSP 2.2.3.13 CPMRatioFinishedIn */
+ typedef [public] struct {
+ uint32 hcursor;
+ uint32 fquick;
+ } wsp_cpmratiofinishedin;
+
+ /* MS-WSP 2.2.3.14 CPMRatioFinishedOut */
+ typedef [public] struct {
+ uint32 ulnumerator;
+ uint32 uldenominator;
+ uint32 crows;
+ uint32 fnewrows;
+ } wsp_cpmratiofinishedout;
+
+ /* MS-WSP 2.2.3.15 CPMRatioFinishedOut */
+ typedef [public] struct {
+ uint32 wid;
+ uint32 cbsofar;
+ uint32 cbpropspec;
+ uint32 cbchunk;
+ wsp_cfullpropspec propspec;
+ } wsp_cpmfetchvaluein;
+
+ typedef [public] struct {
+ uint16 cdims;
+ safearraybound rgsabound[cdims];
+ int8 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_i1_safe2_array;
+
+ typedef [public] struct {
+ uint16 cdims;
+ safearraybound rgsabound[cdims];
+ uint8 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_ui1_safe2_array;
+
+ typedef [public] struct {
+ uint16 cdims;
+ safearraybound rgsabound[cdims];
+ int16 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_i2_safe2_array;
+
+ typedef [public] struct {
+ uint16 cdims;
+ safearraybound rgsabound[cdims];
+ uint16 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_ui2_safe2_array;
+
+ typedef [public] struct {
+ uint16 cdims;
+ safearraybound rgsabound[cdims];
+ int32 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_i4_safe2_array;
+
+ typedef [public] struct {
+ uint16 cdims;
+ safearraybound rgsabound[cdims];
+ uint32 vdata[calc_array_size(rgsabound, cdims)];
+ } vt_ui4_safe2_array;
+
+ typedef [public] struct {
+ uint16 cdims;
+ safearraybound rgsabound[cdims];
+ dlong vdata[calc_array_size(rgsabound, cdims)];
+ } vt_dlong_safe2_array;
+
+ typedef [public] struct {
+ uint16 cdims;
+ safearraybound rgsabound[cdims];
+ vt_bstr vdata[calc_array_size(rgsabound, cdims)];
+ } vt_bstr_safe2_array;
+
+ typedef [public] struct {
+ uint16 cdims;
+ safearraybound rgsabound[cdims];
+ vt_variant_wrap vdata[calc_array_size(rgsabound, cdims)];
+ } vt_variant_wrap_safearray2;
+
+ typedef [public,nodiscriminant,switch_type(uint32)] union {
+ [case(VT_I1)] int8 vt_i1;
+ [case(VT_I1 | VT_ARRAY)] vt_i1_safe2_array vt_i1_array;
+ [case(VT_I1 | VT_VECTOR)] vt_i1_vec vt_i1_vec;
+
+ [case(VT_UI1)] uint8 vt_ui1;
+ [case(VT_UI1 | VT_ARRAY)] vt_ui1_safe2_array vt_ui1_array;
+ [case(VT_UI1 | VT_VECTOR)] vt_ui1_vec vt_ui1_vec;
+
+ [case(VT_I2)] int16 vt_i2;
+ [case(VT_I2 | VT_ARRAY)] vt_i2_safe2_array vt_i2_array;
+ [case(VT_I2 | VT_VECTOR)] vt_i2_vec vt_i2_vec;
+
+ [case(VT_UI2)] uint16 vt_ui2;
+ [case(VT_UI2 | VT_ARRAY)] vt_ui2_safe2_array vt_ui2_array;
+ [case(VT_UI2 | VT_VECTOR)] vt_ui2_vec vt_ui2_vec;
+
+ [case(VT_BOOL)] uint16 vt_bool;
+ [case(VT_BOOL | VT_ARRAY)] vt_ui2_safe2_array vt_bool_array;
+ [case(VT_BOOL | VT_VECTOR)] vt_ui2_vec vt_bool_vec;
+
+ [case(VT_I4)] int32 vt_i4;
+ [case(VT_I4 | VT_VECTOR)] vt_i4_vec vt_i4_vec;
+ [case(VT_I4 | VT_ARRAY)] vt_i4_safe2_array vt_i4_array;
+
+ [case(VT_UI4)] uint32 vt_ui4;
+ [case(VT_UI4 | VT_VECTOR)] vt_ui4_vec vt_ui4_vec;
+ [case(VT_UI4 | VT_ARRAY)] vt_ui4_safe2_array vt_ui4_array;
+
+ [case(VT_R4)] uint32 vt_r4;
+ [case(VT_R4 | VT_VECTOR)] vt_i4_vec vt_r4_vec;
+ [case(VT_R4 | VT_ARRAY)] vt_i4_safe2_array vt_r4_array;
+
+ [case(VT_INT)] int32 vt_int;
+ [case(VT_INT | VT_ARRAY)] vt_i4_safe2_array vt_int_array;
+
+ [case(VT_UINT)] uint32 vt_uint;
+ [case(VT_UINT | VT_ARRAY)] vt_ui4_safe2_array vt_uint_array;
+
+ [case(VT_ERROR)] uint32 vt_error;
+ [case(VT_ERROR | VT_VECTOR)] vt_ui4_vec vt_error_vec;
+ [case(VT_ERROR | VT_ARRAY)] vt_ui4_safe2_array vt_error_array;
+
+ [case(VT_I8)] dlong vt_i8;
+ [case(VT_I8 | VT_VECTOR)] vt_dlong_vec vt_i8_vec;
+
+ [case(VT_UI8)] udlong vt_ui8;
+ [case(VT_UI8 | VT_VECTOR)] vt_udlong_vec vt_ui8_vec;
+
+ [case(VT_R8)] dlong vt_r8;
+ [case(VT_R8 | VT_VECTOR)] vt_dlong_vec vt_r8_vec;
+ [case(VT_R8 | VT_ARRAY)] vt_dlong_safe2_array vt_r8_array;
+
+ [case(VT_CY)] dlong vt_cy;
+ [case(VT_CY | VT_VECTOR)] vt_dlong_vec vt_cy_vec;
+ [case(VT_CY | VT_ARRAY)] vt_dlong_safe2_array vt_cy_array;
+
+ [case(VT_DATE)] dlong vt_date;
+ [case(VT_DATE | VT_VECTOR)] vt_dlong_vec vt_date_vec;
+ [case(VT_DATE| VT_ARRAY)] vt_dlong_safe2_array vt_date_array;
+
+ [case(VT_FILETIME)] udlong vt_filetime;
+ [case(VT_FILETIME | VT_VECTOR)] vt_udlong_vec vt_filetime_vec;
+
+ [case(VT_BSTR)] vt_bstr vt_bstr;
+ [case(VT_BSTR | VT_VECTOR)] vt_bstr_vec vt_bstr_v;
+ [case(VT_BSTR | VT_ARRAY)] vt_bstr_safe2_array vt_bstr_array;
+
+ [case(VT_LPWSTR)] vt_lpwstr vt_lpwstr;
+ [case(VT_LPWSTR | VT_VECTOR)] vt_lpwstr_vec vt_lpwstr_v;
+
+ [case(VT_COMPRESSED_LPWSTR)] vt_compressed_lpwstr vt_compressed_lpwstr;
+ [case(VT_COMPRESSED_LPWSTR | VT_VECTOR)] vt_compressed_lpwstr_vec vt_compresseed_lpwstr_v;
+
+ [case(VT_DECIMAL)] vt_decimal vt_decimal;
+ [case(VT_DECIMAL | VT_VECTOR)] vt_decimal_vec vt_decimal_v;
+
+ [case(VT_CLSID)] GUID vt_clid;
+ [case(VT_CLSID | VT_VECTOR)] vt_clsid_vec vt_clsid_v;
+
+ [case(VT_BLOB)] DATA_BLOB vt_blob;
+ [case(VT_BLOB_OBJECT)] DATA_BLOB vt_blob_object;
+
+ [case(VT_NULL)];
+ [case(VT_EMPTY)];
+
+ [case(VT_VARIANT)] vt_variant_wrap vt_variant_wrap;
+ [case(VT_VARIANT | VT_VECTOR)] vt_variant_wrap_vec vt_variant_wrap_vec;
+ [case(VT_VARIANT | VT_ARRAY)] vt_variant_wrap_safearray2 vt_variant_wrap_array;
+ } serialised_types;
+
+ /* MS-WSP 2.2.1.44 SERIALIZEDPROPERTYVALUE */
+ typedef [public] struct {
+ uint32 dwtype;
+ [switch_is(dwtype)] serialised_types rgb;
+ } wsp_serializedpropertyvalue;
+
+ /* MS-WSP 2.2.3.16 CPMFetchValueOut */
+ typedef [public] struct {
+ uint32 cbvalue;
+ uint32 fmoreexists;
+ uint32 fvalueexists;
+ /*
+ * very nearly the same as wsp_cbasestoragevariant, only
+ * different in how array types are represented, also only
+ * a portion of the value (serializedpropertyvalue) is here
+ *
+ * Additionally if the property doesn't exist (e.g.
+ * fvalueexists == 0) cbvalue can still have value
+ * so we can't define the 'vvalue' element below
+ *
+ * uint8 value[cbvalue];
+ */
+ } wsp_cpmfetchvalueout;
+
+ /* MS-WSP 2.2.3.31 CPMSetScopePrioritizationIn */
+ typedef [public] struct {
+ uint32 priority;
+ uint32 eventfrequency;
+ } wsp_cpmsetscopeprioritizationin;
+
+ /* MS-WSP 2.2.3.18 CPMSendNotifyOut */
+ typedef [public] struct {
+ uint32 watchnotify;
+ } wsp_cpmsendnotifyout;
+
+ /* MS-WSP 2.2.3.30 CPMGetRowsetNotifyOut */
+ typedef [public] struct {
+ uint32 wid;
+ uint8 eventinfo;
+ uint8 rowitemstate;
+ uint8 changeditemstate;
+ uint8 rowsetevent;
+ dlong rowseteventdata1;
+ dlong rowseteventdata2;
+ } wsp_cpmgetrowsetnotifyout;
+
+ /* MS-WSP 2.2.3.34 CPMGetScopeStatisticsOut */
+ typedef [public] struct {
+ uint32 dwindexeditems;
+ uint32 dwoutstandingadds;
+ uint32 dwoustandingmodifies;
+ } wsp_cpmgetscopestatisticsout;
+
+ /* MS-WSP 2.2.3.19 CPMGetApproximatePositionIn */
+ typedef [public] struct {
+ uint32 hcursor;
+ uint32 chapt;
+ uint32 bmk;
+ } wsp_cpmgetapproximatepositionin;
+
+ /* MS-WSP 2.2.3.20 CPMGetApproximatePositionOut */
+ typedef [public] struct {
+ uint32 numerator;
+ uint32 denominator;
+ } wsp_cpmgetapproximatepositionout;
+
+ /* MS-WSP 2.2.3.21 CPMCompareBmkIn */
+ typedef [public] struct {
+ uint32 hcursor;
+ uint32 chapt;
+ uint32 bmkfirst;
+ uint32 bmksecond;
+ } wsp_cpmcomparebmkin;
+
+ /* MS-WSP 2.2.3.22 CPMCompareBmkOut */
+ typedef [public] struct {
+ uint32 dwcomparison;
+ } wsp_cpmcomparebmkout;
+
+ /* MS-WSP 2.2.3.1 CPMCiStateInOut */
+ typedef [public] struct {
+ uint32 cbstruct;
+ uint32 cwordlist;
+ uint32 cpersistentindex;
+ uint32 cqueries;
+ uint32 cdocuments;
+ uint32 cfreshtest;
+ uint32 dwmergeprogress;
+ uint32 estate;
+ uint32 cfiltereddocuments;
+ uint32 ctotaldocuments;
+ uint32 cpendingscans;
+ uint32 dwindexsize;
+ uint32 cuniquekeys;
+ uint32 csecqdocuments;
+ uint32 dwpropcachesize;
+ } wsp_cpmcistateinout;
+
+ /* MS-WSP 2.2.3.27 CPMFindIndicesIn */
+ typedef [public] struct {
+ uint32 cwids;
+ uint32 cdepthprev;
+ uint32 pwids[cwids];
+ uint32 prgirowprev[cdepthprev];
+ } wsp_findindicesin;
+
+ /* MS-WSP 2.2.3.28 CPMFindIndicesOut */
+ typedef [public] struct {
+ uint32 cdepthnext;
+ uint32 prgirownext[cdepthnext];
+ } wsp_findindicesout;
+
+ typedef [public] struct {
+ uint32 hcursor;
+ uint32 chapt;
+ } wsp_cpmsresetstartpos;
+
+ typedef [public, nodiscriminant, switch_type(uint32)] union {
+ [case(CPMCONNECT)] wsp_cpmconnectin cpmconnect;
+ [case(CPMCREATEQUERY)] wsp_cpmcreatequeryin cpmcreatequery;
+ [case(CPMFREECURSOR)] wsp_cpmfreecursorin cpmfreecursor;
+ [case(CPMGETROWS)] wsp_cpmgetrowsin cpmgetrows;
+ [case(CPMSETBINDINGSIN)] wsp_cpmsetbindingsin cpmsetbindings;
+ [case(CPMRESTARTPOSITIONIN)] wsp_cpmsresetstartpos cpmresetstartpos;
+ [case(CPMGETQUERYSTATUS)] wsp_cpmgetquerystatusin cpmgetquerystatus;
+ [case(CPMGETQUERYSTATUSEX)] wsp_cpmgetquerystatusexin cpmgetquerystatusex;
+ [case(CPMSETSCOPEPRIORITIZATION)] wsp_cpmsetscopeprioritizationin cpmsetscopeprioritizationin;
+ [case(CPMGETNOTIFY)]; /*header only*/
+ [case(CPMGETROWSETNOTIFY)]; /*header only*/
+ [case(CPMDISCONNECT)]; /*header only*/
+ [case(CPMGETSCOPESTATISTICS)]; /*header only*/
+ [case(CPMGETAPPROXIMATEPOSITION)] wsp_cpmgetapproximatepositionin getapproximateposition;
+ [case(CPMCOMPAREBMK)] wsp_cpmcomparebmkin cpmcomparebmk;
+ [case(CPMCISTATEOUT)] wsp_cpmcistateinout wsp_cpmcistate;
+ [case(CPMFINDINDICES)] wsp_findindicesin wsp_findindices;
+ [case(CPMRATIOFINISHED)] wsp_cpmratiofinishedin wsp_cpmratiofinished;
+ [case(CPMFETCHVALUE)] wsp_cpmfetchvaluein cpmfetchvalue;
+ } req_message;
+
+ typedef [public, nodiscriminant, switch_type(uint32)] union {
+ [case(CPMCONNECT)] wsp_cpmconnectout cpmconnect;
+ [case(CPMCREATEQUERY)] wsp_cpmcreatequeryout cpmcreatequery;
+ [case(CPMFREECURSOR)] wsp_cpmfreecursorout cpmfreecursor;
+ [case(CPMGETROWS)] wsp_cpmgetrowsout cpmgetrows;
+ [case(CPMSETBINDINGSIN)]; /* just has header */
+ [case(CPMRESTARTPOSITIONIN)]; /* just has header */
+ [case(CPMGETQUERYSTATUS)] wsp_cpmgetquerystatusout cpmgetquerystatus;
+ [case(CPMSENDNOTIFYOUT)] wsp_cpmsendnotifyout cpmsendnotifyoutcpmgetquerystatus;
+ [case(CPMGETQUERYSTATUSEX)] wsp_cpmgetquerystatusexout cpmgetquerystatusex;
+ [case(CPMSETSCOPEPRIORITIZATION)]; /* just had header */
+ [case(CPMGETROWSETNOTIFY)] wsp_cpmgetrowsetnotifyout cpmgetrowsetnotifyout;
+ [case(CPMGETAPPROXIMATEPOSITION)] wsp_cpmgetapproximatepositionout getapproximateposition;
+ [case(CPMCOMPAREBMK)] wsp_cpmcomparebmkout cpmcomparebmk;
+ [case(CPMCISTATEOUT)] wsp_cpmcistateinout wsp_cpmcistate;
+ [case(CPMFINDINDICES)] wsp_findindicesout wsp_findindices;
+ [case(CPMGETSCOPESTATISTICS)] wsp_cpmgetscopestatisticsout cpmgetscopestatistics;
+ [case(CPMRATIOFINISHED)] wsp_cpmratiofinishedout wsp_cpmratiofinished;
+ [case(CPMFETCHVALUE)] wsp_cpmfetchvalueout cpmfetchvalue;
+ } resp_message;
+
+ typedef [public] struct {
+ wsp_header header;
+ [switch_is(header.msg)] req_message message;
+ } wsp_request;
+
+ typedef [public] struct {
+ wsp_header header;
+ [switch_is(header.msg)] resp_message message;
+ } wsp_response;
+};
+
diff --git a/librpc/idl/wsp_data.idl b/librpc/idl/wsp_data.idl
new file mode 100644
index 0000000..fde754a
--- /dev/null
+++ b/librpc/idl/wsp_data.idl
@@ -0,0 +1,313 @@
+#include "idl_types.h"
+[
+ pointer_default(unique)
+]
+
+interface constants
+{
+ /*
+ * Use en-us as default locale
+ * see MS-LCID 'Section 2.2 LCID Structure;
+ * for details of this and other language id(s)
+ */
+ const uint32_t WSP_DEFAULT_LCID = 0x00000409;
+ /*
+ * Max size of rows buffer in getrowsout response
+ * see MS-WSP 2.2.3.11
+ */
+ const uint32_t MAX_ROW_BUFF_SIZE = 0x0004000;
+
+ /* values for guidPropertySet */
+ const char* DBPROPSET_FSCIFRMWRK_EXT = "A9BD1526-6A80-11D0-8C9D-0020AF1D740E";
+ const char* DBPROPSET_QUERYEXT = "A7AC77ED-F8D7-11CE-A798-0020F8008025";
+ const char* DBPROPSET_CIFRMWRKCORE_EXT = "AFAFACA5-B5D1-11D0-8C62-00C04FC2DB8D";
+ const char* DBPROPSET_MSIDXS_ROWSETEXT = "AA6EE6B0-E828-11D0-B23E-00AA0047FC01";
+
+ /* Chapter and bookmark handle well known values */
+ const uint32_t DB_NULL_HCHAPTER = 0x00000000;
+ const uint32_t DBBMK_FIRST = 0xFFFFFFFC;
+ const uint32_t DBBMK_LAST = 0xFFFFFFFD;
+ /* properties of DBPROPSET_FSCIFRMWRK_EXT propertyset */
+ const uint32_t DBPROP_CI_CATALOG_NAME = 0x00000002;
+ const uint32_t DBPROP_CI_INCLUDE_SCOPES = 0x00000003;
+ const uint32_t DBPROP_CI_SCOPE_FLAGS = 0x00000004;
+ const uint32_t DBPROP_CI_QUERY_TYPE = 0x00000007;
+ const uint32_t DBPROP_GENERICOPTIONS_STRING = 0x00000006;
+ const uint32_t DBPROP_USECONTENTINDEX = 0x00000002;
+ const uint32_t DBPROP_IGNORENOISEONLYCLAUSES = 0x00000005;
+ const uint32_t DBPROP_DEFERCATALOGVERIFICATION = 0x00000008;
+ const uint32_t DBPROP_IGNORESBRI = 0x0000000E;
+ const uint32_t DBPROP_GENERATEPARSETREE = 0x0000000A;
+ const uint32_t DBPROP_FREETEXTANYTERM = 0x0000000C;
+ const uint32_t DBPROP_FREETEXTUSESTEMMING = 0x0000000D;
+
+ /* properties of DBPROPSET_QUERYEXT propertyset */
+ const uint32_t DBPROP_DEFERNONINDEXEDTRIMMING = 0x00000003;
+ const uint32_t DBPROP_USEEXTENDEDDBTYPES = 0x00000004;
+ const uint32_t DBPROP_FIRSTROWS = 0x00000007;
+ const uint32_t DBPROP_ENABLEROWSETEVENTS = 0x00000010;
+
+ /* properties of DBPROPSET_MSIDXS_ROWSETEXT */
+
+ const uint32_t MSIDXSPROP_ROWSETQUERYSTATUS = 0x02;
+ const uint32_t MSIDXSPROP_COMMAND_LOCALE_STRING = 0x03;
+ const uint32_t MSIDXSPROP_QUERY_RESTRICTION = 0x04;
+ const uint32_t MSIDXSPROP_PARSE_TREE = 0x05;
+ const uint32_t MSIDXSPROP_MAX_RANK = 0x06;
+ const uint32_t MSIDXSPROP_RESULTS_FOUND = 0x07;
+
+ /* flags of DBPROP_CI_SCOPE_FLAGS property */
+ const uint32_t QUERY_DEEP = 0x01;
+ const uint32_t QUERY_VIRTUAL_PATH = 0x02;
+
+ /* query type for BPROP_CI_QUERY_TYPE property */
+ const uint32_t CINORMAL = 0x00000000;
+
+ /* properties of DBPROPSET_CIFRMWRKCORE_EXT propertyset */
+
+ const uint32_t DBPROP_MACHINE = 0x00000002;
+ const uint32_t DBPROP_CLIENT_CLSID = 0x00000003;
+
+ /*
+ * STAT bit constants
+ */
+
+ /* The asynchronous query is still running. */
+ const uint32_t STAT_BUSY = 0x00000000;
+ /* The query is in an error state. */
+ const uint32_t STAT_ERROR = 0x00000001;
+ /* The query is complete and rows can be requested. */
+ const uint32_t STAT_DONE = 0x00000002;
+ /* The query is comp*/
+ const uint32_t STAT_REFRESH = 0x00000003;
+ /*
+ * Noise words were replaced by wildcard characters in the
+ * content query.
+ */
+ const uint32_t STAT_NOISE_WORDS = 0x00000010;
+ /*
+ * The results of the query might be incorrect because the
+ * query involved modified but unindexed files.
+ */
+ const uint32_t STAT_CONTENT_OUT_OF_DATE = 0x00000020;
+ /*
+ * The content query was too complex to complete or
+ * required enumeration instead of use of the content index.
+ */
+ const uint32_t STAT_CONTENT_QUERY_INCOMPLETE = 0x00000080;
+ /*
+ * The results of the query might be incorrect because the
+ * query execution reached the maximum allowable time.
+ */
+ const uint32_t STAT_TIME_LIMIT_EXCEEDED = 0x00000100;
+
+ /*
+ * a const to force an inline array to be evaluated at runtime to
+ * to get around an incomplete type error
+ */
+ const uint32 SINGLE_ITEM = 1;
+
+ /* WSP message types */
+
+ /* CPMConnectIn or CPMConnectOut */
+ const uint32 CPMCONNECT = 0x000000C8;
+ /* CPMDisconnect */
+ const uint32 CPMDISCONNECT = 0x000000C9;
+ /* CPMCreateQueryIn or CPMCreateQueryOut */
+ const uint32 CPMCREATEQUERY = 0x000000CA;
+ /* CPMFreeCursorIn or CPMFreeCursorOut */
+ const uint32 CPMFREECURSOR = 0x000000CB;
+ /* CPMGetRowsIn or CPMGetRowsOut */
+ const uint32 CPMGETROWS = 0x000000CC;
+ /* CPMRatioFinishedIn or CPMRatioFinishedOut */
+ const uint32 CPMRATIOFINISHED = 0x000000CD;
+ /* CPMCompareBmkIn or CPMCompareBmkOut */
+ const uint32 CPMCOMPAREBMK = 0x000000CE;
+ /* CPMGetApproximatePositionIn or CPMGetApproximatePositionOut */
+ const uint32 CPMGETAPPROXIMATEPOSITION = 0x000000CF;
+ /* CPMSetBindingsIn */
+ const uint32 CPMSETBINDINGSIN = 0x000000D0;
+ /* CPMGetNotify */
+ const uint32 CPMGETNOTIFY = 0x000000D1;
+ /* CPMSendNotifyOut */
+ const uint32 CPMSENDNOTIFYOUT = 0x000000D2;
+ /* CPMGetQueryStatusIn or CPMGetQueryStatusOut */
+ const uint32 CPMGETQUERYSTATUS = 0x000000D7;
+ /* CPMCiStateInOut */
+ const uint32 CPMCISTATEOUT = 0x000000D9;
+ /* CPMFetchValueIn or CPMFetchValueOut */
+ const uint32 CPMFETCHVALUE = 0x000000E4;
+ /* CPMGetQueryStatusExIn or CPMGetQueryStatusExOut */
+ const uint32 CPMGETQUERYSTATUSEX = 0x000000E7;
+ /* CPMRestartPositionIn */
+ const uint32 CPMRESTARTPOSITIONIN = 0x000000E8;
+ /* CPMSetCatStateIn (not supported) */
+ const uint32 CPMSETCATSTATEIN = 0x000000EC;
+ /* CPMGetRowsetNotifyIn or CPMGetRowsetNotifyOut */
+ const uint32 CPMGETROWSETNOTIFY = 0x000000F1;
+ /* CPMFindIndicesIn, or CPMFindIndicesOut */
+ const uint32 CPMFINDINDICES = 0x000000F2;
+ /* CPMSetScopePrioritizationIn or CPMSetScopePrioritizationOut */
+ const uint32 CPMSETSCOPEPRIORITIZATION = 0x000000F3;
+ /* CPMGetScopeStatisticsIn or CPMGetScopeStatisticsOut */
+ const uint32 CPMGETSCOPESTATISTICS = 0x000000F4;
+
+ const uint32 DBKIND_GUID_NAME = 0x00000000;
+ const uint32 DBKIND_GUID_PROPID = 0x00000001;
+ const uint32 PRSPEC_LPWSTR = 0x00000000;
+ const uint32 PRSPEC_PROPID = 0x00000001;
+ /* type constants for variant types */
+
+ const uint32 VT_EMPTY = 0x0000;
+ const uint32 VT_NULL = 0x0001;
+ const uint32 VT_I2 = 0x0002;
+ const uint32 VT_I4 = 0x0003;
+ const uint32 VT_R4 = 0x0004;
+ const uint32 VT_R8 = 0x0005;
+ const uint32 VT_CY = 0x0006;
+ const uint32 VT_DATE = 0x0007;
+ const uint32 VT_BSTR = 0x0008;
+ const uint32 VT_I1 = 0x0010;
+ const uint32 VT_UI1 = 0x0011;
+ const uint32 VT_UI2 = 0x0012;
+ const uint32 VT_UI4 = 0x0013;
+ const uint32 VT_I8 = 0x0014;
+ const uint32 VT_UI8 = 0x0015;
+ const uint32 VT_INT = 0x0016;
+ const uint32 VT_UINT = 0x0017;
+ const uint32 VT_ERROR = 0x000A;
+ const uint32 VT_BOOL = 0x000B;
+ const uint32 VT_VARIANT = 0x000C;
+ const uint32 VT_DECIMAL = 0x000E;
+ const uint32 VT_FILETIME = 0x0040;
+ const uint32 VT_BLOB = 0x0041;
+ const uint32 VT_BLOB_OBJECT = 0x0046;
+ const uint32 VT_CLSID = 0x0048;
+ const uint32 VT_LPSTR = 0x001E;
+ const uint32 VT_LPWSTR = 0x001F;
+ const uint32 VT_COMPRESSED_LPWSTR = 0x0023;
+ const uint32 VT_VECTOR = 0x1000;
+ const uint32 VT_ARRAY = 0x2000;
+
+ /* restriction types */
+ const uint32 RTNONE = 0x00000000;
+ const uint32 RTAND = 0x00000001;
+ const uint32 RTOR = 0x00000002;
+ const uint32 RTNOT = 0x00000003;
+ const uint32 RTCONTENT = 0x00000004;
+ const uint32 RTPROPERTY = 0x00000005;
+ const uint32 RTPROXIMITY = 0x00000006;
+ const uint32 RTVECTOR = 0x00000007;
+ const uint32 RTNATLANGUAGE = 0x00000008;
+ const uint32 RTSCOPE = 0x00000009;
+ const uint32 RTREUSEWHERE = 0x00000011;
+ const uint32 RTINTERNALPROP = 0x00FFFFFA;
+ const uint32 RTPHRASE = 0x00FFFFFD;
+ const uint32 RTCOERCE_ADD = 0x0000000A;
+ const uint32 RTCOERCE_MULTIPLY = 0x0000000B;
+ const uint32 RTCOERCE_ABSOLUTE = 0x0000000C;
+ const uint32 RTPROB = 0x0000000D;
+ const uint32 RTFEEDBACK = 0x0000000E;
+ const uint32 RTRELDOC = 0x0000000F;
+
+
+ /* Row seek types */
+ const uint32 EROWSEEKNONE = 0x00000000;
+ const uint32 EROWSEEKNEXT = 0x00000001;
+ const uint32 EROWSEEKAT = 0x00000002;
+ const uint32 EROWSEEKATRATIO = 0x00000003;
+ const uint32 EROWSEEKBYBOOKMARK = 0x00000004;
+
+ const uint32 WINDOWS_7 = 0x00000700;
+ const uint32 WINDOWS_2008 = 0x00010700;
+
+ /* Relops */
+ const uint32 PRLT = 0x00000000;
+ const uint32 PRLE = 0x00000001;
+ const uint32 PRGT = 0x00000002;
+ const uint32 PRGE = 0x00000003;
+ const uint32 PREQ = 0x00000004;
+ const uint32 PRNE = 0x00000005;
+ const uint32 PRRE = 0x00000006;
+ const uint32 PRALLBITS = 0x00000007;
+ const uint32 PRSOMEBITS = 0x00000008;
+ const uint32 PRALL = 0x00000100;
+ const uint32 PRANY = 0x00000200;
+
+ const uint32 PROPAGATE_NONE = 0;
+ const uint32 PROPAGATE_ADD = 1;
+ const uint32 PROPAGATE_DELETE = 2;
+ const uint32 PROPAGATE_MODIFY = 3;
+ const uint32 PROPAGATE_ROWSET = 4;
+
+ const uint32 ROWSETEVENT_ITEMSTATE_NOTINROWSET = 0;
+ const uint32 ROWSETEVENT_ITEMSTATE_INROWSET = 1;
+ const uint32 ROWSETEVENT_ITEMSTATE_UNKNOWN = 2;
+
+ const uint32 ROWSETEVENT_TYPE_DATAEXPIRED = 0;
+ const uint32 ROWSETEVENT_TYPE_FOREGROUNDLOST = 1;
+ const uint32 ROWSETEVENT_TYPE_SCOPESTATISTICS = 2;
+
+ const uint32 DBCOMPARE_LT = 0x00000000;
+ const uint32 DBCOMPARE_EQ = 0x00000001;
+ const uint32 DBCOMPARE_GT = 0x00000002;
+ const uint32 DBCOMPARE_NE = 0x00000003;
+ const uint32 DBCOMPARE_NOTCOMPARABLE = 0x00000004;
+
+ const uint32 VECTOR_RANK_MIN = 0x00000000;
+ const uint32 VECTOR_RANK_MAX = 0x00000001;
+ const uint32 VECTOR_RANK_INNER = 0x00000002;
+ const uint32 VECTOR_RANK_DICE = 0x00000003;
+ const uint32 VECTOR_RANK_JACCARD = 0x00000004;
+
+ const uint32 DBAGGTTYPE_BYNONE = 0x00000000;
+ const uint32 DBAGGTTYPE_SUM = 0x00000001;
+ const uint32 DBAGGTTYPE_MAX = 0x00000002;
+ const uint32 DBAGGTTYPE_MIN = 0x00000003;
+ const uint32 DBAGGTTYPE_AVG = 0x00000004;
+ const uint32 DBAGGTTYPE_COUNT = 0x00000005;
+ const uint32 DBAGGTTYPE_CHILDCOUNT = 0x00000006;
+ const uint32 DBAGGTTYPE_BYFREQ = 0x00000007;
+ const uint32 DBAGGTTYPE_FIRST = 0x00000008;
+ const uint32 DBAGGTTYPE_DATERANGE = 0x00000009;
+ const uint32 DBAGGTTYPE_REPRESENTATIVEOF= 0x0000000a;
+ const uint32 DBAGGTTYPE_EDITDISTANCE = 0x0000000b;
+
+ const uint32 ESEQUENTIAL = 0x00000001;
+ const uint32 ELOCATEABLE = 0x00000003;
+ const uint32 ESCROLLABLE = 0x00000007;
+ const uint32 EASYNCHRONOUS = 0x00000008;
+ const uint32 EFIRSTROWS = 0x00000080;
+ const uint32 EHOLDROWS = 0x00000200;
+ const uint32 ECHAPTERED = 0x00000800;
+ const uint32 EUSECI = 0x00001000;
+ const uint32 EDEFERTRIMMING = 0x00002000;
+ const uint32 ENABLEROWSETEVENTS = 0x00800000;
+ const uint32 EDONOTCOMPUTEEXPENSIVEPROPS = 0x00400000;
+
+ const uint32 CI_STATE_SHADOW_MERGE = 0x00000001;
+ const uint32 CI_STATE_MASTER_MERGE = 0x00000002;
+ const uint32 CI_STATE_ANNEALING_MERGE = 0x00000008;
+ const uint32 CI_STATE_SCANNING = 0x00000010;
+ const uint32 CI_STATE_LOW_MEMORY = 0x00000080;
+ const uint32 CI_STATE_HIGH_IO = 0x00000100;
+ const uint32 CI_STATE_MASTER_MERGE_PAUSED = 0x00000200;
+ const uint32 CI_STATE_READ_ONLY = 0x00000400;
+ const uint32 CI_STATE_BATTERY_POWER = 0x00000800;
+ const uint32 CI_STATE_USER_ACTIVE = 0x00001000;
+ const uint32 CI_STATE_LOW_DISK = 0x00010000;
+ const uint32 CI_STATE_HIGH_CPU = 0x00020000;
+
+ const uint32 STORESTATUSOK = 0x00000000;
+ const uint32 STORESTATUSDEFERRED = 0x00000001;
+ const uint32 STORESTATUSNULL = 0x00000002;
+
+ const uint32 DB_S_ENDOFROWSET = 0x00040EC6;
+
+ const uint32 XOR_CONST = 0x59533959;
+ const uint32 E_UNEXPECTED = 0x8000FFFF;
+ const uint32 WIN_UPDATE_ERR = 0x80070003;
+
+ const uint32 QUERY_SORTASCEND = 0x00000000;
+ const uint32 QUERY_DESCEND = 0x00000001;
+}
diff --git a/librpc/idl/wzcsvc.idl b/librpc/idl/wzcsvc.idl
new file mode 100644
index 0000000..b403c07
--- /dev/null
+++ b/librpc/idl/wzcsvc.idl
@@ -0,0 +1,31 @@
+/*
+ wireless configuration service
+*/
+
+[
+ uuid("621dff68-3c39-4c6c-aae3-e68e2c6503ad"),
+ version(1.0),
+ helpstring("Wireless Configuration Service")
+]
+interface wzcsvc
+{
+
+ void wzcsvc_EnumInterfaces();
+ void wzcsvc_QueryInterface();
+ void wzcsvc_SetInterface();
+ void wzcsvc_RefreshInterface();
+ void wzcsvc_QueryContext();
+ void wzcsvc_SetContext();
+ void wzcsvc_EapolUIResponse();
+ void wzcsvc_EapolGetCustomAuthData();
+ void wzcsvc_EapolSetCustomAuthData();
+ void wzcsvc_EapolGetInterfaceParams();
+ void wzcsvc_EapolSetInterfaceParams();
+ void wzcsvc_EapolReAuthenticateInterface();
+ void wzcsvc_EapolQueryInterfaceState();
+ void wzcsvc_OpenWZCDbLogSession();
+ void wzcsvc_CloseWZCDbLogSession();
+ void wzcsvc_EnumWZCDbLogRecords();
+ void wzcsvc_FlushWZCdbLog();
+ void wzcsvc_GetWZCDbLogRecord();
+}
diff --git a/librpc/idl/xattr.idl b/librpc/idl/xattr.idl
new file mode 100644
index 0000000..e2f7cb4
--- /dev/null
+++ b/librpc/idl/xattr.idl
@@ -0,0 +1,239 @@
+#include "idl_types.h"
+
+/*
+ IDL structures for xattr file attributes
+
+ this has nothing to do with RPC, we are just using our NDR/IDL
+ infrastructure as a convenient way to store linearised information
+ about a file in a architecture independent manner
+*/
+
+import "security.idl";
+
+[
+ version(0.0),
+ helper("../librpc/ndr/ndr_xattr.h"),
+ pyhelper("librpc/ndr/py_xattr.c"),
+ pointer_default(unique)
+]
+interface xattr
+{
+ const char *XATTR_DOSATTRIB_NAME = "user.DosAttrib";
+ const char *XATTR_DOSATTRIB_NAME_S3 = "user.DOSATTRIB";
+ const int XATTR_DOSATTRIB_ESTIMATED_SIZE = 64;
+
+ /* we store basic dos attributes in a DosAttrib xattr. By
+ using a union we can cope with new version of this
+ structure more easily */
+
+ /*
+ * the FFFF level is never really used,
+ * it's used to pass the information from
+ * the old hex string attrib information
+ * we have a handwritten parser which converts
+ * the hex string to the xattr_DosInfoFFFFCompat structure
+ */
+
+ typedef struct {
+ uint32 attrib;
+ } xattr_DosInfoFFFFCompat;
+
+ typedef struct {
+ uint32 attrib;
+ uint32 ea_size;
+ udlong size;
+ udlong alloc_size;
+ NTTIME create_time;
+ NTTIME change_time;
+ } xattr_DosInfo1;
+
+/*
+ We use xattrDosInfo1 again when we store values.
+ Because the sticky write time is now stored in the opendb
+ and xattr_DosInfo2Old is only present to parse existing
+ values from disk.
+
+ const int XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME = 0x1;
+*/
+ typedef struct {
+ uint32 flags;
+ uint32 attrib;
+ uint32 ea_size;
+ udlong size;
+ udlong alloc_size;
+ NTTIME create_time;
+ NTTIME change_time;
+ NTTIME write_time; /* only used when sticky write time is set */
+ utf8string name;
+ } xattr_DosInfo2Old;
+
+ typedef [bitmap32bit] bitmap {
+ XATTR_DOSINFO_ATTRIB = 0x00000001,
+ XATTR_DOSINFO_EA_SIZE = 0x00000002,
+ XATTR_DOSINFO_SIZE = 0x00000004,
+ XATTR_DOSINFO_ALLOC_SIZE = 0x00000008,
+ XATTR_DOSINFO_CREATE_TIME = 0x00000010,
+ XATTR_DOSINFO_CHANGE_TIME = 0x00000020,
+ XATTR_DOSINFO_ITIME = 0x00000040
+ } xattr_DosInfoValidFlags;
+
+ typedef struct {
+ xattr_DosInfoValidFlags valid_flags;
+ uint32 attrib;
+ uint32 ea_size;
+ udlong size;
+ udlong alloc_size;
+ NTTIME create_time;
+ NTTIME change_time;
+ } xattr_DosInfo3;
+
+ typedef struct {
+ xattr_DosInfoValidFlags valid_flags;
+ uint32 attrib;
+ NTTIME itime;
+ NTTIME create_time;
+ } xattr_DosInfo4;
+
+ typedef struct {
+ xattr_DosInfoValidFlags valid_flags;
+ uint32 attrib;
+ NTTIME create_time;
+ } xattr_DosInfo5;
+
+ typedef [public,switch_type(uint16)] union {
+ [case(0xFFFF)] xattr_DosInfoFFFFCompat compatinfoFFFF;
+ [case(1)] xattr_DosInfo1 info1;
+ [case(2)] xattr_DosInfo2Old oldinfo2;
+ [case(3)] xattr_DosInfo3 info3;
+ [case(4)] xattr_DosInfo4 info4;
+ [case(5)] xattr_DosInfo5 info5;
+ } xattr_DosInfo;
+
+ typedef [public] struct {
+ uint16 version;
+ [switch_is(version)] xattr_DosInfo info;
+ } xattr_DosAttrib;
+
+ typedef [public,nopush,nopull,noprint] struct {
+ astring attrib_hex;
+ uint16 version;
+ [switch_is(version)] xattr_DosInfo info;
+ } xattr_DOSATTRIB;
+
+ /* we store DOS style extended attributes in a DosEAs xattr */
+ const char *XATTR_DOSEAS_NAME = "user.DosEAs";
+
+ typedef struct {
+ utf8string name;
+ DATA_BLOB value;
+ } xattr_EA;
+
+ typedef [public] struct {
+ uint16 num_eas;
+ [size_is(num_eas)] xattr_EA *eas;
+ } xattr_DosEAs;
+
+ /* Slightly different version, used by the vfs_xattr_tdb module */
+ typedef [public] struct {
+ uint32 num_eas;
+ xattr_EA eas[num_eas];
+ } tdb_xattrs;
+
+ /* we store stream information in this xattr structure. Then
+ the streams themselves are stored in
+ user.DosStream.STREAMNAME or in external files, according
+ to the flags */
+ const char *XATTR_DOSSTREAMS_NAME = "user.DosStreams";
+
+ const int XATTR_STREAM_FLAG_INTERNAL = 0x00000001;
+
+ /* stream data is stored in attributes with the given prefix */
+ const char *XATTR_DOSSTREAM_PREFIX = "user.DosStream.";
+
+ const int XATTR_MAX_STREAM_SIZE = 0x4000;
+ const int XATTR_MAX_STREAM_SIZE_TDB = 0x100000;
+
+ typedef struct {
+ uint32 flags;
+ udlong size;
+ udlong alloc_size;
+ utf8string name;
+ } xattr_DosStream;
+
+ typedef [public] struct {
+ uint32 num_streams;
+ [size_is(num_streams)] xattr_DosStream *streams;
+ } xattr_DosStreams;
+
+
+ /* we store the NT ACL a NTACL xattr. It is versioned so we
+ can later add other acl attribs (such as posix acl mapping)
+
+ we put this xattr in the security namespace to ensure that
+ only trusted users can write to the ACL
+
+ stored in "security.NTACL"
+
+ Version 1. raw SD stored as Samba4 does it.
+ Version 2. raw SD + last changed hash so we
+ can discard if this doesn't match the underlying ACL hash.
+ */
+
+ const char *XATTR_NTACL_NAME = "security.NTACL";
+
+ const int XATTR_SD_HASH_SIZE = 64;
+ const int XATTR_SD_HASH_TYPE_NONE = 0x0;
+ const int XATTR_SD_HASH_TYPE_SHA256 = 0x1;
+
+ typedef [public] struct {
+ security_descriptor *sd;
+ uint8 hash[16];
+ } security_descriptor_hash_v2; /* Hash never used in this version. */
+
+ typedef [public] struct {
+ security_descriptor *sd;
+ uint16 hash_type;
+ uint8 hash[64]; /* 64 bytes hash. */
+ } security_descriptor_hash_v3;
+
+ typedef [public] struct {
+ security_descriptor *sd;
+ uint16 hash_type;
+ uint8 hash[64]; /* 64 bytes hash. */
+ utf8string description; /* description of what created
+ * this hash (to allow
+ * forensics later, if we have
+ * a bug in one codepath */
+ /*
+ * "time" is always set to 0. Left here to avoid
+ * bumping the union versions. Remove in case a v5 is
+ * necessary.
+ */
+ NTTIME time;
+ uint8 sys_acl_hash[64]; /* 64 bytes hash. */
+ } security_descriptor_hash_v4;
+
+ typedef [switch_type(uint16)] union {
+ [case(1)] security_descriptor *sd;
+ [case(2)] security_descriptor_hash_v2 *sd_hs2;
+ [case(3)] security_descriptor_hash_v3 *sd_hs3;
+ [case(4)] security_descriptor_hash_v4 *sd_hs4;
+ } xattr_NTACL_Info;
+
+ typedef [public] struct {
+ uint16 version;
+ [switch_is(version)] xattr_NTACL_Info info;
+ } xattr_NTACL;
+
+ /*
+ * A wrapper of the common information required to be in the
+ * hash of the ACL, for the acl_xattr and acl_tdb modules.
+ */
+ [public] typedef struct {
+ DATA_BLOB acl_as_blob;
+ uid_t owner;
+ gid_t group;
+ mode_t mode;
+ } xattr_sys_acl_hash_wrapper;
+
+}
diff --git a/librpc/ndr.pc.in b/librpc/ndr.pc.in
new file mode 100644
index 0000000..6828ac0
--- /dev/null
+++ b/librpc/ndr.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ndr
+Description: Network Data Representation Core Library
+Requires: samba-util talloc
+Version: @PACKAGE_VERSION@
+Libs: @LIB_RPATH@ -L${libdir} -lndr
+Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 -D_GNU_SOURCE=1
diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h
new file mode 100644
index 0000000..03d1aea
--- /dev/null
+++ b/librpc/ndr/libndr.h
@@ -0,0 +1,918 @@
+/*
+ Unix SMB/CIFS implementation.
+ rpc interface definitions
+
+ 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/>.
+*/
+
+/* 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 __LIBNDR_H__
+#define __LIBNDR_H__
+
+#include <talloc.h>
+#include "../lib/util/discard.h" /* for discard_const */
+#include "../lib/util/data_blob.h"
+#include "../lib/util/time.h"
+#include "../lib/util/charset/charset.h"
+
+/*
+ this provides definitions for the libcli/rpc/ MSRPC library
+*/
+
+
+/*
+ We store the token mapping in an array that is resized as necessary.
+*/
+struct ndr_token;
+
+struct ndr_token_list {
+ struct ndr_token *tokens;
+ uint32_t count;
+};
+
+struct ndr_compression_state;
+
+#define LIBNDR_STATIC_ASSERT(msg, cond) \
+ typedef char static_assert_##msg[(cond) ? 1 : -1]
+
+/*
+ * If you’re considering changing the size of this type, see also
+ * $scalar_alignment in pidl/lib/Parse/Pidl/NDR.pm.
+ */
+typedef enum {
+ LIBNDR_FLAG_BIGENDIAN = 1U << 0,
+ LIBNDR_FLAG_NOALIGN = 1U << 1,
+
+ LIBNDR_FLAG_STR_ASCII = 1U << 2,
+ LIBNDR_FLAG_STR_LEN4 = 1U << 3,
+ LIBNDR_FLAG_STR_SIZE4 = 1U << 4,
+ LIBNDR_FLAG_STR_NOTERM = 1U << 5,
+ LIBNDR_FLAG_STR_NULLTERM = 1U << 6,
+ LIBNDR_FLAG_STR_SIZE2 = 1U << 7,
+ LIBNDR_FLAG_STR_BYTESIZE = 1U << 8,
+ LIBNDR_FLAG_STR_NO_EMBEDDED_NUL = 1U << 9,
+ LIBNDR_FLAG_STR_CONFORMANT = 1U << 10,
+ LIBNDR_FLAG_STR_CHARLEN = 1U << 11,
+ LIBNDR_FLAG_STR_UTF8 = 1U << 12,
+ LIBNDR_FLAG_STR_RAW8 = 1U << 13,
+
+ /*
+ * Mark an element as SECRET, it won't be printed via
+ * ndr_print* unless NDR_PRINT_SECRETS is specified.
+ */
+ LIBNDR_FLAG_IS_SECRET = 1U << 14,
+
+ /* Disable string token compression */
+ LIBNDR_FLAG_NO_COMPRESSION = 1U << 15,
+
+ /*
+ * don't debug NDR_ERR_BUFSIZE failures,
+ * as the available buffer might be incomplete.
+ *
+ * return NDR_ERR_INCOMPLETE_BUFFER instead.
+ */
+ LIBNDR_FLAG_INCOMPLETE_BUFFER = 1U << 16,
+
+ /*
+ * This lets ndr_pull_subcontext_end() return
+ * NDR_ERR_UNREAD_BYTES.
+ */
+ LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES = 1U << 17,
+
+ /* set if relative pointers should *not* be marshalled in reverse order */
+ LIBNDR_FLAG_NO_RELATIVE_REVERSE = 1U << 18,
+
+ /* set if relative pointers are marshalled in reverse order */
+ LIBNDR_FLAG_RELATIVE_REVERSE = 1U << 19,
+
+ LIBNDR_FLAG_REF_ALLOC = 1U << 20,
+ LIBNDR_FLAG_REMAINING = 1U << 21,
+ LIBNDR_FLAG_ALIGN2 = 1U << 22,
+ LIBNDR_FLAG_ALIGN4 = 1U << 23,
+ LIBNDR_FLAG_ALIGN8 = 1U << 24,
+
+ LIBNDR_PRINT_ARRAY_HEX = 1U << 25,
+ LIBNDR_PRINT_SET_VALUES = 1U << 26,
+
+ /* used to force a section of IDL to be little-endian */
+ LIBNDR_FLAG_LITTLE_ENDIAN = 1U << 27,
+
+ /* used to check if alignment padding is zero */
+ LIBNDR_FLAG_PAD_CHECK = 1U << 28,
+
+ LIBNDR_FLAG_NDR64 = 1U << 29,
+
+ /* set if an object uuid will be present */
+ LIBNDR_FLAG_OBJECT_PRESENT = 1U << 30,
+
+ /* set to avoid recursion in ndr_size_*() calculation */
+ LIBNDR_FLAG_NO_NDR_SIZE = 1U << 31,
+
+ /*
+ * present to keep the size of this enumeration 64 bits until we need a
+ * 33rd flag.
+ */
+ LIBNDR_FLAG_0x100000000 = UINT64_C(1) << 32,
+} libndr_flags;
+LIBNDR_STATIC_ASSERT(libndr_flags_are_64_bit, sizeof (libndr_flags) == 8);
+#define PRI_LIBNDR_FLAGS PRIx64
+#define PRI_LIBNDR_FLAGS_DECIMAL PRIu64
+
+/*
+* If you’re considering changing the size of this type, see also
+* $scalar_alignment in pidl/lib/Parse/Pidl/NDR.pm.
+*/
+typedef enum {
+ /*
+ flags passed to control parse flow
+ These are deliberately in a different range to the NDR_IN/NDR_OUT
+ flags to catch mixups
+ */
+ NDR_SCALARS = 0x100,
+ NDR_BUFFERS = 0x200,
+
+ /*
+ flags passed to ndr_print_*() and ndr pull/push for functions
+ These are deliberately in a different range to the
+ NDR_SCALARS/NDR_BUFFERS flags to catch mixups
+ */
+ NDR_IN = 0x10,
+ NDR_OUT = 0x20,
+ NDR_BOTH = 0x30,
+ NDR_SET_VALUES = 0x40,
+} ndr_flags_type;
+LIBNDR_STATIC_ASSERT(ndr_flags_are_32_bit, sizeof (ndr_flags_type) == 4);
+#define PRI_NDR_FLAGS_TYPE PRIx32
+
+#undef LIBNDR_STATIC_ASSERT
+
+/* this is the base structure passed to routines that
+ parse MSRPC formatted data
+
+ note that in Samba4 we use separate routines and structures for
+ MSRPC marshalling and unmarshalling. Also note that these routines
+ are being kept deliberately very simple, and are not tied to a
+ particular transport
+*/
+struct ndr_pull {
+ libndr_flags flags; /* LIBNDR_FLAG_* */
+ uint8_t *data;
+ uint32_t data_size;
+ uint32_t offset;
+
+ uint32_t relative_highest_offset;
+ uint32_t relative_base_offset;
+ uint32_t relative_rap_convert;
+ struct ndr_token_list relative_base_list;
+
+ struct ndr_token_list relative_list;
+ struct ndr_token_list array_size_list;
+ struct ndr_token_list array_length_list;
+ struct ndr_token_list switch_list;
+
+ struct ndr_compression_state *cstate;
+
+ TALLOC_CTX *current_mem_ctx;
+
+ /* this is used to ensure we generate unique reference IDs
+ between request and reply */
+ uint32_t ptr_count;
+ uint32_t recursion_depth;
+ /*
+ * The global maximum depth for recursion. When set it overrides the
+ * value supplied by the max_recursion idl attribute. This is needed
+ * for fuzzing as ASAN uses a low threshold for stack depth to check
+ * for stack overflow.
+ */
+ uint32_t global_max_recursion;
+};
+
+/* structure passed to functions that generate NDR formatted data */
+struct ndr_push {
+ libndr_flags flags; /* LIBNDR_FLAG_* */
+ uint8_t *data;
+ uint32_t alloc_size;
+ uint32_t offset;
+ bool fixed_buf_size;
+
+ uint32_t relative_base_offset;
+ uint32_t relative_end_offset;
+ struct ndr_token_list relative_base_list;
+
+ struct ndr_token_list switch_list;
+ struct ndr_token_list relative_list;
+ struct ndr_token_list relative_begin_list;
+ struct ndr_token_list nbt_string_list;
+ struct ndr_token_list dns_string_list;
+ struct ndr_token_list full_ptr_list;
+
+ struct ndr_compression_state *cstate;
+
+ /* this is used to ensure we generate unique reference IDs */
+ uint32_t ptr_count;
+};
+
+/* structure passed to functions that print IDL structures */
+struct ndr_print {
+ libndr_flags flags; /* LIBNDR_FLAG_* */
+ uint32_t depth;
+ struct ndr_token_list switch_list;
+ void (*print)(struct ndr_print *, const char *, ...) PRINTF_ATTRIBUTE(2,3);
+ void *private_data;
+ bool no_newline;
+ bool print_secrets;
+};
+
+#define LIBNDR_STRING_FLAGS (0U | \
+ LIBNDR_FLAG_STR_ASCII | \
+ LIBNDR_FLAG_STR_LEN4 | \
+ LIBNDR_FLAG_STR_SIZE4 | \
+ LIBNDR_FLAG_STR_NOTERM | \
+ LIBNDR_FLAG_STR_NULLTERM | \
+ LIBNDR_FLAG_STR_SIZE2 | \
+ LIBNDR_FLAG_STR_BYTESIZE | \
+ LIBNDR_FLAG_STR_NO_EMBEDDED_NUL | \
+ LIBNDR_FLAG_STR_CONFORMANT | \
+ LIBNDR_FLAG_STR_CHARLEN | \
+ LIBNDR_FLAG_STR_UTF8 | \
+ LIBNDR_FLAG_STR_RAW8 | \
+ 0)
+
+#define LIBNDR_ENCODING_FLAGS (0U | \
+ LIBNDR_FLAG_STR_ASCII | \
+ LIBNDR_FLAG_STR_UTF8 | \
+ LIBNDR_FLAG_STR_RAW8 | \
+ 0)
+
+#define LIBNDR_ALIGN_FLAGS ( 0 | \
+ LIBNDR_FLAG_NOALIGN | \
+ LIBNDR_FLAG_REMAINING | \
+ LIBNDR_FLAG_ALIGN2 | \
+ LIBNDR_FLAG_ALIGN4 | \
+ LIBNDR_FLAG_ALIGN8 | \
+ 0)
+
+/* useful macro for debugging */
+#define NDR_PRINT_DEBUG(type, p) (void)ndr_print_debug(1, (ndr_print_fn_t)ndr_print_ ##type, #p, p, __location__, __func__)
+#define NDR_PRINT_DEBUGC(dbgc_class, type, p) ndr_print_debugc(dbgc_class, (ndr_print_fn_t)ndr_print_ ##type, #p, p)
+#define NDR_PRINT_UNION_DEBUG(type, level, p) ndr_print_union_debug((ndr_print_fn_t)ndr_print_ ##type, #p, level, p)
+#define NDR_PRINT_FUNCTION_DEBUG(type, flags, p) ndr_print_function_debug((ndr_print_function_t)ndr_print_ ##type, #type, flags, p)
+#define NDR_PRINT_BOTH_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_BOTH, p)
+#define NDR_PRINT_OUT_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_OUT, p)
+#define NDR_PRINT_IN_DEBUG(type, p) NDR_PRINT_FUNCTION_DEBUG(type, NDR_IN | NDR_SET_VALUES, p)
+
+/**
+ * @brief Prints NDR structure.
+ *
+ * Like NDR_PRINT_DEBUG, but takes a debug level parameter.
+ *
+ * @param[in] l The debug level.
+ * @param[in] type ndr_print_#type is the function that will be called.
+ * @param[in] p Pointer to the struct.
+ *
+ * @code
+ * NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG, wbint_userinfo, state->info);
+ * @endcode
+ *
+ * @return void.
+ */
+#define NDR_PRINT_DEBUG_LEVEL(l, type, p) \
+ (void) ( CHECK_DEBUGLVL(l) \
+ && ndr_print_debug(l, (ndr_print_fn_t)ndr_print_ ##type, #p, p, __location__, __func__) )
+
+/* useful macro for debugging in strings */
+#define NDR_PRINT_STRUCT_STRING(ctx, type, p) ndr_print_struct_string(ctx, (ndr_print_fn_t)ndr_print_ ##type, #p, p)
+#define NDR_PRINT_UNION_STRING(ctx, type, level, p) ndr_print_union_string(ctx, (ndr_print_fn_t)ndr_print_ ##type, #p, level, p)
+#define NDR_PRINT_FUNCTION_STRING(ctx, type, flags, p) ndr_print_function_string(ctx, (ndr_print_function_t)ndr_print_ ##type, #type, flags, p)
+#define NDR_PRINT_BOTH_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_BOTH, p)
+#define NDR_PRINT_OUT_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_OUT, p)
+#define NDR_PRINT_IN_STRING(ctx, type, p) NDR_PRINT_FUNCTION_STRING(ctx, type, NDR_IN | NDR_SET_VALUES, p)
+
+#define NDR_HIDE_SECRET(ndr) \
+ (unlikely(((ndr)->flags & LIBNDR_FLAG_IS_SECRET) && !(ndr)->print_secrets))
+
+#define NDR_BE(ndr) (unlikely(((ndr)->flags & (LIBNDR_FLAG_BIGENDIAN|LIBNDR_FLAG_LITTLE_ENDIAN)) == LIBNDR_FLAG_BIGENDIAN))
+
+enum ndr_err_code {
+ NDR_ERR_SUCCESS = 0,
+ NDR_ERR_ARRAY_SIZE,
+ NDR_ERR_BAD_SWITCH,
+ NDR_ERR_OFFSET,
+ NDR_ERR_RELATIVE,
+ NDR_ERR_CHARCNV,
+ NDR_ERR_LENGTH,
+ NDR_ERR_SUBCONTEXT,
+ NDR_ERR_COMPRESSION,
+ NDR_ERR_STRING,
+ NDR_ERR_VALIDATE,
+ NDR_ERR_BUFSIZE,
+ NDR_ERR_ALLOC,
+ NDR_ERR_RANGE,
+ NDR_ERR_TOKEN,
+ NDR_ERR_IPV4ADDRESS,
+ NDR_ERR_IPV6ADDRESS,
+ NDR_ERR_INVALID_POINTER,
+ NDR_ERR_UNREAD_BYTES,
+ NDR_ERR_NDR64,
+ NDR_ERR_FLAGS,
+ NDR_ERR_INCOMPLETE_BUFFER,
+ NDR_ERR_MAX_RECURSION_EXCEEDED,
+ NDR_ERR_UNDERFLOW
+};
+
+#define NDR_ERR_CODE_IS_SUCCESS(x) (x == NDR_ERR_SUCCESS)
+
+#define NDR_ERR_HAVE_NO_MEMORY(x) do { \
+ if (NULL == (x)) { \
+ return NDR_ERR_ALLOC; \
+ } \
+} while (0)
+
+/*
+ * Values here are chosen to be distinct from but recognisable as the
+ * values in ntifs.h and claims.idl
+ */
+enum ndr_compression_alg {
+ NDR_COMPRESSION_NONE = 0, /* 0x00 in ntifs.h */
+ NDR_COMPRESSION_XPRESS_LZNT1 = 102, /* MS-XCA 0x02 in ntifs.h
+ * (Unimplemented)
+ */
+ NDR_COMPRESSION_XPRESS_RAW = 103, /* MS-XCA 0x03 in ntifs.h
+ * (implemented in
+ * lib/compression but
+ * not connected to libndr)
+ */
+ NDR_COMPRESSION_XPRESS_HUFF_RAW = 104, /* MS-XCA 0x04 in ntifs.h */
+ NDR_COMPRESSION_MSZIP_CAB = 201,
+ NDR_COMPRESSION_MSZIP = 202,
+ NDR_COMPRESSION_XPRESS = 203,
+ NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2 = 204, /* Unimplemented */
+ NDR_COMPRESSION_INVALID = 255,
+};
+
+#define NDR_PULL_CHECK_FLAGS(ndr, ndr_flags) do { \
+ if (unlikely((ndr_flags) & ~(NDR_SCALARS|NDR_BUFFERS))) { \
+ return ndr_pull_error(ndr, NDR_ERR_FLAGS, "Invalid pull struct ndr_flags 0x%"PRI_NDR_FLAGS_TYPE, ndr_flags); \
+ } \
+} while (0)
+
+#define NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags) do { \
+ if ((ndr_flags) & ~(NDR_SCALARS|NDR_BUFFERS)) \
+ return ndr_push_error(ndr, NDR_ERR_FLAGS, "Invalid push struct ndr_flags 0x%"PRI_NDR_FLAGS_TYPE, ndr_flags); \
+} while (0)
+
+#define NDR_PULL_CHECK_FN_FLAGS(ndr, flags) do { \
+ if ((flags) & ~(NDR_BOTH|NDR_SET_VALUES)) { \
+ return ndr_pull_error(ndr, NDR_ERR_FLAGS, "Invalid fn pull flags 0x%"PRI_NDR_FLAGS_TYPE, flags); \
+ } \
+} while (0)
+
+#define NDR_PUSH_CHECK_FN_FLAGS(ndr, flags) do { \
+ if ((flags) & ~(NDR_BOTH|NDR_SET_VALUES)) \
+ return ndr_push_error(ndr, NDR_ERR_FLAGS, "Invalid fn push flags 0x%"PRI_NDR_FLAGS_TYPE, flags); \
+} while (0)
+
+#define NDR_PULL_NEED_BYTES(ndr, n) do { \
+ if (unlikely(\
+ (n) > ndr->data_size || \
+ ndr->offset + (n) > ndr->data_size || \
+ ndr->offset + (n) < ndr->offset)) { \
+ if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) { \
+ uint32_t _available = ndr->data_size - ndr->offset; \
+ uint32_t _missing = n - _available; \
+ ndr->relative_highest_offset = _missing; \
+ } \
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull bytes %zu (%s)", (size_t)n, __location__); \
+ } \
+} while(0)
+
+#define NDR_ALIGN(ndr, n) ndr_align_size(ndr->offset, n)
+
+#define NDR_ROUND(size, n) (((size)+((n)-1)) & ~((n)-1))
+
+#define NDR_PULL_ALIGN(ndr, n) do { \
+ if (unlikely(!(ndr->flags & LIBNDR_FLAG_NOALIGN))) { \
+ if (unlikely(ndr->flags & LIBNDR_FLAG_PAD_CHECK)) { \
+ ndr_check_padding(ndr, n); \
+ } \
+ if(unlikely( \
+ ((ndr->offset + (n-1)) & (~(n-1))) < ndr->offset)) {\
+ return ndr_pull_error( \
+ ndr, \
+ NDR_ERR_BUFSIZE, \
+ "Pull align (overflow) %zu", (size_t)n); \
+ } \
+ ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \
+ } \
+ if (unlikely(ndr->offset > ndr->data_size)) { \
+ if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) { \
+ uint32_t _missing = ndr->offset - ndr->data_size; \
+ ndr->relative_highest_offset = _missing; \
+ } \
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull align %zu", (size_t)n); \
+ } \
+} while(0)
+
+#define NDR_PUSH_NEED_BYTES(ndr, n) NDR_CHECK(ndr_push_expand(ndr, n))
+
+#define NDR_PUSH_ALIGN(ndr, n) do { \
+ if (likely(!(ndr->flags & LIBNDR_FLAG_NOALIGN))) { \
+ uint32_t _pad = ((ndr->offset + (n-1)) & ~(n-1)) - ndr->offset; \
+ while (_pad--) NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 0)); \
+ } \
+} while(0)
+
+#define NDR_RECURSION_CHECK(ndr, d) do { \
+ uint32_t _ndr_min_ = (d); \
+ if (ndr->global_max_recursion && ndr->global_max_recursion < (d)) { \
+ _ndr_min_ = ndr->global_max_recursion; \
+ } \
+ ndr->recursion_depth++; \
+ if (unlikely(ndr->recursion_depth > _ndr_min_)) { \
+ return ndr_pull_error( \
+ ndr, \
+ NDR_ERR_MAX_RECURSION_EXCEEDED, \
+ "Depth of recursion exceeds (%u)", \
+ (unsigned) d); \
+ } \
+} while (0)
+
+#define NDR_RECURSION_UNWIND(ndr) do { \
+ if (unlikely(ndr->recursion_depth == 0)) { \
+ return ndr_pull_error( \
+ ndr, \
+ NDR_ERR_UNDERFLOW, \
+ "ndr_pull.recursion_depth is 0"); \
+ } \
+ ndr->recursion_depth--; \
+} while (0)
+
+/* these are used to make the error checking on each element in libndr
+ less tedious, hopefully making the code more readable */
+#define NDR_CHECK(call) do { \
+ enum ndr_err_code _status; \
+ _status = call; \
+ if (unlikely(!NDR_ERR_CODE_IS_SUCCESS(_status))) { \
+ return _status; \
+ } \
+} while (0)
+
+/* if the call fails then free the ndr pointer */
+#define NDR_CHECK_FREE(call) do { \
+ enum ndr_err_code _status; \
+ _status = call; \
+ if (unlikely(!NDR_ERR_CODE_IS_SUCCESS(_status))) { \
+ talloc_free(ndr); \
+ return _status; \
+ } \
+} while (0)
+
+#define NDR_PULL_GET_MEM_CTX(ndr) (ndr->current_mem_ctx)
+
+#define NDR_PULL_SET_MEM_CTX(ndr, mem_ctx, flgs) do {\
+ if ( (flgs == 0) || (ndr->flags & flgs) ) {\
+ if (!(mem_ctx)) {\
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "NDR_PULL_SET_MEM_CTX(NULL): %s\n", __location__); \
+ }\
+ ndr->current_mem_ctx = discard_const(mem_ctx);\
+ }\
+} while(0)
+
+#define _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr) do {\
+ if (!ndr->current_mem_ctx) {\
+ ndr->current_mem_ctx = talloc_new(ndr);\
+ if (!ndr->current_mem_ctx) {\
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "_NDR_PULL_FIX_CURRENT_MEM_CTX() failed: %s\n", __location__); \
+ }\
+ }\
+} while(0)
+
+#define NDR_PULL_ALLOC(ndr, s) do { \
+ _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\
+ (s) = talloc_ptrtype(ndr->current_mem_ctx, (s)); \
+ if (unlikely(!(s))) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %s failed: %s\n", # s, __location__); \
+} while (0)
+
+#define NDR_PULL_ALLOC_N(ndr, s, n) do { \
+ _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\
+ (s) = talloc_array_ptrtype(ndr->current_mem_ctx, (s), n); \
+ if (unlikely(!(s))) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %zu * %s failed: %s\n", (size_t)n, # s, __location__); \
+} while (0)
+
+
+#define NDR_PUSH_ALLOC_SIZE(ndr, s, size) do { \
+ (s) = talloc_array(ndr, uint8_t, size); \
+ if (unlikely(!(s))) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %zu failed: %s\n", (size_t)size, __location__); \
+} while (0)
+
+#define NDR_PUSH_ALLOC(ndr, s) do { \
+ (s) = talloc_ptrtype(ndr, (s)); \
+ if (unlikely(!(s))) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %s failed: %s\n", # s, __location__); \
+} while (0)
+
+#define NDR_ZERO_STRUCT(x) ndr_zero_memory(&(x), sizeof(x))
+#define NDR_ZERO_STRUCTP(x) do { \
+ if ((x) != NULL) { \
+ ndr_zero_memory((x), sizeof(*(x))); \
+ } \
+} while(0)
+
+/* these are used when generic fn pointers are needed for ndr push/pull fns */
+typedef enum ndr_err_code (*ndr_push_flags_fn_t)(struct ndr_push *, ndr_flags_type ndr_flags, const void *);
+typedef enum ndr_err_code (*ndr_pull_flags_fn_t)(struct ndr_pull *, ndr_flags_type ndr_flags, void *);
+typedef void (*ndr_print_fn_t)(struct ndr_print *, const char *, const void *);
+typedef void (*ndr_print_function_t)(struct ndr_print *, const char *, ndr_flags_type, const void *);
+
+#include "../libcli/util/error.h"
+#include "librpc/gen_ndr/misc.h"
+
+extern const struct ndr_syntax_id ndr_transfer_syntax_ndr;
+extern const struct ndr_syntax_id ndr_transfer_syntax_ndr64;
+extern const struct ndr_syntax_id ndr_syntax_id_null;
+
+struct ndr_interface_call_pipe {
+ const char *name;
+ const char *chunk_struct_name;
+ size_t chunk_struct_size;
+ ndr_push_flags_fn_t ndr_push;
+ ndr_pull_flags_fn_t ndr_pull;
+ ndr_print_fn_t ndr_print;
+};
+
+struct ndr_interface_call_pipes {
+ uint32_t num_pipes;
+ const struct ndr_interface_call_pipe *pipes;
+};
+
+struct ndr_interface_call {
+ const char *name;
+ size_t struct_size;
+ ndr_push_flags_fn_t ndr_push;
+ ndr_pull_flags_fn_t ndr_pull;
+ ndr_print_function_t ndr_print;
+ struct ndr_interface_call_pipes in_pipes;
+ struct ndr_interface_call_pipes out_pipes;
+};
+
+struct ndr_interface_public_struct {
+ const char *name;
+ size_t struct_size;
+ ndr_push_flags_fn_t ndr_push;
+ ndr_pull_flags_fn_t ndr_pull;
+ ndr_print_function_t ndr_print;
+};
+
+struct ndr_interface_string_array {
+ uint32_t count;
+ const char * const *names;
+};
+
+struct ndr_interface_table {
+ const char *name;
+ struct ndr_syntax_id syntax_id;
+ const char *helpstring;
+ uint32_t num_calls;
+ const struct ndr_interface_call *calls;
+ uint32_t num_public_structs;
+ const struct ndr_interface_public_struct *public_structs;
+ const struct ndr_interface_string_array *endpoints;
+ const struct ndr_interface_string_array *authservices;
+};
+
+struct ndr_interface_list {
+ struct ndr_interface_list *prev, *next;
+ const struct ndr_interface_table *table;
+};
+
+struct sockaddr_storage;
+
+/*********************************************************************
+ Map an NT error code from a NDR error code.
+*********************************************************************/
+NTSTATUS ndr_map_error2ntstatus(enum ndr_err_code ndr_err);
+int ndr_map_error2errno(enum ndr_err_code ndr_err);
+const char *ndr_map_error2string(enum ndr_err_code ndr_err);
+#define ndr_errstr ndr_map_error2string
+
+/* FIXME: Use represent_as instead */
+struct dom_sid;
+enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid);
+enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid);
+void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid);
+enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid);
+void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+size_t ndr_size_dom_sid28(const struct dom_sid *sid, libndr_flags flags);
+enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid);
+enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid);
+void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid);
+size_t ndr_size_dom_sid0(const struct dom_sid *sid, libndr_flags flags);
+void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid);
+void ndr_print_sockaddr_storage(struct ndr_print *ndr, const char *name, const struct sockaddr_storage *ss);
+void ndr_zero_memory(void *ptr, size_t len);
+bool ndr_syntax_id_equal(const struct ndr_syntax_id *i1, const struct ndr_syntax_id *i2);
+
+struct ndr_syntax_id_buf { char buf[39 /*GUID*/ + 3 /* "/0x" */ + 8]; };
+char *ndr_syntax_id_buf_string(
+ const struct ndr_syntax_id *id, struct ndr_syntax_id_buf *buf);
+char *ndr_syntax_id_to_string(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *id);
+
+bool ndr_syntax_id_from_string(const char *s, struct ndr_syntax_id *id);
+enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, ndr_push_flags_fn_t fn);
+enum ndr_err_code ndr_push_struct_into_fixed_blob(DATA_BLOB *blob,
+ const void *p,
+ ndr_push_flags_fn_t fn);
+enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_push_flags_fn_t fn);
+size_t ndr_size_struct(const void *p, libndr_flags flags, ndr_push_flags_fn_t push);
+size_t ndr_size_union(const void *p, libndr_flags flags, uint32_t level, ndr_push_flags_fn_t push);
+uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr);
+void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset);
+enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset);
+enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p);
+enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p);
+enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p);
+enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p);
+enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p);
+enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p);
+uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr);
+void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset);
+enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset);
+enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p);
+enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset);
+enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p);
+enum ndr_err_code ndr_pull_relative_ptr_short(struct ndr_pull *ndr, uint16_t *v);
+size_t ndr_align_size(uint32_t offset, size_t n);
+struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx);
+enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob);
+enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr);
+enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size);
+struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx);
+DATA_BLOB ndr_push_blob(struct ndr_push *ndr);
+enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size);
+void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
+bool ndr_print_debug(int level, ndr_print_fn_t fn, const char *name, void *ptr, const char *location, const char *function);
+void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr);
+void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr);
+void ndr_print_function_debug(ndr_print_function_t fn, const char *name, ndr_flags_type flags, void *ptr);
+char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr);
+char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr);
+char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
+ ndr_print_function_t fn, const char *name,
+ ndr_flags_type flags, void *ptr);
+void ndr_set_flags(libndr_flags *pflags, libndr_flags new_flags);
+enum ndr_err_code _ndr_pull_error(struct ndr_pull *ndr,
+ enum ndr_err_code ndr_err,
+ const char *function,
+ const char *location,
+ const char *format, ...) PRINTF_ATTRIBUTE(5,6);
+#define ndr_pull_error(ndr, ndr_err, ...) \
+ _ndr_pull_error(ndr, \
+ ndr_err, \
+ __FUNCTION__, \
+ __location__, \
+ __VA_ARGS__)
+enum ndr_err_code _ndr_push_error(struct ndr_push *ndr,
+ enum ndr_err_code ndr_err,
+ const char *function,
+ const char *location,
+ const char *format, ...) PRINTF_ATTRIBUTE(5,6);
+#define ndr_push_error(ndr, ndr_err, ...) \
+ _ndr_push_error(ndr, \
+ ndr_err, \
+ __FUNCTION__, \
+ __location__, \
+ __VA_ARGS__)
+enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
+ struct ndr_pull **_subndr,
+ size_t header_size,
+ ssize_t size_is);
+enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
+ struct ndr_pull *subndr,
+ size_t header_size,
+ ssize_t size_is);
+enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
+ struct ndr_push **_subndr,
+ size_t header_size,
+ ssize_t size_is);
+enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
+ struct ndr_push *subndr,
+ size_t header_size,
+ ssize_t size_is);
+enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
+ struct ndr_token_list *list,
+ const void *key,
+ uint32_t value);
+enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list *list, const void *key, uint32_t *v,
+ int(*_cmp_fn)(const void*,const void*), bool erase);
+enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list, const void *key, uint32_t *v);
+enum ndr_err_code ndr_token_peek(struct ndr_token_list *list, const void *key, uint32_t *v);
+enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p);
+enum ndr_err_code ndr_get_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size);
+enum ndr_err_code ndr_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size);
+enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, const void *p, uint32_t size);
+enum ndr_err_code ndr_check_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t size);
+enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p);
+enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length);
+enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length);
+enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, const void *p, uint32_t length);
+enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length);
+enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t count);
+enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t count);
+enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val);
+enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val);
+enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val);
+/* retrieve a switch value (for push) and remove it from the list */
+enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr,
+ const void *p,
+ uint32_t *v);
+/* retrieve a switch value and remove it from the list */
+uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p);
+/* retrieve a switch value and remove it from the list */
+enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr,
+ const void *p,
+ uint32_t *v);
+enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, ndr_pull_flags_fn_t fn);
+enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, ndr_pull_flags_fn_t fn);
+_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_noalloc(const uint8_t *buf,
+ size_t buflen,
+ void *p,
+ ndr_pull_flags_fn_t fn,
+ size_t *consumed);
+enum ndr_err_code ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
+ void *p, ndr_pull_flags_fn_t fn);
+enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_pull_flags_fn_t fn);
+enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_pull_flags_fn_t fn);
+
+/* from libndr_basic.h */
+#define NDR_SCALAR_PROTO(name, type) \
+enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, ndr_flags_type ndr_flags, type v); \
+enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, type *v); \
+void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, type v);
+
+#define NDR_SCALAR_PTR_PROTO(name, type) \
+enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const type *v); \
+enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, type **v); \
+void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, const type *v);
+
+#define NDR_BUFFER_PROTO(name, type) \
+enum ndr_err_code ndr_push_ ## name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const type *v); \
+enum ndr_err_code ndr_pull_ ## name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, type *v); \
+void ndr_print_ ## name(struct ndr_print *ndr, const char *var_name, const type *v);
+
+NDR_SCALAR_PROTO(uint8, uint8_t)
+NDR_SCALAR_PROTO(int8, int8_t)
+NDR_SCALAR_PROTO(uint16, uint16_t)
+NDR_SCALAR_PROTO(int16, int16_t)
+NDR_SCALAR_PROTO(uint1632, uint16_t)
+NDR_SCALAR_PROTO(uint32, uint32_t)
+NDR_SCALAR_PROTO(uint3264, uint32_t)
+NDR_SCALAR_PROTO(int32, int32_t)
+NDR_SCALAR_PROTO(int3264, int32_t)
+NDR_SCALAR_PROTO(udlong, uint64_t)
+NDR_SCALAR_PROTO(udlongr, uint64_t)
+NDR_SCALAR_PROTO(dlong, int64_t)
+NDR_SCALAR_PROTO(hyper, uint64_t)
+NDR_SCALAR_PROTO(int64, int64_t)
+NDR_SCALAR_PROTO(pointer, void *)
+NDR_SCALAR_PROTO(time_t, time_t)
+NDR_SCALAR_PROTO(uid_t, uid_t)
+NDR_SCALAR_PROTO(gid_t, gid_t)
+NDR_SCALAR_PROTO(NTSTATUS, NTSTATUS)
+NDR_SCALAR_PROTO(WERROR, WERROR)
+NDR_SCALAR_PROTO(HRESULT, HRESULT)
+NDR_SCALAR_PROTO(NTTIME, NTTIME)
+NDR_SCALAR_PROTO(NTTIME_1sec, NTTIME)
+NDR_SCALAR_PROTO(NTTIME_hyper, NTTIME)
+NDR_SCALAR_PROTO(DATA_BLOB, DATA_BLOB)
+NDR_SCALAR_PROTO(ipv4address, const char *)
+NDR_SCALAR_PROTO(ipv6address, const char *)
+NDR_SCALAR_PROTO(string, const char *)
+NDR_SCALAR_PROTO(u16string, const unsigned char *)
+NDR_SCALAR_PROTO(double, double)
+
+enum ndr_err_code ndr_pull_policy_handle(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct policy_handle *r);
+enum ndr_err_code ndr_push_policy_handle(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct policy_handle *r);
+void ndr_print_policy_handle(struct ndr_print *ndr, const char *name, const struct policy_handle *r);
+bool ndr_policy_handle_empty(const struct policy_handle *h);
+#define is_valid_policy_hnd(hnd) (!ndr_policy_handle_empty(hnd))
+bool ndr_policy_handle_equal(const struct policy_handle *hnd1,
+ const struct policy_handle *hnd2);
+
+void ndr_check_padding(struct ndr_pull *ndr, size_t n);
+enum ndr_err_code ndr_pull_generic_ptr(struct ndr_pull *ndr, uint32_t *v);
+enum ndr_err_code ndr_pull_ref_ptr(struct ndr_pull *ndr, uint32_t *v);
+enum ndr_err_code ndr_pull_bytes(struct ndr_pull *ndr, uint8_t *data, uint32_t n);
+enum ndr_err_code ndr_pull_array_uint8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint8_t *data, uint32_t n);
+enum ndr_err_code ndr_push_align(struct ndr_push *ndr, size_t size);
+enum ndr_err_code ndr_pull_align(struct ndr_pull *ndr, size_t size);
+enum ndr_err_code ndr_push_union_align(struct ndr_push *ndr, size_t size);
+enum ndr_err_code ndr_pull_union_align(struct ndr_pull *ndr, size_t size);
+enum ndr_err_code ndr_push_trailer_align(struct ndr_push *ndr, size_t size);
+enum ndr_err_code ndr_pull_trailer_align(struct ndr_pull *ndr, size_t size);
+enum ndr_err_code ndr_push_bytes(struct ndr_push *ndr, const uint8_t *data, uint32_t n);
+enum ndr_err_code ndr_push_zero(struct ndr_push *ndr, uint32_t n);
+enum ndr_err_code ndr_push_array_uint8(struct ndr_push *ndr, ndr_flags_type ndr_flags, const uint8_t *data, uint32_t n);
+enum ndr_err_code ndr_push_unique_ptr(struct ndr_push *ndr, const void *p);
+enum ndr_err_code ndr_push_full_ptr(struct ndr_push *ndr, const void *p);
+enum ndr_err_code ndr_push_ref_ptr(struct ndr_push *ndr);
+void ndr_print_struct(struct ndr_print *ndr, const char *name, const char *type);
+void ndr_print_null(struct ndr_print *ndr);
+void ndr_print_enum(struct ndr_print *ndr, const char *name, const char *type, const char *val, uint32_t value);
+void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const char *flag_name, uint32_t flag, uint32_t value);
+void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const char *flag_name, uint32_t flag, uint32_t value);
+void ndr_print_ptr(struct ndr_print *ndr, const char *name, const void *p);
+void ndr_print_union(struct ndr_print *ndr, const char *name, int level, const char *type);
+void ndr_print_bad_level(struct ndr_print *ndr, const char *name, uint16_t level);
+void ndr_print_array_uint8(struct ndr_print *ndr, const char *name, const uint8_t *data, uint32_t count);
+uint32_t ndr_size_DATA_BLOB(int ret, const DATA_BLOB *data, ndr_flags_type flags);
+
+/* strings */
+uint32_t ndr_charset_length(const void *var, charset_t chset);
+size_t ndr_string_array_size(struct ndr_push *ndr, const char *s);
+uint32_t ndr_size_string(int ret, const char * const* string, ndr_flags_type flags);
+enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char ***_a);
+enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char **a);
+void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a);
+size_t ndr_size_string_array(const char **a, uint32_t count, libndr_flags flags);
+uint32_t ndr_string_length(const void *_var, uint32_t element_size);
+enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size);
+enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset);
+enum ndr_err_code ndr_pull_charset_to_null(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset);
+enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset);
+enum ndr_err_code ndr_push_charset_to_null(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset);
+
+/* GUIDs */
+bool GUID_equal(const struct GUID *u1, const struct GUID *u2);
+struct GUID_ndr_buf { uint8_t buf[16]; };
+NTSTATUS GUID_to_ndr_buf(const struct GUID *guid, struct GUID_ndr_buf *buf);
+NTSTATUS GUID_to_ndr_blob(const struct GUID *guid, TALLOC_CTX *mem_ctx, DATA_BLOB *b);
+NTSTATUS GUID_from_ndr_blob(const DATA_BLOB *b, struct GUID *guid);
+NTSTATUS GUID_from_data_blob(const DATA_BLOB *s, struct GUID *guid);
+NTSTATUS GUID_from_string(const char *s, struct GUID *guid);
+struct GUID GUID_zero(void);
+bool GUID_all_zero(const struct GUID *u);
+int GUID_compare(const struct GUID *u1, const struct GUID *u2);
+char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid);
+char *GUID_string2(TALLOC_CTX *mem_ctx, const struct GUID *guid);
+char *GUID_hexstring(TALLOC_CTX *mem_ctx, const struct GUID *guid);
+struct GUID GUID_random(void);
+
+/* Format is "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" */
+ /* 32 chars + 4 ' ' + \0 + 2 for adding {} */
+struct GUID_txt_buf { char buf[39]; };
+_PUBLIC_ char* GUID_buf_string(const struct GUID *guid,
+ struct GUID_txt_buf *dst);
+
+_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint8_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint16(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint32(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t *v);
+_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint1632(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v);
+_PUBLIC_ enum ndr_err_code ndr_push_enum_uint8(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint8_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_enum_uint16(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_enum_uint32(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t v);
+_PUBLIC_ enum ndr_err_code ndr_push_enum_uint1632(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v);
+
+_PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b);
+
+_PUBLIC_ enum ndr_err_code ndr_push_timespec(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct timespec *t);
+_PUBLIC_ enum ndr_err_code ndr_pull_timespec(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct timespec *t);
+_PUBLIC_ void ndr_print_timespec(struct ndr_print *ndr, const char *name,
+ const struct timespec *t);
+
+_PUBLIC_ enum ndr_err_code ndr_push_timeval(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct timeval *t);
+_PUBLIC_ enum ndr_err_code ndr_pull_timeval(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct timeval *t);
+_PUBLIC_ void ndr_print_timeval(struct ndr_print *ndr, const char *name,
+ const struct timeval *t);
+
+_PUBLIC_ void ndr_print_libndr_flags(struct ndr_print *ndr, const char *name,
+ libndr_flags flags);
+
+
+#endif /* __LIBNDR_H__ */
diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c
new file mode 100644
index 0000000..1478faa
--- /dev/null
+++ b/librpc/ndr/ndr.c
@@ -0,0 +1,2040 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libndr interface
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 2005-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 provides the core routines for NDR parsing functions
+
+ see http://www.opengroup.org/onlinepubs/9629399/chap14.htm for details
+ of NDR encoding rules
+*/
+
+#include "includes.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/ndr/ndr_private.h"
+#include "../lib/util/dlinklist.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_PARSE
+
+#define NDR_BASE_MARSHALL_SIZE 1024
+
+/*
+ * This value is arbitrary, but designed to reduce the memory a client
+ * can allocate and the work the client can force in processing a
+ * malicious packet.
+ *
+ * In an ideal world this would be controlled by range() restrictions
+ * on array sizes and careful IDL construction to avoid arbitrary
+ * linked lists, but this is a backstop for now.
+ */
+#define NDR_TOKEN_MAX_LIST_SIZE 65535
+
+size_t ndr_token_max_list_size(void) {
+ return NDR_TOKEN_MAX_LIST_SIZE;
+};
+
+/* this guid indicates NDR encoding in a protocol tower */
+const struct ndr_syntax_id ndr_transfer_syntax_ndr = {
+ { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
+ 2
+};
+
+const struct ndr_syntax_id ndr_transfer_syntax_ndr64 = {
+ { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
+ 1
+};
+
+const struct ndr_syntax_id ndr_syntax_id_null = {
+ { 0, 0, 0, { 0, 0 }, { 0, 0, 0, 0, 0, 0 } },
+ 0
+};
+
+/*
+ work out the number of bytes needed to align on a n byte boundary
+*/
+_PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
+{
+ if ((offset & (n-1)) == 0) return 0;
+ return n - (offset & (n-1));
+}
+
+/*
+ initialise a ndr parse structure from a data blob
+*/
+_PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
+{
+ struct ndr_pull *ndr;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_pull);
+ if (!ndr) return NULL;
+ ndr->current_mem_ctx = mem_ctx;
+
+ ndr->data = blob->data;
+ ndr->data_size = blob->length;
+
+ return ndr;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB b;
+ uint32_t append = 0;
+ bool ok;
+
+ if (blob->length == 0) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append);
+ if (ndr_err == NDR_ERR_TOKEN) {
+ append = 0;
+ ndr_err = NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_err);
+
+ if (ndr->data_size == 0) {
+ ndr->data = NULL;
+ append = UINT32_MAX;
+ }
+
+ if (append == UINT32_MAX) {
+ /*
+ * append == UINT32_MAX means that
+ * ndr->data is either NULL or a valid
+ * talloc child of ndr, which means
+ * we can use data_blob_append() without
+ * data_blob_talloc() of the existing callers data
+ */
+ b = data_blob_const(ndr->data, ndr->data_size);
+ } else {
+ b = data_blob_talloc(ndr, ndr->data, ndr->data_size);
+ if (b.data == NULL) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
+ }
+ }
+
+ ok = data_blob_append(ndr, &b, blob->data, blob->length);
+ if (!ok) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
+ }
+
+ ndr->data = b.data;
+ ndr->data_size = b.length;
+
+ return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr)
+{
+ uint32_t skip = 0;
+ uint32_t append = 0;
+ enum ndr_err_code ndr_err;
+
+ if (ndr->relative_base_offset != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
+ "%s", __location__);
+ }
+ if (ndr->relative_highest_offset != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
+ "%s", __location__);
+ }
+ if (ndr->relative_list.count != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
+ "%s", __location__);
+ }
+ if (ndr->relative_base_list.count != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_RELATIVE,
+ "%s", __location__);
+ }
+
+ /*
+ * we need to keep up to 7 bytes
+ * in order to get the alignment right.
+ */
+ skip = ndr->offset & 0xFFFFFFF8;
+
+ if (skip == 0) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ ndr->offset -= skip;
+ ndr->data_size -= skip;
+
+ ndr_err = ndr_token_peek(&ndr->array_size_list, ndr, &append);
+ if (ndr_err == NDR_ERR_TOKEN) {
+ /*
+ * here we assume, that ndr->data is not a
+ * talloc child of ndr.
+ */
+ ndr->data += skip;
+ return NDR_ERR_SUCCESS;
+ }
+
+ memmove(ndr->data, ndr->data + skip, ndr->data_size);
+
+ ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size);
+ if (ndr->data_size != 0 && ndr->data == NULL) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ advance by 'size' bytes
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
+{
+ NDR_PULL_NEED_BYTES(ndr, size);
+ ndr->offset += size;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ set the parse offset to 'ofs'
+*/
+static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
+{
+ ndr->offset = ofs;
+ if (ndr->offset > ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_set_offset %"PRIu32" failed",
+ ofs);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/* create a ndr_push structure, ready for some marshalling */
+_PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
+{
+ struct ndr_push *ndr;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_push);
+ if (!ndr) {
+ return NULL;
+ }
+
+ ndr->flags = 0;
+ ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
+ ndr->data = talloc_array(ndr, uint8_t, ndr->alloc_size);
+ if (!ndr->data) {
+ talloc_free(ndr);
+ return NULL;
+ }
+
+ return ndr;
+}
+
+/* return a DATA_BLOB structure for the current ndr_push marshalled data */
+_PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
+{
+ DATA_BLOB blob;
+ blob = data_blob_const(ndr->data, ndr->offset);
+ if (ndr->alloc_size > ndr->offset) {
+ ndr->data[ndr->offset] = 0;
+ }
+ return blob;
+}
+
+
+/*
+ expand the available space in the buffer to ndr->offset + extra_size
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
+{
+ uint32_t size = extra_size + ndr->offset;
+
+ if (size < ndr->offset) {
+ /* extra_size overflowed the offset */
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %"PRIu32,
+ size);
+ }
+
+ if (ndr->fixed_buf_size) {
+ if (ndr->alloc_size >= size) {
+ return NDR_ERR_SUCCESS;
+ }
+ return ndr_push_error(ndr,
+ NDR_ERR_BUFSIZE,
+ "Overflow of fixed buffer in "
+ "push_expand to %"PRIu32,
+ size);
+ }
+
+ if (ndr->alloc_size > size) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
+ if (size == UINT32_MAX) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand");
+ }
+ if (size+1 > ndr->alloc_size) {
+ ndr->alloc_size = size+1;
+ }
+ ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
+ if (!ndr->data) {
+ return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %"PRIu32,
+ ndr->alloc_size);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_debugc_helper(struct ndr_print *ndr, const char *format, ...)
+{
+ va_list ap;
+ char *s = NULL;
+ uint32_t i;
+ int ret;
+ int dbgc_class;
+
+ va_start(ap, format);
+ ret = vasprintf(&s, format, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ return;
+ }
+
+ dbgc_class = *(int *)ndr->private_data;
+
+ if (ndr->no_newline) {
+ DEBUGADDC(dbgc_class, 1,("%s", s));
+ free(s);
+ return;
+ }
+
+ for (i=0;i<ndr->depth;i++) {
+ DEBUGADDC(dbgc_class, 1,(" "));
+ }
+
+ DEBUGADDC(dbgc_class, 1,("%s\n", s));
+ free(s);
+}
+
+_PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
+{
+ va_list ap;
+ char *s = NULL;
+ uint32_t i;
+ int ret;
+
+ va_start(ap, format);
+ ret = vasprintf(&s, format, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ return;
+ }
+
+ if (ndr->no_newline) {
+ DEBUGADD(1,("%s", s));
+ free(s);
+ return;
+ }
+
+ for (i=0;i<ndr->depth;i++) {
+ DEBUGADD(1,(" "));
+ }
+
+ DEBUGADD(1,("%s\n", s));
+ free(s);
+}
+
+_PUBLIC_ void ndr_print_printf_helper(struct ndr_print *ndr, const char *format, ...)
+{
+ va_list ap;
+ uint32_t i;
+
+ if (!ndr->no_newline) {
+ for (i=0;i<ndr->depth;i++) {
+ printf(" ");
+ }
+ }
+
+ va_start(ap, format);
+ vprintf(format, ap);
+ va_end(ap);
+ if (!ndr->no_newline) {
+ printf("\n");
+ }
+}
+
+_PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
+{
+ va_list ap;
+ uint32_t i;
+
+ if (!ndr->no_newline) {
+ for (i=0;i<ndr->depth;i++) {
+ ndr->private_data = talloc_asprintf_append_buffer(
+ (char *)ndr->private_data, " ");
+ }
+ }
+
+ va_start(ap, format);
+ ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
+ format, ap);
+ va_end(ap);
+ if (!ndr->no_newline) {
+ ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
+ "\n");
+ }
+}
+
+/*
+ a useful helper function for printing idl structures via DEBUGC()
+*/
+_PUBLIC_ void ndr_print_debugc(int dbgc_class, ndr_print_fn_t fn, const char *name, void *ptr)
+{
+ struct ndr_print *ndr;
+
+ DEBUGC(dbgc_class, 1,(" "));
+
+ ndr = talloc_zero(NULL, struct ndr_print);
+ if (!ndr) return;
+ ndr->private_data = &dbgc_class;
+ ndr->print = ndr_print_debugc_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+#ifdef DEBUG_PASSWORD
+ if (CHECK_DEBUGLVL(100)) {
+ ndr->print_secrets = true;
+ }
+#endif
+
+ fn(ndr, name, ptr);
+ talloc_free(ndr);
+}
+
+/*
+ a useful helper function for printing idl structures via DEBUG()
+*/
+_PUBLIC_ bool ndr_print_debug(int level,
+ ndr_print_fn_t fn,
+ const char *name,
+ void *ptr,
+ const char *location,
+ const char *function)
+{
+ struct ndr_print *ndr;
+
+ DEBUGLF(level, (" "), location, function);
+
+ ndr = talloc_zero(NULL, struct ndr_print);
+ if (!ndr) return false;
+ ndr->print = ndr_print_debug_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+#ifdef DEBUG_PASSWORD
+ if (CHECK_DEBUGLVL(100)) {
+ ndr->print_secrets = true;
+ }
+#endif
+
+ fn(ndr, name, ptr);
+ talloc_free(ndr);
+ return true;
+}
+
+/*
+ a useful helper function for printing idl unions via DEBUG()
+*/
+_PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
+{
+ struct ndr_print *ndr;
+
+ DEBUG(1,(" "));
+
+ ndr = talloc_zero(NULL, struct ndr_print);
+ if (!ndr) return;
+ ndr->print = ndr_print_debug_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+#ifdef DEBUG_PASSWORD
+ if (CHECK_DEBUGLVL(100)) {
+ ndr->print_secrets = true;
+ }
+#endif
+
+ ndr_print_set_switch_value(ndr, ptr, level);
+ fn(ndr, name, ptr);
+ talloc_free(ndr);
+}
+
+/*
+ a useful helper function for printing idl function calls via DEBUG()
+*/
+_PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, ndr_flags_type flags, void *ptr)
+{
+ struct ndr_print *ndr;
+
+ DEBUG(1,(" "));
+
+ ndr = talloc_zero(NULL, struct ndr_print);
+ if (!ndr) return;
+ ndr->print = ndr_print_debug_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+#ifdef DEBUG_PASSWORD
+ if (CHECK_DEBUGLVL(100)) {
+ ndr->print_secrets = true;
+ }
+#endif
+
+ fn(ndr, name, flags, ptr);
+ talloc_free(ndr);
+}
+
+/*
+ a useful helper function for printing idl structures to a string
+*/
+_PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
+{
+ struct ndr_print *ndr;
+ char *ret = NULL;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_print);
+ if (!ndr) return NULL;
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (!ndr->private_data) {
+ goto failed;
+ }
+ ndr->print = ndr_print_string_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+
+ fn(ndr, name, ptr);
+ ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
+failed:
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ a useful helper function for printing idl unions to a string
+*/
+_PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
+{
+ struct ndr_print *ndr;
+ char *ret = NULL;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_print);
+ if (!ndr) return NULL;
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (!ndr->private_data) {
+ goto failed;
+ }
+ ndr->print = ndr_print_string_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ ndr_print_set_switch_value(ndr, ptr, level);
+ fn(ndr, name, ptr);
+ ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
+failed:
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ a useful helper function for printing idl function calls to a string
+*/
+_PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
+ ndr_print_function_t fn, const char *name,
+ ndr_flags_type flags, void *ptr)
+{
+ struct ndr_print *ndr;
+ char *ret = NULL;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_print);
+ if (!ndr) return NULL;
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (!ndr->private_data) {
+ goto failed;
+ }
+ ndr->print = ndr_print_string_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ fn(ndr, name, flags, ptr);
+ ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
+failed:
+ talloc_free(ndr);
+ return ret;
+}
+
+_PUBLIC_ void ndr_set_flags(libndr_flags *pflags, libndr_flags new_flags)
+{
+ /* the big/little endian flags are inter-dependent */
+ if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
+ (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
+ (*pflags) &= ~LIBNDR_FLAG_NDR64;
+ }
+ if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
+ (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
+ (*pflags) &= ~LIBNDR_FLAG_NDR64;
+ }
+ if (new_flags & LIBNDR_ALIGN_FLAGS) {
+ /* Ensure we only have the passed-in
+ align flag set in the new_flags,
+ remove any old align flag. */
+ (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
+ }
+ if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
+ (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
+ }
+ (*pflags) |= new_flags;
+}
+
+/*
+ return and possibly log an NDR error
+*/
+_PUBLIC_ enum ndr_err_code _ndr_pull_error(struct ndr_pull *ndr,
+ enum ndr_err_code ndr_err,
+ const char *function,
+ const char *location,
+ const char *format, ...)
+{
+ char *s=NULL;
+ va_list ap;
+ int ret;
+
+ if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
+ switch (ndr_err) {
+ case NDR_ERR_BUFSIZE:
+ return NDR_ERR_INCOMPLETE_BUFFER;
+ default:
+ break;
+ }
+ }
+
+ va_start(ap, format);
+ ret = vasprintf(&s, format, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ return NDR_ERR_ALLOC;
+ }
+
+ D_WARNING("%s: ndr_pull_error(%s): %s at %s\n",
+ function,
+ ndr_map_error2string(ndr_err),
+ s,
+ location);
+
+ free(s);
+
+ return ndr_err;
+}
+
+/*
+ return and possibly log an NDR error
+*/
+_PUBLIC_ enum ndr_err_code _ndr_push_error(struct ndr_push *ndr,
+ enum ndr_err_code ndr_err,
+ const char *function,
+ const char *location,
+ const char *format, ...)
+{
+ char *s=NULL;
+ va_list ap;
+ int ret;
+
+ va_start(ap, format);
+ ret = vasprintf(&s, format, ap);
+ va_end(ap);
+
+ if (ret == -1) {
+ return NDR_ERR_ALLOC;
+ }
+
+ D_WARNING("%s: ndr_push_error(%s): %s at %s\n",
+ function,
+ ndr_map_error2string(ndr_err),
+ s,
+ location);
+
+ free(s);
+
+ return ndr_err;
+}
+
+/*
+ handle subcontext buffers, which in midl land are user-marshalled, but
+ we use magic in pidl to make them easier to cope with
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
+ struct ndr_pull **_subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ struct ndr_pull *subndr;
+ uint32_t r_content_size;
+ bool force_le = false;
+ bool force_be = false;
+
+ switch (header_size) {
+ case 0: {
+ uint32_t content_size = ndr->data_size - ndr->offset;
+ if (size_is >= 0) {
+ content_size = size_is;
+ }
+ r_content_size = content_size;
+ break;
+ }
+
+ case 2: {
+ uint16_t content_size;
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
+ if (size_is >= 0 && size_is != content_size) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%zd) (0x%04zx) mismatch content_size %"PRIu16" (0x%04"PRIx16")",
+ size_is, size_is,
+ content_size,
+ content_size);
+ }
+ r_content_size = content_size;
+ break;
+ }
+
+ case 4: {
+ uint32_t content_size;
+ NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
+ if (size_is >= 0 && size_is != content_size) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%zd) (0x%08zx) mismatch content_size %"PRIu32" (0x%08"PRIx32")",
+ size_is, size_is,
+ content_size,
+ content_size);
+ }
+ r_content_size = content_size;
+ break;
+ }
+ case 0xFFFFFC01: {
+ /*
+ * Common Type Header for the Serialization Stream
+ * See [MS-RPCE] 2.2.6 Type Serialization Version 1
+ */
+ uint8_t version;
+ uint8_t drep;
+ uint16_t hdrlen;
+ uint32_t filler;
+ uint32_t content_size;
+ uint32_t reserved;
+
+ /* version */
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
+
+ if (version != 1) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
+ "Bad subcontext (PULL) Common Type Header version %"PRIu8" != 1",
+ version);
+ }
+
+ /*
+ * 0x10 little endian
+ * 0x00 big endian
+ */
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
+ if (drep == 0x10) {
+ force_le = true;
+ } else if (drep == 0x00) {
+ force_be = true;
+ } else {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
+ "Bad subcontext (PULL) Common Type Header invalid drep 0x%02"PRIX8,
+ drep);
+ }
+
+ /* length of the "Private Header for Constructed Type" */
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
+ if (hdrlen != 8) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
+ "Bad subcontext (PULL) Common Type Header length %"PRIu16" != 8",
+ hdrlen);
+ }
+
+ /* filler should be ignored */
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
+
+ /*
+ * Private Header for Constructed Type
+ */
+ /* length - will be updated later */
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
+ if (size_is >= 0 && size_is != content_size) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%zd) mismatch content_size %"PRIu32,
+ size_is, content_size);
+ }
+ /* the content size must be a multiple of 8 */
+ if ((content_size % 8) != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
+ "Bad subcontext (PULL) size_is(%zd) not padded to 8 content_size %"PRIu32,
+ size_is, content_size);
+ }
+ r_content_size = content_size;
+
+ /* reserved */
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
+ break;
+ }
+ case 0xFFFFFFFF:
+ /*
+ * a shallow copy like subcontext
+ * useful for DCERPC pipe chunks.
+ */
+ subndr = talloc_zero(ndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(subndr);
+
+ subndr->flags = ndr->flags;
+ subndr->current_mem_ctx = ndr->current_mem_ctx;
+ subndr->data = ndr->data;
+ subndr->offset = ndr->offset;
+ subndr->data_size = ndr->data_size;
+
+ *_subndr = subndr;
+ return NDR_ERR_SUCCESS;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %zu",
+ header_size);
+ }
+
+ NDR_PULL_NEED_BYTES(ndr, r_content_size);
+
+ subndr = talloc_zero(ndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(subndr);
+ subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
+ subndr->current_mem_ctx = ndr->current_mem_ctx;
+
+ subndr->data = ndr->data + ndr->offset;
+ subndr->offset = 0;
+ subndr->data_size = r_content_size;
+
+ if (force_le) {
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
+ } else if (force_be) {
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ }
+
+ *_subndr = subndr;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
+ struct ndr_pull *subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ uint32_t advance;
+ uint32_t highest_ofs;
+
+ if (header_size == 0xFFFFFFFF) {
+ advance = subndr->offset - ndr->offset;
+ } else if (size_is >= 0) {
+ advance = size_is;
+ } else if (header_size > 0) {
+ advance = subndr->data_size;
+ } else {
+ advance = subndr->offset;
+ }
+
+ if (subndr->offset > ndr->relative_highest_offset) {
+ highest_ofs = subndr->offset;
+ } else {
+ highest_ofs = subndr->relative_highest_offset;
+ }
+ if (!(subndr->flags & LIBNDR_FLAG_SUBCONTEXT_NO_UNREAD_BYTES)) {
+ /*
+ * avoid an error unless SUBCONTEXT_NO_UNREAD_BYTES is specified
+ */
+ highest_ofs = advance;
+ }
+ if (highest_ofs < advance) {
+ return ndr_pull_error(subndr, NDR_ERR_UNREAD_BYTES,
+ "not all bytes consumed ofs[%"PRIu32"] advance[%"PRIu32"]",
+ highest_ofs, advance);
+ }
+
+ NDR_CHECK(ndr_pull_advance(ndr, advance));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
+ struct ndr_push **_subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ struct ndr_push *subndr;
+
+ subndr = ndr_push_init_ctx(ndr);
+ NDR_ERR_HAVE_NO_MEMORY(subndr);
+ subndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
+
+ if (size_is > 0) {
+ enum ndr_err_code status;
+
+ status = ndr_push_zero(subndr, size_is);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(subndr);
+ return status;
+ }
+ subndr->offset = 0;
+ subndr->relative_end_offset = size_is;
+ }
+
+ *_subndr = subndr;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a subcontext header
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
+ struct ndr_push *subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ ssize_t padding_len;
+
+ if (size_is >= 0) {
+ padding_len = size_is - subndr->offset;
+ if (padding_len < 0) {
+ return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %"PRIu32" is larger than size_is(%zd)",
+ subndr->offset, size_is);
+ }
+ subndr->offset = size_is;
+ }
+
+ switch (header_size) {
+ case 0:
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
+ break;
+
+ case 0xFFFFFC01:
+ /*
+ * Common Type Header for the Serialization Stream
+ * See [MS-RPCE] 2.2.6 Type Serialization Version 1
+ */
+ padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
+ if (padding_len > 0) {
+ NDR_CHECK(ndr_push_zero(subndr, padding_len));
+ }
+
+ /* version */
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
+
+ /*
+ * 0x10 little endian
+ * 0x00 big endian
+ */
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
+
+ /* length of the "Private Header for Constructed Type" */
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
+
+ /* filler */
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
+
+ /*
+ * Private Header for Constructed Type
+ */
+ /* length - will be updated later */
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
+
+ /* reserved */
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %zu",
+ header_size);
+ }
+
+ NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
+ return NDR_ERR_SUCCESS;
+}
+
+
+struct ndr_token {
+ const void *key;
+ uint32_t value;
+};
+
+/*
+ store a token in the ndr context, for later retrieval
+*/
+_PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
+ struct ndr_token_list *list,
+ const void *key,
+ uint32_t value)
+{
+ if (list->tokens == NULL) {
+ list->tokens = talloc_array(mem_ctx, struct ndr_token, 10);
+ if (list->tokens == NULL) {
+ NDR_ERR_HAVE_NO_MEMORY(list->tokens);
+ }
+ } else {
+ struct ndr_token *new_tokens = NULL;
+ uint32_t alloc_count = talloc_array_length(list->tokens);
+
+ /*
+ * Check every time we have not allocated too many
+ * tokens. This ensures developer sanity when
+ * debugging the boundary condition
+ */
+ if (list->count >= NDR_TOKEN_MAX_LIST_SIZE) {
+ return NDR_ERR_RANGE;
+ }
+ if (list->count == alloc_count) {
+ uint32_t new_alloc;
+ /*
+ * Double the list, until we start in chunks
+ * of 1000
+ */
+ uint32_t increment = MIN(list->count, 1000);
+ new_alloc = alloc_count + increment;
+ if (new_alloc < alloc_count) {
+ return NDR_ERR_RANGE;
+ }
+ new_tokens = talloc_realloc(mem_ctx, list->tokens,
+ struct ndr_token, new_alloc);
+ NDR_ERR_HAVE_NO_MEMORY(new_tokens);
+ list->tokens = new_tokens;
+ }
+ }
+ list->tokens[list->count].key = key;
+ list->tokens[list->count].value = value;
+ list->count++;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ retrieve a token from a ndr context, using cmp_fn to match the tokens
+*/
+_PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list *list,
+ const void *key, uint32_t *v,
+ comparison_fn_t _cmp_fn,
+ bool erase)
+{
+ struct ndr_token *tokens = list->tokens;
+ unsigned i;
+ if (_cmp_fn) {
+ for (i = list->count - 1; i < list->count; i--) {
+ if (_cmp_fn(tokens[i].key, key) == 0) {
+ goto found;
+ }
+ }
+ } else {
+ for (i = list->count - 1; i < list->count; i--) {
+ if (tokens[i].key == key) {
+ goto found;
+ }
+ }
+ }
+ return NDR_ERR_TOKEN;
+found:
+ *v = tokens[i].value;
+ if (erase) {
+ if (i != list->count - 1) {
+ tokens[i] = tokens[list->count - 1];
+ }
+ list->count--;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ retrieve a token from a ndr context
+*/
+_PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list *list,
+ const void *key, uint32_t *v)
+{
+ return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
+}
+
+/*
+ peek at but don't removed a token from a ndr context
+*/
+_PUBLIC_ enum ndr_err_code ndr_token_peek(struct ndr_token_list *list,
+ const void *key, uint32_t *v)
+{
+ return ndr_token_retrieve_cmp_fn(list, key, v, NULL, false);
+}
+
+/*
+ pull an array size field and add it to the array_size_list token list
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
+{
+ enum ndr_err_code ret;
+ uint32_t size;
+ NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
+ ret = ndr_token_store(ndr, &ndr->array_size_list, p, size);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_pull_error(ndr, ret,
+ "More than %d NDR tokens stored for array_size",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ return ret;
+}
+
+/*
+ get the stored array size field
+*/
+_PUBLIC_ enum ndr_err_code ndr_get_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size)
+{
+ return ndr_token_peek(&ndr->array_size_list, p, size);
+}
+
+/*
+ get and remove from the stored list the stored array size field
+*/
+_PUBLIC_ enum ndr_err_code ndr_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t *size)
+{
+ return ndr_token_retrieve(&ndr->array_size_list, p, size);
+}
+
+/*
+ * check the stored array size field and remove from the stored list
+ * (the array_size NDR token list). We try to remove when possible to
+ * avoid the list growing towards the bounds check
+ */
+_PUBLIC_ enum ndr_err_code ndr_check_steal_array_size(struct ndr_pull *ndr, const void *p, uint32_t size)
+{
+ uint32_t stored;
+ NDR_CHECK(ndr_steal_array_size(ndr, p, &stored));
+ if (stored != size) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "Bad array size - got %u expected %u\n",
+ stored, size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ * check the stored array size field (leaving it on the array_size
+ * token list)
+ */
+_PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, const void *p, uint32_t size)
+{
+ uint32_t stored;
+ NDR_CHECK(ndr_get_array_size(ndr, p, &stored));
+ if (stored != size) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "Bad array size - got %"PRIu32" expected %"PRIu32"\n",
+ stored, size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull an array length field and add it to the array_length_list token list
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
+{
+ enum ndr_err_code ret;
+ uint32_t length, offset;
+ NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
+ if (offset != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "non-zero array offset %"PRIu32"\n", offset);
+ }
+ NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
+ ret = ndr_token_store(ndr, &ndr->array_length_list, p, length);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_pull_error(ndr, ret,
+ "More than %d NDR tokens stored for array_length_list",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ return ret;
+}
+
+/*
+ get the stored array length field
+*/
+_PUBLIC_ enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length)
+{
+ return ndr_token_peek(&ndr->array_length_list, p, length);
+}
+
+/*
+ * check the stored array length field and remove from the stored list
+ * (the array_size NDR token list). We try to remove when possible to
+ * avoid the list growing towards the bounds check
+ */
+_PUBLIC_ enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length)
+{
+ return ndr_token_retrieve(&ndr->array_length_list, p, length);
+}
+/*
+ check the stored array length field, removing it from the list
+*/
+_PUBLIC_ enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length)
+{
+ uint32_t stored;
+ NDR_CHECK(ndr_steal_array_length(ndr, p, &stored));
+ if (stored != length) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "Bad array length: got %"PRIu32" expected %"PRIu32"\n",
+ stored, length);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t count)
+{
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ int64_t tmp = 0 - (int64_t)count;
+ uint64_t ncount = tmp;
+
+ NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, ncount));
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t count)
+{
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ int64_t tmp = 0 - (int64_t)count;
+ uint64_t ncount1 = tmp;
+ uint64_t ncount2;
+
+ NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &ncount2));
+ if (ncount1 == ncount2) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "Bad pipe trailer[%"PRIu64" should be %"PRIu64"] size was %"PRIu32"\"",
+ ncount2,
+ ncount1,
+ count);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ store a switch value
+ */
+_PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
+{
+ enum ndr_err_code ret =
+ ndr_token_store(ndr, &ndr->switch_list, p, val);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_push_error(ndr, ret,
+ "More than %d NDR tokens stored for switch_list",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ return ret;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
+{
+
+ enum ndr_err_code ret =
+ ndr_token_store(ndr, &ndr->switch_list, p, val);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_pull_error(ndr, ret,
+ "More than %d NDR tokens stored for switch_list",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ return ret;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
+{
+ return ndr_token_store(ndr, &ndr->switch_list, p, val);
+}
+
+/* retrieve a switch value (for push) and remove it from the list */
+_PUBLIC_ enum ndr_err_code ndr_push_steal_switch_value(struct ndr_push *ndr,
+ const void *p,
+ uint32_t *v)
+{
+ return ndr_token_retrieve(&ndr->switch_list, p, v);
+}
+
+/* retrieve a switch value and remove it from the list */
+_PUBLIC_ uint32_t ndr_print_steal_switch_value(struct ndr_print *ndr, const void *p)
+{
+ enum ndr_err_code status;
+ uint32_t v;
+
+ status = ndr_token_retrieve(&ndr->switch_list, p, &v);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ return 0;
+ }
+
+ return v;
+}
+
+/* retrieve a switch value and remove it from the list */
+_PUBLIC_ enum ndr_err_code ndr_pull_steal_switch_value(struct ndr_pull *ndr,
+ const void *p,
+ uint32_t *v)
+{
+ return ndr_token_retrieve(&ndr->switch_list, p, v);
+}
+
+/*
+ pull a struct from a blob using NDR
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ ndr_pull_flags_fn_t fn)
+{
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(blob, mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+ NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ talloc_free(ndr);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a struct from a blob using NDR - failing if all bytes are not consumed
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
+ void *p, ndr_pull_flags_fn_t fn)
+{
+ struct ndr_pull *ndr;
+ uint32_t highest_ofs;
+ ndr = ndr_pull_init_blob(blob, mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+ NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ if (ndr->offset > ndr->relative_highest_offset) {
+ highest_ofs = ndr->offset;
+ } else {
+ highest_ofs = ndr->relative_highest_offset;
+ }
+ if (highest_ofs < ndr->data_size) {
+ enum ndr_err_code ret;
+ ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
+ "not all bytes consumed ofs[%"PRIu32"] size[%"PRIu32"]",
+ highest_ofs, ndr->data_size);
+ talloc_free(ndr);
+ return ret;
+ }
+ talloc_free(ndr);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ * pull a struct from a blob using NDR
+ *
+ * This only works for structures with NO allocated memory, like
+ * objectSID and GUID. This helps because we parse these a lot.
+ */
+_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_noalloc(const uint8_t *buf,
+ size_t buflen,
+ void *p,
+ ndr_pull_flags_fn_t fn,
+ size_t *consumed)
+{
+ /*
+ * We init this structure on the stack here, to avoid a
+ * talloc() as otherwise this call to the fn() is assured not
+ * to be doing any allocation, eg SIDs and GUIDs.
+ *
+ * This allows us to keep the safety of the PIDL-generated
+ * code without the talloc() overhead.
+ */
+ struct ndr_pull ndr = {
+ .data = discard_const_p(uint8_t, buf),
+ .data_size = buflen,
+ .current_mem_ctx = (void *)-1,
+ };
+
+ NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ *consumed = MAX(ndr.offset, ndr.relative_highest_offset);
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a struct from a blob using NDR - failing if all bytes are not consumed
+
+ This only works for structures with NO allocated memory, like
+ objectSID and GUID. This helps because we parse these a lot.
+*/
+_PUBLIC_ enum ndr_err_code
+ndr_pull_struct_blob_all_noalloc(const DATA_BLOB *blob,
+ void *p,
+ ndr_pull_flags_fn_t fn)
+{
+ size_t consumed;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_pull_struct_blob_noalloc(blob->data,
+ blob->length,
+ p,
+ fn,
+ &consumed);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_err;
+ }
+
+ if (consumed < blob->length) {
+ D_WARNING("not all bytes consumed ofs[%zu] size[%zu]",
+ consumed,
+ blob->length);
+ return NDR_ERR_UNREAD_BYTES;
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a union from a blob using NDR, given the union discriminator
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
+ void *p,
+ uint32_t level, ndr_pull_flags_fn_t fn)
+{
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(blob, mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+ NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
+ NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ talloc_free(ndr);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a union from a blob using NDR, given the union discriminator,
+ failing if all bytes are not consumed
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
+ void *p,
+ uint32_t level, ndr_pull_flags_fn_t fn)
+{
+ struct ndr_pull *ndr;
+ uint32_t highest_ofs;
+ ndr = ndr_pull_init_blob(blob, mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+ NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
+ NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ if (ndr->offset > ndr->relative_highest_offset) {
+ highest_ofs = ndr->offset;
+ } else {
+ highest_ofs = ndr->relative_highest_offset;
+ }
+ if (highest_ofs < ndr->data_size) {
+ enum ndr_err_code ret;
+ ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
+ "not all bytes consumed ofs[%"PRIu32"] size[%"PRIu32"]",
+ highest_ofs, ndr->data_size);
+ talloc_free(ndr);
+ return ret;
+ }
+ talloc_free(ndr);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a struct to a blob using NDR
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, ndr_push_flags_fn_t fn)
+{
+ struct ndr_push *ndr;
+ ndr = ndr_push_init_ctx(mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+
+ NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+
+ *blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob->data);
+ talloc_free(ndr);
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a struct into a provided blob using NDR.
+
+ We error because we want to have the performance issue (extra
+ talloc() calls) show up as an error, not just slower code. This is
+ used for things like GUIDs, which we expect to be a fixed size, and
+ SIDs that we can pre-calculate the size for.
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
+ DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
+{
+ struct ndr_push ndr = {
+ .data = blob->data,
+ .alloc_size = blob->length,
+ .fixed_buf_size = true
+ };
+
+ NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
+
+ if (ndr.offset != blob->length) {
+ return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
+ "buffer was either too large or small "
+ "ofs[%"PRIu32"] size[%zu]",
+ ndr.offset, blob->length);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a union to a blob using NDR
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+ uint32_t level, ndr_push_flags_fn_t fn)
+{
+ struct ndr_push *ndr;
+ ndr = ndr_push_init_ctx(mem_ctx);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+
+ NDR_CHECK_FREE(ndr_push_set_switch_value(ndr, p, level));
+ NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+
+ *blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob->data);
+ talloc_free(ndr);
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ generic ndr_size_*() handler for structures
+*/
+_PUBLIC_ size_t ndr_size_struct(const void *p, libndr_flags flags, ndr_push_flags_fn_t push)
+{
+ struct ndr_push *ndr;
+ enum ndr_err_code status;
+ size_t ret;
+
+ /* avoid recursion */
+ if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
+
+ /* Avoid following a NULL pointer */
+ if (p == NULL) {
+ return 0;
+ }
+
+ ndr = ndr_push_init_ctx(NULL);
+ if (!ndr) return 0;
+ ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
+ status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(ndr);
+ return 0;
+ }
+ ret = ndr->offset;
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ generic ndr_size_*() handler for unions
+*/
+_PUBLIC_ size_t ndr_size_union(const void *p, libndr_flags flags, uint32_t level, ndr_push_flags_fn_t push)
+{
+ struct ndr_push *ndr;
+ enum ndr_err_code status;
+ size_t ret;
+
+ /* avoid recursion */
+ if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
+
+ /* Avoid following a NULL pointer */
+ if (p == NULL) {
+ return 0;
+ }
+
+ ndr = ndr_push_init_ctx(NULL);
+ if (!ndr) return 0;
+ ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
+
+ status = ndr_push_set_switch_value(ndr, p, level);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(ndr);
+ return 0;
+ }
+ status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(ndr);
+ return 0;
+ }
+ ret = ndr->offset;
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ get the current base for relative pointers for the push
+*/
+_PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
+{
+ return ndr->relative_base_offset;
+}
+
+/*
+ restore the old base for relative pointers for the push
+*/
+_PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+}
+
+/*
+ setup the current base for relative pointers for the push
+ called in the NDR_SCALAR stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
+{
+ enum ndr_err_code ret;
+ ndr->relative_base_offset = offset;
+ ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_push_error(ndr, ret,
+ "More than %d NDR tokens stored for relative_base_list",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ return ret;
+}
+
+/*
+ setup the current base for relative pointers for the push
+ called in the NDR_BUFFERS stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
+{
+ return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
+}
+
+/*
+ push a relative object - stage1
+ this is called during SCALARS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
+{
+ enum ndr_err_code ret;
+ if (p == NULL) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_push_error(ndr, ret,
+ "More than %d NDR tokens stored for relative_list",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ NDR_CHECK(ret);
+ return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
+}
+
+/*
+ push a short relative object - stage1
+ this is called during SCALARS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
+{
+ enum ndr_err_code ret;
+ if (p == NULL) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ ret = ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_push_error(ndr, ret,
+ "More than %d NDR tokens stored for relative_list",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ NDR_CHECK(ret);
+ return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
+}
+/*
+ push a relative object - stage2
+ this is called during buffers processing
+*/
+static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
+{
+ uint32_t save_offset;
+ uint32_t ptr_offset = 0xFFFFFFFF;
+ if (p == NULL) {
+ return NDR_ERR_SUCCESS;
+ }
+ save_offset = ndr->offset;
+ NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
+ if (ptr_offset > ndr->offset) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_push_relative_ptr2 ptr_offset(%"PRIu32") > ndr->offset(%"PRIu32")",
+ ptr_offset, ndr->offset);
+ }
+ ndr->offset = ptr_offset;
+ if (save_offset < ndr->relative_base_offset) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_push_relative_ptr2 save_offset(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")",
+ save_offset, ndr->relative_base_offset);
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
+ ndr->offset = save_offset;
+ return NDR_ERR_SUCCESS;
+}
+/*
+ push a short relative object - stage2
+ this is called during buffers processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
+{
+ uint32_t save_offset;
+ uint32_t ptr_offset = 0xFFFF;
+ uint32_t relative_offset;
+ size_t pad;
+ size_t align = 1;
+
+ if (p == NULL) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (ndr->offset < ndr->relative_base_offset) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_push_relative_ptr2 ndr->offset(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")",
+ ndr->offset, ndr->relative_base_offset);
+ }
+
+ relative_offset = ndr->offset - ndr->relative_base_offset;
+
+ if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
+ align = 1;
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+ align = 2;
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
+ align = 4;
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
+ align = 8;
+ }
+
+ pad = ndr_align_size(relative_offset, align);
+ if (pad != 0) {
+ NDR_CHECK(ndr_push_zero(ndr, pad));
+ }
+
+ relative_offset = ndr->offset - ndr->relative_base_offset;
+ if (relative_offset > UINT16_MAX) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_push_relative_ptr2 relative_offset(%"PRIu32") > UINT16_MAX",
+ relative_offset);
+ }
+
+ save_offset = ndr->offset;
+ NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
+ if (ptr_offset > ndr->offset) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_push_short_relative_ptr2 ptr_offset(%"PRIu32") > ndr->offset(%"PRIu32")",
+ ptr_offset, ndr->offset);
+ }
+ ndr->offset = ptr_offset;
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
+ ndr->offset = save_offset;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a relative object - stage2 start
+ this is called during buffers processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
+{
+ enum ndr_err_code ret;
+ if (p == NULL) {
+ return NDR_ERR_SUCCESS;
+ }
+ if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
+ uint32_t relative_offset;
+ size_t pad;
+ size_t align = 1;
+
+ if (ndr->offset < ndr->relative_base_offset) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_push_relative_ptr2_start ndr->offset(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")",
+ ndr->offset, ndr->relative_base_offset);
+ }
+
+ relative_offset = ndr->offset - ndr->relative_base_offset;
+
+ if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
+ align = 1;
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+ align = 2;
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
+ align = 4;
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
+ align = 8;
+ }
+
+ pad = ndr_align_size(relative_offset, align);
+ if (pad) {
+ NDR_CHECK(ndr_push_zero(ndr, pad));
+ }
+
+ return ndr_push_relative_ptr2(ndr, p);
+ }
+ if (ndr->relative_end_offset == -1) {
+ return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+ "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %"PRIu32,
+ ndr->relative_end_offset);
+ }
+ ret = ndr_token_store(ndr,
+ &ndr->relative_begin_list,
+ p,
+ ndr->offset);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_push_error(ndr, ret,
+ "More than %d NDR tokens stored for array_size",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ return ret;
+}
+
+/*
+ push a relative object - stage2 end
+ this is called during buffers processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
+{
+ uint32_t begin_offset = 0xFFFFFFFF;
+ ssize_t len;
+ uint32_t correct_offset = 0;
+ uint32_t align = 1;
+ uint32_t pad = 0;
+
+ if (p == NULL) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
+ /* better say more than calculation a too small buffer */
+ NDR_PUSH_ALIGN(ndr, 8);
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (ndr->relative_end_offset < ndr->offset) {
+ return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+ "ndr_push_relative_ptr2_end:"
+ "relative_end_offset %"PRIu32" < offset %"PRIu32,
+ ndr->relative_end_offset, ndr->offset);
+ }
+
+ NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
+
+ /* we have marshalled a buffer, see how long it was */
+ len = ndr->offset - begin_offset;
+
+ if (len < 0) {
+ return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+ "ndr_push_relative_ptr2_end:"
+ "offset %"PRIu32" - begin_offset %"PRIu32" < 0",
+ ndr->offset, begin_offset);
+ }
+
+ if (ndr->relative_end_offset < len) {
+ return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+ "ndr_push_relative_ptr2_end:"
+ "relative_end_offset %"PRIu32" < len %zd",
+ ndr->offset, len);
+ }
+
+ /* the reversed offset is at the end of the main buffer */
+ correct_offset = ndr->relative_end_offset - len;
+
+ if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
+ align = 1;
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+ align = 2;
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
+ align = 4;
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
+ align = 8;
+ }
+
+ pad = ndr_align_size(correct_offset, align);
+ if (pad) {
+ correct_offset += pad;
+ correct_offset -= align;
+ }
+
+ if (correct_offset < begin_offset) {
+ return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+ "ndr_push_relative_ptr2_end: "
+ "correct_offset %"PRIu32" < begin_offset %"PRIu32,
+ correct_offset, begin_offset);
+ }
+
+ if (len > 0) {
+ uint32_t clear_size = correct_offset - begin_offset;
+
+ clear_size = MIN(clear_size, len);
+
+ /* now move the marshalled buffer to the end of the main buffer */
+ memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
+
+ if (clear_size) {
+ /* and wipe out old buffer within the main buffer */
+ memset(ndr->data + begin_offset, '\0', clear_size);
+ }
+ }
+
+ /* and set the end offset for the next buffer */
+ ndr->relative_end_offset = correct_offset;
+
+ /* finally write the offset to the main buffer */
+ ndr->offset = correct_offset;
+ NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
+
+ /* restore to where we were in the main buffer */
+ ndr->offset = begin_offset;
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ get the current base for relative pointers for the pull
+*/
+_PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
+{
+ return ndr->relative_base_offset;
+}
+
+/*
+ restore the old base for relative pointers for the pull
+*/
+_PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+}
+
+/*
+ setup the current base for relative pointers for the pull
+ called in the NDR_SCALAR stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
+{
+ enum ndr_err_code ret;
+ ndr->relative_base_offset = offset;
+ ret = ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_pull_error(ndr, ret,
+ "More than %d NDR tokens stored for relative_base_list",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ return ret;
+}
+
+/*
+ setup the current base for relative pointers for the pull
+ called in the NDR_BUFFERS stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
+{
+ return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
+}
+
+/*
+ pull a relative object - stage1
+ called during SCALARS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
+{
+ enum ndr_err_code ret;
+ rel_offset += ndr->relative_base_offset;
+ if (rel_offset > ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_relative_ptr1 rel_offset(%"PRIu32") > ndr->data_size(%"PRIu32")",
+ rel_offset, ndr->data_size);
+ }
+ ret = ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
+ if (ret == NDR_ERR_RANGE) {
+ return ndr_pull_error(ndr, ret,
+ "More than %d NDR tokens stored for relative_list",
+ NDR_TOKEN_MAX_LIST_SIZE);
+ }
+ return ret;
+}
+
+/*
+ pull a relative object - stage2
+ called during BUFFERS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
+{
+ uint32_t rel_offset;
+ NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
+ return ndr_pull_set_offset(ndr, rel_offset);
+}
+
+static const struct {
+ enum ndr_err_code err;
+ const char *string;
+} ndr_err_code_strings[] = {
+ { NDR_ERR_SUCCESS, "Success" },
+ { NDR_ERR_ARRAY_SIZE, "Bad Array Size" },
+ { NDR_ERR_BAD_SWITCH, "Bad Switch" },
+ { NDR_ERR_OFFSET, "Offset Error" },
+ { NDR_ERR_RELATIVE, "Relative Pointer Error" },
+ { NDR_ERR_CHARCNV, "Character Conversion Error" },
+ { NDR_ERR_LENGTH, "Length Error" },
+ { NDR_ERR_SUBCONTEXT, "Subcontext Error" },
+ { NDR_ERR_COMPRESSION, "Compression Error" },
+ { NDR_ERR_STRING, "String Error" },
+ { NDR_ERR_VALIDATE, "Validate Error" },
+ { NDR_ERR_BUFSIZE, "Buffer Size Error" },
+ { NDR_ERR_ALLOC, "Allocation Error" },
+ { NDR_ERR_RANGE, "Range Error" },
+ { NDR_ERR_TOKEN, "Token Error" },
+ { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
+ { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
+ { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
+ { NDR_ERR_NDR64, "NDR64 assertion error" },
+ { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" },
+ { NDR_ERR_MAX_RECURSION_EXCEEDED, "Maximum Recursion Exceeded" },
+ { NDR_ERR_UNDERFLOW, "Underflow" },
+ { 0, NULL }
+};
+
+_PUBLIC_ const char *ndr_map_error2string(enum ndr_err_code ndr_err)
+{
+ int i;
+ for (i = 0; ndr_err_code_strings[i].string != NULL; i++) {
+ if (ndr_err_code_strings[i].err == ndr_err)
+ return ndr_err_code_strings[i].string;
+ }
+ return "Unknown error";
+}
diff --git a/librpc/ndr/ndr_ODJ.c b/librpc/ndr/ndr_ODJ.c
new file mode 100644
index 0000000..86630b8
--- /dev/null
+++ b/librpc/ndr/ndr_ODJ.c
@@ -0,0 +1,65 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special ODJ structures
+
+ Copyright (C) Guenther Deschner 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 "includes.h"
+#include "../librpc/gen_ndr/ndr_ODJ.h"
+#include "../librpc/ndr/ndr_ODJ.h"
+
+uint32_t odj_switch_level_from_guid(const struct GUID *r)
+{
+ struct {
+ uint16_t level;
+ const char *guid;
+ } levels[] = {
+ {
+ .level = 1,
+ .guid = ODJ_GUID_JOIN_PROVIDER
+ },{
+ .level = 2,
+ .guid = ODJ_GUID_JOIN_PROVIDER2
+ },{
+ .level = 3,
+ .guid = ODJ_GUID_JOIN_PROVIDER3
+ },{
+ .level = 4,
+ .guid = ODJ_GUID_CERT_PROVIDER
+ },{
+ .level = 5,
+ .guid = ODJ_GUID_POLICY_PROVIDER
+ }
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(levels); i++) {
+ struct GUID guid;
+ NTSTATUS status;
+
+ status = GUID_from_string(levels[i].guid, &guid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return 0;
+ }
+ if (GUID_equal(&guid, r)) {
+ return levels[i].level;
+ }
+ }
+
+ return 0;
+}
diff --git a/librpc/ndr/ndr_ODJ.h b/librpc/ndr/ndr_ODJ.h
new file mode 100644
index 0000000..f57f2d7
--- /dev/null
+++ b/librpc/ndr/ndr_ODJ.h
@@ -0,0 +1,22 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special ODJ structures
+
+ Copyright (C) Guenther Deschner 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/>.
+*/
+
+uint32_t odj_switch_level_from_guid(const struct GUID *r);
diff --git a/librpc/ndr/ndr_auth.c b/librpc/ndr/ndr_auth.c
new file mode 100644
index 0000000..0600586
--- /dev/null
+++ b/librpc/ndr/ndr_auth.c
@@ -0,0 +1,44 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Helper routines for marshalling the internal 'auth.idl'
+
+ 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 "librpc/ndr/ndr_auth.h"
+#include "librpc/ndr/libndr.h"
+
+_PUBLIC_ void ndr_print_cli_credentials(struct ndr_print *ndr, const char *name, struct cli_credentials *v)
+{
+ ndr->print(ndr, "%-25s: NULL", name);
+}
+
+/*
+ cli_credentials does not have a network representation, just pull/push a NULL pointer
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_cli_credentials(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct cli_credentials *v)
+{
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_cli_credentials(struct ndr_push *ndr, ndr_flags_type ndr_flags, struct cli_credentials *v)
+{
+ return ndr_push_pointer(ndr, ndr_flags, NULL);
+}
+
+
diff --git a/librpc/ndr/ndr_auth.h b/librpc/ndr/ndr_auth.h
new file mode 100644
index 0000000..9cc4ec2
--- /dev/null
+++ b/librpc/ndr/ndr_auth.h
@@ -0,0 +1,32 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Helper routines for marshalling the internal 'auth.idl'
+
+ 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/>.
+*/
+
+/*
+ cli_credentials does not have a network representation, just pull/push a NULL pointer
+*/
+
+#include "librpc/gen_ndr/ndr_auth.h"
+
+struct cli_credentials;
+_PUBLIC_ enum ndr_err_code ndr_pull_cli_credentials(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct cli_credentials *v);
+_PUBLIC_ enum ndr_err_code ndr_push_cli_credentials(struct ndr_push *ndr, ndr_flags_type ndr_flags, struct cli_credentials *v);
+
+_PUBLIC_ void ndr_print_cli_credentials(struct ndr_print *ndr, const char *name, struct cli_credentials *v);
diff --git a/librpc/ndr/ndr_backupkey.c b/librpc/ndr/ndr_backupkey.c
new file mode 100644
index 0000000..9ce1abb
--- /dev/null
+++ b/librpc/ndr/ndr_backupkey.c
@@ -0,0 +1,222 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for top backup key protocol marshalling/unmarshalling
+
+ Copyright (C) Matthieu Patou 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 "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_backupkey.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+static uint32_t backupkeyguid_to_uint(const struct GUID *guid)
+{
+ struct GUID tmp;
+ NTSTATUS status;
+ bool match;
+
+ status = GUID_from_string(BACKUPKEY_RESTORE_GUID, &tmp);
+ if (NT_STATUS_IS_OK(status)) {
+ match = GUID_equal(guid, &tmp);
+ if (match) {
+ return BACKUPKEY_RESTORE_GUID_INTEGER;
+ }
+ }
+
+ status = GUID_from_string(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID, &tmp);
+ if (NT_STATUS_IS_OK(status)) {
+ match = GUID_equal(guid, &tmp);
+ if (match) {
+ return BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER;
+ }
+ }
+
+ return BACKUPKEY_INVALID_GUID_INTEGER;
+}
+
+_PUBLIC_ void ndr_print_bkrp_BackupKey(struct ndr_print *ndr, const char *name, ndr_flags_type flags, const struct bkrp_BackupKey *r)
+{
+ ndr_print_struct(ndr, name, "bkrp_BackupKey");
+ if (r == NULL) { ndr_print_null(ndr); return; }
+ ndr->depth++;
+ if (flags & NDR_SET_VALUES) {
+ ndr->flags |= LIBNDR_PRINT_SET_VALUES;
+ }
+ if (flags & NDR_IN) {
+ union bkrp_data_in_blob inblob = {
+ .empty._empty_ = '\0',
+ };
+ DATA_BLOB blob;
+ uint32_t level;
+ enum ndr_err_code ndr_err;
+
+ ndr_print_struct(ndr, "in", "bkrp_BackupKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "guidActionAgent", r->in.guidActionAgent);
+ ndr->depth++;
+ ndr_print_GUID(ndr, "guidActionAgent", r->in.guidActionAgent);
+ ndr->depth--;
+
+ level = backupkeyguid_to_uint(r->in.guidActionAgent);
+ ndr_err = ndr_print_set_switch_value(ndr, &inblob, level);
+ if (unlikely(!NDR_ERR_CODE_IS_SUCCESS(ndr_err))) { \
+ DEBUG(0,("ERROR: ndr_print_bkrp_BackupKey ndr_print_set_switch_value failed: %d\n", ndr_err));
+ return;
+ }
+ blob.data = r->in.data_in;
+ blob.length = r->in.data_in_len;
+ ndr_err = ndr_pull_union_blob(&blob, ndr, &inblob, level,
+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_data_in_blob);
+
+ ndr_print_ptr(ndr, "data_in", r->in.data_in);
+ ndr->depth++;
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ ndr_print_bkrp_data_in_blob(ndr, "data_in", &inblob);
+ } else {
+ ndr_print_array_uint8(ndr, "data_in", r->in.data_in, r->in.data_in_len);
+ }
+ ndr->depth--;
+
+ ndr_print_uint32(ndr, "data_in_len", r->in.data_in_len);
+ ndr_print_uint32(ndr, "param", r->in.param);
+ ndr->depth--;
+ }
+ if (flags & NDR_OUT) {
+ ndr_print_struct(ndr, "out", "bkrp_BackupKey");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "data_out", r->out.data_out);
+ ndr->depth++;
+ ndr_print_ptr(ndr, "data_out", *r->out.data_out);
+ ndr->depth++;
+
+ if (*r->out.data_out) {
+ ndr_print_array_uint8(ndr, "data_out", *r->out.data_out, *r->out.data_out_len);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ ndr_print_ptr(ndr, "data_out_len", r->out.data_out_len);
+ ndr->depth++;
+ ndr_print_uint32(ndr, "data_out_len", *r->out.data_out_len);
+ ndr->depth--;
+ ndr_print_WERROR(ndr, "result", r->out.result);
+ ndr->depth--;
+ }
+ ndr->depth--;
+}
+
+/* We have manual push/pull because we didn't manage to do the alignment
+ * purely in PIDL as the padding is sized so that the whole access_check_v3
+ * struct size is a multiple of 8 (as specified in 2.2.2.3 of ms-bkrp.pdf)
+ */
+_PUBLIC_ enum ndr_err_code ndr_push_bkrp_access_check_v2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct bkrp_access_check_v2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ size_t ofs;
+ size_t pad;
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0x00000001));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->nonce_len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->nonce, r->nonce_len));
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, &r->sid));
+ /* We articially increment the offset of 20 bytes (size of hash
+ * coming after the pad) so that ndr_align can determine easily
+ * the correct pad size to make the whole struct 8 bytes aligned
+ */
+ ofs = ndr->offset + 20;
+ pad = ndr_align_size(ofs, 8);
+ NDR_CHECK(ndr_push_zero(ndr, pad));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->hash, 20));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_bkrp_access_check_v2(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct bkrp_access_check_v2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ size_t ofs;
+ size_t pad;
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->magic));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->nonce_len));
+ NDR_PULL_ALLOC_N(ndr, r->nonce, r->nonce_len);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->nonce, r->nonce_len));
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->sid));
+ ofs = ndr->offset + 20;
+ pad = ndr_align_size(ofs, 8);
+ NDR_CHECK(ndr_pull_advance(ndr, pad));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->hash, 20));
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/* We have manual push/pull because we didn't manage to do the alignment
+ * purely in PIDL as the padding is sized so that the whole access_check_v3
+ * struct size is a multiple of 16 (as specified in 2.2.2.4 of ms-bkrp.pdf)
+ */
+_PUBLIC_ enum ndr_err_code ndr_push_bkrp_access_check_v3(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct bkrp_access_check_v3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ size_t ofs;
+ size_t pad;
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0x00000001));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->nonce_len));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->nonce, r->nonce_len));
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, &r->sid));
+ /* We articially increment the offset of 64 bytes (size of hash
+ * coming after the pad) so that ndr_align can determine easily
+ * the correct pad size to make the whole struct 16 bytes aligned
+ */
+ ofs = ndr->offset + 64;
+ pad = ndr_align_size(ofs, 16);
+ NDR_CHECK(ndr_push_zero(ndr, pad));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->hash, 64));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_bkrp_access_check_v3(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct bkrp_access_check_v3 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ size_t ofs;
+ size_t pad;
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->magic));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->nonce_len));
+ NDR_PULL_ALLOC_N(ndr, r->nonce, r->nonce_len);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->nonce, r->nonce_len));
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->sid));
+ ofs = ndr->offset + 64;
+ pad = ndr_align_size(ofs, 16);
+ NDR_CHECK(ndr_pull_advance(ndr, pad));
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->hash, 64));
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_backupkey.h b/librpc/ndr/ndr_backupkey.h
new file mode 100644
index 0000000..20386d2
--- /dev/null
+++ b/librpc/ndr/ndr_backupkey.h
@@ -0,0 +1,23 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for top backup key protocol marshalling/unmarshalling
+
+ Copyright (C) Matthieu Patou 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/>.
+*/
+
+_PUBLIC_ enum ndr_err_code ndr_push_bkrp_access_check_v2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct bkrp_access_check_v2 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_bkrp_access_check_v2(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct bkrp_access_check_v2 *r);
diff --git a/librpc/ndr/ndr_basic.c b/librpc/ndr/ndr_basic.c
new file mode 100644
index 0000000..5fd1573
--- /dev/null
+++ b/librpc/ndr/ndr_basic.c
@@ -0,0 +1,1596 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling basic types
+
+ 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 "replace.h"
+#include "system/network.h"
+#include "librpc/ndr/libndr.h"
+#include "lib/util/util_net.h"
+#include "lib/util/debug.h"
+#include "lib/util/util.h"
+#include "lib/util/bytearray.h"
+
+#define NDR_PULL_U16(ndr, ofs) \
+ (NDR_BE(ndr) ? PULL_BE_U16(ndr->data,ofs) : PULL_LE_U16(ndr->data,ofs))
+
+#define NDR_PULL_U32(ndr, ofs) \
+ (NDR_BE(ndr) ? PULL_BE_U32(ndr->data,ofs) : PULL_LE_U32(ndr->data,ofs))
+
+#define NDR_PULL_I32(ndr, ofs) \
+ (int32_t)(NDR_BE(ndr) ? PULL_BE_U32(ndr->data,ofs) : PULL_LE_U32(ndr->data,ofs))
+
+#define NDR_PULL_I64(ndr, ofs) \
+ (NDR_BE(ndr) ? PULL_BE_I64((ndr)->data, ofs) : PULL_LE_I64((ndr)->data, ofs))
+
+#define NDR_PUSH_U16(ndr, ofs, v) \
+ do { \
+ if (NDR_BE(ndr)) { \
+ PUSH_BE_U16(ndr->data, ofs, v); \
+ } else { \
+ PUSH_LE_U16(ndr->data, ofs, v); \
+ } \
+ } while (0)
+
+#define NDR_PUSH_U32(ndr, ofs, v) \
+ do { \
+ if (NDR_BE(ndr)) { \
+ PUSH_BE_U32(ndr->data, ofs, v); \
+ } else { \
+ PUSH_LE_U32(ndr->data, ofs, v); \
+ } \
+ } while (0)
+
+#define NDR_PUSH_I32(ndr, ofs, v) \
+ do { \
+ if (NDR_BE(ndr)) { \
+ PUSH_BE_U32(ndr->data, ofs, v); \
+ } else { \
+ PUSH_LE_U32(ndr->data, ofs, v); \
+ } \
+ } while (0)
+
+#define NDR_PUSH_I64(ndr, ofs, v) \
+ do { \
+ if (NDR_BE(ndr)) { \
+ PUSH_BE_I64((ndr)->data, ofs, v); \
+ } else { \
+ PUSH_LE_I64((ndr)->data, ofs, v); \
+ } \
+ } while (0)
+
+static void ndr_dump_data(struct ndr_print *ndr, const uint8_t *buf, int len);
+
+/*
+ check for data leaks from the server by looking for non-zero pad bytes
+ these could also indicate that real structure elements have been
+ mistaken for padding in the IDL
+*/
+_PUBLIC_ void ndr_check_padding(struct ndr_pull *ndr, size_t n)
+{
+ size_t ofs2 = (ndr->offset + (n-1)) & ~(n-1);
+ size_t i;
+ for (i=ndr->offset;i<ofs2;i++) {
+ if (ndr->data[i] != 0) {
+ break;
+ }
+ }
+ if (i<ofs2) {
+ DEBUG(0,("WARNING: Non-zero padding to %zu: ", n));
+ for (i=ndr->offset;i<ofs2;i++) {
+ DEBUG(0,("%02x ", ndr->data[i]));
+ }
+ DEBUG(0,("\n"));
+ }
+
+}
+
+/*
+ parse a int8_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_int8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, int8_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_NEED_BYTES(ndr, 1);
+ *v = (int8_t)PULL_BE_U8(ndr->data, ndr->offset);
+ ndr->offset += 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a uint8_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_uint8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint8_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_NEED_BYTES(ndr, 1);
+ *v = PULL_BE_U8(ndr->data, ndr->offset);
+ ndr->offset += 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a int16_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_int16(struct ndr_pull *ndr, ndr_flags_type ndr_flags, int16_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_ALIGN(ndr, 2);
+ NDR_PULL_NEED_BYTES(ndr, 2);
+ *v = (uint16_t)NDR_PULL_U16(ndr, ndr->offset);
+ ndr->offset += 2;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a uint16_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_uint16(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_ALIGN(ndr, 2);
+ NDR_PULL_NEED_BYTES(ndr, 2);
+ *v = NDR_PULL_U16(ndr, ndr->offset);
+ ndr->offset += 2;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a uint1632_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_uint1632(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) {
+ uint32_t v32 = 0;
+ enum ndr_err_code err = ndr_pull_uint32(ndr, ndr_flags, &v32);
+ *v = v32;
+ if (unlikely(v32 != *v)) {
+ DEBUG(0,(__location__ ": non-zero upper 16 bits 0x%08"PRIx32"\n", v32));
+ return NDR_ERR_NDR64;
+ }
+ return err;
+ }
+ return ndr_pull_uint16(ndr, ndr_flags, v);
+}
+
+/*
+ parse a int32_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_int32(struct ndr_pull *ndr, ndr_flags_type ndr_flags, int32_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_ALIGN(ndr, 4);
+ NDR_PULL_NEED_BYTES(ndr, 4);
+ *v = NDR_PULL_I32(ndr, ndr->offset);
+ ndr->offset += 4;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a uint32_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_uint32(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_ALIGN(ndr, 4);
+ NDR_PULL_NEED_BYTES(ndr, 4);
+ *v = NDR_PULL_U32(ndr, ndr->offset);
+ ndr->offset += 4;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a arch dependent uint32/uint64
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_uint3264(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t *v)
+{
+ uint64_t v64 = 0;
+ enum ndr_err_code err;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (likely(!(ndr->flags & LIBNDR_FLAG_NDR64))) {
+ return ndr_pull_uint32(ndr, ndr_flags, v);
+ }
+ err = ndr_pull_hyper(ndr, ndr_flags, &v64);
+ if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+ return err;
+ }
+ *v = (uint32_t)v64;
+ if (unlikely(v64 != *v)) {
+ DEBUG(0,(__location__ ": non-zero upper 32 bits 0x%016"PRIx64"\n",
+ v64));
+ return ndr_pull_error(ndr, NDR_ERR_NDR64, __location__ ": non-zero upper 32 bits 0x%016"PRIx64"\n",
+ v64);
+ }
+ return err;
+}
+
+/*
+ parse a double
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_double(struct ndr_pull *ndr, ndr_flags_type ndr_flags, double *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_ALIGN(ndr, 8);
+ NDR_PULL_NEED_BYTES(ndr, 8);
+ memcpy(v, ndr->data+ndr->offset, 8);
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a pointer referent identifier stored in 2 bytes
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr_short(struct ndr_pull *ndr, uint16_t *v)
+{
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, v));
+ if (*v != 0) {
+ ndr->ptr_count++;
+ }
+ *(v) -= ndr->relative_rap_convert;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a pointer referent identifier
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_generic_ptr(struct ndr_pull *ndr, uint32_t *v)
+{
+ NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, v));
+ if (*v != 0) {
+ ndr->ptr_count++;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a ref pointer referent identifier
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_ref_ptr(struct ndr_pull *ndr, uint32_t *v)
+{
+ NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, v));
+ /* ref pointers always point to data */
+ *v = 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a udlong
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_udlong(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint64_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_ALIGN(ndr, 4);
+ NDR_PULL_NEED_BYTES(ndr, 8);
+ *v = NDR_PULL_U32(ndr, ndr->offset);
+ *v |= (uint64_t)(NDR_PULL_U32(ndr, ndr->offset+4)) << 32;
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a udlongr
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_udlongr(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint64_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_ALIGN(ndr, 4);
+ NDR_PULL_NEED_BYTES(ndr, 8);
+ *v = ((uint64_t)NDR_PULL_U32(ndr, ndr->offset)) << 32;
+ *v |= NDR_PULL_U32(ndr, ndr->offset+4);
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a dlong
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_dlong(struct ndr_pull *ndr, ndr_flags_type ndr_flags, int64_t *v)
+{
+ return ndr_pull_udlong(ndr, ndr_flags, (uint64_t *)v);
+}
+
+/*
+ parse a hyper
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_hyper(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint64_t *v)
+{
+ NDR_PULL_ALIGN(ndr, 8);
+ if (NDR_BE(ndr)) {
+ return ndr_pull_udlongr(ndr, ndr_flags, v);
+ }
+ return ndr_pull_udlong(ndr, ndr_flags, v);
+}
+
+/*
+ parse an int64
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_int64(struct ndr_pull *ndr, ndr_flags_type ndr_flags, int64_t *v)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_ALIGN(ndr, 8);
+ NDR_PULL_NEED_BYTES(ndr, 8);
+ *v = NDR_PULL_I64(ndr, ndr->offset);
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a pointer
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_pointer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, void* *v)
+{
+ uintptr_t h;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PULL_ALIGN(ndr, sizeof(h));
+ NDR_PULL_NEED_BYTES(ndr, sizeof(h));
+ memcpy(&h, ndr->data+ndr->offset, sizeof(h));
+ ndr->offset += sizeof(h);
+ *v = (void *)h;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a NTSTATUS
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_NTSTATUS(struct ndr_pull *ndr, ndr_flags_type ndr_flags, NTSTATUS *status)
+{
+ uint32_t v;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *status = NT_STATUS(v);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a NTSTATUS
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_NTSTATUS(struct ndr_push *ndr, ndr_flags_type ndr_flags, NTSTATUS status)
+{
+ return ndr_push_uint32(ndr, ndr_flags, NT_STATUS_V(status));
+}
+
+_PUBLIC_ void ndr_print_NTSTATUS(struct ndr_print *ndr, const char *name, NTSTATUS r)
+{
+ ndr->print(ndr, "%-25s: %s", name, nt_errstr(r));
+}
+
+/*
+ pull a WERROR
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_WERROR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, WERROR *status)
+{
+ uint32_t v;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *status = W_ERROR(v);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a HRESULT
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_HRESULT(struct ndr_pull *ndr, ndr_flags_type ndr_flags, HRESULT *status)
+{
+ uint32_t v;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &v));
+ *status = HRES_ERROR(v);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a uint8_t enum
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint8_t *v)
+{
+ return ndr_pull_uint8(ndr, ndr_flags, v);
+}
+
+/*
+ parse a uint16_t enum
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint16(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v)
+{
+ return ndr_pull_uint16(ndr, ndr_flags, v);
+}
+
+/*
+ parse a uint1632_t enum (uint32_t on NDR64)
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint1632(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint16_t *v)
+{
+ if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) {
+ uint32_t v32;
+ NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &v32));
+ *v = v32;
+ if (v32 != *v) {
+ DEBUG(0,(__location__ ": non-zero upper 16 bits 0x%08"PRIx32"\n", v32));
+ return NDR_ERR_NDR64;
+ }
+ return NDR_ERR_SUCCESS;
+ }
+ return ndr_pull_uint16(ndr, ndr_flags, v);
+}
+
+/*
+ parse a uint32_t enum
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_enum_uint32(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint32_t *v)
+{
+ return ndr_pull_uint32(ndr, ndr_flags, v);
+}
+
+/*
+ push a uint8_t enum
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_enum_uint8(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint8_t v)
+{
+ return ndr_push_uint8(ndr, ndr_flags, v);
+}
+
+/*
+ push a uint16_t enum
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_enum_uint16(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v)
+{
+ return ndr_push_uint16(ndr, ndr_flags, v);
+}
+
+/*
+ push a uint32_t enum
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_enum_uint32(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t v)
+{
+ return ndr_push_uint32(ndr, ndr_flags, v);
+}
+
+/*
+ push a uint1632_t enum
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_enum_uint1632(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v)
+{
+ if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) {
+ return ndr_push_uint32(ndr, ndr_flags, v);
+ }
+ return ndr_push_uint16(ndr, ndr_flags, v);
+}
+
+/*
+ push a WERROR
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_WERROR(struct ndr_push *ndr, ndr_flags_type ndr_flags, WERROR status)
+{
+ return ndr_push_uint32(ndr, NDR_SCALARS, W_ERROR_V(status));
+}
+
+_PUBLIC_ void ndr_print_WERROR(struct ndr_print *ndr, const char *name, WERROR r)
+{
+ ndr->print(ndr, "%-25s: %s", name, win_errstr(r));
+}
+
+/*
+ push a HRESULT
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_HRESULT(struct ndr_push *ndr, ndr_flags_type ndr_flags, HRESULT status)
+{
+ return ndr_push_uint32(ndr, NDR_SCALARS, HRES_ERROR_V(status));
+}
+
+_PUBLIC_ void ndr_print_HRESULT(struct ndr_print *ndr, const char *name, HRESULT r)
+{
+ ndr->print(ndr, "%-25s: %s", name, hresult_errstr(r));
+}
+
+
+/*
+ parse a set of bytes
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_bytes(struct ndr_pull *ndr, uint8_t *data, uint32_t n)
+{
+ NDR_PULL_NEED_BYTES(ndr, n);
+ memcpy(data, ndr->data + ndr->offset, n);
+ ndr->offset += n;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull an array of uint8
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_array_uint8(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uint8_t *data, uint32_t n)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+ return ndr_pull_bytes(ndr, data, n);
+}
+
+/*
+ push a int8_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_int8(struct ndr_push *ndr, ndr_flags_type ndr_flags, int8_t v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_NEED_BYTES(ndr, 1);
+ PUSH_BE_U8(ndr->data, ndr->offset, (uint8_t)v);
+ ndr->offset += 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a uint8_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_uint8(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint8_t v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_NEED_BYTES(ndr, 1);
+ PUSH_BE_U8(ndr->data, ndr->offset, v);
+ ndr->offset += 1;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a int16_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_int16(struct ndr_push *ndr, ndr_flags_type ndr_flags, int16_t v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_ALIGN(ndr, 2);
+ NDR_PUSH_NEED_BYTES(ndr, 2);
+ NDR_PUSH_U16(ndr, ndr->offset, (uint16_t)v);
+ ndr->offset += 2;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a uint16_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_uint16(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_ALIGN(ndr, 2);
+ NDR_PUSH_NEED_BYTES(ndr, 2);
+ NDR_PUSH_U16(ndr, ndr->offset, v);
+ ndr->offset += 2;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a uint1632
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_uint1632(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint16_t v)
+{
+ if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) {
+ return ndr_push_uint32(ndr, ndr_flags, v);
+ }
+ return ndr_push_uint16(ndr, ndr_flags, v);
+}
+
+/*
+ push a int32_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_int32(struct ndr_push *ndr, ndr_flags_type ndr_flags, int32_t v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_ALIGN(ndr, 4);
+ NDR_PUSH_NEED_BYTES(ndr, 4);
+ NDR_PUSH_I32(ndr, ndr->offset, v);
+ ndr->offset += 4;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a uint32_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_uint32(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_ALIGN(ndr, 4);
+ NDR_PUSH_NEED_BYTES(ndr, 4);
+ NDR_PUSH_U32(ndr, ndr->offset, v);
+ ndr->offset += 4;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a uint3264
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_uint3264(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint32_t v)
+{
+ if (unlikely(ndr->flags & LIBNDR_FLAG_NDR64)) {
+ return ndr_push_hyper(ndr, ndr_flags, v);
+ }
+ return ndr_push_uint32(ndr, ndr_flags, v);
+}
+
+/*
+ push a udlong
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_udlong(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint64_t v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_ALIGN(ndr, 4);
+ NDR_PUSH_NEED_BYTES(ndr, 8);
+ NDR_PUSH_U32(ndr, ndr->offset, (v & 0xFFFFFFFF));
+ NDR_PUSH_U32(ndr, ndr->offset+4, (v>>32));
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a udlongr
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_udlongr(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint64_t v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_ALIGN(ndr, 4);
+ NDR_PUSH_NEED_BYTES(ndr, 8);
+ NDR_PUSH_U32(ndr, ndr->offset, (v>>32));
+ NDR_PUSH_U32(ndr, ndr->offset+4, (v & 0xFFFFFFFF));
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a dlong
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_dlong(struct ndr_push *ndr, ndr_flags_type ndr_flags, int64_t v)
+{
+ return ndr_push_udlong(ndr, NDR_SCALARS, (uint64_t)v);
+}
+
+/*
+ push a hyper
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_hyper(struct ndr_push *ndr, ndr_flags_type ndr_flags, uint64_t v)
+{
+ NDR_PUSH_ALIGN(ndr, 8);
+ if (NDR_BE(ndr)) {
+ return ndr_push_udlongr(ndr, NDR_SCALARS, v);
+ }
+ return ndr_push_udlong(ndr, NDR_SCALARS, v);
+}
+
+/*
+ push an int64
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_int64(struct ndr_push *ndr, ndr_flags_type ndr_flags, int64_t v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_ALIGN(ndr, 8);
+ NDR_PUSH_NEED_BYTES(ndr, 8);
+ NDR_PUSH_I64(ndr, ndr->offset, v);
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a double
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_double(struct ndr_push *ndr, ndr_flags_type ndr_flags, double v)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_ALIGN(ndr, 8);
+ NDR_PUSH_NEED_BYTES(ndr, 8);
+ memcpy(ndr->data+ndr->offset, &v, 8);
+ ndr->offset += 8;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a pointer
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_pointer(struct ndr_push *ndr, ndr_flags_type ndr_flags, void* v)
+{
+ uintptr_t h = (intptr_t)v;
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_PUSH_ALIGN(ndr, sizeof(h));
+ NDR_PUSH_NEED_BYTES(ndr, sizeof(h));
+ memcpy(ndr->data+ndr->offset, &h, sizeof(h));
+ ndr->offset += sizeof(h);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_align(struct ndr_push *ndr, size_t size)
+{
+ /* this is a nasty hack to make pidl work with NDR64 */
+ if (size == 5) {
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ size = 8;
+ } else {
+ size = 4;
+ }
+ } else if (size == 3) {
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ size = 4;
+ } else {
+ size = 2;
+ }
+ }
+ NDR_PUSH_ALIGN(ndr, size);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_align(struct ndr_pull *ndr, size_t size)
+{
+ /* this is a nasty hack to make pidl work with NDR64 */
+ if (size == 5) {
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ size = 8;
+ } else {
+ size = 4;
+ }
+ } else if (size == 3) {
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ size = 4;
+ } else {
+ size = 2;
+ }
+ }
+ NDR_PULL_ALIGN(ndr, size);
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_union_align(struct ndr_push *ndr, size_t size)
+{
+ /* MS-RPCE section 2.2.5.3.4.4 */
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ return ndr_push_align(ndr, size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_union_align(struct ndr_pull *ndr, size_t size)
+{
+ /* MS-RPCE section 2.2.5.3.4.4 */
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ return ndr_pull_align(ndr, size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_trailer_align(struct ndr_push *ndr, size_t size)
+{
+ /* MS-RPCE section 2.2.5.3.4.1 */
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ return ndr_push_align(ndr, size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_trailer_align(struct ndr_pull *ndr, size_t size)
+{
+ /* MS-RPCE section 2.2.5.3.4.1 */
+ if (ndr->flags & LIBNDR_FLAG_NDR64) {
+ return ndr_pull_align(ndr, size);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push some bytes
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_bytes(struct ndr_push *ndr, const uint8_t *data, uint32_t n)
+{
+ if (unlikely(n == 0)) {
+ return NDR_ERR_SUCCESS;
+ }
+ if (unlikely(data == NULL)) {
+ return NDR_ERR_INVALID_POINTER;
+ }
+ NDR_PUSH_NEED_BYTES(ndr, n);
+ memcpy(ndr->data + ndr->offset, data, n);
+ ndr->offset += n;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push some zero bytes
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_zero(struct ndr_push *ndr, uint32_t n)
+{
+ NDR_PUSH_NEED_BYTES(ndr, n);
+ memset(ndr->data + ndr->offset, 0, n);
+ ndr->offset += n;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push an array of uint8
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_array_uint8(struct ndr_push *ndr, ndr_flags_type ndr_flags, const uint8_t *data, uint32_t n)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+ return ndr_push_bytes(ndr, data, n);
+}
+
+/*
+ push a unique non-zero value if a pointer is non-NULL, otherwise 0
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_unique_ptr(struct ndr_push *ndr, const void *p)
+{
+ uint32_t ptr = 0;
+ if (p) {
+ ptr = ndr->ptr_count * 4;
+ ptr |= 0x00020000;
+ ndr->ptr_count++;
+ }
+ return ndr_push_uint3264(ndr, NDR_SCALARS, ptr);
+}
+
+/*
+ push a 'simple' full non-zero value if a pointer is non-NULL, otherwise 0
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_full_ptr(struct ndr_push *ndr, const void *p)
+{
+ enum ndr_err_code ret = NDR_ERR_SUCCESS;
+ uint32_t ptr = 0;
+ if (p) {
+ /* Check if the pointer already exists and has an id */
+ ret = ndr_token_peek(&ndr->full_ptr_list, p, &ptr);
+ if (ret == NDR_ERR_TOKEN) {
+ ndr->ptr_count++;
+ ptr = ndr->ptr_count;
+ ret = ndr_token_store(ndr, &ndr->full_ptr_list, p, ptr);
+ if (ret != NDR_ERR_SUCCESS) {
+ return ret;
+ }
+ } else if (ret != NDR_ERR_SUCCESS) {
+ return ret;
+ }
+ }
+ return ndr_push_uint3264(ndr, NDR_SCALARS, ptr);
+}
+
+/*
+ push always a 0, if a pointer is NULL it's a fatal error
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_ref_ptr(struct ndr_push *ndr)
+{
+ return ndr_push_uint3264(ndr, NDR_SCALARS, 0xAEF1AEF1);
+}
+
+
+/*
+ push a NTTIME
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_NTTIME(struct ndr_push *ndr, ndr_flags_type ndr_flags, NTTIME t)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_push_udlong(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a NTTIME
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME(struct ndr_pull *ndr, ndr_flags_type ndr_flags, NTTIME *t)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_pull_udlong(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a NTTIME_1sec
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_NTTIME_1sec(struct ndr_push *ndr, ndr_flags_type ndr_flags, NTTIME t)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ t /= 10000000;
+ NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a NTTIME_1sec
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_1sec(struct ndr_pull *ndr, ndr_flags_type ndr_flags, NTTIME *t)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, t));
+ (*t) *= 10000000;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ pull a NTTIME_hyper
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_NTTIME_hyper(struct ndr_pull *ndr, ndr_flags_type ndr_flags, NTTIME *t)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a NTTIME_hyper
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_NTTIME_hyper(struct ndr_push *ndr, ndr_flags_type ndr_flags, NTTIME t)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a time_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_time_t(struct ndr_push *ndr, ndr_flags_type ndr_flags, time_t t)
+{
+ return ndr_push_uint32(ndr, ndr_flags, t);
+}
+
+/*
+ pull a time_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_time_t(struct ndr_pull *ndr, ndr_flags_type ndr_flags, time_t *t)
+{
+ uint32_t tt;
+ NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &tt));
+ *t = tt;
+ return NDR_ERR_SUCCESS;
+}
+
+
+/*
+ push a uid_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_uid_t(struct ndr_push *ndr, ndr_flags_type ndr_flags, uid_t u)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ return ndr_push_hyper(ndr, NDR_SCALARS, (uint64_t)u);
+}
+
+/*
+ pull a uid_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_uid_t(struct ndr_pull *ndr, ndr_flags_type ndr_flags, uid_t *u)
+{
+ uint64_t uu = 0;
+ NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &uu));
+ *u = (uid_t)uu;
+ if (unlikely(uu != *u)) {
+ DEBUG(0,(__location__ ": uid_t pull doesn't fit 0x%016"PRIx64"\n",
+ uu));
+ return NDR_ERR_NDR64;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+
+/*
+ push a gid_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_gid_t(struct ndr_push *ndr, ndr_flags_type ndr_flags, gid_t g)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ return ndr_push_hyper(ndr, NDR_SCALARS, (uint64_t)g);
+}
+
+/*
+ pull a gid_t
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_gid_t(struct ndr_pull *ndr, ndr_flags_type ndr_flags, gid_t *g)
+{
+ uint64_t gg = 0;
+ NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &gg));
+ *g = (gid_t)gg;
+ if (unlikely(gg != *g)) {
+ DEBUG(0,(__location__ ": gid_t pull doesn't fit 0x%016"PRIx64"\n",
+ gg));
+ return NDR_ERR_NDR64;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+
+/*
+ pull a ipv4address
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_ipv4address(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **address)
+{
+ uint32_t addr;
+ struct in_addr in;
+ NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &addr));
+ in.s_addr = htonl(addr);
+ *address = talloc_strdup(ndr->current_mem_ctx, inet_ntoa(in));
+ NDR_ERR_HAVE_NO_MEMORY(*address);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a ipv4address
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_ipv4address(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *address)
+{
+ uint32_t addr;
+ if (!is_ipaddress_v4(address)) {
+ return ndr_push_error(ndr, NDR_ERR_IPV4ADDRESS,
+ "Invalid IPv4 address: '%s'",
+ address);
+ }
+ addr = inet_addr(address);
+ NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, htonl(addr)));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ print a ipv4address
+*/
+_PUBLIC_ void ndr_print_ipv4address(struct ndr_print *ndr, const char *name,
+ const char *address)
+{
+ ndr->print(ndr, "%-25s: %s", name, address);
+}
+
+/*
+ pull a ipv6address
+*/
+#define IPV6_BYTES 16
+#define IPV6_ADDR_STR_LEN 39
+_PUBLIC_ enum ndr_err_code ndr_pull_ipv6address(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **address)
+{
+ uint8_t addr[IPV6_BYTES];
+ char *addr_str = talloc_strdup(ndr->current_mem_ctx, "");
+ int i;
+ NDR_ERR_HAVE_NO_MEMORY(addr_str);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, ndr_flags, addr, IPV6_BYTES));
+ for (i = 0; i < IPV6_BYTES; ++i) {
+ addr_str = talloc_asprintf_append(addr_str, "%02x", addr[i]);
+ NDR_ERR_HAVE_NO_MEMORY(addr_str);
+ /* We need a ':' every second byte but the last one */
+ if (i%2 == 1 && i != (IPV6_BYTES - 1)) {
+ addr_str = talloc_strdup_append(addr_str, ":");
+ NDR_ERR_HAVE_NO_MEMORY(addr_str);
+ }
+ }
+ *address = addr_str;
+ NDR_ERR_HAVE_NO_MEMORY(*address);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a ipv6address
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_ipv6address(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *address)
+{
+#ifdef AF_INET6
+ uint8_t addr[IPV6_BYTES];
+ int ret;
+
+ if (!is_ipaddress(address)) {
+ return ndr_push_error(ndr, NDR_ERR_IPV6ADDRESS,
+ "Invalid IPv6 address: '%s'",
+ address);
+ }
+ ret = inet_pton(AF_INET6, address, addr);
+ if (ret <= 0) {
+ return NDR_ERR_IPV6ADDRESS;
+ }
+
+ NDR_CHECK(ndr_push_array_uint8(ndr, ndr_flags, addr, IPV6_BYTES));
+
+ return NDR_ERR_SUCCESS;
+#else
+ return NDR_ERR_IPV6ADDRESS;
+#endif
+}
+
+/*
+ print a ipv6address
+*/
+_PUBLIC_ void ndr_print_ipv6address(struct ndr_print *ndr, const char *name,
+ const char *address)
+{
+ ndr->print(ndr, "%-25s: %s", name, address);
+}
+#undef IPV6_BYTES
+
+_PUBLIC_ void ndr_print_struct(struct ndr_print *ndr, const char *name, const char *type)
+{
+ ndr->print(ndr, "%s: struct %s", name, type);
+}
+
+_PUBLIC_ void ndr_print_null(struct ndr_print *ndr)
+{
+ ndr->print(ndr, "UNEXPECTED NULL POINTER");
+}
+
+_PUBLIC_ void ndr_print_enum(struct ndr_print *ndr, const char *name, const char *type,
+ const char *val, uint32_t value)
+{
+ if (ndr->flags & LIBNDR_PRINT_ARRAY_HEX) {
+ ndr->print(ndr, "%-25s: %s (0x%"PRIX32")", name, val?val:"UNKNOWN_ENUM_VALUE", value);
+ } else {
+ ndr->print(ndr, "%-25s: %s (%"PRIu32")", name, val?val:"UNKNOWN_ENUM_VALUE", value);
+ }
+}
+
+_PUBLIC_ void ndr_print_bitmap_flag(struct ndr_print *ndr, size_t size, const char *flag_name, uint32_t flag, uint32_t value)
+{
+ if (flag == 0) {
+ return;
+ }
+
+ /* this is an attempt to support multi-bit bitmap masks */
+ value &= flag;
+
+ while (!(flag & 1)) {
+ flag >>= 1;
+ value >>= 1;
+ }
+ if (flag == 1) {
+ ndr->print(ndr, " %"PRIu32": %-25s", value, flag_name);
+ } else {
+ ndr->print(ndr, "0x%02"PRIx32": %-25s (%"PRIu32")", value, flag_name, value);
+ }
+}
+
+_PUBLIC_ void ndr_print_int8(struct ndr_print *ndr, const char *name, int8_t v)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ ndr->print(ndr, "%-25s: %"PRId8, name, v);
+}
+
+_PUBLIC_ void ndr_print_uint8(struct ndr_print *ndr, const char *name, uint8_t v)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ ndr->print(ndr, "%-25s: 0x%02"PRIx8" (%"PRIu8")", name, v, v);
+}
+
+_PUBLIC_ void ndr_print_int16(struct ndr_print *ndr, const char *name, int16_t v)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ ndr->print(ndr, "%-25s: %"PRId16, name, v);
+}
+
+_PUBLIC_ void ndr_print_uint16(struct ndr_print *ndr, const char *name, uint16_t v)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ ndr->print(ndr, "%-25s: 0x%04"PRIx16" (%"PRIu16")", name, v, v);
+}
+
+_PUBLIC_ void ndr_print_int32(struct ndr_print *ndr, const char *name, int32_t v)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ ndr->print(ndr, "%-25s: %"PRId32, name, v);
+}
+
+_PUBLIC_ void ndr_print_uint32(struct ndr_print *ndr, const char *name, uint32_t v)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ ndr->print(ndr, "%-25s: 0x%08"PRIx32" (%"PRIu32")", name, v, v);
+}
+
+_PUBLIC_ void ndr_print_int3264(struct ndr_print *ndr, const char *name, int32_t v)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ ndr->print(ndr, "%-25s: %"PRId32, name, v);
+}
+
+_PUBLIC_ void ndr_print_uint3264(struct ndr_print *ndr, const char *name, uint32_t v)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ ndr->print(ndr, "%-25s: 0x%08"PRIx32" (%"PRIu32")", name, v, v);
+}
+
+_PUBLIC_ void ndr_print_udlong(struct ndr_print *ndr, const char *name, uint64_t v)
+{
+ ndr->print(ndr, "%-25s: 0x%016"PRIx64" (%"PRIu64")", name, v, v);
+}
+
+_PUBLIC_ void ndr_print_udlongr(struct ndr_print *ndr, const char *name, uint64_t v)
+{
+ ndr_print_udlong(ndr, name, v);
+}
+
+_PUBLIC_ void ndr_print_dlong(struct ndr_print *ndr, const char *name, int64_t v)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ ndr->print(ndr, "%-25s: 0x%016"PRIx64" (%"PRId64")", name, v, v);
+}
+
+_PUBLIC_ void ndr_print_double(struct ndr_print *ndr, const char *name, double v)
+{
+ ndr->print(ndr, "%-25s: %f", name, v);
+}
+
+_PUBLIC_ void ndr_print_hyper(struct ndr_print *ndr, const char *name, uint64_t v)
+{
+ ndr_print_dlong(ndr, name, v);
+}
+
+_PUBLIC_ void ndr_print_int64(struct ndr_print *ndr, const char *name, int64_t v)
+{
+ ndr_print_dlong(ndr, name, v);
+}
+
+_PUBLIC_ void ndr_print_pointer(struct ndr_print *ndr, const char *name, void *v)
+{
+ ndr->print(ndr, "%-25s: %p", name, v);
+}
+
+_PUBLIC_ void ndr_print_ptr(struct ndr_print *ndr, const char *name, const void *p)
+{
+ if (p) {
+ ndr->print(ndr, "%-25s: *", name);
+ } else {
+ ndr->print(ndr, "%-25s: NULL", name);
+ }
+}
+
+_PUBLIC_ void ndr_print_NTTIME(struct ndr_print *ndr, const char *name, NTTIME t)
+{
+ ndr->print(ndr, "%-25s: %s", name, nt_time_string(ndr, t));
+}
+
+_PUBLIC_ void ndr_print_NTTIME_1sec(struct ndr_print *ndr, const char *name, NTTIME t)
+{
+ /* this is a standard NTTIME here
+ * as it's already converted in the pull/push code
+ */
+ ndr_print_NTTIME(ndr, name, t);
+}
+
+_PUBLIC_ void ndr_print_NTTIME_hyper(struct ndr_print *ndr, const char *name, NTTIME t)
+{
+ ndr_print_NTTIME(ndr, name, t);
+}
+
+_PUBLIC_ void ndr_print_time_t(struct ndr_print *ndr, const char *name, time_t t)
+{
+ if (t == (time_t)-1 || t == 0) {
+ ndr->print(ndr, "%-25s: (time_t)%d", name, (int)t);
+ } else {
+ ndr->print(ndr, "%-25s: %s", name, timestring(ndr, t));
+ }
+}
+
+_PUBLIC_ void ndr_print_uid_t(struct ndr_print *ndr, const char *name, uid_t u)
+{
+ ndr_print_dlong(ndr, name, u);
+}
+
+_PUBLIC_ void ndr_print_gid_t(struct ndr_print *ndr, const char *name, gid_t g)
+{
+ ndr_print_dlong(ndr, name, g);
+}
+
+_PUBLIC_ void ndr_print_union(struct ndr_print *ndr, const char *name, int level, const char *type)
+{
+ if (ndr->flags & LIBNDR_PRINT_ARRAY_HEX) {
+ ndr->print(ndr, "%-25s: union %s(case 0x%X)", name, type, level);
+ } else {
+ ndr->print(ndr, "%-25s: union %s(case %d)", name, type, level);
+ }
+}
+
+_PUBLIC_ void ndr_print_bad_level(struct ndr_print *ndr, const char *name, uint16_t level)
+{
+ ndr->print(ndr, "UNKNOWN LEVEL %"PRIu16, level);
+}
+
+_PUBLIC_ void ndr_print_array_uint8(struct ndr_print *ndr, const char *name,
+ const uint8_t *data, uint32_t count)
+{
+ uint32_t i;
+#define _ONELINE_LIMIT 32
+
+ if (data == NULL) {
+ ndr->print(ndr, "%s: ARRAY(%"PRIu32") : NULL", name, count);
+ return;
+ }
+
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%s: ARRAY(%"PRIu32"): <REDACTED SECRET VALUES>", name, count);
+ return;
+ }
+
+ if (count <= _ONELINE_LIMIT && (ndr->flags & LIBNDR_PRINT_ARRAY_HEX)) {
+ char s[(_ONELINE_LIMIT + 1) * 2];
+ for (i=0;i<count;i++) {
+ snprintf(&s[i*2], 3, "%02"PRIx8, data[i]);
+ }
+ s[i*2] = 0;
+ ndr->print(ndr, "%-25s: %s", name, s);
+ return;
+ }
+
+ ndr->print(ndr, "%s: ARRAY(%"PRIu32")", name, count);
+ if (count > _ONELINE_LIMIT && (ndr->flags & LIBNDR_PRINT_ARRAY_HEX)) {
+ ndr_dump_data(ndr, data, count);
+ return;
+ }
+
+ ndr->depth++;
+ for (i=0;i<count;i++) {
+ char *idx=NULL;
+ if (asprintf(&idx, "[%"PRIu32"]", i) != -1) {
+ ndr_print_uint8(ndr, idx, data[i]);
+ free(idx);
+ }
+ }
+ ndr->depth--;
+#undef _ONELINE_LIMIT
+}
+
+static void ndr_print_dump_data_cb(const char *buf, void *private_data)
+{
+ struct ndr_print *ndr = (struct ndr_print *)private_data;
+
+ ndr->print(ndr, "%s", buf);
+}
+
+/*
+ ndr_print version of dump_data()
+ */
+static void ndr_dump_data(struct ndr_print *ndr, const uint8_t *buf, int len)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ return;
+ }
+ ndr->no_newline = true;
+ dump_data_cb(buf, len, true, ndr_print_dump_data_cb, ndr);
+ ndr->no_newline = false;
+}
+
+
+_PUBLIC_ void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_BLOB r)
+{
+ ndr->print(ndr, "%-25s: DATA_BLOB length=%zu", name, r.length);
+ if (r.length) {
+ ndr_dump_data(ndr, r.data, r.length);
+ }
+}
+
+
+/*
+ * Push a DATA_BLOB onto the wire.
+ * 1) When called with LIBNDR_FLAG_ALIGN* alignment flags set, push padding
+ * bytes _only_. The length is determined by the alignment required and the
+ * current ndr offset.
+ * 2) When called with the LIBNDR_FLAG_REMAINING flag, push the byte array to
+ * the ndr buffer.
+ * 3) Otherwise, push a uint3264 length _and_ a corresponding byte array to the
+ * ndr buffer.
+ */
+_PUBLIC_ enum ndr_err_code ndr_push_DATA_BLOB(struct ndr_push *ndr, ndr_flags_type ndr_flags, DATA_BLOB blob)
+{
+ if (ndr->flags & LIBNDR_FLAG_REMAINING) {
+ /* nothing to do */
+ } else if (ndr->flags & (LIBNDR_ALIGN_FLAGS & ~LIBNDR_FLAG_NOALIGN)) {
+ if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+ blob.length = NDR_ALIGN(ndr, 2);
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
+ blob.length = NDR_ALIGN(ndr, 4);
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
+ blob.length = NDR_ALIGN(ndr, 8);
+ }
+ NDR_PUSH_ALLOC_SIZE(ndr, blob.data, blob.length);
+ data_blob_clear(&blob);
+ } else {
+ NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, blob.length));
+ }
+ NDR_CHECK(ndr_push_bytes(ndr, blob.data, blob.length));
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ * Pull a DATA_BLOB from the wire.
+ * 1) when called with LIBNDR_FLAG_ALIGN* alignment flags set, pull padding
+ * bytes _only_. The length is determined by the alignment required and the
+ * current ndr offset.
+ * 2) When called with the LIBNDR_FLAG_REMAINING flag, pull all remaining bytes
+ * from the ndr buffer.
+ * 3) Otherwise, pull a uint3264 length _and_ a corresponding byte array from the
+ * ndr buffer.
+ */
+_PUBLIC_ enum ndr_err_code ndr_pull_DATA_BLOB(struct ndr_pull *ndr, ndr_flags_type ndr_flags, DATA_BLOB *blob)
+{
+ uint32_t length = 0;
+
+ if (ndr->flags & LIBNDR_FLAG_REMAINING) {
+ length = ndr->data_size - ndr->offset;
+ } else if (ndr->flags & (LIBNDR_ALIGN_FLAGS & ~LIBNDR_FLAG_NOALIGN)) {
+ if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+ length = NDR_ALIGN(ndr, 2);
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
+ length = NDR_ALIGN(ndr, 4);
+ } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
+ length = NDR_ALIGN(ndr, 8);
+ }
+ if (ndr->data_size - ndr->offset < length) {
+ length = ndr->data_size - ndr->offset;
+ }
+ } else {
+ NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
+ }
+ if (length == 0) {
+ /* skip the talloc for an empty blob */
+ blob->data = NULL;
+ blob->length = 0;
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_PULL_NEED_BYTES(ndr, length);
+ *blob = data_blob_talloc(ndr->current_mem_ctx, ndr->data+ndr->offset, length);
+ ndr->offset += length;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ uint32_t ndr_size_DATA_BLOB(int ret, const DATA_BLOB *data, ndr_flags_type flags)
+{
+ if (!data) return ret;
+ return ret + data->length;
+}
+
+_PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b)
+{
+ ndr->print(ndr, "%-25s: %s", name, b?"true":"false");
+}
+
+_PUBLIC_ NTSTATUS ndr_map_error2ntstatus(enum ndr_err_code ndr_err)
+{
+ switch (ndr_err) {
+ case NDR_ERR_SUCCESS:
+ return NT_STATUS_OK;
+ case NDR_ERR_BUFSIZE:
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ case NDR_ERR_TOKEN:
+ return NT_STATUS_INTERNAL_ERROR;
+ case NDR_ERR_ALLOC:
+ return NT_STATUS_NO_MEMORY;
+ case NDR_ERR_ARRAY_SIZE:
+ return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
+ case NDR_ERR_INVALID_POINTER:
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ case NDR_ERR_UNREAD_BYTES:
+ return NT_STATUS_PORT_MESSAGE_TOO_LONG;
+ default:
+ break;
+ }
+
+ /* we should map all error codes to different status codes */
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+_PUBLIC_ int ndr_map_error2errno(enum ndr_err_code ndr_err)
+{
+ switch (ndr_err) {
+ case NDR_ERR_SUCCESS:
+ return 0;
+ case NDR_ERR_BUFSIZE:
+ return ENOSPC;
+ case NDR_ERR_TOKEN:
+ return EINVAL;
+ case NDR_ERR_ALLOC:
+ return ENOMEM;
+ case NDR_ERR_ARRAY_SIZE:
+ return EMSGSIZE;
+ case NDR_ERR_INVALID_POINTER:
+ return EINVAL;
+ case NDR_ERR_UNREAD_BYTES:
+ return EOVERFLOW;
+ default:
+ break;
+ }
+
+ /* we should map all error codes to different status codes */
+ return EINVAL;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_timespec(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct timespec *t)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t->tv_sec));
+ NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, t->tv_nsec));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_timespec(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct timespec *t)
+{
+ uint64_t secs = 0;
+ uint32_t nsecs = 0;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &secs));
+ NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &nsecs));
+ t->tv_sec = secs;
+ t->tv_nsec = nsecs;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_timespec(struct ndr_print *ndr, const char *name,
+ const struct timespec *t)
+{
+ char *str = timestring(ndr, t->tv_sec);
+ ndr->print(ndr, "%-25s: %s.%ld", name, str, t->tv_nsec);
+ TALLOC_FREE(str);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_timeval(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct timeval *t)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_push_hyper(ndr, ndr_flags, t->tv_sec));
+ NDR_CHECK(ndr_push_uint32(ndr, ndr_flags, t->tv_usec));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_timeval(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct timeval *t)
+{
+ uint64_t secs = 0;
+ uint32_t usecs = 0;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ NDR_CHECK(ndr_pull_hyper(ndr, ndr_flags, &secs));
+ NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &usecs));
+ t->tv_sec = secs;
+ t->tv_usec = usecs;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_timeval(struct ndr_print *ndr, const char *name,
+ const struct timeval *t)
+{
+ ndr->print(ndr, "%-25s: %s.%ld", name, timestring(ndr, t->tv_sec),
+ (long)t->tv_usec);
+}
+
+_PUBLIC_ void ndr_print_libndr_flags(struct ndr_print *ndr, const char *name,
+ libndr_flags flags)
+{
+ ndr->print(ndr, "%-25s: 0x%016"PRI_LIBNDR_FLAGS" (%"PRI_LIBNDR_FLAGS_DECIMAL")", name, flags, flags);
+}
diff --git a/librpc/ndr/ndr_bkupblobs.c b/librpc/ndr/ndr_bkupblobs.c
new file mode 100644
index 0000000..34c1839
--- /dev/null
+++ b/librpc/ndr/ndr_bkupblobs.c
@@ -0,0 +1,82 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ helper routines for BKUP Blobs marshalling
+
+ Copyright (C) Matthieu Patou <mat@matws.net> 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 "librpc/gen_ndr/ndr_bkupblobs.h"
+
+
+_PUBLIC_ enum ndr_err_code ndr_push_bkup_NTBackupFile(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct bkup_NTBackupFile *r)
+{
+ uint32_t cntr_streams_0;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ for (cntr_streams_0 = 0; cntr_streams_0 < r->num_stream; cntr_streams_0++) {
+ NDR_CHECK(ndr_push_bkup_Win32StreamId(ndr, NDR_SCALARS, &r->streams[cntr_streams_0]));
+ }
+ NDR_CHECK(ndr_push_trailer_align(ndr, 8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+#define _TMP_PULL_REALLOC_N(ndr, s, t, n) do { \
+ _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\
+ (s) = talloc_realloc(ndr->current_mem_ctx, (s), t, n); \
+ if (!(s)) { \
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, \
+ "Alloc %u * %s failed: %s\n", \
+ (unsigned)n, # s, __location__); \
+ } \
+} while (0)
+
+_PUBLIC_ enum ndr_err_code ndr_pull_bkup_NTBackupFile(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct bkup_NTBackupFile *r)
+{
+ uint32_t cntr_streams_0;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t remaining = ndr->data_size - ndr->offset;
+ r->num_stream = 0;
+ r->streams = NULL;
+ for (cntr_streams_0 = 0; remaining > 0; cntr_streams_0++) {
+ r->num_stream += 1;
+ _TMP_PULL_REALLOC_N(ndr, r->streams,
+ struct bkup_Win32StreamId,
+ r->num_stream);
+ NDR_CHECK(ndr_pull_bkup_Win32StreamId(ndr,
+ NDR_SCALARS,
+ &r->streams[cntr_streams_0]));
+ remaining = ndr->data_size - ndr->offset;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_cab.c b/librpc/ndr/ndr_cab.c
new file mode 100644
index 0000000..ae3353b
--- /dev/null
+++ b/librpc/ndr/ndr_cab.c
@@ -0,0 +1,442 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling cab structures
+
+ 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_cab.h"
+#include "librpc/ndr/ndr_compression.h"
+
+#define OFFSET_OF_FOLDER_COFFCABSTART(folder) (36 /* cfheader size */ + (size_t)(folder)*8)
+
+_PUBLIC_ void ndr_print_cf_time(struct ndr_print *ndr, const char *name, const struct cf_time *r)
+{
+ uint8_t hour = 0, minute = 0, seconds = 0;
+ char *s;
+ if (r == NULL) { ndr_print_null(ndr); return; }
+ hour = r->time >> 11;
+ minute = (r->time >> 5) & 0x3f;
+ seconds = (r->time << 1) & 0x3e;
+ s = talloc_asprintf(ndr, "%02d:%02d:%02d", hour, minute, seconds);
+ if (s == NULL) { return; }
+ ndr_print_string(ndr, "time", s);
+ talloc_free(s);
+}
+
+_PUBLIC_ void ndr_print_cf_date(struct ndr_print *ndr, const char *name, const struct cf_date *r)
+{
+ uint16_t year = 0;
+ uint8_t month = 0, day = 0;
+ char *s;
+ if (r == NULL) { ndr_print_null(ndr); return; }
+ year = (r->date >> 9);
+ year += 1980;
+ month = (r->date >> 5 & 0xf);
+ day = (r->date & 0x1f);
+ s = talloc_asprintf(ndr, "%02"PRIu8"/%02"PRIu8"/%04"PRIu16, day, month, year);
+ if (s == NULL) { return; }
+ ndr_print_string(ndr, "date", s);
+ talloc_free(s);
+}
+
+uint32_t ndr_count_cfdata(const struct cab_file *r)
+{
+ uint32_t count = 0, i;
+
+ for (i = 0; i < r->cfheader.cFolders; i++) {
+ if (count + r->cffolders[i].cCFData < count) {
+ /* Integer wrap. */
+ return 0;
+ }
+ count += r->cffolders[i].cCFData;
+ }
+
+ return count;
+}
+
+static uint32_t ndr_cab_compute_checksum(uint8_t *data, uint32_t length, uint32_t seed)
+{
+ int num_ulong;
+ uint32_t checksum;
+ uint8_t *pb;
+ uint32_t ul;
+
+ num_ulong = length / 4;
+ checksum = seed;
+ pb = data;
+
+ while (num_ulong-- > 0) {
+ ul = (uint32_t)(*pb++);
+ ul |= (((uint32_t)(*pb++)) << 8);
+ ul |= (((uint32_t)(*pb++)) << 16);
+ ul |= (((uint32_t)(*pb++)) << 24);
+
+ checksum ^= ul;
+ }
+
+ ul = 0;
+
+ switch (length % 4) {
+ case 3:
+ ul |= (((uint32_t)(*pb++)) << 16);
+ FALL_THROUGH;
+ case 2:
+ ul |= (((uint32_t)(*pb++)) << 8);
+ FALL_THROUGH;
+ case 1:
+ ul |= (uint32_t)(*pb++);
+ FALL_THROUGH;
+ default:
+ break;
+ }
+
+ checksum ^= ul;
+
+ return checksum;
+}
+
+/* Push all CFDATA of a folder.
+ *
+ * This works on a folder level because compression type is set per
+ * folder, and a compression state can be shared between CFDATA of the
+ * same folder.
+ *
+ * This is not a regular NDR func as we pass the compression type and
+ * the number of CFDATA as extra arguments
+ */
+static enum ndr_err_code ndr_push_folder_cfdata(struct ndr_push *ndr,
+ const struct CFDATA *r,
+ enum cf_compress_type cab_ctype,
+ size_t num_cfdata)
+{
+ size_t i;
+ enum ndr_compression_alg ndr_ctype = 0;
+
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
+
+ if (cab_ctype == CF_COMPRESS_MSZIP) {
+ ndr_ctype = NDR_COMPRESSION_MSZIP_CAB;
+ NDR_CHECK(ndr_push_compression_state_init(ndr, ndr_ctype));
+ }
+
+ for (i = 0; i < num_cfdata; i++, r++) {
+ uint32_t compressed_length = 0;
+ uint32_t csum, csumPartial;
+ size_t compressed_offset, csum_offset, data_offset;
+
+ if (!r->ab.data) {
+ return ndr_push_error(ndr, NDR_ERR_LENGTH,
+ "NULL uncompressed data blob");
+ }
+ if (r->ab.length != r->cbUncomp) {
+ return ndr_push_error(ndr, NDR_ERR_LENGTH,
+ "Uncompressed data blob size != uncompressed data size field");
+ }
+
+ /*
+ * checksum is a function of the size fields
+ * and the potentially compressed data bytes,
+ * which haven't been compressed yet so
+ * remember offset, write zeroes, fill out
+ * later
+ */
+ csum_offset = ndr->offset;
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+
+ /*
+ * similarly, we don't know the compressed
+ * size yet, remember offset, write zeros,
+ * fill out later
+ */
+ compressed_offset = ndr->offset;
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->cbUncomp));
+
+ data_offset = ndr->offset;
+
+ switch (cab_ctype) {
+ case CF_COMPRESS_NONE:
+ /* just copy the data */
+ NDR_PUSH_NEED_BYTES(ndr, r->ab.length);
+ NDR_CHECK(ndr_push_bytes(ndr, r->ab.data, r->ab.length));
+ compressed_length = r->ab.length;
+ break;
+ case CF_COMPRESS_LZX:
+ /*
+ * we have not yet worked out the details of LZX
+ * compression
+ */
+ return NDR_ERR_COMPRESSION;
+
+ case CF_COMPRESS_MSZIP: {
+ struct ndr_push *push_sub, *push_compress;
+
+ /* compress via subcontext */
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &push_sub, 0, -1));
+
+ /*
+ * This assignment replaces a call to
+ * ndr_push_compression_state_init(push_sub, ndr_ctype))
+ * here. This is instead done outside the loop.
+ */
+ push_sub->cstate = ndr->cstate;
+
+ NDR_CHECK(ndr_push_compression_start(push_sub, &push_compress));
+ ndr_set_flags(&push_compress->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_push_DATA_BLOB(push_compress, NDR_SCALARS, r->ab));
+ NDR_CHECK(ndr_push_compression_end(push_sub, push_compress));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, push_sub, 0, -1));
+ compressed_length = push_sub->offset;
+
+ break;
+ }
+ default:
+ return NDR_ERR_BAD_SWITCH;
+ }
+
+ /* we can now write the compressed size and the checksum */
+ SSVAL(ndr->data, compressed_offset, compressed_length);
+
+ /*
+ * Create checksum over compressed data.
+ *
+ * The 8 bytes are the header size.
+ *
+ * We have already have written the checksum and set it to zero,
+ * earlier. So we know that after the checksum end the value
+ * for the compressed length comes the blob data.
+ *
+ * NDR already did all the checks for integer wraps.
+ */
+ csumPartial = ndr_cab_compute_checksum(&ndr->data[data_offset],
+ compressed_length, 0);
+
+ /*
+ * Checksum over header (compressed and uncompressed length).
+ *
+ * The first 4 bytes are the checksum size.
+ * The second 4 bytes are the size of the compressed and
+ * uncompressed length fields.
+ *
+ * NDR already did all the checks for integer wraps.
+ */
+ csum = ndr_cab_compute_checksum(&ndr->data[compressed_offset],
+ data_offset - compressed_offset,
+ csumPartial);
+
+ SIVAL(ndr->data, csum_offset, csum);
+ }
+
+ TALLOC_FREE(ndr->cstate);
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_cab_file(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct cab_file *r)
+{
+ uint32_t cntr_cffolders_0;
+ uint32_t cntr_cffiles_0;
+ size_t processed_cfdata = 0;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t i;
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_CFHEADER(ndr, NDR_SCALARS, &r->cfheader));
+ for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (r->cfheader.cFolders); cntr_cffolders_0++) {
+ NDR_CHECK(ndr_push_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0]));
+ }
+ for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (r->cfheader.cFiles); cntr_cffiles_0++) {
+ NDR_CHECK(ndr_push_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0]));
+ }
+#if 0
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_count_cfdata(r)));
+#endif
+
+ /* write in the folder header the offset of its first data block */
+ for (i = 0; i < r->cfheader.cFolders; i++) {
+ size_t off = OFFSET_OF_FOLDER_COFFCABSTART(i);
+ /* check that the offset we want to
+ * write to is always inside our
+ * current push buffer
+ */
+ if (off >= ndr->offset) {
+ return ndr_push_error(ndr, NDR_ERR_OFFSET,
+ "trying to write past current push buffer size");
+ }
+ SIVAL(ndr->data, off, ndr->offset);
+ NDR_CHECK(ndr_push_folder_cfdata(ndr, r->cfdata + processed_cfdata, r->cffolders[i].typeCompress, r->cffolders[i].cCFData));
+ processed_cfdata += r->cffolders[i].cCFData;
+ }
+ NDR_CHECK(ndr_push_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+
+
+ /* write total file size in header */
+ SIVAL(ndr->data, 8, ndr->offset);
+
+ return NDR_ERR_SUCCESS;
+}
+
+
+/* Pull all CFDATA of a folder.
+ *
+ * This works on a folder level because compression type is set per
+ * folder, and a compression state can be shared between CFDATA of the
+ * same folder.
+ *
+ * This is not a regular NDR func as we pass the compression type and
+ * the number of CFDATA as extra arguments
+ */
+static enum ndr_err_code ndr_pull_folder_cfdata(struct ndr_pull *ndr,
+ struct CFDATA *r,
+ enum cf_compress_type cab_ctype,
+ size_t num_cfdata)
+{
+ size_t i;
+ enum ndr_compression_alg ndr_ctype = 0;
+
+ if (cab_ctype == CF_COMPRESS_MSZIP) {
+ ndr_ctype = NDR_COMPRESSION_MSZIP_CAB;
+ NDR_CHECK(ndr_pull_compression_state_init(ndr, NDR_COMPRESSION_MSZIP_CAB, &ndr->cstate));
+ }
+
+ for (i = 0; i < num_cfdata; i++, r++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->csum));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->cbData));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->cbUncomp));
+
+ switch (cab_ctype) {
+ case CF_COMPRESS_NONE:
+ /* just copy the data */
+ NDR_PULL_NEED_BYTES(ndr, r->cbUncomp);
+ r->ab = data_blob_talloc(ndr->current_mem_ctx,
+ ndr->data+ndr->offset,
+ r->cbUncomp);
+ if (r->ab.data == NULL) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC,
+ "failed to allocate buffer for uncompressed CFDATA block");
+ }
+ ndr->offset += r->cbUncomp;
+ break;
+
+ case CF_COMPRESS_LZX:
+ /* just copy the data (LZX decompression not implemented yet) */
+ NDR_PULL_NEED_BYTES(ndr, r->cbData);
+ r->ab = data_blob_talloc(ndr->current_mem_ctx,
+ ndr->data+ndr->offset,
+ r->cbData);
+ if (r->ab.data == NULL) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC,
+ "failed to allocate buffer for LZX-compressed CFDATA block");
+ }
+ ndr->offset += r->cbData;
+ break;
+
+ case CF_COMPRESS_MSZIP: {
+ struct ndr_pull *pull_sub, *pull_compress;
+ NDR_PULL_NEED_BYTES(ndr, r->cbData);
+ /* decompress via subcontext */
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &pull_sub, 0, r->cbData));
+ pull_sub->cstate = ndr->cstate;
+ NDR_CHECK(ndr_pull_compression_start(pull_sub, &pull_compress,
+ ndr_ctype, r->cbUncomp, r->cbData));
+ ndr_set_flags(&pull_compress->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(pull_compress, NDR_SCALARS, &r->ab));
+ NDR_CHECK(ndr_pull_compression_end(pull_sub, pull_compress, ndr_ctype, r->cbUncomp));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, pull_sub, 0, r->cbData));
+
+ break;
+ }
+ default:
+ return NDR_ERR_BAD_SWITCH;
+ }
+ }
+
+ TALLOC_FREE(ndr->cstate);
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_cab_file(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct cab_file *r)
+{
+ uint32_t size_cffolders_0 = 0;
+ uint32_t cntr_cffolders_0;
+ TALLOC_CTX *_mem_save_cffolders_0 = NULL;
+ uint32_t size_cffiles_0 = 0;
+ uint32_t cntr_cffiles_0;
+ TALLOC_CTX *_mem_save_cffiles_0 = NULL;
+ uint32_t size_cfdata_0 = 0;
+ size_t processed_cfdata = 0;
+ TALLOC_CTX *_mem_save_cfdata_0 = NULL;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX|LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NOALIGN);
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_CFHEADER(ndr, NDR_SCALARS, &r->cfheader));
+ size_cffolders_0 = r->cfheader.cFolders;
+ NDR_PULL_ALLOC_N(ndr, r->cffolders, size_cffolders_0);
+ _mem_save_cffolders_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cffolders, 0);
+ for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (size_cffolders_0); cntr_cffolders_0++) {
+ NDR_CHECK(ndr_pull_CFFOLDER(ndr, NDR_SCALARS, &r->cffolders[cntr_cffolders_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffolders_0, 0);
+ size_cffiles_0 = r->cfheader.cFiles;
+ NDR_PULL_ALLOC_N(ndr, r->cffiles, size_cffiles_0);
+ _mem_save_cffiles_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cffiles, 0);
+ for (cntr_cffiles_0 = 0; cntr_cffiles_0 < (size_cffiles_0); cntr_cffiles_0++) {
+ NDR_CHECK(ndr_pull_CFFILE(ndr, NDR_SCALARS, &r->cffiles[cntr_cffiles_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cffiles_0, 0);
+#if 0
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->cfdata_count));
+#else
+ r->cfdata_count = ndr_count_cfdata(r);
+#endif
+ size_cfdata_0 = r->cfdata_count;
+ NDR_PULL_ALLOC_N(ndr, r->cfdata, size_cfdata_0);
+ _mem_save_cfdata_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->cfdata, 0);
+ for (cntr_cffolders_0 = 0; cntr_cffolders_0 < (size_cffolders_0); cntr_cffolders_0++) {
+ NDR_CHECK(ndr_pull_folder_cfdata(ndr,
+ r->cfdata + processed_cfdata,
+ r->cffolders[cntr_cffolders_0].typeCompress,
+ r->cffolders[cntr_cffolders_0].cCFData));
+ processed_cfdata += r->cffolders[cntr_cffolders_0].cCFData;
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_cfdata_0, 0);
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_cab.h b/librpc/ndr/ndr_cab.h
new file mode 100644
index 0000000..39b6bc9
--- /dev/null
+++ b/librpc/ndr/ndr_cab.h
@@ -0,0 +1,22 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling cab structures
+
+ 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/>.
+*/
+
+uint32_t ndr_count_cfdata(const struct cab_file *r);
diff --git a/librpc/ndr/ndr_claims.c b/librpc/ndr/ndr_claims.c
new file mode 100644
index 0000000..9612626
--- /dev/null
+++ b/librpc/ndr/ndr_claims.c
@@ -0,0 +1,90 @@
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_claims.h"
+#include "librpc/ndr/ndr_claims.h"
+
+#include "librpc/ndr/ndr_compression.h"
+#include "lib/compression/lzxpress_huffman.h"
+
+enum ndr_compression_alg ndr_claims_compression_alg(enum CLAIMS_COMPRESSION_FORMAT wire_alg)
+{
+ switch (wire_alg) {
+ case CLAIMS_COMPRESSION_FORMAT_NONE:
+ return NDR_COMPRESSION_NONE;
+
+ case CLAIMS_COMPRESSION_FORMAT_LZNT1:
+ return NDR_COMPRESSION_INVALID;
+
+ case CLAIMS_COMPRESSION_FORMAT_XPRESS:
+ return NDR_COMPRESSION_INVALID;
+
+ case CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF:
+ return NDR_COMPRESSION_XPRESS_HUFF_RAW;
+ }
+ return NDR_COMPRESSION_INVALID;
+}
+
+
+enum CLAIMS_COMPRESSION_FORMAT ndr_claims_actual_wire_compression_alg(enum CLAIMS_COMPRESSION_FORMAT specified_compression,
+ size_t uncompressed_claims_size) {
+ if (uncompressed_claims_size < CLAIM_UPPER_COMPRESSION_THRESHOLD) {
+ return CLAIMS_COMPRESSION_FORMAT_NONE;
+ }
+
+ return specified_compression;
+}
+
+size_t ndr_claims_compressed_size(struct CLAIMS_SET_NDR *claims_set,
+ enum CLAIMS_COMPRESSION_FORMAT wire_alg,
+ int flags)
+{
+ TALLOC_CTX *frame = NULL;
+ DATA_BLOB tmp_blob;
+ uint8_t * tmp_compressed;
+ ssize_t compressed_size;
+ enum ndr_err_code ndr_err;
+ enum CLAIMS_COMPRESSION_FORMAT actual_wire_alg;
+
+ if (claims_set == NULL) {
+ return 0;
+ }
+
+ frame = talloc_stackframe();
+
+ ndr_err = ndr_push_struct_blob(&tmp_blob,
+ frame,
+ claims_set,
+ (ndr_push_flags_fn_t)ndr_push_CLAIMS_SET_NDR);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ DBG_ERR("Failed to push claims while determining compressed size\n");
+ TALLOC_FREE(frame);
+ return 0;
+ }
+
+ actual_wire_alg = ndr_claims_actual_wire_compression_alg(wire_alg,
+ tmp_blob.length);
+
+ switch (actual_wire_alg) {
+ case CLAIMS_COMPRESSION_FORMAT_NONE:
+ TALLOC_FREE(frame);
+ return tmp_blob.length;
+
+ case CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF:
+ compressed_size = lzxpress_huffman_compress_talloc(frame,
+ tmp_blob.data,
+ tmp_blob.length,
+ &tmp_compressed);
+
+ TALLOC_FREE(frame);
+
+ if (compressed_size < 0) {
+ DBG_ERR("Failed to compress claims (for determining compressed size)\n");
+ return 0;
+ }
+ return compressed_size;
+
+ default:
+ TALLOC_FREE(frame);
+ DBG_ERR("Invalid chosen compression algorithm while determining compressed claim size\n");
+ return 0;
+ }
+}
diff --git a/librpc/ndr/ndr_claims.h b/librpc/ndr/ndr_claims.h
new file mode 100644
index 0000000..03f4046
--- /dev/null
+++ b/librpc/ndr/ndr_claims.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for helping the compression in claims
+
+ Copyright (C) Andrew Bartlett 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/>.
+*/
+
+#ifndef _LIBRPC_NDR_NDR_CLAIMS_H
+#define _LIBRPC_NDR_NDR_CLAIMS_H
+
+enum ndr_compression_alg ndr_claims_compression_alg(enum CLAIMS_COMPRESSION_FORMAT wire_alg);
+enum CLAIMS_COMPRESSION_FORMAT ndr_claims_actual_wire_compression_alg(enum CLAIMS_COMPRESSION_FORMAT specified_compression,
+ size_t uncompressed_claims_size);
+
+size_t ndr_claims_compressed_size(struct CLAIMS_SET_NDR *claims_set,
+ enum CLAIMS_COMPRESSION_FORMAT wire_alg,
+ int flags);
+
+
+#endif /* _LIBRPC_NDR_NDR_CLAIMS_H */
diff --git a/librpc/ndr/ndr_compression.c b/librpc/ndr/ndr_compression.c
new file mode 100644
index 0000000..6630b51
--- /dev/null
+++ b/librpc/ndr/ndr_compression.c
@@ -0,0 +1,1092 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libndr compression support
+
+ Copyright (C) Stefan Metzmacher 2005
+ Copyright (C) Matthieu Suiche 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/compression/lzxpress.h"
+#include "../lib/compression/lzxpress_huffman.h"
+#include "librpc/ndr/libndr.h"
+#include "../librpc/ndr/ndr_compression.h"
+#include <zlib.h>
+
+struct ndr_compression_state {
+ enum ndr_compression_alg type;
+ union {
+ struct {
+ struct z_stream_s *z;
+ uint8_t *dict;
+ size_t dict_size;
+ } mszip;
+ struct {
+ struct lzxhuff_compressor_mem *mem;
+ } lzxpress_huffman;
+ } alg;
+};
+
+static voidpf ndr_zlib_alloc(voidpf opaque, uInt items, uInt size)
+{
+ return talloc_zero_size(opaque, items * size);
+}
+
+static void ndr_zlib_free(voidpf opaque, voidpf address)
+{
+ talloc_free(address);
+}
+
+static enum ndr_err_code ndr_pull_compression_mszip_cab_chunk(struct ndr_pull *ndrpull,
+ struct ndr_push *ndrpush,
+ struct ndr_compression_state *state,
+ ssize_t decompressed_len,
+ ssize_t compressed_len)
+{
+ DATA_BLOB comp_chunk;
+ uint32_t comp_chunk_offset;
+ uint32_t comp_chunk_size;
+ DATA_BLOB plain_chunk;
+ uint32_t plain_chunk_offset;
+ uint32_t plain_chunk_size;
+ z_stream *z = state->alg.mszip.z;
+ int z_ret;
+
+ plain_chunk_size = decompressed_len;
+
+ if (plain_chunk_size > 0x00008000) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad MSZIP CAB plain chunk size %08"PRIX32" > 0x00008000 (PULL)",
+ plain_chunk_size);
+ }
+
+
+ comp_chunk_size = compressed_len;
+
+ DEBUG(9,("MSZIP CAB plain_chunk_size: %08"PRIX32" (%"PRIu32") comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
+ plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
+
+ comp_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
+ comp_chunk.length = comp_chunk_size;
+ comp_chunk.data = ndrpull->data + comp_chunk_offset;
+
+ plain_chunk_offset = ndrpush->offset;
+ NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
+ plain_chunk.length = plain_chunk_size;
+ plain_chunk.data = ndrpush->data + plain_chunk_offset;
+
+ if (comp_chunk.length < 2) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad MSZIP CAB comp chunk size %zu < 2 (PULL)",
+ comp_chunk.length);
+ }
+ /* CK = Chris Kirmse, official Microsoft purloiner */
+ if (comp_chunk.data[0] != 'C' ||
+ comp_chunk.data[1] != 'K') {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad MSZIP CAB invalid prefix [%c%c] != [CK]",
+ comp_chunk.data[0], comp_chunk.data[1]);
+ }
+
+ /*
+ * This is a MSZIP block. It is actually using the deflate
+ * algorithm which can be decompressed by zlib. zlib will try
+ * to decompress as much as it can in each run. If we provide
+ * all the input and enough room for the uncompressed output,
+ * one call is enough. It will loop over all the sub-blocks
+ * that make up a deflate block.
+ *
+ * See corresponding push function for more info.
+ */
+
+ z->next_in = comp_chunk.data + 2;
+ z->avail_in = comp_chunk.length - 2;
+ z->next_out = plain_chunk.data;
+ z->avail_out = plain_chunk.length;
+
+ /*
+ * Each MSZIP CDATA contains a complete deflate stream
+ * i.e. the stream starts and ends in the CFDATA but the
+ * _dictionary_ is shared between all CFDATA of a CFFOLDER.
+ *
+ * When decompressing, the initial dictionary of the first
+ * CDATA is empty. All other CFDATA use the previous CFDATA
+ * uncompressed output as dictionary.
+ */
+
+ if (state->alg.mszip.dict_size) {
+ z_ret = inflateSetDictionary(z, state->alg.mszip.dict, state->alg.mszip.dict_size);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "zlib inflateSetDictionary error %s (%d) %s (PULL)",
+ zError(z_ret), z_ret, z->msg);
+ }
+ }
+
+ z_ret = inflate(z, Z_FINISH);
+ if (z_ret == Z_OK) {
+ /*
+ * Z_OK here means there was no error but the stream
+ * hasn't been fully decompressed because there was
+ * not enough room for the output, which should not
+ * happen
+ */
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "zlib inflate error not enough space for output (PULL)");
+ }
+ if (z_ret != Z_STREAM_END) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "zlib inflate error %s (%d) %s (PULL)", zError(z_ret), z_ret, z->msg);
+ }
+
+ if (z->total_out < plain_chunk.length) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "zlib uncompressed output is smaller than expected (%lu < %zu) (PULL)",
+ z->total_out, plain_chunk.length);
+ }
+
+ /*
+ * Keep a copy of the output to set as dictionary for the
+ * next decompression call.
+ *
+ * The input pointer seems to be still valid between calls, so
+ * we can just store that instead of copying the memory over
+ * the dict temp buffer.
+ */
+ state->alg.mszip.dict = plain_chunk.data;
+ state->alg.mszip.dict_size = plain_chunk.length;
+
+ z_ret = inflateReset(z);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "zlib inflateReset error %s (%d) %s (PULL)",
+ zError(z_ret), z_ret, z->msg);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_push_compression_mszip_cab_chunk(struct ndr_push *ndrpush,
+ struct ndr_pull *ndrpull,
+ struct ndr_compression_state *state)
+{
+ DATA_BLOB comp_chunk;
+ uint32_t comp_chunk_size;
+ DATA_BLOB plain_chunk;
+ uint32_t plain_chunk_size;
+ uint32_t plain_chunk_offset;
+ uint32_t max_plain_size = 0x00008000;
+ /*
+ * The maximum compressed size of each MSZIP block is 32k + 12 bytes
+ * header size.
+ */
+ uint32_t max_comp_size = 0x00008000 + 12;
+ int z_ret;
+ z_stream *z;
+
+ if (ndrpull->data_size <= ndrpull->offset) {
+ return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+ "strange NDR pull size and offset (integer overflow?)");
+
+ }
+
+ plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
+ plain_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
+
+ plain_chunk.data = ndrpull->data + plain_chunk_offset;
+ plain_chunk.length = plain_chunk_size;
+
+ NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
+
+ comp_chunk.data = ndrpush->data + ndrpush->offset;
+ comp_chunk.length = max_comp_size;
+
+ /* CK = Chris Kirmse, official Microsoft purloiner */
+ comp_chunk.data[0] = 'C';
+ comp_chunk.data[1] = 'K';
+
+ z = state->alg.mszip.z;
+ z->next_in = plain_chunk.data;
+ z->avail_in = plain_chunk.length;
+ z->total_in = 0;
+
+ z->next_out = comp_chunk.data + 2;
+ z->avail_out = comp_chunk.length;
+ z->total_out = 0;
+
+ /*
+ * See pull function for explanations of the MSZIP format.
+ *
+ * The CFDATA block contains a full deflate stream. Each stream
+ * uses the uncompressed input of the previous CFDATA in the
+ * same CFFOLDER as a dictionary for the compression.
+ */
+
+ if (state->alg.mszip.dict_size) {
+ z_ret = deflateSetDictionary(z, state->alg.mszip.dict, state->alg.mszip.dict_size);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "zlib deflateSetDictionary error %s (%d) %s (PUSH)",
+ zError(z_ret), z_ret, z->msg);
+ }
+ }
+
+ /*
+ * Z_FINISH should make deflate process all of the input in
+ * one call. If the stream is not finished there was an error
+ * e.g. not enough room to store the compressed output.
+ */
+ z_ret = deflate(z, Z_FINISH);
+ if (z_ret != Z_STREAM_END) {
+ return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+ "zlib deflate error %s (%d) %s (PUSH)",
+ zError(z_ret), z_ret, z->msg);
+ }
+
+ if (z->avail_in) {
+ return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+ "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
+ z->avail_in);
+ }
+
+ comp_chunk_size = 2 + z->total_out;
+ if (comp_chunk_size < z->total_out) {
+ return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+ "strange NDR push compressed size (integer overflow?)");
+ }
+
+ z_ret = deflateReset(z);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "zlib deflateReset error %s (%d) %s (PUSH)",
+ zError(z_ret), z_ret, z->msg);
+ }
+
+ if (plain_chunk.length > talloc_array_length(state->alg.mszip.dict)) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "zlib dict buffer is too big (PUSH)");
+ }
+
+ /*
+ * Keep a copy of the input to set as dictionary for the next
+ * compression call.
+ *
+ * Ideally we would just store the input pointer and length
+ * without copying but the memory gets invalidated between the
+ * calls, so we just copy to a dedicated buffer we know is
+ * still going to be valid for the lifetime of the
+ * compressions state object.
+ */
+ memcpy(state->alg.mszip.dict, plain_chunk.data, plain_chunk.length);
+ state->alg.mszip.dict_size = plain_chunk.length;
+
+ DEBUG(9,("MSZIP comp plain_chunk_size: %08zX (%zu) comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
+ plain_chunk.length,
+ plain_chunk.length,
+ comp_chunk_size, comp_chunk_size));
+
+ ndrpush->offset += comp_chunk_size;
+ return NDR_ERR_SUCCESS;
+}
+
+
+static enum ndr_err_code ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull,
+ struct ndr_push *ndrpush,
+ z_stream *z,
+ bool *last)
+{
+ DATA_BLOB comp_chunk;
+ uint32_t comp_chunk_offset;
+ uint32_t comp_chunk_size;
+ DATA_BLOB plain_chunk;
+ uint32_t plain_chunk_offset;
+ uint32_t plain_chunk_size;
+ int z_ret;
+
+ NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
+ if (plain_chunk_size > 0x00008000) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad MSZIP plain chunk size %08"PRIX32" > 0x00008000 (PULL)",
+ plain_chunk_size);
+ }
+
+ NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
+
+ DEBUG(9,("MSZIP plain_chunk_size: %08"PRIX32" (%"PRIu32") comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
+ plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
+
+ comp_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
+ comp_chunk.length = comp_chunk_size;
+ comp_chunk.data = ndrpull->data + comp_chunk_offset;
+
+ plain_chunk_offset = ndrpush->offset;
+ NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
+ plain_chunk.length = plain_chunk_size;
+ plain_chunk.data = ndrpush->data + plain_chunk_offset;
+
+ if (comp_chunk.length < 2) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad MSZIP comp chunk size %zu < 2 (PULL)",
+ comp_chunk.length);
+ }
+ /* CK = Chris Kirmse, official Microsoft purloiner */
+ if (comp_chunk.data[0] != 'C' ||
+ comp_chunk.data[1] != 'K') {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad MSZIP invalid prefix [%c%c] != [CK]",
+ comp_chunk.data[0], comp_chunk.data[1]);
+ }
+
+ z->next_in = comp_chunk.data + 2;
+ z->avail_in = comp_chunk.length -2;
+ z->total_in = 0;
+
+ z->next_out = plain_chunk.data;
+ z->avail_out = plain_chunk.length;
+ z->total_out = 0;
+
+ if (!z->opaque) {
+ /* the first time we need to initialize completely */
+ z->zalloc = ndr_zlib_alloc;
+ z->zfree = ndr_zlib_free;
+ z->opaque = ndrpull;
+
+ z_ret = inflateInit2(z, -MAX_WBITS);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad inflateInit2 error %s(%d) (PULL)",
+ zError(z_ret), z_ret);
+
+ }
+ }
+
+ /* call inflate until we get Z_STREAM_END or an error */
+ while (true) {
+ z_ret = inflate(z, Z_BLOCK);
+ if (z_ret != Z_OK) break;
+ }
+
+ if (z_ret != Z_STREAM_END) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad inflate(Z_BLOCK) error %s(%d) (PULL)",
+ zError(z_ret), z_ret);
+ }
+
+ if (z->avail_in) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "MSZIP not all avail_in[%u] bytes consumed (PULL)",
+ z->avail_in);
+ }
+
+ if (z->avail_out) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "MSZIP not all avail_out[%u] bytes consumed (PULL)",
+ z->avail_out);
+ }
+
+ if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
+ /* this is the last chunk */
+ *last = true;
+ }
+
+ z_ret = inflateReset(z);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad inflateReset error %s(%d) (PULL)",
+ zError(z_ret), z_ret);
+ }
+
+ z_ret = inflateSetDictionary(z, plain_chunk.data, plain_chunk.length);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad inflateSetDictionary error %s(%d) (PULL)",
+ zError(z_ret), z_ret);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_push_compression_mszip_chunk(struct ndr_push *ndrpush,
+ struct ndr_pull *ndrpull,
+ z_stream *z,
+ bool *last)
+{
+ DATA_BLOB comp_chunk;
+ uint32_t comp_chunk_size;
+ uint32_t comp_chunk_size_offset;
+ DATA_BLOB plain_chunk;
+ uint32_t plain_chunk_size;
+ uint32_t plain_chunk_offset;
+ uint32_t max_plain_size = 0x00008000;
+ /*
+ * The maximum compressed size of each MSZIP block is 32k + 12 bytes
+ * header size.
+ */
+ uint32_t max_comp_size = 0x00008000 + 12;
+ uint32_t tmp_offset;
+ int z_ret;
+
+ plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
+ plain_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
+
+ plain_chunk.data = ndrpull->data + plain_chunk_offset;
+ plain_chunk.length = plain_chunk_size;
+
+ if (plain_chunk_size < max_plain_size) {
+ *last = true;
+ }
+
+ NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size));
+ comp_chunk_size_offset = ndrpush->offset;
+ NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE));
+
+ NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
+
+ comp_chunk.data = ndrpush->data + ndrpush->offset;
+ comp_chunk.length = max_comp_size;
+
+ /* CK = Chris Kirmse, official Microsoft purloiner */
+ comp_chunk.data[0] = 'C';
+ comp_chunk.data[1] = 'K';
+
+ z->next_in = plain_chunk.data;
+ z->avail_in = plain_chunk.length;
+ z->total_in = 0;
+
+ z->next_out = comp_chunk.data + 2;
+ z->avail_out = comp_chunk.length;
+ z->total_out = 0;
+
+ if (!z->opaque) {
+ /* the first time we need to initialize completely */
+ z->zalloc = ndr_zlib_alloc;
+ z->zfree = ndr_zlib_free;
+ z->opaque = ndrpull;
+
+ /* TODO: find how to trigger the same parameters windows uses */
+ z_ret = deflateInit2(z,
+ Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED,
+ -MAX_WBITS,
+ 8, /* memLevel */
+ Z_DEFAULT_STRATEGY);
+ if (z_ret != Z_OK) {
+ return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+ "Bad deflateInit2 error %s(%d) (PUSH)",
+ zError(z_ret), z_ret);
+
+ }
+ }
+
+ /* call deflate until we get Z_STREAM_END or an error */
+ while (true) {
+ z_ret = deflate(z, Z_FINISH);
+ if (z_ret != Z_OK) break;
+ }
+ if (z_ret != Z_STREAM_END) {
+ return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+ "Bad deflate(Z_BLOCK) error %s(%d) (PUSH)",
+ zError(z_ret), z_ret);
+ }
+
+ if (z->avail_in) {
+ return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+ "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
+ z->avail_in);
+ }
+
+ comp_chunk_size = 2 + z->total_out;
+
+ z_ret = deflateReset(z);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad deflateReset error %s(%d) (PULL)",
+ zError(z_ret), z_ret);
+ }
+
+ z_ret = deflateSetDictionary(z, plain_chunk.data, plain_chunk.length);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "Bad deflateSetDictionary error %s(%d) (PULL)",
+ zError(z_ret), z_ret);
+ }
+
+ tmp_offset = ndrpush->offset;
+ ndrpush->offset = comp_chunk_size_offset;
+ NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk_size));
+ ndrpush->offset = tmp_offset;
+
+ DEBUG(9,("MSZIP comp plain_chunk_size: %08zX (%zu) comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
+ plain_chunk.length,
+ plain_chunk.length,
+ comp_chunk_size, comp_chunk_size));
+
+ ndrpush->offset += comp_chunk_size;
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull,
+ struct ndr_push *ndrpush,
+ bool *last)
+{
+ DATA_BLOB comp_chunk;
+ DATA_BLOB plain_chunk;
+ uint32_t comp_chunk_offset;
+ uint32_t plain_chunk_offset;
+ uint32_t comp_chunk_size;
+ uint32_t plain_chunk_size;
+ ssize_t ret;
+
+ NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
+ if (plain_chunk_size > 0x00010000) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad XPRESS plain chunk size %08"PRIX32" > 0x00010000 (PULL)",
+ plain_chunk_size);
+ }
+
+ NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
+
+ comp_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
+ comp_chunk.length = comp_chunk_size;
+ comp_chunk.data = ndrpull->data + comp_chunk_offset;
+
+ plain_chunk_offset = ndrpush->offset;
+ NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
+ plain_chunk.length = plain_chunk_size;
+ plain_chunk.data = ndrpush->data + plain_chunk_offset;
+
+ DEBUG(9,("XPRESS plain_chunk_size: %08"PRIX32" (%"PRIu32") comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
+ plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
+
+ /* Uncompressing the buffer using LZ Xpress algorithm */
+ ret = lzxpress_decompress(comp_chunk.data,
+ comp_chunk.length,
+ plain_chunk.data,
+ plain_chunk.length);
+ if (ret < 0) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "XPRESS lzxpress_decompress() returned %zd\n",
+ ret);
+ }
+ plain_chunk.length = ret;
+
+ if ((plain_chunk_size < 0x00010000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
+ /* this is the last chunk */
+ *last = true;
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_push_compression_xpress_chunk(struct ndr_push *ndrpush,
+ struct ndr_pull *ndrpull,
+ bool *last)
+{
+ DATA_BLOB comp_chunk;
+ uint32_t comp_chunk_size_offset;
+ DATA_BLOB plain_chunk;
+ uint32_t plain_chunk_size;
+ uint32_t plain_chunk_offset;
+ uint32_t max_plain_size = 0x00010000;
+ uint32_t max_comp_size = 0x00020000 + 2; /* TODO: use the correct value here */
+ uint32_t tmp_offset;
+ ssize_t ret;
+
+ plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
+ plain_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
+
+ plain_chunk.data = ndrpull->data + plain_chunk_offset;
+ plain_chunk.length = plain_chunk_size;
+
+ if (plain_chunk_size < max_plain_size) {
+ *last = true;
+ }
+
+ NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size));
+ comp_chunk_size_offset = ndrpush->offset;
+ NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE));
+
+ NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
+
+ comp_chunk.data = ndrpush->data + ndrpush->offset;
+ comp_chunk.length = max_comp_size;
+
+ /* Compressing the buffer using LZ Xpress algorithm */
+ ret = lzxpress_compress(plain_chunk.data,
+ plain_chunk.length,
+ comp_chunk.data,
+ comp_chunk.length);
+ if (ret < 0) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "XPRESS lzxpress_compress() returned %zd\n",
+ ret);
+ }
+ comp_chunk.length = ret;
+
+ tmp_offset = ndrpush->offset;
+ ndrpush->offset = comp_chunk_size_offset;
+ NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk.length));
+ ndrpush->offset = tmp_offset;
+
+ ndrpush->offset += comp_chunk.length;
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_compression_none(struct ndr_pull *ndrpull,
+ struct ndr_push *ndrpush,
+ ssize_t decompressed_len,
+ ssize_t compressed_len)
+{
+ DATA_BLOB comp_chunk;
+ uint32_t comp_chunk_size = compressed_len;
+ uint32_t comp_chunk_offset;
+
+ if (decompressed_len != compressed_len) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "decompressed len %zd != compressed_len %zd in 'NONE' compression!",
+ decompressed_len,
+ compressed_len);
+ }
+
+ if (comp_chunk_size != compressed_len) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "compressed_len %zd overflows uint32_t in 'NONE' compression!",
+ compressed_len);
+ }
+
+ comp_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
+ comp_chunk.length = comp_chunk_size;
+ comp_chunk.data = ndrpull->data + comp_chunk_offset;
+
+ NDR_CHECK(ndr_push_array_uint8(ndrpush,
+ NDR_SCALARS,
+ comp_chunk.data,
+ comp_chunk.length));
+
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_push_compression_none(struct ndr_push *ndrpush,
+ struct ndr_pull *ndrpull)
+{
+ DATA_BLOB plain_chunk;
+ uint32_t plain_chunk_size;
+ uint32_t plain_chunk_offset;
+
+ plain_chunk_size = ndrpull->data_size - ndrpull->offset;
+ plain_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
+
+ plain_chunk.data = ndrpull->data + plain_chunk_offset;
+ plain_chunk.length = plain_chunk_size;
+
+ NDR_CHECK(ndr_push_array_uint8(ndrpush,
+ NDR_SCALARS,
+ plain_chunk.data,
+ plain_chunk.length));
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_pull_compression_xpress_huff_raw_chunk(struct ndr_pull *ndrpull,
+ struct ndr_push *ndrpush,
+ ssize_t decompressed_len,
+ ssize_t compressed_len)
+{
+ DATA_BLOB comp_chunk;
+ uint32_t comp_chunk_offset;
+ uint32_t comp_chunk_size;
+ DATA_BLOB plain_chunk;
+ uint32_t plain_chunk_offset;
+ uint32_t plain_chunk_size;
+ ssize_t ret;
+
+ plain_chunk_size = decompressed_len;
+ comp_chunk_size = compressed_len;
+
+ DEBUG(9,("XPRESS_HUFF plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
+ plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
+
+ comp_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
+ comp_chunk.length = comp_chunk_size;
+ comp_chunk.data = ndrpull->data + comp_chunk_offset;
+
+ plain_chunk_offset = ndrpush->offset;
+ NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
+ plain_chunk.length = plain_chunk_size;
+ plain_chunk.data = ndrpush->data + plain_chunk_offset;
+
+ /* Decompressing the buffer using LZ Xpress w/ Huffman algorithm */
+ ret = lzxpress_huffman_decompress(comp_chunk.data,
+ comp_chunk.length,
+ plain_chunk.data,
+ plain_chunk.length);
+ if (ret < 0) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "XPRESS HUFF lzxpress_huffman_decompress() returned %zd\n",
+ ret);
+ }
+
+ if (plain_chunk.length != ret) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "XPRESS HUFF lzxpress_huffman_decompress() output is not as expected (%zd != %zu) (PULL)",
+ ret, plain_chunk.length);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code ndr_push_compression_xpress_huff_raw_chunk(struct ndr_push *ndrpush,
+ struct ndr_pull *ndrpull,
+ struct ndr_compression_state *state)
+{
+ DATA_BLOB comp_chunk;
+ DATA_BLOB plain_chunk;
+ uint32_t plain_chunk_size;
+ uint32_t plain_chunk_offset;
+ ssize_t ret;
+
+ struct lzxhuff_compressor_mem *mem = state->alg.lzxpress_huffman.mem;
+
+ if (ndrpull->data_size <= ndrpull->offset) {
+ return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+ "strange NDR pull size and offset (integer overflow?)");
+
+ }
+
+ plain_chunk_size = ndrpull->data_size - ndrpull->offset;
+ plain_chunk_offset = ndrpull->offset;
+ NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
+
+ plain_chunk.data = ndrpull->data + plain_chunk_offset;
+ plain_chunk.length = plain_chunk_size;
+
+ comp_chunk.length = lzxpress_huffman_max_compressed_size(plain_chunk_size);
+ NDR_CHECK(ndr_push_expand(ndrpush, comp_chunk.length));
+
+ comp_chunk.data = ndrpush->data + ndrpush->offset;
+
+
+ /* Compressing the buffer using LZ Xpress w/ Huffman algorithm */
+ ret = lzxpress_huffman_compress(mem,
+ plain_chunk.data,
+ plain_chunk.length,
+ comp_chunk.data,
+ comp_chunk.length);
+ if (ret < 0) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "XPRESS HUFF lzxpress_huffman_compress() returned %zd\n",
+ ret);
+ }
+
+ if (ret > comp_chunk.length) {
+ return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
+ "XPRESS HUFF lzxpress_huffman_compress() output is not as expected (%zd > %zu) (PULL)",
+ ret, comp_chunk.length);
+ }
+
+ ndrpush->offset += ret;
+ return NDR_ERR_SUCCESS;
+}
+
+
+/*
+ handle compressed subcontext buffers, which in midl land are user-marshalled, but
+ we use magic in pidl to make them easier to cope with
+*/
+enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr,
+ struct ndr_pull **_comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len,
+ ssize_t compressed_len)
+{
+ struct ndr_push *ndrpush;
+ struct ndr_pull *comndr;
+ DATA_BLOB uncompressed;
+ bool last = false;
+ z_stream z;
+
+ ndrpush = ndr_push_init_ctx(subndr);
+ NDR_ERR_HAVE_NO_MEMORY(ndrpush);
+
+ switch (compression_alg) {
+ case NDR_COMPRESSION_NONE:
+ NDR_CHECK(ndr_pull_compression_none(subndr, ndrpush,
+ decompressed_len,
+ compressed_len));
+ break;
+ case NDR_COMPRESSION_MSZIP_CAB:
+ NDR_CHECK(ndr_pull_compression_mszip_cab_chunk(subndr, ndrpush,
+ subndr->cstate,
+ decompressed_len,
+ compressed_len));
+ break;
+ case NDR_COMPRESSION_MSZIP:
+ ZERO_STRUCT(z);
+ while (!last) {
+ NDR_CHECK(ndr_pull_compression_mszip_chunk(subndr, ndrpush, &z, &last));
+ }
+ break;
+
+ case NDR_COMPRESSION_XPRESS:
+ while (!last) {
+ NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr, ndrpush, &last));
+ }
+ break;
+
+ case NDR_COMPRESSION_XPRESS_HUFF_RAW:
+ NDR_CHECK(ndr_pull_compression_xpress_huff_raw_chunk(subndr, ndrpush,
+ decompressed_len,
+ compressed_len));
+ break;
+
+ default:
+ return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)",
+ compression_alg);
+ }
+
+ uncompressed = ndr_push_blob(ndrpush);
+ if (uncompressed.length != decompressed_len) {
+ return ndr_pull_error(subndr, NDR_ERR_COMPRESSION,
+ "Bad uncompressed_len [%zu] != [%zd](0x%08zX) (PULL)",
+ uncompressed.length,
+ decompressed_len,
+ decompressed_len);
+ }
+
+ comndr = talloc_zero(subndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(comndr);
+ comndr->flags = subndr->flags;
+ comndr->current_mem_ctx = subndr->current_mem_ctx;
+
+ comndr->data = uncompressed.data;
+ comndr->data_size = uncompressed.length;
+ comndr->offset = 0;
+
+ *_comndr = comndr;
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr,
+ struct ndr_pull *comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len)
+{
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a compressed subcontext
+*/
+enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr,
+ struct ndr_push **_uncomndr)
+{
+ struct ndr_push *uncomndr;
+ enum ndr_compression_alg compression_alg = subndr->cstate->type;
+
+ switch (compression_alg) {
+ case NDR_COMPRESSION_NONE:
+ case NDR_COMPRESSION_MSZIP_CAB:
+ case NDR_COMPRESSION_MSZIP:
+ case NDR_COMPRESSION_XPRESS:
+ case NDR_COMPRESSION_XPRESS_HUFF_RAW:
+ break;
+ default:
+ return ndr_push_error(subndr, NDR_ERR_COMPRESSION,
+ "Bad compression algorithm %d (PUSH)",
+ compression_alg);
+ }
+
+ uncomndr = ndr_push_init_ctx(subndr);
+ NDR_ERR_HAVE_NO_MEMORY(uncomndr);
+ uncomndr->flags = subndr->flags;
+
+ *_uncomndr = uncomndr;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a compressed subcontext
+*/
+enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr,
+ struct ndr_push *uncomndr)
+{
+ struct ndr_pull *ndrpull;
+ bool last = false;
+ z_stream z;
+
+ enum ndr_compression_alg compression_alg = subndr->cstate->type;
+
+ ndrpull = talloc_zero(uncomndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(ndrpull);
+ ndrpull->flags = uncomndr->flags;
+ ndrpull->data = uncomndr->data;
+ ndrpull->data_size = uncomndr->offset;
+ ndrpull->offset = 0;
+
+ switch (compression_alg) {
+ case NDR_COMPRESSION_NONE:
+ NDR_CHECK(ndr_push_compression_none(subndr, ndrpull));
+ break;
+
+ case NDR_COMPRESSION_MSZIP_CAB:
+ NDR_CHECK(ndr_push_compression_mszip_cab_chunk(subndr, ndrpull, subndr->cstate));
+ break;
+
+ case NDR_COMPRESSION_MSZIP:
+ ZERO_STRUCT(z);
+ while (!last) {
+ NDR_CHECK(ndr_push_compression_mszip_chunk(subndr, ndrpull, &z, &last));
+ }
+ break;
+
+ case NDR_COMPRESSION_XPRESS:
+ while (!last) {
+ NDR_CHECK(ndr_push_compression_xpress_chunk(subndr, ndrpull, &last));
+ }
+ break;
+
+ case NDR_COMPRESSION_XPRESS_HUFF_RAW:
+ NDR_CHECK(ndr_push_compression_xpress_huff_raw_chunk(subndr, ndrpull, subndr->cstate));
+ break;
+
+ default:
+ return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)",
+ compression_alg);
+ }
+
+ talloc_free(uncomndr);
+ return NDR_ERR_SUCCESS;
+}
+
+static enum ndr_err_code generic_mszip_init(struct ndr_compression_state *state)
+{
+ z_stream *z = talloc_zero(state, z_stream);
+ NDR_ERR_HAVE_NO_MEMORY(z);
+
+ z->zalloc = ndr_zlib_alloc;
+ z->zfree = ndr_zlib_free;
+ z->opaque = state;
+
+ state->alg.mszip.z = z;
+ state->alg.mszip.dict_size = 0;
+ /* pre-alloc dictionary */
+ state->alg.mszip.dict = talloc_array(state, uint8_t, 0x8000);
+ NDR_ERR_HAVE_NO_MEMORY(state->alg.mszip.dict);
+
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_compression_state_init(struct ndr_pull *ndr,
+ enum ndr_compression_alg compression_alg,
+ struct ndr_compression_state **state)
+{
+ struct ndr_compression_state *s;
+ int z_ret;
+
+ s = talloc_zero(ndr, struct ndr_compression_state);
+ NDR_ERR_HAVE_NO_MEMORY(s);
+ s->type = compression_alg;
+
+ switch (compression_alg) {
+ case NDR_COMPRESSION_NONE:
+ case NDR_COMPRESSION_MSZIP:
+ case NDR_COMPRESSION_XPRESS:
+ case NDR_COMPRESSION_XPRESS_HUFF_RAW:
+ break;
+ case NDR_COMPRESSION_MSZIP_CAB:
+ NDR_CHECK(generic_mszip_init(s));
+ z_ret = inflateInit2(s->alg.mszip.z, -MAX_WBITS);
+ if (z_ret != Z_OK) {
+ return ndr_pull_error(ndr, NDR_ERR_COMPRESSION,
+ "zlib inflateinit2 error %s (%d) %s (PULL)",
+ zError(z_ret), z_ret, s->alg.mszip.z->msg);
+ }
+ break;
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_COMPRESSION,
+ "Bad compression algorithm %d (PULL)",
+ compression_alg);
+ break;
+ }
+
+ *state = s;
+
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_compression_state_init(struct ndr_push *ndr,
+ enum ndr_compression_alg compression_alg)
+{
+ struct ndr_compression_state *s;
+ int z_ret;
+
+ /*
+ * Avoid confusion, NULL out ndr->cstate at the start of the
+ * compression block
+ */
+ ndr->cstate = NULL;
+
+ s = talloc_zero(ndr, struct ndr_compression_state);
+ NDR_ERR_HAVE_NO_MEMORY(s);
+ s->type = compression_alg;
+
+ switch (compression_alg) {
+ case NDR_COMPRESSION_NONE:
+ case NDR_COMPRESSION_XPRESS:
+ break;
+
+ case NDR_COMPRESSION_XPRESS_HUFF_RAW:
+ s->alg.lzxpress_huffman.mem = talloc(s, struct lzxhuff_compressor_mem);
+ if (s->alg.lzxpress_huffman.mem == NULL) {
+ return NDR_ERR_ALLOC;
+ }
+ break;
+
+ case NDR_COMPRESSION_MSZIP:
+ break;
+ case NDR_COMPRESSION_MSZIP_CAB:
+ NDR_CHECK(generic_mszip_init(s));
+ z_ret = deflateInit2(s->alg.mszip.z,
+ Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED,
+ -MAX_WBITS,
+ 8, /* memLevel */
+ Z_DEFAULT_STRATEGY);
+ if (z_ret != Z_OK) {
+ return ndr_push_error(ndr, NDR_ERR_COMPRESSION,
+ "zlib inflateinit2 error %s (%d) %s (PUSH)",
+ zError(z_ret), z_ret, s->alg.mszip.z->msg);
+ }
+ break;
+ default:
+ return ndr_push_error(ndr, NDR_ERR_COMPRESSION,
+ "Bad compression algorithm %d (PUSH)",
+ compression_alg);
+ break;
+ }
+
+ ndr->cstate = s;
+
+ return NDR_ERR_SUCCESS;
+}
+
diff --git a/librpc/ndr/ndr_compression.h b/librpc/ndr/ndr_compression.h
new file mode 100644
index 0000000..3d335b2
--- /dev/null
+++ b/librpc/ndr/ndr_compression.h
@@ -0,0 +1,60 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libndr compression support
+
+ Copyright (C) Stefan Metzmacher 2005
+ Copyright (C) Matthieu Suiche 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 __LIBRPC_NDR_NDR_COMPRESSION_H__
+#define __LIBRPC_NDR_NDR_COMPRESSION_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+/* The following definitions come from librpc/ndr/ndr_compression.c */
+
+enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr,
+ struct ndr_pull **_comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len,
+ ssize_t compressed_len);
+enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr,
+ struct ndr_pull *comndr,
+ enum ndr_compression_alg compression_alg,
+ ssize_t decompressed_len);
+enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr,
+ struct ndr_push **_uncomndr);
+enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr,
+ struct ndr_push *uncomndr);
+
+enum ndr_err_code ndr_pull_compression_state_init(struct ndr_pull *ndr,
+ enum ndr_compression_alg compression_alg,
+ struct ndr_compression_state **state);
+void ndr_pull_compression_state_free(struct ndr_compression_state *state);
+enum ndr_err_code ndr_push_compression_state_init(struct ndr_push *ndr,
+ enum ndr_compression_alg compression_alg);
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif /* __LIBRPC_NDR_NDR_COMPRESSION_H__ */
+
diff --git a/librpc/ndr/ndr_dcerpc.c b/librpc/ndr/ndr_dcerpc.c
new file mode 100644
index 0000000..b368bfa
--- /dev/null
+++ b/librpc/ndr/ndr_dcerpc.c
@@ -0,0 +1,316 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Manually parsed structures found in the DCERPC protocol
+
+ Copyright (C) Stefan Metzmacher 2014
+ Copyright (C) Gregor Beck 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 "includes.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_ncacn_packet(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct ncacn_packet *r)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->rpc_vers));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->rpc_vers_minor));
+ NDR_CHECK(ndr_push_dcerpc_pkt_type(ndr, NDR_SCALARS, r->ptype));
+ NDR_CHECK(ndr_push_dcerpc_pfc_flags(ndr, NDR_SCALARS, r->pfc_flags));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->drep, 4));
+ if (r->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
+ ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
+ }
+ if (!(r->drep[0] & DCERPC_DREP_LE)) {
+ ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->frag_length));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->auth_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->call_id));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->u, r->ptype));
+ NDR_CHECK(ndr_push_dcerpc_payload(ndr, NDR_SCALARS, &r->u));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_ncacn_packet(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct ncacn_packet *r)
+{
+ uint32_t size_drep_0 = 0;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->rpc_vers));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->rpc_vers_minor));
+ NDR_CHECK(ndr_pull_dcerpc_pkt_type(ndr, NDR_SCALARS, &r->ptype));
+ NDR_CHECK(ndr_pull_dcerpc_pfc_flags(ndr, NDR_SCALARS, &r->pfc_flags));
+ size_drep_0 = 4;
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->drep, size_drep_0));
+ if (r->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
+ ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
+ }
+ if (!(r->drep[0] & DCERPC_DREP_LE)) {
+ ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->frag_length));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->auth_length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->call_id));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->u, r->ptype));
+ NDR_CHECK(ndr_pull_dcerpc_payload(ndr, NDR_SCALARS, &r->u));
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_ncacn_packet(struct ndr_print *ndr, const char *name, const struct ncacn_packet *r)
+{
+ ndr_print_struct(ndr, name, "ncacn_packet");
+ if (r == NULL) { ndr_print_null(ndr); return; }
+ ndr->depth++;
+ ndr_print_uint8(ndr, "rpc_vers", r->rpc_vers);
+ ndr_print_uint8(ndr, "rpc_vers_minor", r->rpc_vers_minor);
+ ndr_print_dcerpc_pkt_type(ndr, "ptype", r->ptype);
+ ndr_print_dcerpc_pfc_flags(ndr, "pfc_flags", r->pfc_flags);
+ ndr_print_array_uint8(ndr, "drep", r->drep, 4);
+ if (r->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
+ ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
+ }
+ if (!(r->drep[0] & DCERPC_DREP_LE)) {
+ ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+ ndr_print_uint16(ndr, "frag_length", r->frag_length);
+ ndr_print_uint16(ndr, "auth_length", r->auth_length);
+ ndr_print_uint32(ndr, "call_id", r->call_id);
+ ndr_print_set_switch_value(ndr, &r->u, r->ptype);
+ ndr_print_dcerpc_payload(ndr, "u", &r->u);
+ ndr->depth--;
+}
+
+/*
+ * This function was generated by pidl and
+ * has been extended by the (_available == 0) check.
+ *
+ * That's why we ignore the 80 char per line limit.
+ */
+enum ndr_err_code ndr_pull_dcerpc_bind_nak(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dcerpc_bind_nak *r)
+{
+ uint32_t size_versions_0 = 0;
+ uint32_t cntr_versions_0;
+ TALLOC_CTX *_mem_save_versions_0 = NULL;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t _available;
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dcerpc_bind_nak_reason(ndr, NDR_SCALARS, &r->reject_reason));
+ _available = ndr->data_size - ndr->offset;
+ if (_available == 0) {
+ /*
+ * This works around a bug in older
+ * Samba (<= 4.1) releases.
+ *
+ * See bug #11327.
+ */
+ r->num_versions = 0;
+ } else {
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->num_versions));
+ }
+ size_versions_0 = r->num_versions;
+ NDR_PULL_ALLOC_N(ndr, r->versions, size_versions_0);
+ _mem_save_versions_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->versions, 0);
+ for (cntr_versions_0 = 0; cntr_versions_0 < (size_versions_0); cntr_versions_0++) {
+ NDR_CHECK(ndr_pull_dcerpc_bind_nak_version(ndr, NDR_SCALARS, &r->versions[cntr_versions_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_versions_0, 0);
+ {
+ libndr_flags _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ }
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+const uint8_t DCERPC_SEC_VT_MAGIC[] = {0x8a,0xe3,0x13,0x71,0x02,0xf4,0x36,0x71};
+
+_PUBLIC_ enum ndr_err_code ndr_push_dcerpc_sec_vt_count(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dcerpc_sec_vt_count *r)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ /* nothing */
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dcerpc_sec_vt_count(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dcerpc_sec_vt_count *r)
+{
+ uint32_t _saved_ofs = ndr->offset;
+
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ r->count = 0;
+
+ while (true) {
+ uint16_t command;
+ uint16_t length;
+
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &command));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &length));
+ NDR_CHECK(ndr_pull_advance(ndr, length));
+
+ r->count += 1;
+
+ if (command & DCERPC_SEC_VT_COMMAND_END) {
+ break;
+ }
+ }
+
+ ndr->offset = _saved_ofs;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pop_dcerpc_sec_verification_trailer(
+ struct ndr_pull *ndr, TALLOC_CTX *mem_ctx,
+ struct dcerpc_sec_verification_trailer **_r)
+{
+ enum ndr_err_code ndr_err;
+ uint32_t ofs;
+ uint32_t min_ofs = 0;
+ struct dcerpc_sec_verification_trailer *r;
+ DATA_BLOB sub_blob = data_blob_null;
+ struct ndr_pull *sub_ndr = NULL;
+ uint32_t remaining;
+
+ *_r = NULL;
+
+ r = talloc_zero(mem_ctx, struct dcerpc_sec_verification_trailer);
+ if (r == NULL) {
+ return NDR_ERR_ALLOC;
+ }
+
+ if (ndr->data_size < sizeof(DCERPC_SEC_VT_MAGIC)) {
+ /*
+ * we return with r->count = 0
+ */
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+ }
+
+ ofs = ndr->data_size - sizeof(DCERPC_SEC_VT_MAGIC);
+ /* the magic is 4 byte aligned */
+ ofs &= ~3;
+
+ if (ofs > DCERPC_SEC_VT_MAX_SIZE) {
+ /*
+ * We just scan the last 1024 bytes.
+ */
+ min_ofs = ofs - DCERPC_SEC_VT_MAX_SIZE;
+ } else {
+ min_ofs = 0;
+ }
+
+ while (true) {
+ int ret;
+
+ ret = memcmp(&ndr->data[ofs],
+ DCERPC_SEC_VT_MAGIC,
+ sizeof(DCERPC_SEC_VT_MAGIC));
+ if (ret == 0) {
+ sub_blob = data_blob_const(&ndr->data[ofs],
+ ndr->data_size - ofs);
+ break;
+ }
+
+ if (ofs <= min_ofs) {
+ break;
+ }
+
+ ofs -= 4;
+ }
+
+ if (sub_blob.length == 0) {
+ /*
+ * we return with r->count = 0
+ */
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+ }
+
+ sub_ndr = ndr_pull_init_blob(&sub_blob, r);
+ if (sub_ndr == NULL) {
+ TALLOC_FREE(r);
+ return NDR_ERR_ALLOC;
+ }
+
+ ndr_err = ndr_pull_dcerpc_sec_verification_trailer(sub_ndr,
+ NDR_SCALARS | NDR_BUFFERS,
+ r);
+ if (ndr_err == NDR_ERR_ALLOC) {
+ TALLOC_FREE(r);
+ return NDR_ERR_ALLOC;
+ }
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto ignore_error;
+ }
+
+ remaining = sub_ndr->data_size - sub_ndr->offset;
+ if (remaining > 16) {
+ /*
+ * we expect not more than 16 byte of additional
+ * padding after the verification trailer.
+ */
+ goto ignore_error;
+ }
+
+ /*
+ * We assume that we got a real verification trailer.
+ *
+ * We remove it from the available stub data.
+ */
+ ndr->data_size = ofs;
+
+ TALLOC_FREE(sub_ndr);
+
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+
+ignore_error:
+ TALLOC_FREE(sub_ndr);
+ /*
+ * just ignore the error, it's likely
+ * that the magic we found belongs to
+ * the stub data.
+ *
+ * we return with r->count = 0
+ */
+ ZERO_STRUCTP(r);
+ *_r = r;
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_dcerpc.h b/librpc/ndr/ndr_dcerpc.h
new file mode 100644
index 0000000..d4ff927
--- /dev/null
+++ b/librpc/ndr/ndr_dcerpc.h
@@ -0,0 +1,29 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Manually parsed structures found in the DCERPC protocol
+
+ Copyright (C) Stefan Metzmacher 2014
+ Copyright (C) Gregor Beck 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/>.
+*/
+
+enum ndr_err_code ndr_pop_dcerpc_sec_verification_trailer(
+ struct ndr_pull *ndr, TALLOC_CTX *mem_ctx,
+ struct dcerpc_sec_verification_trailer **_r);
+
+#ifndef NDR_DCERPC_REQUEST_OBJECT_PRESENT
+#define NDR_DCERPC_REQUEST_OBJECT_PRESENT (!!(ndr->flags & LIBNDR_FLAG_OBJECT_PRESENT))
+#endif /* NDR_DCERPC_REQUEST_OBJECT_PRESENT */
diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c
new file mode 100644
index 0000000..9cc54c1
--- /dev/null
+++ b/librpc/ndr/ndr_dns.c
@@ -0,0 +1,327 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ manipulate dns name structures
+
+ Copyright (C) 2010 Kai Blin <kai@samba.org>
+
+ Heavily based on nbtname.c which is:
+
+ Copyright (C) Andrew Tridgell 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/>.
+*/
+
+/*
+ see rfc1002 for the detailed format of compressed names
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_dns.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_dnsp.h"
+#include "system/locale.h"
+#include "lib/util/util_net.h"
+#include "ndr_dns_utils.h"
+
+/* don't allow an unlimited number of name components */
+#define MAX_COMPONENTS 128
+
+/**
+ print a dns string
+*/
+_PUBLIC_ void ndr_print_dns_string(struct ndr_print *ndr,
+ const char *name,
+ const char *s)
+{
+ ndr_print_string(ndr, name, s);
+}
+
+/*
+ pull one component of a dns_string
+*/
+static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr,
+ uint8_t **component,
+ uint32_t *offset,
+ uint32_t *max_offset)
+{
+ uint8_t len;
+ unsigned int loops = 0;
+ while (loops < 5) {
+ if (*offset >= ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD DNS NAME component, bad offset");
+ }
+ len = ndr->data[*offset];
+ if (len == 0) {
+ *offset += 1;
+ *max_offset = MAX(*max_offset, *offset);
+ *component = NULL;
+ return NDR_ERR_SUCCESS;
+ }
+ if ((len & 0xC0) == 0xC0) {
+ /* its a label pointer */
+ if (1 + *offset >= ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD DNS NAME component, " \
+ "bad label offset");
+ }
+ *max_offset = MAX(*max_offset, *offset + 2);
+ *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset];
+ *max_offset = MAX(*max_offset, *offset);
+ loops++;
+ continue;
+ }
+ if ((len & 0xC0) != 0) {
+ /* its a reserved length field */
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD DNS NAME component, " \
+ "reserved length field: 0x%02"PRIx8,
+ (len &0xC));
+ }
+ if (*offset + len + 1 > ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD DNS NAME component, "\
+ "length too long");
+ }
+ *component = (uint8_t*)talloc_strndup(ndr,
+ (const char *)&ndr->data[1 + *offset], len);
+ NDR_ERR_HAVE_NO_MEMORY(*component);
+ *offset += len + 1;
+ *max_offset = MAX(*max_offset, *offset);
+ return NDR_ERR_SUCCESS;
+ }
+
+ /* too many pointers */
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD DNS NAME component, too many pointers");
+}
+
+/**
+ pull a dns_string from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_dns_string(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ const char **s)
+{
+ uint32_t offset = ndr->offset;
+ uint32_t max_offset = offset;
+ unsigned num_components;
+ char *name;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ name = talloc_strdup(ndr->current_mem_ctx, "");
+
+ /* break up name into a list of components */
+ for (num_components=0; num_components<MAX_COMPONENTS;
+ num_components++) {
+ uint8_t *component = NULL;
+ NDR_CHECK(ndr_pull_component(ndr, &component, &offset,
+ &max_offset));
+ if (component == NULL) break;
+ if (num_components > 0) {
+ name = talloc_asprintf_append_buffer(name, ".%s",
+ component);
+ } else {
+ name = talloc_asprintf_append_buffer(name, "%s",
+ component);
+ }
+ NDR_ERR_HAVE_NO_MEMORY(name);
+ }
+ if (num_components == MAX_COMPONENTS) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD DNS NAME too many components");
+ }
+
+ (*s) = name;
+ ndr->offset = max_offset;
+
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a dns string to the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const char *s)
+{
+ return ndr_push_dns_string_list(ndr,
+ &ndr->dns_string_list,
+ ndr_flags,
+ s,
+ false);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dns_txt_record(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dns_txt_record *r)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ enum ndr_err_code ndr_err;
+ uint32_t data_size = ndr->data_size;
+ uint32_t record_size = 0;
+ ndr_err = ndr_token_retrieve(&ndr->array_size_list, r,
+ &record_size);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NDR_PULL_NEED_BYTES(ndr, record_size);
+ ndr->data_size = ndr->offset + record_size;
+ }
+ NDR_CHECK(ndr_pull_align(ndr, 1));
+ NDR_CHECK(ndr_pull_dnsp_string_list(ndr, NDR_SCALARS, &r->txt));
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 1));
+ ndr->data_size = data_size;
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct dns_res_rec *r)
+{
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ uint32_t _saved_offset1, _saved_offset2;
+ uint16_t length;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX |
+ LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ libndr_flags _flags_save_name = ndr->flags;
+
+ NDR_CHECK(ndr_push_align(ndr, 4));
+
+ switch (r->rr_type) {
+ case DNS_QTYPE_TKEY:
+ case DNS_QTYPE_TSIG:
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NO_COMPRESSION);
+ break;
+ default:
+ break;
+ }
+ NDR_CHECK(ndr_push_dns_string(ndr, NDR_SCALARS, r->name));
+ ndr->flags = _flags_save_name;
+
+ NDR_CHECK(ndr_push_dns_qtype(ndr, NDR_SCALARS, r->rr_type));
+ NDR_CHECK(ndr_push_dns_qclass(ndr, NDR_SCALARS, r->rr_class));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl));
+ _saved_offset1 = ndr->offset;
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+ if (r->length > 0) {
+ uint32_t _saved_offset3;
+
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->rdata,
+ r->rr_type));
+ _saved_offset3 = ndr->offset;
+ NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_SCALARS,
+ &r->rdata));
+ if ((ndr->offset != _saved_offset3) &&
+ (r->unexpected.length > 0)) {
+ /*
+ * ndr_push_dns_rdata pushed a known
+ * record, but we have something
+ * unexpected. That's invalid.
+ */
+ return ndr_push_error(ndr,
+ NDR_ERR_LENGTH,
+ "Invalid...Unexpected " \
+ "blob length is too " \
+ "large");
+ }
+ }
+ if (r->unexpected.length > UINT16_MAX) {
+ return ndr_push_error(ndr, NDR_ERR_LENGTH,
+ "Unexpected blob length "\
+ "is too large");
+ }
+
+ NDR_CHECK(ndr_push_bytes(ndr, r->unexpected.data,
+ r->unexpected.length));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 4));
+ length = ndr->offset - (_saved_offset1 + 2);
+ _saved_offset2 = ndr->offset;
+ ndr->offset = _saved_offset1;
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, length));
+ ndr->offset = _saved_offset2;
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_dns_rdata(ndr, NDR_BUFFERS,
+ &r->rdata));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct dns_res_rec *r)
+{
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ uint32_t _saved_offset1;
+ uint32_t pad, length;
+
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX |
+ LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_dns_string(ndr, NDR_SCALARS, &r->name));
+ NDR_CHECK(ndr_pull_dns_qtype(ndr, NDR_SCALARS, &r->rr_type));
+ NDR_CHECK(ndr_pull_dns_qclass(ndr, NDR_SCALARS, &r->rr_class));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->ttl));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->length));
+ _saved_offset1 = ndr->offset;
+ if (r->length > 0) {
+ NDR_CHECK(ndr_token_store(ndr, &ndr->array_size_list,
+ &r->rdata,
+ r->length));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->rdata,
+ r->rr_type));
+ NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_SCALARS,
+ &r->rdata));
+ } else {
+ ZERO_STRUCT(r->rdata);
+ }
+ length = ndr->offset - _saved_offset1;
+ if (length > r->length) {
+ return ndr_pull_error(ndr, NDR_ERR_LENGTH, "TODO");
+ }
+
+ r->unexpected = data_blob_null;
+ pad = r->length - length;
+ if (pad > 0) {
+ NDR_PULL_NEED_BYTES(ndr, pad);
+ r->unexpected = data_blob_talloc(ndr->current_mem_ctx,
+ ndr->data +
+ ndr->offset,
+ pad);
+ if (r->unexpected.data == NULL) {
+ return ndr_pull_error(ndr,
+ NDR_ERR_ALLOC,
+ "Failed to allocate a " \
+ "data blob");
+ }
+ ndr->offset += pad;
+ }
+
+
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_dns_rdata(ndr, NDR_BUFFERS, &r->rdata));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_dns.h b/librpc/ndr/ndr_dns.h
new file mode 100644
index 0000000..15617eb
--- /dev/null
+++ b/librpc/ndr/ndr_dns.h
@@ -0,0 +1,40 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ manipulate dns name structures
+
+ Copyright (C) 2010 Kai Blin <kai@samba.org>
+
+ Heavily based on nbtname.c which is:
+
+ Copyright (C) Andrew Tridgell 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/>.
+*/
+
+void ndr_print_dns_string(struct ndr_print *ndr,
+ const char *name,
+ const char *s);
+enum ndr_err_code ndr_pull_dns_string(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ const char **s);
+enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const char *s);
+enum ndr_err_code ndr_push_dns_res_rec(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct dns_res_rec *r);
+enum ndr_err_code ndr_pull_dns_res_rec(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct dns_res_rec *r);
diff --git a/librpc/ndr/ndr_dns_utils.c b/librpc/ndr/ndr_dns_utils.c
new file mode 100644
index 0000000..a2e0464
--- /dev/null
+++ b/librpc/ndr/ndr_dns_utils.c
@@ -0,0 +1,134 @@
+#include "includes.h"
+#include "../librpc/ndr/libndr.h"
+#include "ndr_dns_utils.h"
+
+
+/**
+ push a dns/nbt string list to the wire
+*/
+enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
+ struct ndr_token_list *string_list,
+ ndr_flags_type ndr_flags,
+ const char *s,
+ bool is_nbt)
+{
+ const char *start = s;
+ bool use_compression;
+ size_t max_length;
+ if (is_nbt) {
+ use_compression = true;
+ /*
+ * Max length is longer in NBT/Wins, because Windows counts
+ * the semi-decompressed size of the netbios name (16 bytes)
+ * rather than the wire size of 32, which is what you'd expect
+ * if it followed RFC1002 (it uses the short form in
+ * [MS-WINSRA]). In other words the maximum size of the
+ * "scope" is 237, not 221.
+ *
+ * We make the size limit slightly larger than 255 + 16,
+ * because the 237 scope limit is already enforced in the
+ * winsserver code with a specific return value; bailing out
+ * here would muck with that.
+ */
+ max_length = 274;
+ } else {
+ use_compression = !(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION);
+ max_length = 255;
+ }
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ while (s && *s) {
+ enum ndr_err_code ndr_err;
+ char *compname;
+ size_t complen;
+ uint32_t offset;
+
+ if (use_compression) {
+ /* see if we have pushed the remaining string already,
+ * if so we use a label pointer to this string
+ */
+ ndr_err = ndr_token_retrieve_cmp_fn(string_list, s,
+ &offset,
+ (comparison_fn_t)strcmp,
+ false);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ uint8_t b[2];
+
+ if (offset > 0x3FFF) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "offset for dns string " \
+ "label pointer " \
+ "%"PRIu32"[%08"PRIX32"] > 0x00003FFF",
+ offset, offset);
+ }
+
+ b[0] = 0xC0 | (offset>>8);
+ b[1] = (offset & 0xFF);
+
+ return ndr_push_bytes(ndr, b, 2);
+ }
+ }
+
+ complen = strcspn(s, ".");
+
+ /* the length must fit into 6 bits (i.e. <= 63) */
+ if (complen > 0x3F) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "component length %zu[%08zX] > " \
+ "0x0000003F",
+ complen,
+ complen);
+ }
+
+ if (complen == 0 && s[complen] == '.') {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "component length is 0 "
+ "(consecutive dots)");
+ }
+
+ if (is_nbt && s[complen] == '.' && s[complen + 1] == '\0') {
+ /* nbt names are sometimes usernames, and we need to
+ * keep a trailing dot to ensure it is byte-identical,
+ * (not just semantically identical given DNS
+ * semantics). */
+ complen++;
+ }
+
+ compname = talloc_asprintf(ndr, "%c%*.*s",
+ (unsigned char)complen,
+ (unsigned char)complen,
+ (unsigned char)complen, s);
+ NDR_ERR_HAVE_NO_MEMORY(compname);
+
+ /* remember the current component + the rest of the string
+ * so it can be reused later
+ */
+ if (use_compression) {
+ NDR_CHECK(ndr_token_store(ndr, string_list, s,
+ ndr->offset));
+ }
+
+ /* push just this component into the blob */
+ NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname,
+ complen+1));
+ talloc_free(compname);
+
+ s += complen;
+ if (*s == '.') {
+ s++;
+ }
+ if (s - start > max_length) {
+ return ndr_push_error(ndr, NDR_ERR_STRING,
+ "name > %zu characters long",
+ max_length);
+ }
+ }
+
+ /* if we reach the end of the string and have pushed the last component
+ * without using a label pointer, we need to terminate the string
+ */
+ return ndr_push_bytes(ndr, (const uint8_t *)"", 1);
+}
diff --git a/librpc/ndr/ndr_dns_utils.h b/librpc/ndr/ndr_dns_utils.h
new file mode 100644
index 0000000..b07496f
--- /dev/null
+++ b/librpc/ndr/ndr_dns_utils.h
@@ -0,0 +1,6 @@
+
+enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
+ struct ndr_token_list *string_list,
+ ndr_flags_type ndr_flags,
+ const char *s,
+ bool is_nbt);
diff --git a/librpc/ndr/ndr_dnsp.c b/librpc/ndr/ndr_dnsp.c
new file mode 100644
index 0000000..b4cad86
--- /dev/null
+++ b/librpc/ndr/ndr_dnsp.c
@@ -0,0 +1,263 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Manually parsed structures found in DNSP
+
+ 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 "librpc/gen_ndr/ndr_dnsp.h"
+
+/*
+ print a dnsp_name
+*/
+_PUBLIC_ void ndr_print_dnsp_name(struct ndr_print *ndr, const char *name,
+ const char *dns_name)
+{
+ ndr->print(ndr, "%-25s: %s", name, dns_name);
+}
+
+/*
+ pull a dnsp_name
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_dnsp_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **name)
+{
+ uint8_t len, count, termination;
+ int i;
+ uint32_t total_len, raw_offset;
+ char *ret;
+
+ NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &len));
+ NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &count));
+
+ raw_offset = ndr->offset;
+
+ ret = talloc_strdup(ndr->current_mem_ctx, "");
+ if (!ret) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_name");
+ }
+ total_len = 1;
+
+ for (i=0; i<count; i++) {
+ uint8_t sublen, newlen;
+ NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &sublen));
+ newlen = total_len + sublen;
+ if (newlen < total_len) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE,
+ "Failed to pull dnsp_name");
+ }
+ if (i != count-1) {
+ if (newlen == UINT8_MAX) {
+ return ndr_pull_error(
+ ndr, NDR_ERR_RANGE,
+ "Failed to pull dnsp_name");
+ }
+ newlen++; /* for the '.' */
+ }
+ ret = talloc_realloc(ndr->current_mem_ctx, ret, char, newlen);
+ if (!ret) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_name");
+ }
+ NDR_CHECK(ndr_pull_bytes(ndr, (uint8_t *)&ret[total_len-1], sublen));
+ if (i != count-1) {
+ ret[newlen-2] = '.';
+ }
+ ret[newlen-1] = 0;
+ total_len = newlen;
+ }
+ NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &termination));
+ if (termination != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_name - not NUL terminated");
+ }
+ if (ndr->offset > raw_offset + len) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_name - overrun by %"PRIu32" bytes",
+ ndr->offset - (raw_offset + len));
+ }
+ /* there could be additional pad bytes */
+ while (ndr->offset < raw_offset + len) {
+ uint8_t pad;
+ NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &pad));
+ }
+ (*name) = ret;
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_dnsp_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *name)
+{
+ int count, total_len, i;
+
+ /* count the dots */
+ for (count=i=0; name[i]; i++) {
+ if (name[i] == '.') count++;
+ }
+ total_len = strlen(name) + 1;
+
+ /*
+ * cope with names ending in '.'
+ */
+ if (name[0] == '\0') {
+ /*
+ * Don't access name[-1] for the "" input, which has
+ * the same meaning as a lone '.'.
+ *
+ * This allows a round-trip of a dnsRecord from
+ * Windows of a MX record of '.'
+ */
+ } else if (name[strlen(name)-1] != '.') {
+ total_len++;
+ count++;
+ }
+ if (total_len > 255 || count > 255) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "dns_name of length %d larger than 255", total_len);
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, (uint8_t)total_len));
+ NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, (uint8_t)count));
+ for (i=0; i<count; i++) {
+ const char *p = strchr(name, '.');
+ size_t sublen = p?(p-name):strlen(name);
+ NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, (uint8_t)sublen));
+ NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)name, sublen));
+ name += sublen + 1;
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, 0));
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ print a dnsp_string
+*/
+_PUBLIC_ void ndr_print_dnsp_string(struct ndr_print *ndr, const char *name,
+ const char *dns_string)
+{
+ ndr->print(ndr, "%-25s: %s", name, dns_string);
+}
+
+/*
+ pull a dnsp_string
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_dnsp_string(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **string)
+{
+ uint8_t len;
+ char *ret;
+
+ NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &len));
+
+ ret = talloc_zero_array(ndr->current_mem_ctx, char, len + 1);
+ if (!ret) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_string");
+ }
+ NDR_CHECK(ndr_pull_bytes(ndr, (uint8_t *)ret, len));
+
+ (*string) = ret;
+ NDR_PULL_ALIGN(ndr, 1);
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_dnsp_string(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *string)
+{
+ int total_len;
+ total_len = strlen(string);
+ if (total_len > 255) {
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+ "dns_name of length %d larger than 255", total_len);
+ }
+ NDR_CHECK(ndr_push_uint8(ndr, ndr_flags, (uint8_t)total_len));
+ NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)string, total_len));
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ * print a dnsp_string_list
+ */
+_PUBLIC_ void ndr_print_dnsp_string_list(struct ndr_print *ndr, const char *name,
+ const struct dnsp_string_list *list)
+{
+ uint32_t i;
+
+ ndr->no_newline = true;
+ for (i=0; i<ndr->depth; i++) {
+ ndr->print(ndr, " ");
+ }
+ ndr->print(ndr, "%-25s:", name);
+ for (i=0; i<list->count; i++) {
+ ndr->print(ndr, " \"%s\"", list->str[i]);
+ }
+ ndr->print(ndr, "\n");
+ ndr->no_newline = false;
+}
+
+/*
+ * pull a dnsp_string_list
+ */
+_PUBLIC_ enum ndr_err_code ndr_pull_dnsp_string_list(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dnsp_string_list *list)
+{
+ list->count = 0;
+ list->str = talloc_array(ndr->current_mem_ctx, const char *,
+ list->count);
+ if (! list->str) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_string_list");
+ }
+
+ while (ndr->offset < ndr->data_size) {
+ list->str = talloc_realloc(ndr->current_mem_ctx, list->str,
+ const char *, list->count+1);
+ if (! list->str) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull dnsp_string_list");
+ }
+ NDR_CHECK(ndr_pull_dnsp_string(ndr, ndr_flags, &list->str[list->count]));
+ list->count++;
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_dnsp_string_list(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dnsp_string_list *list)
+{
+ uint8_t i;
+
+ for (i=0; i<list->count; i++) {
+ NDR_CHECK(ndr_push_dnsp_string(ndr, ndr_flags, list->str[i]));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_dnsp_string_list_copy(TALLOC_CTX *mem_ctx,
+ const struct dnsp_string_list *src,
+ struct dnsp_string_list *dst)
+{
+ size_t i;
+
+ dst->count = 0;
+ dst->str = talloc_zero_array(mem_ctx, const char *, src->count);
+ if (dst->str == NULL) {
+ return NDR_ERR_ALLOC;
+ }
+
+ for (i = 0; i < src->count; i++) {
+ dst->str[i] = talloc_strdup(dst->str, src->str[i]);
+ if (dst->str[i] == NULL) {
+ TALLOC_FREE(dst->str);
+ return NDR_ERR_ALLOC;
+ }
+ }
+
+ dst->count = src->count;
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_dnsp.h b/librpc/ndr/ndr_dnsp.h
new file mode 100644
index 0000000..1f68f29
--- /dev/null
+++ b/librpc/ndr/ndr_dnsp.h
@@ -0,0 +1,33 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Manually parsed structures found in the DNSP IDL
+
+ 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/>.
+*/
+
+void ndr_print_dnsp_name(struct ndr_print *ndr, const char *name,
+ const char *dns_name);
+enum ndr_err_code ndr_pull_dnsp_name(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **name);
+enum ndr_err_code ndr_push_dnsp_name(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *name);
+void ndr_print_dnsp_string(struct ndr_print *ndr, const char *name,
+ const char *dns_string);
+enum ndr_err_code ndr_pull_dnsp_string(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **string);
+enum ndr_err_code ndr_push_dnsp_string(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *string);
+
+enum ndr_err_code ndr_dnsp_string_list_copy(TALLOC_CTX *mem_ctx,
+ const struct dnsp_string_list *src,
+ struct dnsp_string_list *dst);
diff --git a/librpc/ndr/ndr_dnsserver.c b/librpc/ndr/ndr_dnsserver.c
new file mode 100644
index 0000000..814a366
--- /dev/null
+++ b/librpc/ndr/ndr_dnsserver.c
@@ -0,0 +1,100 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Manually parsed structures for DNSSERVER
+
+ Copyright (C) Amitay Isaacs 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 "librpc/gen_ndr/ndr_dnsp.h"
+#include "librpc/gen_ndr/ndr_dnsserver.h"
+
+/*
+ * parsing DNS_RPC_RECORDS_ARRAY
+ */
+
+enum ndr_err_code ndr_pull_DNS_RPC_RECORDS_ARRAY(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags, struct DNS_RPC_RECORDS_ARRAY *rec)
+{
+ rec->count = 0;
+ rec->rec = talloc_array(ndr->current_mem_ctx, struct DNS_RPC_RECORDS, rec->count);
+ if (! rec->rec) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull DNS_RPC_RECORDS_ARRAY");
+ }
+
+ while (ndr->offset < ndr->data_size) {
+ rec->rec = talloc_realloc(ndr->current_mem_ctx, rec->rec, struct DNS_RPC_RECORDS, rec->count+1);
+ if (! rec->rec) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull DNS_RPC_RECORDS_ARRAY");
+ }
+ NDR_CHECK(ndr_pull_DNS_RPC_RECORDS(ndr, ndr_flags, &rec->rec[rec->count]));
+ NDR_PULL_ALIGN(ndr, 4);
+ rec->count++;
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_DNS_RPC_RECORDS_ARRAY(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags, const struct DNS_RPC_RECORDS_ARRAY *rec)
+{
+ int i;
+
+ for (i=0; i<rec->count; i++) {
+ NDR_CHECK(ndr_push_DNS_RPC_RECORDS(ndr, ndr_flags, &rec->rec[i]));
+ NDR_PUSH_ALIGN(ndr, 4);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ * Parsing of DNS_RPC_RECORD_STRING
+ */
+
+enum ndr_err_code ndr_pull_DNS_RPC_RECORD_STRING(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags, struct DNS_RPC_RECORD_STRING *rec)
+{
+ rec->count = 0;
+ rec->str = talloc_array(ndr->current_mem_ctx, struct DNS_RPC_NAME, rec->count);
+ if (! rec->str) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull DNS_RPC_RECORD_STRING");
+ }
+
+ while (ndr->offset < ndr->data_size) {
+ rec->str = talloc_realloc(ndr->current_mem_ctx, rec->str, struct DNS_RPC_NAME, rec->count+1);
+ if (! rec->str) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Failed to pull DNS_RPC_RECORD_STRING");
+ }
+ NDR_CHECK(ndr_pull_DNS_RPC_NAME(ndr, ndr_flags, &rec->str[rec->count]));
+ rec->count++;
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_DNS_RPC_RECORD_STRING(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags, const struct DNS_RPC_RECORD_STRING *rec)
+{
+ int i;
+
+ for (i=0; i<rec->count; i++) {
+ NDR_CHECK(ndr_push_DNS_RPC_NAME(ndr, ndr_flags, &rec->str[i]));
+ }
+
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_dnsserver.h b/librpc/ndr/ndr_dnsserver.h
new file mode 100644
index 0000000..04eb220
--- /dev/null
+++ b/librpc/ndr/ndr_dnsserver.h
@@ -0,0 +1,25 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Manually parsed structures for DNSSERVER
+
+ Copyright (C) Amitay Isaacs 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/>.
+*/
+
+enum ndr_err_code ndr_pull_DNS_RPC_RECORDS_ARRAY(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags, struct DNS_RPC_RECORDS_ARRAY *rec);
+enum ndr_err_code ndr_push_DNS_RPC_RECORDS_ARRAY(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags, const struct DNS_RPC_RECORDS_ARRAY *rec);
diff --git a/librpc/ndr/ndr_drsblobs.c b/librpc/ndr/ndr_drsblobs.c
new file mode 100644
index 0000000..b6eea17
--- /dev/null
+++ b/librpc/ndr/ndr_drsblobs.c
@@ -0,0 +1,220 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Manually parsed structures found in the DRS protocol
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
+ Copyright (C) Guenther Deschner <gd@samba.org> 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 "librpc/gen_ndr/ndr_drsblobs.h"
+#include "../lib/util/asn1.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_AuthenticationInformationArray(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct AuthenticationInformationArray *r)
+{
+ uint32_t cntr_array_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ for (cntr_array_0 = 0; cntr_array_0 < r->count; cntr_array_0++) {
+ NDR_CHECK(ndr_push_AuthenticationInformation(ndr, NDR_SCALARS, &r->array[cntr_array_0]));
+ }
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_AuthenticationInformationArray(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct AuthenticationInformationArray *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ r->count = 0;
+ NDR_PULL_ALLOC_N(ndr, r->array, r->count);
+ /* entry is at least 16 bytes large */
+ while (ndr->offset + 16 <= ndr->data_size) {
+ r->array = talloc_realloc(ndr, r->array, struct AuthenticationInformation, r->count + 1);
+ NDR_ERR_HAVE_NO_MEMORY(r->array);
+ NDR_CHECK(ndr_pull_AuthenticationInformation(ndr, NDR_SCALARS, &r->array[r->count]));
+ r->count++;
+ }
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_trustAuthInOutBlob(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct trustAuthInOutBlob *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, (r->count > 0)?12:0));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, (r->count > 0)?12 + ndr_size_AuthenticationInformationArray(&r->current, 0):0));
+ {
+ struct ndr_push *_ndr_current;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_current, 0, ((r->count > 0)?12 + ndr_size_AuthenticationInformationArray(&r->current, 0):0) - ((r->count > 0)?12:0)));
+ NDR_CHECK(ndr_push_AuthenticationInformationArray(_ndr_current, NDR_SCALARS, &r->current));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_current, 0, ((r->count > 0)?12 + ndr_size_AuthenticationInformationArray(&r->current, 0):0) - ((r->count > 0)?12:0)));
+ }
+ {
+ libndr_flags _flags_save_AuthenticationInformationArray = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ {
+ struct ndr_push *_ndr_previous;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_previous, 0, -1));
+ NDR_CHECK(ndr_push_AuthenticationInformationArray(_ndr_previous, NDR_SCALARS, &r->previous));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_previous, 0, -1));
+ }
+ ndr->flags = _flags_save_AuthenticationInformationArray;
+ }
+ NDR_CHECK(ndr_push_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+
+_PUBLIC_ enum ndr_err_code ndr_pull_trustDomainPasswords(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct trustDomainPasswords *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t offset;
+ NDR_PULL_ALIGN(ndr, 4);
+ NDR_PULL_NEED_BYTES(ndr, 8);
+
+ offset = ndr->offset;
+ ndr->offset = ndr->data_size - 8;
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->outgoing_size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->incoming_size));
+
+ ndr->offset = offset;
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->confounder, 512));
+ {
+ struct ndr_pull *_ndr_outgoing;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_outgoing, 0, r->outgoing_size));
+ NDR_CHECK(ndr_pull_trustAuthInOutBlob(_ndr_outgoing, NDR_SCALARS|NDR_BUFFERS, &r->outgoing));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_outgoing, 0, r->outgoing_size));
+ }
+ {
+ struct ndr_pull *_ndr_incoming;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_incoming, 0, r->incoming_size));
+ NDR_CHECK(ndr_pull_trustAuthInOutBlob(_ndr_incoming, NDR_SCALARS|NDR_BUFFERS, &r->incoming));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_incoming, 0, r->incoming_size));
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->outgoing_size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->incoming_size));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_MSPrefixMap_Entry(struct ndr_print *ndr, const char *name, const struct drsuapi_MSPrefixMap_Entry *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_MSPrefixMap_Entry");
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ ndr->depth++;
+ ndr_print_uint16(ndr, "entryID", r->entryID);
+ ndr->print(ndr, "%-25s: length=%"PRIu16, "oid", r->length);
+ if (r->binary_oid) {
+ char *partial_oid = NULL;
+ DATA_BLOB oid_blob = data_blob_const(r->binary_oid, r->length);
+ char *hex_str = data_blob_hex_string_upper(ndr, &oid_blob);
+ ber_read_partial_OID_String(ndr, oid_blob, &partial_oid);
+ ndr->depth++;
+ ndr->print(ndr, "%-25s: 0x%s (%s)", "binary_oid", hex_str, partial_oid);
+ ndr->depth--;
+ talloc_free(hex_str);
+ talloc_free(partial_oid);
+ }
+ ndr->depth--;
+ ndr->flags = _flags_save_STRUCT;
+ }
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_supplementalCredentialsSubBlob(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct supplementalCredentialsSubBlob *r)
+{
+ uint32_t cntr_packages_0;
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ if ((r->signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE)
+ && (r->num_packages == 0)) {
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_push_align(ndr, 3));
+ NDR_CHECK(ndr_push_charset(ndr, NDR_SCALARS, SUPPLEMENTAL_CREDENTIALS_PREFIX, 0x30, sizeof(uint16_t), CH_UTF16));
+ NDR_CHECK(ndr_push_supplementalCredentialsSignature(ndr, NDR_SCALARS, SUPPLEMENTAL_CREDENTIALS_SIGNATURE));
+ if (r->num_packages > 0) {
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->num_packages));
+ }
+ for (cntr_packages_0 = 0; cntr_packages_0 < (r->num_packages); cntr_packages_0++) {
+ NDR_CHECK(ndr_push_supplementalCredentialsPackage(ndr, NDR_SCALARS, &r->packages[cntr_packages_0]));
+ }
+ NDR_CHECK(ndr_push_trailer_align(ndr, 3));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_supplementalCredentialsSubBlob(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct supplementalCredentialsSubBlob *r)
+{
+ uint32_t size_prefix_0 = 0;
+ uint32_t size_packages_0 = 0;
+ uint32_t cntr_packages_0;
+ TALLOC_CTX *_mem_save_packages_0 = NULL;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t remaining = 0;
+ NDR_CHECK(ndr_pull_align(ndr, 3));
+ size_prefix_0 = 0x30;
+ remaining = ndr->data_size - ndr->offset;
+ if (remaining >= size_prefix_0) {
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->prefix, size_prefix_0, sizeof(uint16_t), CH_UTF16));
+ } else {
+ r->prefix = NULL;
+ }
+ remaining = ndr->data_size - ndr->offset;
+ if (remaining >= 2) {
+ NDR_CHECK(ndr_pull_supplementalCredentialsSignature(ndr, NDR_SCALARS, &r->signature));
+ } else {
+ r->signature = 0;
+ }
+ remaining = ndr->data_size - ndr->offset;
+ if (remaining > 0) {
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->num_packages));
+ } else {
+ r->num_packages = 0;
+ }
+ size_packages_0 = r->num_packages;
+ NDR_PULL_ALLOC_N(ndr, r->packages, size_packages_0);
+ _mem_save_packages_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->packages, 0);
+ for (cntr_packages_0 = 0; cntr_packages_0 < (size_packages_0); cntr_packages_0++) {
+ NDR_CHECK(ndr_pull_supplementalCredentialsPackage(ndr, NDR_SCALARS, &r->packages[cntr_packages_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_packages_0, 0);
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 3));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_drsblobs.h b/librpc/ndr/ndr_drsblobs.h
new file mode 100644
index 0000000..d310808
--- /dev/null
+++ b/librpc/ndr/ndr_drsblobs.h
@@ -0,0 +1,23 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Manually parsed structures found in the DRS protocol
+
+ Copyright (C) Andrew Bartlett <abartlet@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/>.
+*/
+
+_PUBLIC_ enum ndr_err_code ndr_pull_trustDomainPasswords(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct trustDomainPasswords *r);
+_PUBLIC_ void ndr_print_drsuapi_MSPrefixMap_Entry(struct ndr_print *ndr, const char *name, const struct drsuapi_MSPrefixMap_Entry *r);
diff --git a/librpc/ndr/ndr_drsuapi.c b/librpc/ndr/ndr_drsuapi.c
new file mode 100644
index 0000000..63d1d74
--- /dev/null
+++ b/librpc/ndr/ndr_drsuapi.c
@@ -0,0 +1,577 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for printing some linked list structs in DRSUAPI
+
+ Copyright (C) Stefan (metze) Metzmacher 2005
+ Copyright (C) Matthieu Patou 2013
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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_drsuapi.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "../lib/util/asn1.h"
+#include "librpc/ndr/ndr_compression.h"
+/* We don't need multibyte if we're just comparing to 'ff' */
+#undef strncasecmp
+
+void ndr_print_drsuapi_DsReplicaObjectListItem(struct ndr_print *ndr, const char *name,
+ const struct drsuapi_DsReplicaObjectListItem *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectListItem");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "next_object", r->next_object);
+ ndr_print_drsuapi_DsReplicaObject(ndr, "object", &r->object);
+ ndr->depth--;
+ if (r->next_object) {
+ ndr_print_drsuapi_DsReplicaObjectListItem(ndr, "next_object", r->next_object);
+ }
+}
+
+void ndr_print_drsuapi_DsReplicaObjectListItemEx(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectListItemEx *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaObjectListItemEx");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "next_object", r->next_object);
+ ndr_print_drsuapi_DsReplicaObject(ndr, "object", &r->object);
+ ndr_print_uint32(ndr, "is_nc_prefix", r->is_nc_prefix);
+ ndr_print_ptr(ndr, "parent_object_guid", r->parent_object_guid);
+ ndr->depth++;
+ if (r->parent_object_guid) {
+ ndr_print_GUID(ndr, "parent_object_guid", r->parent_object_guid);
+ }
+ ndr->depth--;
+ ndr_print_ptr(ndr, "meta_data_ctr", r->meta_data_ctr);
+ ndr->depth++;
+ if (r->meta_data_ctr) {
+ ndr_print_drsuapi_DsReplicaMetaDataCtr(ndr, "meta_data_ctr", r->meta_data_ctr);
+ }
+ ndr->depth--;
+ ndr->depth--;
+ if (r->next_object) {
+ ndr_print_drsuapi_DsReplicaObjectListItemEx(ndr, "next_object", r->next_object);
+ }
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaOID(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaOID *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaOID");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "length", r->length);
+ ndr->print(ndr, "%-25s: length=%"PRIu32, "oid", r->length);
+ if (r->binary_oid) {
+ char *partial_oid = NULL;
+ DATA_BLOB oid_blob = data_blob_const(r->binary_oid, r->length);
+ char *hex_str = data_blob_hex_string_upper(ndr, &oid_blob);
+ ber_read_partial_OID_String(ndr, oid_blob, &partial_oid);
+ ndr->depth++;
+ ndr->print(ndr, "%-25s: 0x%s (%s)", "binary_oid", hex_str, partial_oid);
+ ndr->depth--;
+ talloc_free(hex_str);
+ talloc_free(partial_oid);
+ }
+ ndr->depth--;
+}
+
+static void _print_drsuapi_DsAttributeValue_attid(struct ndr_print *ndr, const char *name,
+ const struct drsuapi_DsAttributeValue *r)
+{
+ uint32_t v;
+
+ ndr_print_struct(ndr, name, "drsuapi_DsAttributeValue");
+ ndr->depth++;
+ if (r->blob == NULL || r->blob->data == NULL) {
+ ndr_print_string(ndr, "attid", "NULL");
+ } else if (r->blob->length < 4) {
+ ndr_print_DATA_BLOB(ndr, "attid", *r->blob);
+ } else {
+ v = IVAL(r->blob->data, 0);
+ ndr_print_uint32(ndr, "attid", v);
+ }
+ ndr->depth--;
+}
+
+static void _print_drsuapi_DsAttributeValue_str(struct ndr_print *ndr, const char *name,
+ const struct drsuapi_DsAttributeValue *r)
+{
+ void *p;
+ size_t converted_size = 0;
+
+ ndr_print_struct(ndr, name, "drsuapi_DsAttributeValue");
+ ndr->depth++;
+ if (r->blob == NULL || r->blob->data == NULL) {
+ ndr_print_string(ndr, "string", "NULL");
+ } else if (!convert_string_talloc(ndr,
+ CH_UTF16, CH_UNIX,
+ r->blob->data,
+ r->blob->length,
+ &p, &converted_size)) {
+ ndr_print_DATA_BLOB(ndr, "string (INVALID CONVERSION)",
+ *r->blob);
+ } else {
+ char *str = (char *)p;
+ ndr_print_string(ndr, "string", str);
+ talloc_free(str);
+ }
+ ndr->depth--;
+}
+
+static void _print_drsuapi_DsAttributeValueCtr(struct ndr_print *ndr,
+ const char *name,
+ const struct drsuapi_DsAttributeValueCtr *r,
+ void (*print_val_fn)(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAttributeValue *r))
+{
+ uint32_t cntr_values_1;
+ ndr_print_struct(ndr, name, "drsuapi_DsAttributeValueCtr");
+ ndr->depth++;
+ ndr_print_uint32(ndr, "num_values", r->num_values);
+ ndr_print_ptr(ndr, "values", r->values);
+ ndr->depth++;
+ if (r->values) {
+ ndr->print(ndr, "%s: ARRAY(%"PRIu32")", "values", r->num_values);
+ ndr->depth++;
+ for (cntr_values_1=0;cntr_values_1<r->num_values;cntr_values_1++) {
+ char *idx_1=NULL;
+ if (asprintf(&idx_1, "[%"PRIu32"]", cntr_values_1) != -1) {
+ //ndr_print_drsuapi_DsAttributeValue(ndr, "values", &r->values[cntr_values_1]);
+ print_val_fn(ndr, "values", &r->values[cntr_values_1]);
+ free(idx_1);
+ }
+ }
+ ndr->depth--;
+ }
+ ndr->depth--;
+ ndr->depth--;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsReplicaAttribute(struct ndr_print *ndr,
+ const char *name,
+ const struct drsuapi_DsReplicaAttribute *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsReplicaAttribute");
+ ndr->depth++;
+ ndr_print_drsuapi_DsAttributeId(ndr, "attid", r->attid);
+ switch (r->attid) {
+ case DRSUAPI_ATTID_objectClass:
+ case DRSUAPI_ATTID_possSuperiors:
+ case DRSUAPI_ATTID_subClassOf:
+ case DRSUAPI_ATTID_governsID:
+ case DRSUAPI_ATTID_mustContain:
+ case DRSUAPI_ATTID_mayContain:
+ case DRSUAPI_ATTID_rDNAttId:
+ case DRSUAPI_ATTID_attributeID:
+ case DRSUAPI_ATTID_attributeSyntax:
+ case DRSUAPI_ATTID_auxiliaryClass:
+ case DRSUAPI_ATTID_systemPossSuperiors:
+ case DRSUAPI_ATTID_systemMayContain:
+ case DRSUAPI_ATTID_systemMustContain:
+ case DRSUAPI_ATTID_systemAuxiliaryClass:
+ case DRSUAPI_ATTID_transportAddressAttribute:
+ /* ATTIDs for classSchema and attributeSchema */
+ _print_drsuapi_DsAttributeValueCtr(ndr, "value_ctr", &r->value_ctr,
+ _print_drsuapi_DsAttributeValue_attid);
+ break;
+ case DRSUAPI_ATTID_cn:
+ case DRSUAPI_ATTID_ou:
+ case DRSUAPI_ATTID_description:
+ case DRSUAPI_ATTID_displayName:
+ case DRSUAPI_ATTID_dMDLocation:
+ case DRSUAPI_ATTID_adminDisplayName:
+ case DRSUAPI_ATTID_adminDescription:
+ case DRSUAPI_ATTID_lDAPDisplayName:
+ case DRSUAPI_ATTID_name:
+ _print_drsuapi_DsAttributeValueCtr(ndr, "value_ctr", &r->value_ctr,
+ _print_drsuapi_DsAttributeValue_str);
+ break;
+ default:
+ _print_drsuapi_DsAttributeValueCtr(ndr, "value_ctr", &r->value_ctr,
+ ndr_print_drsuapi_DsAttributeValue);
+ break;
+ }
+ ndr->depth--;
+}
+
+enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesMSZIPCtr1(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct drsuapi_DsGetNCChangesMSZIPCtr1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t decompressed_length = 0;
+ uint32_t compressed_length = 0;
+ if (r->ts) {
+ {
+ struct ndr_push *_ndr_ts;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1));
+ {
+ struct ndr_push *_ndr_ts_compressed;
+ NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_MSZIP));
+ NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts));
+ decompressed_length = _ndr_ts_compressed->offset;
+ NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed));
+ }
+ compressed_length = _ndr_ts->offset;
+ talloc_free(_ndr_ts);
+ }
+ }
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ts) {
+ {
+ struct ndr_push *_ndr_ts;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1));
+ {
+ struct ndr_push *_ndr_ts_compressed;
+ NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_MSZIP));
+ NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts));
+ NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed));
+ }
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesMSZIPCtr6(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct drsuapi_DsGetNCChangesMSZIPCtr6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t decompressed_length = 0;
+ uint32_t compressed_length = 0;
+ if (r->ts) {
+ {
+ struct ndr_push *_ndr_ts;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1));
+ {
+ struct ndr_push *_ndr_ts_compressed;
+ NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_MSZIP));
+ NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts));
+ decompressed_length = _ndr_ts_compressed->offset;
+ NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed));
+ }
+ compressed_length = _ndr_ts->offset;
+ talloc_free(_ndr_ts);
+ }
+ }
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ts) {
+ {
+ struct ndr_push *_ndr_ts;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1));
+ {
+ struct ndr_push *_ndr_ts_compressed;
+ NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_MSZIP));
+ NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts));
+ NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed));
+ }
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr1(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr1 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t decompressed_length = 0;
+ uint32_t compressed_length = 0;
+ if (r->ts) {
+ {
+ struct ndr_push *_ndr_ts;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1));
+ {
+ struct ndr_push *_ndr_ts_compressed;
+ NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2));
+ NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts));
+ decompressed_length = _ndr_ts_compressed->offset;
+ NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed));
+ }
+ compressed_length = _ndr_ts->offset;
+ talloc_free(_ndr_ts);
+ }
+ }
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ts) {
+ {
+ struct ndr_push *_ndr_ts;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1));
+ {
+ struct ndr_push *_ndr_ts_compressed;
+ NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2));
+ NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts));
+ NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed));
+ }
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr6(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct drsuapi_DsGetNCChangesWIN2K3_LZ77_DIRECT2Ctr6 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t decompressed_length = 0;
+ uint32_t compressed_length = 0;
+ if (r->ts) {
+ {
+ struct ndr_push *_ndr_ts;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1));
+ {
+ struct ndr_push *_ndr_ts_compressed;
+ NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2));
+ NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts));
+ decompressed_length = _ndr_ts_compressed->offset;
+ NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed));
+ }
+ compressed_length = _ndr_ts->offset;
+ talloc_free(_ndr_ts);
+ }
+ }
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->ts) {
+ {
+ struct ndr_push *_ndr_ts;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1));
+ {
+ struct ndr_push *_ndr_ts_compressed;
+ NDR_CHECK(ndr_push_compression_state_init(_ndr_ts, NDR_COMPRESSION_WIN2K3_LZ77_DIRECT2));
+ NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed));
+ NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts));
+ NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed));
+ }
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1));
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ size_t ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary_without_Binary(const struct drsuapi_DsReplicaObjectIdentifier3Binary *r, libndr_flags flags)
+{
+ return ndr_size_struct((const struct drsuapi_DsReplicaObjectIdentifier3 *)r, flags, (ndr_push_flags_fn_t)ndr_push_drsuapi_DsReplicaObjectIdentifier3);
+}
+
+_PUBLIC_ void ndr_print_drsuapi_SecBufferType(struct ndr_print *ndr, const char *name, enum drsuapi_SecBufferType r)
+{
+ const char *val = NULL;
+
+ switch (r & 0x00000007) {
+ case DRSUAPI_SECBUFFER_EMPTY: val = "DRSUAPI_SECBUFFER_EMPTY"; break;
+ case DRSUAPI_SECBUFFER_DATA: val = "DRSUAPI_SECBUFFER_DATA"; break;
+ case DRSUAPI_SECBUFFER_TOKEN: val = "DRSUAPI_SECBUFFER_TOKEN"; break;
+ case DRSUAPI_SECBUFFER_PKG_PARAMS: val = "DRSUAPI_SECBUFFER_PKG_PARAMS"; break;
+ case DRSUAPI_SECBUFFER_MISSING: val = "DRSUAPI_SECBUFFER_MISSING"; break;
+ case DRSUAPI_SECBUFFER_EXTRA: val = "DRSUAPI_SECBUFFER_EXTRA"; break;
+ case DRSUAPI_SECBUFFER_STREAM_TRAILER: val = "DRSUAPI_SECBUFFER_STREAM_TRAILER"; break;
+ case DRSUAPI_SECBUFFER_STREAM_HEADER: val = "DRSUAPI_SECBUFFER_STREAM_HEADER"; break;
+ }
+
+ if (r & DRSUAPI_SECBUFFER_READONLY) {
+ char *v = talloc_asprintf(ndr, "DRSUAPI_SECBUFFER_READONLY | %s", val);
+ ndr_print_enum(ndr, name, "ENUM", v, r);
+ } else {
+ ndr_print_enum(ndr, name, "ENUM", val, r);
+ }
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsAddEntry_AttrErrListItem_V1(struct ndr_print *ndr, const char *name, const struct drsuapi_DsAddEntry_AttrErrListItem_V1 *r)
+{
+ ndr_print_struct(ndr, name, "drsuapi_DsAddEntry_AttrErrListItem_V1");
+ ndr->depth++;
+ ndr_print_ptr(ndr, "next", r->next);
+ ndr_print_drsuapi_DsAddEntry_AttrErr_V1(ndr, "err_data", &r->err_data);
+ ndr->depth--;
+ if (r->next) {
+ ndr_print_drsuapi_DsAddEntry_AttrErrListItem_V1(ndr, "next", r->next);
+ }
+}
+
+enum ndr_err_code ndr_push_drsuapi_DsBindInfo(struct ndr_push *ndr, ndr_flags_type ndr_flags, const union drsuapi_DsBindInfo *r)
+{
+ libndr_flags _flags_save = ndr->flags;
+ ndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t level;
+ NDR_CHECK(ndr_push_steal_switch_value(ndr, r, &level));
+ NDR_CHECK(ndr_push_union_align(ndr, 4));
+ switch (level) {
+ case 24: {
+ {
+ struct ndr_push *_ndr_info24;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info24, 0, 24));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfo24(_ndr_info24, NDR_SCALARS, &r->info24));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info24, 0, 24));
+ }
+ break; }
+
+ case 28: {
+ {
+ struct ndr_push *_ndr_info28;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info28, 0, 28));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfo28(_ndr_info28, NDR_SCALARS, &r->info28));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info28, 0, 28));
+ }
+ break; }
+
+ case 48: {
+ {
+ struct ndr_push *_ndr_info48;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info48, 0, 48));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfo48(_ndr_info48, NDR_SCALARS, &r->info48));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info48, 0, 48));
+ }
+ break; }
+
+ case 52: {
+ {
+ struct ndr_push *_ndr_info52;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info52, 0, 52));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfo52(_ndr_info52, NDR_SCALARS, &r->info52));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info52, 0, 52));
+ }
+ break; }
+
+ default: {
+ {
+ struct ndr_push *_ndr_Fallback;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_Fallback, 0, level));
+ NDR_CHECK(ndr_push_drsuapi_DsBindInfoFallBack(_ndr_Fallback, NDR_SCALARS, &r->Fallback));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_Fallback, 0, level));
+ }
+ break; }
+
+ }
+ }
+ ndr->flags = _flags_save;
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_drsuapi_DsBindInfo(struct ndr_pull *ndr, ndr_flags_type ndr_flags, union drsuapi_DsBindInfo *r)
+{
+ libndr_flags _flags_save = ndr->flags;
+ ndr->flags = ndr->flags & ~LIBNDR_FLAG_NDR64;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t level;
+ NDR_CHECK(ndr_pull_steal_switch_value(ndr, r, &level));
+ NDR_CHECK(ndr_pull_union_align(ndr, 4));
+ switch (level) {
+ case 24: {
+ {
+ struct ndr_pull *_ndr_info24;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info24, 0, 24));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfo24(_ndr_info24, NDR_SCALARS, &r->info24));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info24, 0, 24));
+ }
+ break; }
+
+ case 28: {
+ {
+ struct ndr_pull *_ndr_info28;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info28, 0, 28));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfo28(_ndr_info28, NDR_SCALARS, &r->info28));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info28, 0, 28));
+ }
+ break; }
+
+ case 48: {
+ {
+ struct ndr_pull *_ndr_info48;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info48, 0, 48));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfo48(_ndr_info48, NDR_SCALARS, &r->info48));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info48, 0, 48));
+ }
+ break; }
+
+ case 52: {
+ {
+ struct ndr_pull *_ndr_info52;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info52, 0, 52));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfo52(_ndr_info52, NDR_SCALARS, &r->info52));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info52, 0, 52));
+ }
+ break; }
+
+ default: {
+ {
+ struct ndr_pull *_ndr_Fallback;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_Fallback, 0, level));
+ NDR_CHECK(ndr_pull_drsuapi_DsBindInfoFallBack(_ndr_Fallback, NDR_SCALARS, &r->Fallback));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_Fallback, 0, level));
+ }
+ break; }
+
+ }
+ }
+ ndr->flags = _flags_save;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_drsuapi_DsBindInfo(struct ndr_print *ndr, const char *name, const union drsuapi_DsBindInfo *r)
+{
+ uint32_t level;
+ level = ndr_print_steal_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "drsuapi_DsBindInfo");
+ switch (level) {
+ case 24:
+ ndr_print_drsuapi_DsBindInfo24(ndr, "info24", &r->info24);
+ break;
+
+ case 28:
+ ndr_print_drsuapi_DsBindInfo28(ndr, "info28", &r->info28);
+ break;
+
+ case 48:
+ ndr_print_drsuapi_DsBindInfo48(ndr, "info48", &r->info48);
+ break;
+
+ case 52:
+ ndr_print_drsuapi_DsBindInfo52(ndr, "info52", &r->info52);
+ break;
+
+ default:
+ ndr_print_drsuapi_DsBindInfoFallBack(ndr, "Fallback", &r->Fallback);
+ break;
+
+ }
+}
diff --git a/librpc/ndr/ndr_drsuapi.h b/librpc/ndr/ndr_drsuapi.h
new file mode 100644
index 0000000..6399a34
--- /dev/null
+++ b/librpc/ndr/ndr_drsuapi.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for printing some linked list structs in DRSUAPI
+
+ Copyright (C) Stefan (metze) Metzmacher 2005-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 _LIBRPC_NDR_NDR_DRSUAPI_H
+#define _LIBRPC_NDR_NDR_DRSUAPI_H
+
+void ndr_print_drsuapi_DsReplicaObjectListItem(struct ndr_print *ndr, const char *name,
+ const struct drsuapi_DsReplicaObjectListItem *r);
+
+void ndr_print_drsuapi_DsReplicaObjectListItemEx(struct ndr_print *ndr, const char *name,
+ const struct drsuapi_DsReplicaObjectListItemEx *r);
+
+size_t ndr_size_drsuapi_DsReplicaObjectIdentifier3Binary_without_Binary(const struct drsuapi_DsReplicaObjectIdentifier3Binary *r, libndr_flags flags);
+
+
+#endif /* _LIBRPC_NDR_NDR_DRSUAPI_H */
diff --git a/librpc/ndr/ndr_frsrpc.c b/librpc/ndr/ndr_frsrpc.c
new file mode 100644
index 0000000..78c00ed
--- /dev/null
+++ b/librpc/ndr/ndr_frsrpc.c
@@ -0,0 +1,92 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ helper routines for FRSRPC marshalling
+
+ Copyright (C) Stefan (metze) Metzmacher 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 "librpc/gen_ndr/ndr_frsrpc.h"
+
+enum ndr_err_code ndr_push_frsrpc_CommPktChunkCtr(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct frsrpc_CommPktChunkCtr *r)
+{
+ uint32_t cntr_chunks_0;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 2));
+ for (cntr_chunks_0 = 0; cntr_chunks_0 < r->num_chunks; cntr_chunks_0++) {
+ NDR_CHECK(ndr_push_frsrpc_CommPktChunk(ndr, NDR_SCALARS, &r->chunks[cntr_chunks_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+#define _TMP_PULL_REALLOC_N(ndr, s, t, n) do { \
+ _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\
+ (s) = talloc_realloc(ndr->current_mem_ctx, (s), t, n); \
+ if (!(s)) { \
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC, \
+ "Alloc %u * %s failed: %s\n", \
+ (unsigned)n, # s, __location__); \
+ } \
+} while (0)
+
+enum ndr_err_code ndr_pull_frsrpc_CommPktChunkCtr(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct frsrpc_CommPktChunkCtr *r)
+{
+ uint32_t cntr_chunks_0;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t remaining = ndr->data_size - ndr->offset;
+ r->num_chunks = 0;
+ r->chunks = NULL;
+ for (cntr_chunks_0 = 0; remaining > 0; cntr_chunks_0++) {
+ r->num_chunks += 1;
+ _TMP_PULL_REALLOC_N(ndr, r->chunks,
+ struct frsrpc_CommPktChunk,
+ r->num_chunks);
+ NDR_CHECK(ndr_pull_frsrpc_CommPktChunk(ndr,
+ NDR_SCALARS,
+ &r->chunks[cntr_chunks_0]));
+ remaining = ndr->data_size - ndr->offset;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+size_t ndr_size_frsrpc_CommPktChunkCtr(const struct frsrpc_CommPktChunkCtr *r,
+ libndr_flags flags)
+{
+ flags |= LIBNDR_FLAG_NOALIGN;
+ return ndr_size_struct(r, flags,
+ (ndr_push_flags_fn_t)ndr_push_frsrpc_CommPktChunkCtr);
+}
diff --git a/librpc/ndr/ndr_frsrpc.h b/librpc/ndr/ndr_frsrpc.h
new file mode 100644
index 0000000..afdfd66
--- /dev/null
+++ b/librpc/ndr/ndr_frsrpc.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ helper routines for FRSRPC marshalling
+
+ Copyright (C) Stefan (metze) Metzmacher 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 _LIBRPC_NDR_NDR_FRSRPC_H
+#define _LIBRPC_NDR_NDR_FRSRPC_H
+
+enum ndr_err_code ndr_push_frsrpc_CommPktChunkCtr(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct frsrpc_CommPktChunkCtr *r);
+enum ndr_err_code ndr_pull_frsrpc_CommPktChunkCtr(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct frsrpc_CommPktChunkCtr *r);
+size_t ndr_size_frsrpc_CommPktChunkCtr(const struct frsrpc_CommPktChunkCtr *r,
+ libndr_flags flags);
+
+#endif /* _LIBRPC_NDR_NDR_FRSRPC_H */
diff --git a/librpc/ndr/ndr_ioctl.c b/librpc/ndr/ndr_ioctl.c
new file mode 100644
index 0000000..7e76abc
--- /dev/null
+++ b/librpc/ndr/ndr_ioctl.c
@@ -0,0 +1,40 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Manually parsed structures for IOCTL/FSCTL
+
+ Copyright (C) Stefan Metzmacher 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 "includes.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
+
+_PUBLIC_ void ndr_print_fsctl_net_iface_info(struct ndr_print *ndr, const char *name, const struct fsctl_net_iface_info *r)
+{
+ ndr_print_struct(ndr, name, "fsctl_net_iface_info");
+ if (r == NULL) { ndr_print_null(ndr); return; }
+ ndr->depth++;
+ ndr_print_ptr(ndr, "next", r->next);
+ ndr_print_uint32(ndr, "ifindex", r->ifindex);
+ ndr_print_fsctl_net_iface_capability(ndr, "capability", r->capability);
+ ndr_print_uint32(ndr, "reserved", (ndr->flags & LIBNDR_PRINT_SET_VALUES)?0:r->reserved);
+ ndr_print_hyper(ndr, "linkspeed", r->linkspeed);
+ ndr_print_fsctl_sockaddr_storage(ndr, "sockaddr", &r->sockaddr);
+ ndr->depth--;
+ if (r->next) {
+ ndr_print_fsctl_net_iface_info(ndr, "next", r->next);
+ }
+}
diff --git a/librpc/ndr/ndr_krb5pac.c b/librpc/ndr/ndr_krb5pac.c
new file mode 100644
index 0000000..60eacd3
--- /dev/null
+++ b/librpc/ndr/ndr_krb5pac.c
@@ -0,0 +1,130 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling spoolss subcontext buffer structures
+
+ Copyright (C) Stefan Metzmacher 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 "librpc/gen_ndr/ndr_krb5pac.h"
+
+size_t _ndr_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, libndr_flags flags)
+{
+ size_t s = ndr_size_PAC_INFO(r, level, flags);
+ switch (level) {
+ case PAC_TYPE_LOGON_INFO:
+ return NDR_ROUND(s,8);
+ case PAC_TYPE_UPN_DNS_INFO:
+ return NDR_ROUND(s,8);
+ default:
+ return s;
+ }
+}
+
+enum ndr_err_code ndr_push_PAC_BUFFER(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct PAC_BUFFER *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_PAC_TYPE(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, _ndr_size_PAC_INFO(r->info,r->type,LIBNDR_FLAG_ALIGN8)));
+ {
+ libndr_flags _flags_save_PAC_INFO = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->info));
+ ndr->flags = _flags_save_PAC_INFO;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ libndr_flags _flags_save_PAC_INFO = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ if (r->info) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->info));
+ {
+ struct ndr_push *_ndr_info_pad;
+ struct ndr_push *_ndr_info;
+ size_t _ndr_size = _ndr_size_PAC_INFO(r->info, r->type, LIBNDR_FLAG_ALIGN8);
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_info_pad, 0, NDR_ROUND(_ndr_size, 8)));
+ NDR_CHECK(ndr_push_subcontext_start(_ndr_info_pad, &_ndr_info, 0, _ndr_size));
+ NDR_CHECK(ndr_push_set_switch_value(_ndr_info, r->info, r->type));
+ NDR_CHECK(ndr_push_PAC_INFO(_ndr_info, NDR_SCALARS|NDR_BUFFERS, r->info));
+ NDR_CHECK(ndr_push_subcontext_end(_ndr_info_pad, _ndr_info, 0, _ndr_size));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_info_pad, 0, NDR_ROUND(_ndr_size, 8)));
+ }
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->info));
+ }
+ ndr->flags = _flags_save_PAC_INFO;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct PAC_BUFFER *r)
+{
+ uint32_t _ptr_info;
+ TALLOC_CTX *_mem_save_info_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_PAC_TYPE(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->_ndr_size));
+ {
+ libndr_flags _flags_save_PAC_INFO = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info));
+ if (_ptr_info) {
+ NDR_PULL_ALLOC(ndr, r->info);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->info, _ptr_info));
+ } else {
+ r->info = NULL;
+ }
+ ndr->flags = _flags_save_PAC_INFO;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->_pad));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ libndr_flags _flags_save_PAC_INFO = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8);
+ if (r->info) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->info));
+ _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->info, 0);
+ {
+ struct ndr_pull *_ndr_info_pad;
+ struct ndr_pull *_ndr_info;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info_pad, 0, NDR_ROUND(r->_ndr_size, 8)));
+ NDR_CHECK(ndr_pull_subcontext_start(_ndr_info_pad, &_ndr_info, 0, r->_ndr_size));
+ NDR_CHECK(ndr_pull_set_switch_value(_ndr_info, r->info, r->type));
+ NDR_CHECK(ndr_pull_PAC_INFO(_ndr_info, NDR_SCALARS|NDR_BUFFERS, r->info));
+ NDR_CHECK(ndr_pull_subcontext_end(_ndr_info_pad, _ndr_info, 0, r->_ndr_size));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info_pad, 0, NDR_ROUND(r->_ndr_size, 8)));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_PAC_INFO;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_krb5pac.h b/librpc/ndr/ndr_krb5pac.h
new file mode 100644
index 0000000..e009133
--- /dev/null
+++ b/librpc/ndr/ndr_krb5pac.h
@@ -0,0 +1,25 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling spoolss subcontext buffer structures
+
+ Copyright (C) Stefan Metzmacher 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 "librpc/gen_ndr/ndr_krb5pac.h"
+
+size_t _ndr_size_PAC_INFO(const union PAC_INFO *r, uint32_t level, libndr_flags flags);
diff --git a/librpc/ndr/ndr_misc.c b/librpc/ndr/ndr_misc.c
new file mode 100644
index 0000000..de8dcb4
--- /dev/null
+++ b/librpc/ndr/ndr_misc.c
@@ -0,0 +1,77 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ UUID/GUID/policy_handle functions
+
+ Copyright (C) Andrew Tridgell 2003.
+ Copyright (C) Stefan (metze) Metzmacher 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 "system/network.h"
+#include "librpc/ndr/libndr.h"
+#include "libcli/util/ntstatus.h"
+#include "lib/util/util_str_hex.h"
+
+_PUBLIC_ void ndr_print_GUID(struct ndr_print *ndr, const char *name, const struct GUID *guid)
+{
+ struct GUID_txt_buf buf;
+ ndr->print(ndr, "%-25s: %s", name, GUID_buf_string(guid, &buf));
+}
+
+bool ndr_syntax_id_equal(const struct ndr_syntax_id *i1,
+ const struct ndr_syntax_id *i2)
+{
+ return GUID_equal(&i1->uuid, &i2->uuid)
+ && (i1->if_version == i2->if_version);
+}
+
+char *ndr_syntax_id_buf_string(
+ const struct ndr_syntax_id *id, struct ndr_syntax_id_buf *dst)
+{
+ struct GUID_txt_buf guid_buf;
+
+ snprintf(dst->buf,
+ sizeof(dst->buf),
+ "%s/0x%08"PRIx32,
+ GUID_buf_string(&id->uuid, &guid_buf),
+ id->if_version);
+
+ return dst->buf;
+}
+
+_PUBLIC_ char *ndr_syntax_id_to_string(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *id)
+{
+ struct ndr_syntax_id_buf buf;
+ return talloc_strdup(mem_ctx, ndr_syntax_id_buf_string(id, &buf));
+}
+
+_PUBLIC_ bool ndr_syntax_id_from_string(const char *s, struct ndr_syntax_id *id)
+{
+ bool ok;
+
+ ok = parse_guid_string(s, &id->uuid);
+ if (!ok) {
+ return false;
+ }
+
+ if (strncmp(s + 36, "/0x", 3) != 0) {
+ return false;
+ }
+
+ ok = hex_uint32(s+39, &id->if_version);
+ return ok;
+}
diff --git a/librpc/ndr/ndr_nbt.c b/librpc/ndr/ndr_nbt.c
new file mode 100644
index 0000000..6f54198
--- /dev/null
+++ b/librpc/ndr/ndr_nbt.c
@@ -0,0 +1,406 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ CLDAP server structures
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Andrew Bartlett <abartlet@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/>.
+*/
+
+/* parser auto-generated by pidl, then hand-modified by abartlet */
+
+#include "includes.h"
+#include "../libcli/nbt/libnbt.h"
+#include "../libcli/netlogon/netlogon.h"
+#include "ndr_dns_utils.h"
+
+
+/* don't allow an unlimited number of name components */
+#define MAX_COMPONENTS 128
+
+/**
+ print a nbt string
+*/
+_PUBLIC_ void ndr_print_nbt_string(struct ndr_print *ndr, const char *name, const char *s)
+{
+ ndr_print_string(ndr, name, s);
+}
+
+/*
+ pull one component of a nbt_string
+*/
+static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr,
+ uint8_t **component,
+ uint32_t *offset,
+ uint32_t *max_offset)
+{
+ uint8_t len;
+ unsigned int loops = 0;
+ while (loops < 5) {
+ if (*offset >= ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME component");
+ }
+ len = ndr->data[*offset];
+ if (len == 0) {
+ *offset += 1;
+ *max_offset = MAX(*max_offset, *offset);
+ *component = NULL;
+ return NDR_ERR_SUCCESS;
+ }
+ if ((len & 0xC0) == 0xC0) {
+ /* its a label pointer */
+ if (1 + *offset >= ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME component");
+ }
+ *max_offset = MAX(*max_offset, *offset + 2);
+ *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset];
+ *max_offset = MAX(*max_offset, *offset);
+ loops++;
+ continue;
+ }
+ if ((len & 0xC0) != 0) {
+ /* its a reserved length field */
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME component");
+ }
+ if (*offset + len + 1 > ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME component");
+ }
+ *component = (uint8_t*)talloc_strndup(
+ ndr->current_mem_ctx,
+ (const char *)&ndr->data[1 + *offset], len);
+ NDR_ERR_HAVE_NO_MEMORY(*component);
+ *offset += len + 1;
+ *max_offset = MAX(*max_offset, *offset);
+ return NDR_ERR_SUCCESS;
+ }
+
+ /* too many pointers */
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "BAD NBT NAME component");
+}
+
+/**
+ pull a nbt_string from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_nbt_string(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **s)
+{
+ uint32_t offset = ndr->offset;
+ uint32_t max_offset = offset;
+ unsigned num_components;
+ char *name;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ name = NULL;
+
+ /* break up name into a list of components */
+ for (num_components=0;num_components<MAX_COMPONENTS;num_components++) {
+ uint8_t *component = NULL;
+ NDR_CHECK(ndr_pull_component(ndr, &component, &offset, &max_offset));
+ if (component == NULL) break;
+ if (name) {
+ name = talloc_asprintf_append_buffer(name, ".%s", component);
+ NDR_ERR_HAVE_NO_MEMORY(name);
+ } else {
+ name = (char *)component;
+ }
+ }
+ if (num_components == MAX_COMPONENTS) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "BAD NBT NAME too many components");
+ }
+ if (num_components == 0) {
+ name = talloc_strdup(ndr->current_mem_ctx, "");
+ NDR_ERR_HAVE_NO_MEMORY(name);
+ }
+
+ (*s) = name;
+ ndr->offset = max_offset;
+
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a nbt string to the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *s)
+{
+ return ndr_push_dns_string_list(ndr,
+ &ndr->dns_string_list,
+ ndr_flags,
+ s,
+ true);
+}
+
+
+/* Manually modified to handle the dom_sid being optional based on if it is present or all zero */
+enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_REQUEST(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct NETLOGON_SAM_LOGON_REQUEST *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->request_count));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->acct_control));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_dom_sid0(&r->sid, ndr->flags)));
+ if (ndr_size_dom_sid0(&r->sid, ndr->flags)) {
+ struct ndr_push *_ndr_sid;
+ libndr_flags _flags_save_DATA_BLOB = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_push_DATA_BLOB(ndr, NDR_SCALARS, r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags)));
+ NDR_CHECK(ndr_push_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sid, 0, ndr_size_dom_sid0(&r->sid, ndr->flags)));
+ }
+ NDR_CHECK(ndr_push_netlogon_nt_version_flags(ndr, NDR_SCALARS, r->nt_version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/* Manually modified to handle the dom_sid being optional based on if it is present (size is non-zero) or not */
+enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_REQUEST(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct NETLOGON_SAM_LOGON_REQUEST *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->request_count));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->computer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->user_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->mailslot_name));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->acct_control));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sid_size));
+ if (r->sid_size) {
+ libndr_flags _flags_save_DATA_BLOB = ndr->flags;
+ struct ndr_pull *_ndr_sid;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_pull_DATA_BLOB(ndr, NDR_SCALARS, &r->_pad));
+ ndr->flags = _flags_save_DATA_BLOB;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sid, 0, r->sid_size));
+ NDR_CHECK(ndr_pull_dom_sid0(_ndr_sid, NDR_SCALARS|NDR_BUFFERS, &r->sid));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sid, 0, r->sid_size));
+ } else {
+ ZERO_STRUCT(r->sid);
+ }
+ NDR_CHECK(ndr_pull_netlogon_nt_version_flags(ndr, NDR_SCALARS, &r->nt_version));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/* Manually modified to only push some parts of the structure if certain flags are set */
+enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct NETLOGON_SAM_LOGON_RESPONSE_EX *r)
+{
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_netlogon_command(ndr, NDR_SCALARS, r->command));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->sbz));
+ NDR_CHECK(ndr_push_nbt_server_type(ndr, NDR_SCALARS, r->server_type));
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->forest));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->dns_domain));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_dns_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->domain_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->pdc_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->user_name));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->server_site));
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->client_site));
+ if (r->nt_version & NETLOGON_NT_VERSION_5EX_WITH_IP) {
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, ndr_size_nbt_sockaddr(&r->sockaddr, ndr->flags)));
+ {
+ struct ndr_push *_ndr_sockaddr;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_sockaddr, 0, ndr_size_nbt_sockaddr(&r->sockaddr, ndr->flags)));
+ NDR_CHECK(ndr_push_nbt_sockaddr(_ndr_sockaddr, NDR_SCALARS|NDR_BUFFERS, &r->sockaddr));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_sockaddr, 0, ndr_size_nbt_sockaddr(&r->sockaddr, ndr->flags)));
+ }
+ }
+ if (r->nt_version & NETLOGON_NT_VERSION_WITH_CLOSEST_SITE) {
+ NDR_CHECK(ndr_push_nbt_string(ndr, NDR_SCALARS, r->next_closest_site));
+ }
+ NDR_CHECK(ndr_push_netlogon_nt_version_flags(ndr, NDR_SCALARS, r->nt_version));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lmnt_token));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_push_GUID(ndr, NDR_BUFFERS, &r->domain_uuid));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/* Manually modified to only pull some parts of the structure if certain flags provided */
+enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct NETLOGON_SAM_LOGON_RESPONSE_EX *r,
+ uint32_t nt_version_flags)
+{
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ZERO_STRUCTP(r);
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_netlogon_command(ndr, NDR_SCALARS, &r->command));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->sbz));
+ NDR_CHECK(ndr_pull_nbt_server_type(ndr, NDR_SCALARS, &r->server_type));
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->domain_uuid));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->forest));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->dns_domain));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_dns_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->domain_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->pdc_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->user_name));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->server_site));
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->client_site));
+ if (nt_version_flags & NETLOGON_NT_VERSION_5EX_WITH_IP) {
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sockaddr_size));
+ {
+ struct ndr_pull *_ndr_sockaddr;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_sockaddr, 0, r->sockaddr_size));
+ NDR_CHECK(ndr_pull_nbt_sockaddr(_ndr_sockaddr, NDR_SCALARS|NDR_BUFFERS, &r->sockaddr));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_sockaddr, 0, r->sockaddr_size));
+ }
+ }
+ if (nt_version_flags & NETLOGON_NT_VERSION_WITH_CLOSEST_SITE) {
+ NDR_CHECK(ndr_pull_nbt_string(ndr, NDR_SCALARS, &r->next_closest_site));
+ }
+ NDR_CHECK(ndr_pull_netlogon_nt_version_flags(ndr, NDR_SCALARS, &r->nt_version));
+ if (r->nt_version != nt_version_flags) {
+ return NDR_ERR_VALIDATE;
+ }
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lmnt_token));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->lm20_token));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_BUFFERS, &r->domain_uuid));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netlogon_samlogon_response(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct netlogon_samlogon_response *r)
+{
+ if (r->ntver == NETLOGON_NT_VERSION_1) {
+ NDR_CHECK(ndr_push_NETLOGON_SAM_LOGON_RESPONSE_NT40(
+ ndr, ndr_flags, &r->data.nt4));
+ } else if (r->ntver & NETLOGON_NT_VERSION_5EX) {
+ NDR_CHECK(ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(
+ ndr, ndr_flags, &r->data.nt5_ex));
+ } else if (r->ntver & NETLOGON_NT_VERSION_5) {
+ NDR_CHECK(ndr_push_NETLOGON_SAM_LOGON_RESPONSE(
+ ndr, ndr_flags, &r->data.nt5));
+ } else {
+ return NDR_ERR_BAD_SWITCH;
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netlogon_samlogon_response(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct netlogon_samlogon_response *r)
+{
+ if (ndr->data_size < 8) {
+ return NDR_ERR_BUFSIZE;
+ }
+
+ /* lmnttoken */
+ if (SVAL(ndr->data, ndr->data_size - 4) != 0xffff) {
+ return NDR_ERR_TOKEN;
+ }
+ /* lm20token */
+ if (SVAL(ndr->data, ndr->data_size - 2) != 0xffff) {
+ return NDR_ERR_TOKEN;
+ }
+
+ r->ntver = IVAL(ndr->data, ndr->data_size - 8);
+
+ if (r->ntver == NETLOGON_NT_VERSION_1) {
+ NDR_CHECK(ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_NT40(
+ ndr, ndr_flags, &r->data.nt4));
+ } else if (r->ntver & NETLOGON_NT_VERSION_5EX) {
+ NDR_CHECK(ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(
+ ndr, ndr_flags, &r->data.nt5_ex, r->ntver));
+ if (ndr->offset < ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
+ "not all bytes consumed ofs[%"PRIu32"] size[%"PRIu32"]",
+ ndr->offset, ndr->data_size);
+ }
+ } else if (r->ntver & NETLOGON_NT_VERSION_5) {
+ NDR_CHECK(ndr_pull_NETLOGON_SAM_LOGON_RESPONSE(
+ ndr, ndr_flags, &r->data.nt5));
+ } else {
+ return NDR_ERR_BAD_SWITCH;
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netlogon_samlogon_response(struct ndr_print *ndr, const char *name, const struct netlogon_samlogon_response *r)
+{
+ ndr_print_struct(ndr, name, "netlogon_samlogon_response");
+ if (r == NULL) { ndr_print_null(ndr); return; }
+ if (r->ntver == NETLOGON_NT_VERSION_1) {
+ ndr_print_NETLOGON_SAM_LOGON_RESPONSE_NT40(ndr, "data.nt4", &r->data.nt4);
+ } else if (r->ntver & NETLOGON_NT_VERSION_5EX) {
+ ndr_print_NETLOGON_SAM_LOGON_RESPONSE_EX(ndr, "data.nt5_ex", &r->data.nt5_ex);
+ } else if (r->ntver & NETLOGON_NT_VERSION_5) {
+ ndr_print_NETLOGON_SAM_LOGON_RESPONSE(ndr, "data.nt5", &r->data.nt5);
+ }
+}
diff --git a/librpc/ndr/ndr_nbt.h b/librpc/ndr/ndr_nbt.h
new file mode 100644
index 0000000..00ee8a1
--- /dev/null
+++ b/librpc/ndr/ndr_nbt.h
@@ -0,0 +1,42 @@
+#/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special netlogon types
+
+ Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
+ Copyright (C) Guenther Deschner 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/>.
+*/
+
+/* The following definitions come from ../librpc/ndr/ndr_nbt.c */
+
+#ifndef _LIBRPC_NDR_NDR_NBT_H
+#define _LIBRPC_NDR_NDR_NBT_H
+
+#include "librpc/gen_ndr/nbt.h"
+
+NDR_SCALAR_PROTO(nbt_string, const char *)
+
+enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_REQUEST(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct NETLOGON_SAM_LOGON_REQUEST *r);
+enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_REQUEST(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct NETLOGON_SAM_LOGON_REQUEST *r);
+enum ndr_err_code ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct NETLOGON_SAM_LOGON_RESPONSE_EX *r);
+enum ndr_err_code ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct NETLOGON_SAM_LOGON_RESPONSE_EX *r,
+ uint32_t nt_version_flags);
+enum ndr_err_code ndr_push_netlogon_samlogon_response(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct netlogon_samlogon_response *r);
+enum ndr_err_code ndr_pull_netlogon_samlogon_response(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct netlogon_samlogon_response *r);
+void ndr_print_netlogon_samlogon_response(struct ndr_print *ndr, const char *name, const struct netlogon_samlogon_response *r);
+
+#endif /* _LIBRPC_NDR_NDR_NBT_H */
diff --git a/librpc/ndr/ndr_negoex.c b/librpc/ndr/ndr_negoex.c
new file mode 100644
index 0000000..26b98f4
--- /dev/null
+++ b/librpc/ndr/ndr_negoex.c
@@ -0,0 +1,521 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special NEGOEX structures
+
+ Copyright (C) Stefan Metzmacher 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 "includes.h"
+#include "librpc/gen_ndr/ndr_negoex.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/ndr/ndr_negoex.h"
+
+void ndr_print_negoex_BYTE_VECTOR(struct ndr_print *ndr, const char *name, const struct negoex_BYTE_VECTOR *r)
+{
+ ndr_print_struct(ndr, name, "negoex_BYTE_VECTOR");
+ if (r == NULL) { ndr_print_null(ndr); return; }
+ ndr->depth++;
+ ndr_print_DATA_BLOB(ndr, "blob", r->blob);
+ ndr->depth--;
+}
+
+enum ndr_err_code ndr_push_negoex_BYTE_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_BYTE_VECTOR *r)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 5));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->blob.data));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->blob.length));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->blob.data) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->blob.data));
+#if 0
+ NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->blob.length));
+#endif
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->blob.data, r->blob.length));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->blob.data));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_BYTE_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_BYTE_VECTOR *r)
+{
+ uint32_t _ptr_data;
+ uint32_t size_data_1 = 0;
+ TALLOC_CTX *_mem_save_data_0 = NULL;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ r->_dummy = NULL;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 5));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_data));
+ if (_ptr_data) {
+ NDR_PULL_ALLOC(ndr, r->blob.data);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->blob.data, _ptr_data));
+ } else {
+ r->blob.data = NULL;
+ }
+ r->blob.length = 0;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size_data_1));
+ r->_length = size_data_1;
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->blob.data) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->blob.data));
+ _mem_save_data_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->blob.data, 0);
+#if 0
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->blob.data));
+ size_data_1 = ndr_get_array_size(ndr, &r->blob.data);
+#else
+ size_data_1 = r->_length;
+#endif
+ NDR_PULL_ALLOC_N(ndr, r->blob.data, size_data_1);
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->blob.data, size_data_1));
+ r->blob.length = size_data_1;
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_data_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+#if 0
+ if (r->blob.data) {
+ NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->blob.data, r->blob.length));
+ }
+#endif
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_negoex_AUTH_SCHEME_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_AUTH_SCHEME_VECTOR *r)
+{
+ uint32_t cntr_array_1;
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 5));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->array));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->array));
+#if 0
+ NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->count));
+#endif
+ for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+ NDR_CHECK(ndr_push_negoex_AUTH_SCHEME(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->array));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_AUTH_SCHEME_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_AUTH_SCHEME_VECTOR *r)
+{
+ uint32_t _ptr_array;
+ uint32_t size_array_1 = 0;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0 = NULL;
+ TALLOC_CTX *_mem_save_array_1 = NULL;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 5));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->array, _ptr_array));
+ } else {
+ r->array = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+#if 0
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ size_array_1 = ndr_get_array_size(ndr, &r->array);
+#else
+ size_array_1 = r->count;
+#endif
+ NDR_PULL_ALLOC_N(ndr, r->array, size_array_1);
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+ NDR_CHECK(ndr_pull_negoex_AUTH_SCHEME(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+#if 0
+ if (r->array) {
+ NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->array, r->count));
+ }
+#endif
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_negoex_EXTENSION_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_EXTENSION_VECTOR *r)
+{
+ uint32_t cntr_array_1;
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 5));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->array));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->array));
+#if 0
+ NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->count));
+#endif
+ for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+ NDR_CHECK(ndr_push_negoex_EXTENSION(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+ NDR_CHECK(ndr_push_negoex_EXTENSION(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->array));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_EXTENSION_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_EXTENSION_VECTOR *r)
+{
+ uint32_t _ptr_array;
+ uint32_t size_array_1 = 0;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0 = NULL;
+ TALLOC_CTX *_mem_save_array_1 = NULL;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 5));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->array, _ptr_array));
+ } else {
+ r->array = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+#if 0
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ size_array_1 = ndr_get_array_size(ndr, &r->array);
+#else
+ size_array_1 = r->count;
+#endif
+ NDR_PULL_ALLOC_N(ndr, r->array, size_array_1);
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+ NDR_CHECK(ndr_pull_negoex_EXTENSION(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+ NDR_CHECK(ndr_pull_negoex_EXTENSION(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+#if 0
+ if (r->array) {
+ NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->array, r->count));
+ }
+#endif
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_negoex_ALERT_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_ALERT_VECTOR *r)
+{
+ uint32_t cntr_array_1;
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 5));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->array));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->count));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->array));
+#if 0
+ NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->count));
+#endif
+ for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+ NDR_CHECK(ndr_push_negoex_ALERT(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < (r->count); cntr_array_1++) {
+ NDR_CHECK(ndr_push_negoex_ALERT(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->array));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_ALERT_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_ALERT_VECTOR *r)
+{
+ uint32_t _ptr_array;
+ uint32_t size_array_1 = 0;
+ uint32_t cntr_array_1;
+ TALLOC_CTX *_mem_save_array_0 = NULL;
+ TALLOC_CTX *_mem_save_array_1 = NULL;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 5));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_array));
+ if (_ptr_array) {
+ NDR_PULL_ALLOC(ndr, r->array);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->array, _ptr_array));
+ } else {
+ r->array = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->count));
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->array) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->array));
+ _mem_save_array_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+#if 0
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->array));
+ size_array_1 = ndr_get_array_size(ndr, &r->array);
+#else
+ size_array_1 = r->count;
+#endif
+ NDR_PULL_ALLOC_N(ndr, r->array, size_array_1);
+ _mem_save_array_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->array, 0);
+ for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+ NDR_CHECK(ndr_pull_negoex_ALERT(ndr, NDR_SCALARS, &r->array[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < (size_array_1); cntr_array_1++) {
+ NDR_CHECK(ndr_pull_negoex_ALERT(ndr, NDR_BUFFERS, &r->array[cntr_array_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_array_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+#if 0
+ if (r->array) {
+ NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->array, r->count));
+ }
+#endif
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+size_t ndr_negoex_MESSAGE_header_length(const struct negoex_MESSAGE *r)
+{
+ size_t size = 0;
+
+ size += 8; /* signature */
+ size += 4; /* type */
+ size += 4; /* sequence_number */
+ size += 4; /* header_length */
+ size += 4; /* message_length */
+ size += 16; /* conversation_id */
+
+ switch (r->type) {
+ case NEGOEX_MESSAGE_TYPE_INITIATOR_NEGO:
+ case NEGOEX_MESSAGE_TYPE_ACCEPTOR_NEGO:
+ size += 32; /* random */
+ size += 8; /* protocol_version */
+ size += 8; /* auth_schemes */
+ size += 8; /* extensions */
+ break;
+
+ case NEGOEX_MESSAGE_TYPE_INITIATOR_META_DATA:
+ case NEGOEX_MESSAGE_TYPE_ACCEPTOR_META_DATA:
+ case NEGOEX_MESSAGE_TYPE_CHALLENGE:
+ case NEGOEX_MESSAGE_TYPE_AP_REQUEST:
+ size += 16; /* auth_scheme */
+ size += 8; /* exchange */
+ break;
+
+ case NEGOEX_MESSAGE_TYPE_VERIFY:
+ size += 16; /* auth_scheme */
+ size += 4; /* checksum.header_length */
+ size += 4; /* checksum.scheme */
+ size += 4; /* checksum.type */
+ size += 8; /* checksum.value */
+ break;
+
+ case NEGOEX_MESSAGE_TYPE_ALERT:
+ size += 16; /* auth_scheme */
+ size += 4; /* status */
+ size += 8; /* alerts */
+ break;
+ }
+
+ return size;
+}
+
+enum ndr_err_code ndr_pull_negoex_MESSAGE(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_MESSAGE *r)
+{
+ uint32_t _save_relative_base_offset = ndr_pull_get_relative_base_offset(ndr);
+ uint32_t size_signature_0 = 0;
+ uint32_t start_data_size = ndr->data_size;
+ uint32_t saved_offset = 0;
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 5));
+ NDR_CHECK(ndr_pull_setup_relative_base_offset1(ndr, r, ndr->offset));
+ size_signature_0 = 8;
+ NDR_CHECK(ndr_pull_charset(ndr, NDR_SCALARS, &r->signature, size_signature_0, sizeof(uint8_t), CH_DOS));
+ NDR_CHECK(ndr_pull_negoex_MESSAGE_TYPE(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sequence_number));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->header_length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->message_length));
+ saved_offset = ndr->offset;
+ ndr->offset = ndr->relative_base_offset;
+ NDR_PULL_NEED_BYTES(ndr, r->message_length);
+ ndr->data_size = ndr->offset + r->message_length;
+ ndr->offset = saved_offset;
+ NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->conversation_id));
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->p, r->type));
+ NDR_CHECK(ndr_pull_negoex_PAYLOAD(ndr, NDR_SCALARS, &r->p));
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+ ndr->offset = ndr->data_size;
+ ndr->data_size = start_data_size;
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_pull_setup_relative_base_offset2(ndr, r));
+ saved_offset = ndr->offset;
+ ndr->offset = ndr->relative_base_offset;
+ NDR_PULL_NEED_BYTES(ndr, r->message_length);
+ ndr->data_size = ndr->offset + r->message_length;
+ ndr->offset = saved_offset;
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->p, r->type));
+ NDR_CHECK(ndr_pull_negoex_PAYLOAD(ndr, NDR_BUFFERS, &r->p));
+ ndr->offset = ndr->data_size;
+ ndr->data_size = start_data_size;
+ }
+ ndr_pull_restore_relative_base_offset(ndr, _save_relative_base_offset);
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_negoex_MESSAGE_ARRAY(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_MESSAGE_ARRAY *r)
+{
+ uint32_t cntr_messages_0;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 5));
+ for (cntr_messages_0 = 0; cntr_messages_0 < (r->count); cntr_messages_0++) {
+ NDR_CHECK(ndr_push_negoex_MESSAGE(ndr, NDR_SCALARS|NDR_BUFFERS, &r->messages[cntr_messages_0]));
+ }
+ NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_negoex_MESSAGE_ARRAY(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_MESSAGE_ARRAY *r)
+{
+ uint32_t size_messages_0 = 0;
+ uint32_t cntr_messages_0;
+ TALLOC_CTX *_mem_save_messages_0 = NULL;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t saved_offset = ndr->offset;
+ uint32_t available = 0;
+ NDR_CHECK(ndr_pull_align(ndr, 5));
+ r->count = 0;
+ available = ndr->data_size - ndr->offset;
+ while (available > 0) {
+ uint32_t length;
+
+ /*
+ * The common header is 40 bytes
+ * and message_length is at offset 20
+ */
+ NDR_PULL_NEED_BYTES(ndr, 40);
+ ndr->offset += 20;
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length));
+ ndr->offset -= 24;
+ if (length < 40) {
+ /*
+ * let the pull function catch the error
+ */
+ length = 40;
+ }
+ NDR_PULL_NEED_BYTES(ndr, length);
+ ndr->offset += length;
+ available -= length;
+ r->count++;
+ }
+ ndr->offset = saved_offset;
+ size_messages_0 = r->count;
+ NDR_PULL_ALLOC_N(ndr, r->messages, size_messages_0);
+ _mem_save_messages_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->messages, 0);
+ for (cntr_messages_0 = 0; cntr_messages_0 < (size_messages_0); cntr_messages_0++) {
+ NDR_CHECK(ndr_pull_negoex_MESSAGE(ndr, NDR_SCALARS|NDR_BUFFERS, &r->messages[cntr_messages_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_messages_0, 0);
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_negoex.h b/librpc/ndr/ndr_negoex.h
new file mode 100644
index 0000000..094275c
--- /dev/null
+++ b/librpc/ndr/ndr_negoex.h
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special NEGOEX structures
+
+ Copyright (C) Stefan Metzmacher 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 "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/negoex.h"
+
+_PUBLIC_ void ndr_print_negoex_BYTE_VECTOR(struct ndr_print *ndr, const char *name, const struct negoex_BYTE_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_BYTE_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_BYTE_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_BYTE_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_BYTE_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_AUTH_SCHEME_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_AUTH_SCHEME_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_AUTH_SCHEME_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_AUTH_SCHEME_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_EXTENSION_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_EXTENSION_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_EXTENSION_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_EXTENSION_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_ALERT_VECTOR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_ALERT_VECTOR *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_ALERT_VECTOR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_ALERT_VECTOR *r);
+_PUBLIC_ size_t ndr_negoex_MESSAGE_header_length(const struct negoex_MESSAGE *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_MESSAGE(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_MESSAGE *r);
+_PUBLIC_ enum ndr_err_code ndr_push_negoex_MESSAGE_ARRAY(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct negoex_MESSAGE_ARRAY *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_negoex_MESSAGE_ARRAY(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct negoex_MESSAGE_ARRAY *r);
diff --git a/librpc/ndr/ndr_netlogon.c b/librpc/ndr/ndr_netlogon.c
new file mode 100644
index 0000000..56f0eab
--- /dev/null
+++ b/librpc/ndr/ndr_netlogon.c
@@ -0,0 +1,65 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special netlogon types
+
+ Copyright (C) Guenther Deschner 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 "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_SamDatabaseID8Bit(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum netr_SamDatabaseID8Bit r)
+{
+ if (r > 0xff) return NDR_ERR_BUFSIZE;
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_SamDatabaseID8Bit(struct ndr_pull *ndr, ndr_flags_type ndr_flags, enum netr_SamDatabaseID8Bit *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_SamDatabaseID8Bit(struct ndr_print *ndr, const char *name, enum netr_SamDatabaseID8Bit r)
+{
+ ndr_print_netr_SamDatabaseID(ndr, name, r);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_DeltaEnum8Bit(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum netr_DeltaEnum8Bit r)
+{
+ if (r > 0xff) return NDR_ERR_BUFSIZE;
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_DeltaEnum8Bit(struct ndr_pull *ndr, ndr_flags_type ndr_flags, enum netr_DeltaEnum8Bit *r)
+{
+ uint8_t v;
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &v));
+ *r = v;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_netr_DeltaEnum8Bit(struct ndr_print *ndr, const char *name, enum netr_DeltaEnum8Bit r)
+{
+ ndr_print_netr_DeltaEnum(ndr, name, r);
+}
diff --git a/librpc/ndr/ndr_netlogon.h b/librpc/ndr/ndr_netlogon.h
new file mode 100644
index 0000000..66fadde
--- /dev/null
+++ b/librpc/ndr/ndr_netlogon.h
@@ -0,0 +1,28 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special netlogon types
+
+ Copyright (C) Guenther Deschner 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/>.
+*/
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_SamDatabaseID8Bit(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum netr_SamDatabaseID8Bit r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_SamDatabaseID8Bit(struct ndr_pull *ndr, ndr_flags_type ndr_flags, enum netr_SamDatabaseID8Bit *r);
+_PUBLIC_ void ndr_print_netr_SamDatabaseID8Bit(struct ndr_print *ndr, const char *name, enum netr_SamDatabaseID8Bit r);
+
+_PUBLIC_ enum ndr_err_code ndr_push_netr_DeltaEnum8Bit(struct ndr_push *ndr, ndr_flags_type ndr_flags, enum netr_DeltaEnum8Bit r);
+_PUBLIC_ enum ndr_err_code ndr_pull_netr_DeltaEnum8Bit(struct ndr_pull *ndr, ndr_flags_type ndr_flags, enum netr_DeltaEnum8Bit *r);
+_PUBLIC_ void ndr_print_netr_DeltaEnum8Bit(struct ndr_print *ndr, const char *name, enum netr_DeltaEnum8Bit r);
diff --git a/librpc/ndr/ndr_ntlmssp.c b/librpc/ndr/ndr_ntlmssp.c
new file mode 100644
index 0000000..723ae9c
--- /dev/null
+++ b/librpc/ndr/ndr_ntlmssp.c
@@ -0,0 +1,195 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special ntlmssp structures
+
+ 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 "includes.h"
+#include "../librpc/gen_ndr/ndr_ntlmssp.h"
+
+_PUBLIC_ size_t ndr_ntlmssp_string_length(uint32_t negotiate_flags, const char *s)
+{
+ if (!s) {
+ return 0;
+ }
+
+ if (negotiate_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+ return strlen(s) * 2;
+ }
+
+ return strlen(s);
+}
+
+_PUBLIC_ libndr_flags ndr_ntlmssp_negotiated_string_flags(uint32_t negotiate_flags)
+{
+ libndr_flags flags = LIBNDR_FLAG_STR_NOTERM |
+ LIBNDR_FLAG_STR_CHARLEN |
+ LIBNDR_FLAG_REMAINING;
+
+ if (!(negotiate_flags & NTLMSSP_NEGOTIATE_UNICODE)) {
+ flags |= LIBNDR_FLAG_STR_ASCII;
+ }
+
+ return flags;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_AV_PAIR_LIST(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct AV_PAIR_LIST *r)
+{
+ uint32_t cntr_pair_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ for (cntr_pair_0 = 0; cntr_pair_0 < r->count; cntr_pair_0++) {
+ NDR_CHECK(ndr_push_AV_PAIR(ndr, NDR_SCALARS, &r->pair[cntr_pair_0]));
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ for (cntr_pair_0 = 0; cntr_pair_0 < r->count; cntr_pair_0++) {
+ NDR_CHECK(ndr_push_AV_PAIR(ndr, NDR_BUFFERS, &r->pair[cntr_pair_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_AV_PAIR_LIST(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct AV_PAIR_LIST *r)
+{
+ uint32_t cntr_pair_0;
+ TALLOC_CTX *_mem_save_pair_0;
+ if (ndr_flags & NDR_SCALARS) {
+ uint32_t offset = 0;
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ r->count = 0;
+ if (ndr->data_size > 0) {
+ NDR_PULL_NEED_BYTES(ndr, 4);
+ }
+ while (offset + 4 <= ndr->data_size) {
+ uint16_t length;
+ uint16_t type;
+ type = SVAL(ndr->data + offset, 0);
+ if (type == MsvAvEOL) {
+ r->count++;
+ break;
+ }
+ length = SVAL(ndr->data + offset, 2);
+ offset += length + 4;
+ r->count++;
+ }
+ NDR_PULL_ALLOC_N(ndr, r->pair, r->count);
+ _mem_save_pair_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->pair, 0);
+ for (cntr_pair_0 = 0; cntr_pair_0 < r->count; cntr_pair_0++) {
+ NDR_CHECK(ndr_pull_AV_PAIR(ndr, NDR_SCALARS, &r->pair[cntr_pair_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pair_0, 0);
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ _mem_save_pair_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->pair, 0);
+ for (cntr_pair_0 = 0; cntr_pair_0 < r->count; cntr_pair_0++) {
+ NDR_CHECK(ndr_pull_AV_PAIR(ndr, NDR_BUFFERS, &r->pair[cntr_pair_0]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_pair_0, 0);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_ntlmssp_nt_response(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *nt_response,
+ bool ntlmv2)
+{
+ enum ndr_err_code ndr_err;
+
+ if (ntlmv2) {
+ struct NTLMv2_RESPONSE nt;
+ if (nt_response->length > 24) {
+ ndr_err = ndr_pull_struct_blob(nt_response, mem_ctx, &nt,
+ (ndr_pull_flags_fn_t)ndr_pull_NTLMv2_RESPONSE);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NDR_PRINT_DEBUG(NTLMv2_RESPONSE, &nt);
+ }
+ }
+ } else {
+ struct NTLM_RESPONSE nt;
+ if (nt_response->length == 24) {
+ ndr_err = ndr_pull_struct_blob(nt_response, mem_ctx, &nt,
+ (ndr_pull_flags_fn_t)ndr_pull_NTLM_RESPONSE);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NDR_PRINT_DEBUG(NTLM_RESPONSE, &nt);
+ }
+ }
+ }
+}
+
+_PUBLIC_ void ndr_print_ntlmssp_lm_response(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *lm_response,
+ bool ntlmv2)
+{
+ enum ndr_err_code ndr_err;
+
+ if (ntlmv2) {
+ struct LMv2_RESPONSE lm;
+ if (lm_response->length == 24) {
+ ndr_err = ndr_pull_struct_blob(lm_response, mem_ctx, &lm,
+ (ndr_pull_flags_fn_t)ndr_pull_LMv2_RESPONSE);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NDR_PRINT_DEBUG(LMv2_RESPONSE, &lm);
+ }
+ }
+ } else {
+ struct LM_RESPONSE lm;
+ if (lm_response->length == 24) {
+ ndr_err = ndr_pull_struct_blob(lm_response, mem_ctx, &lm,
+ (ndr_pull_flags_fn_t)ndr_pull_LM_RESPONSE);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NDR_PRINT_DEBUG(LM_RESPONSE, &lm);
+ }
+ }
+ }
+}
+
+_PUBLIC_ void ndr_print_ntlmssp_Version(struct ndr_print *ndr, const char *name, const union ntlmssp_Version *r)
+{
+ int level;
+ level = ndr_print_steal_switch_value(ndr, r);
+ switch (level) {
+ case NTLMSSP_NEGOTIATE_VERSION:
+ ndr_print_ntlmssp_VERSION(ndr, name, &r->version);
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list,
+ enum ntlmssp_AvId AvId)
+{
+ struct AV_PAIR *res = NULL;
+ uint32_t i = 0;
+
+ for (i = 0; i < av_list->count; i++) {
+ if (av_list->pair[i].AvId != AvId) {
+ continue;
+ }
+
+ res = discard_const_p(struct AV_PAIR, &av_list->pair[i]);
+ break;
+ }
+
+ return res;
+}
diff --git a/librpc/ndr/ndr_ntlmssp.h b/librpc/ndr/ndr_ntlmssp.h
new file mode 100644
index 0000000..2326a08
--- /dev/null
+++ b/librpc/ndr/ndr_ntlmssp.h
@@ -0,0 +1,35 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special ntlmssp structures
+
+ 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/>.
+*/
+
+_PUBLIC_ size_t ndr_ntlmssp_string_length(uint32_t negotiate_flags, const char *s);
+_PUBLIC_ libndr_flags ndr_ntlmssp_negotiated_string_flags(uint32_t negotiate_flags);
+_PUBLIC_ enum ndr_err_code ndr_push_AV_PAIR_LIST(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct AV_PAIR_LIST *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_AV_PAIR_LIST(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct AV_PAIR_LIST *r);
+_PUBLIC_ void ndr_print_ntlmssp_nt_response(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *nt_response,
+ bool ntlmv2);
+_PUBLIC_ void ndr_print_ntlmssp_lm_response(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *lm_response,
+ bool ntlmv2);
+_PUBLIC_ void ndr_print_ntlmssp_Version(struct ndr_print *ndr, const char *name, const union ntlmssp_Version *r);
+
+_PUBLIC_ struct AV_PAIR *ndr_ntlmssp_find_av(const struct AV_PAIR_LIST *av_list,
+ enum ntlmssp_AvId AvId);
diff --git a/librpc/ndr/ndr_ntprinting.c b/librpc/ndr/ndr_ntprinting.c
new file mode 100644
index 0000000..22010ff
--- /dev/null
+++ b/librpc/ndr/ndr_ntprinting.c
@@ -0,0 +1,87 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special ntprinting structures
+
+ Copyright (C) Guenther Deschner 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 "../librpc/gen_ndr/ndr_ntprinting.h"
+
+_PUBLIC_ libndr_flags ndr_ntprinting_string_flags(libndr_flags string_flags)
+{
+ libndr_flags flags = LIBNDR_FLAG_STR_NULLTERM;
+
+ if (string_flags & LIBNDR_FLAG_STR_ASCII) {
+ flags |= LIBNDR_FLAG_STR_ASCII;
+ } else if (string_flags & LIBNDR_FLAG_STR_RAW8) {
+ flags |= LIBNDR_FLAG_STR_RAW8;
+ } else {
+ flags |= LIBNDR_FLAG_STR_UTF8;
+ }
+
+ return flags;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_ntprinting_printer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct ntprinting_printer *r)
+{
+ uint32_t _ptr_devmode;
+ TALLOC_CTX *_mem_save_devmode_0;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 5));
+ NDR_CHECK(ndr_pull_ntprinting_printer_info(ndr, NDR_SCALARS, &r->info));
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_devmode));
+ if (_ptr_devmode) {
+ NDR_PULL_ALLOC(ndr, r->devmode);
+ } else {
+ r->devmode = NULL;
+ }
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->devmode) {
+ _mem_save_devmode_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->devmode, 0);
+ r->devmode->string_flags = r->info.string_flags;
+ NDR_CHECK(ndr_pull_ntprinting_devicemode(ndr, NDR_SCALARS|NDR_BUFFERS, r->devmode));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_devmode_0, 0);
+ }
+ }
+ if (ndr_flags & NDR_SCALARS) {
+ r->count = 0;
+ NDR_PULL_ALLOC_N(ndr, r->printer_data, r->count);
+ while (ndr->offset + 4 <= ndr->data_size) {
+ uint32_t ptr = 0;
+ ptr = IVAL(ndr->data, ndr->offset);
+ if (ptr == 0) {
+ ndr->offset = ndr->offset + 4;
+ break;
+ }
+ r->printer_data = talloc_realloc(ndr, r->printer_data, struct ntprinting_printer_data, r->count + 1);
+ NDR_ERR_HAVE_NO_MEMORY(r->printer_data);
+ r->printer_data[r->count].string_flags = r->info.string_flags;
+ NDR_CHECK(ndr_pull_ntprinting_printer_data(ndr, NDR_SCALARS, &r->printer_data[r->count]));
+ r->count++;
+ }
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_ntprinting.h b/librpc/ndr/ndr_ntprinting.h
new file mode 100644
index 0000000..4b89707
--- /dev/null
+++ b/librpc/ndr/ndr_ntprinting.h
@@ -0,0 +1,27 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special ntprinting structures
+
+ Copyright (C) Guenther Deschner 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 "../librpc/gen_ndr/ndr_ntprinting.h"
+
+_PUBLIC_ libndr_flags ndr_ntprinting_string_flags(libndr_flags string_flags);
+
+_PUBLIC_ enum ndr_err_code ndr_pull_ntprinting_printer(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct ntprinting_printer *r);
diff --git a/librpc/ndr/ndr_orpc.c b/librpc/ndr/ndr_orpc.c
new file mode 100644
index 0000000..80d9870
--- /dev/null
+++ b/librpc/ndr/ndr_orpc.c
@@ -0,0 +1,163 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling DCOM string arrays
+
+ Copyright (C) Jelmer Vernooij 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 "librpc/gen_ndr/ndr_orpc.h"
+
+enum ndr_err_code ndr_pull_DUALSTRINGARRAY(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct DUALSTRINGARRAY *ar)
+{
+ uint16_t num_entries, security_offset;
+ uint16_t towerid;
+ uint32_t towernum = 0, conformant_size;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &conformant_size));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &num_entries));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &security_offset));
+
+ ar->stringbindings = talloc_array(ndr, struct STRINGBINDING *, 1);
+ ar->stringbindings[0] = NULL;
+
+ do {
+ /* 'Peek' */
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &towerid));
+
+ if (towerid > 0) {
+ ndr->offset -= 2;
+ ar->stringbindings = talloc_realloc(ndr, ar->stringbindings, struct STRINGBINDING *, towernum+2);
+ ar->stringbindings[towernum] = talloc(ndr, struct STRINGBINDING);
+ NDR_CHECK(ndr_pull_STRINGBINDING(ndr, ndr_flags, ar->stringbindings[towernum]));
+ towernum++;
+ }
+ } while (towerid != 0);
+
+ ar->stringbindings[towernum] = NULL;
+ towernum = 0;
+
+ ar->securitybindings = talloc_array(ndr, struct SECURITYBINDING *, 1);
+ ar->securitybindings[0] = NULL;
+
+ do {
+ /* 'Peek' */
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &towerid));
+
+ if (towerid > 0) {
+ ndr->offset -= 2;
+ ar->securitybindings = talloc_realloc(ndr, ar->securitybindings, struct SECURITYBINDING *, towernum+2);
+ ar->securitybindings[towernum] = talloc(ndr, struct SECURITYBINDING);
+ NDR_CHECK(ndr_pull_SECURITYBINDING(ndr, ndr_flags, ar->securitybindings[towernum]));
+ towernum++;
+ }
+ } while (towerid != 0);
+
+ ar->securitybindings[towernum] = NULL;
+
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_DUALSTRINGARRAY(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct DUALSTRINGARRAY *ar)
+{
+ return ndr_push_error(ndr, NDR_ERR_STRING, "ndr_push_DUALSTRINGARRAY not implemented");
+}
+
+/*
+ print a dom_sid
+*/
+void ndr_print_DUALSTRINGARRAY(struct ndr_print *ndr, const char *name, const struct DUALSTRINGARRAY *ar)
+{
+ int i;
+ ndr->print(ndr, "%-25s: DUALSTRINGARRAY", name);
+ ndr->depth++;
+ ndr->print(ndr, "STRING BINDINGS");
+ ndr->depth++;
+ for (i=0;ar->stringbindings[i];i++) {
+ char idx[13]; /* 2^32 has 10 digits */
+ snprintf(idx, sizeof(idx), "[%d]", i);
+ ndr_print_STRINGBINDING(ndr, idx, ar->stringbindings[i]);
+ }
+ ndr->depth--;
+ ndr->print(ndr, "SECURITY BINDINGS");
+ ndr->depth++;
+ for (i=0;ar->securitybindings[i];i++) {
+ char idx[13]; /* 2^32 has 10 digits */
+ snprintf(idx, sizeof(idx), "[%d]", i);
+ ndr_print_SECURITYBINDING(ndr, idx, ar->securitybindings[i]);
+ }
+ ndr->depth--;
+}
+
+enum ndr_err_code ndr_pull_STRINGARRAY(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct STRINGARRAY *ar)
+{
+ uint16_t towerid;
+ uint32_t towernum = 0;
+ uint16_t num_entries;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &num_entries));
+
+ ar->stringbindings = talloc_array(ndr, struct STRINGBINDING *, 1);
+ ar->stringbindings[0] = NULL;
+
+ do {
+ /* 'Peek' */
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &towerid));
+
+ if (towerid > 0) {
+ ndr->offset -= 2;
+ ar->stringbindings = talloc_realloc(ndr, ar->stringbindings, struct STRINGBINDING *, towernum+2);
+ ar->stringbindings[towernum] = talloc(ndr, struct STRINGBINDING);
+ NDR_CHECK(ndr_pull_STRINGBINDING(ndr, ndr_flags, ar->stringbindings[towernum]));
+ towernum++;
+ }
+ } while (towerid != 0);
+
+ ar->stringbindings[towernum] = NULL;
+
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_STRINGARRAY(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct STRINGARRAY *ar)
+{
+ return ndr_push_error(ndr, NDR_ERR_STRING, "ndr_push_STRINGARRAY not implemented");
+}
+
+/*
+ print a dom_sid
+*/
+void ndr_print_STRINGARRAY(struct ndr_print *ndr, const char *name, const struct STRINGARRAY *ar)
+{
+ int i;
+ ndr->print(ndr, "%-25s: STRINGARRAY", name);
+ ndr->depth++;
+ for (i=0;ar->stringbindings[i];i++) {
+ char idx[13]; /* 2^32 has 10 digits */
+ snprintf(idx, sizeof(idx), "[%d]", i);
+ ndr_print_STRINGBINDING(ndr, idx, ar->stringbindings[i]);
+ }
+ ndr->depth--;
+}
diff --git a/librpc/ndr/ndr_preg.c b/librpc/ndr/ndr_preg.c
new file mode 100644
index 0000000..8074e1e
--- /dev/null
+++ b/librpc/ndr/ndr_preg.c
@@ -0,0 +1,69 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling preg structures
+
+ Copyright (C) Guenther Deschner 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 "librpc/gen_ndr/ndr_preg.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_preg_file(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct preg_file *r)
+{
+ uint32_t cntr_entries_0;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_preg_header(ndr, NDR_SCALARS, &r->header));
+ for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) {
+ NDR_CHECK(ndr_push_preg_entry(ndr, NDR_SCALARS, &r->entries[cntr_entries_0]));
+ }
+ NDR_CHECK(ndr_push_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_preg_file(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct preg_file *r)
+{
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_preg_header(ndr, NDR_SCALARS, &r->header));
+ r->num_entries = 0;
+ NDR_PULL_ALLOC_N(ndr, r->entries, r->num_entries);
+ while (ndr->offset + 12 <= ndr->data_size) {
+ r->entries = talloc_realloc(ndr, r->entries, struct preg_entry, r->num_entries + 1);
+ NDR_ERR_HAVE_NO_MEMORY(r->entries);
+ NDR_CHECK(ndr_pull_preg_entry(ndr, NDR_SCALARS, &r->entries[r->num_entries]));
+ r->num_entries++;
+ }
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_preg.h b/librpc/ndr/ndr_preg.h
new file mode 100644
index 0000000..f634225
--- /dev/null
+++ b/librpc/ndr/ndr_preg.h
@@ -0,0 +1,23 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling preg structures
+
+ Copyright (C) Guenther Deschner 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/>.
+*/
+
+_PUBLIC_ enum ndr_err_code ndr_push_preg_file(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct preg_file *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_preg_file(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct preg_file *r);
diff --git a/librpc/ndr/ndr_private.h b/librpc/ndr/ndr_private.h
new file mode 100644
index 0000000..08521be
--- /dev/null
+++ b/librpc/ndr/ndr_private.h
@@ -0,0 +1,32 @@
+/*
+ Unix SMB/CIFS implementation.
+ rpc interface definitions
+
+ 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/>.
+*/
+
+/* This is not a public header file that is installed as part of Samba.
+ *
+ * Instead, this is to allow our python layer to get to the
+ * NDR_TOKEN_MAX_LIST_SIZE
+*/
+
+#ifndef __NDR_PRIVATE_H__
+#define __NDR_PRIVATE_H__
+
+size_t ndr_token_max_list_size(void);
+
+#endif
diff --git a/librpc/ndr/ndr_rap.c b/librpc/ndr/ndr_rap.c
new file mode 100644
index 0000000..ea18a08
--- /dev/null
+++ b/librpc/ndr/ndr_rap.c
@@ -0,0 +1,28 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special rap types
+
+ Copyright (C) Guenther Deschner 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 "librpc/gen_ndr/ndr_rap.h"
+
+_PUBLIC_ void ndr_print_rap_status(struct ndr_print *ndr, const char *name, enum rap_status r)
+{
+ ndr_print_WERROR(ndr, name, W_ERROR(r));
+}
diff --git a/librpc/ndr/ndr_rap.h b/librpc/ndr/ndr_rap.h
new file mode 100644
index 0000000..35a03b1
--- /dev/null
+++ b/librpc/ndr/ndr_rap.h
@@ -0,0 +1,22 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special rap types
+
+ Copyright (C) Guenther Deschner 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/>.
+*/
+
+_PUBLIC_ void ndr_print_rap_status(struct ndr_print *ndr, const char *name, enum rap_status r);
diff --git a/librpc/ndr/ndr_schannel.c b/librpc/ndr/ndr_schannel.c
new file mode 100644
index 0000000..6b08a79
--- /dev/null
+++ b/librpc/ndr/ndr_schannel.c
@@ -0,0 +1,107 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special schannel structures
+
+ 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 "includes.h"
+#include "../librpc/gen_ndr/ndr_schannel.h"
+#include "../librpc/ndr/ndr_schannel.h"
+#include "../libcli/nbt/libnbt.h"
+
+_PUBLIC_ void ndr_print_NL_AUTH_MESSAGE_BUFFER(struct ndr_print *ndr, const char *name, const union NL_AUTH_MESSAGE_BUFFER *r)
+{
+ int level;
+ level = ndr_print_steal_switch_value(ndr, r);
+ switch (level) {
+ case NL_FLAG_OEM_NETBIOS_DOMAIN_NAME:
+ ndr_print_string(ndr, name, r->a);
+ break;
+
+ case NL_FLAG_OEM_NETBIOS_COMPUTER_NAME:
+ ndr_print_string(ndr, name, r->a);
+ break;
+
+ case NL_FLAG_UTF8_DNS_DOMAIN_NAME:
+ ndr_print_nbt_string(ndr, name, r->u);
+ break;
+
+ case NL_FLAG_UTF8_DNS_HOST_NAME:
+ ndr_print_nbt_string(ndr, name, r->u);
+ break;
+
+ case NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME:
+ ndr_print_nbt_string(ndr, name, r->u);
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+_PUBLIC_ void ndr_print_NL_AUTH_MESSAGE_BUFFER_REPLY(struct ndr_print *ndr, const char *name, const union NL_AUTH_MESSAGE_BUFFER_REPLY *r)
+{
+ int level;
+ level = ndr_print_steal_switch_value(ndr, r);
+ switch (level) {
+ case NL_NEGOTIATE_RESPONSE:
+ ndr_print_uint32(ndr, name, r->dummy);
+ break;
+
+ default:
+ break;
+
+ }
+}
+
+void dump_NL_AUTH_SIGNATURE(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob)
+{
+ enum ndr_err_code ndr_err;
+ uint16_t signature_algorithm;
+
+ if (blob->length < 2) {
+ return;
+ }
+
+ signature_algorithm = SVAL(blob->data, 0);
+
+ switch (signature_algorithm) {
+ case NL_SIGN_HMAC_MD5: {
+ struct NL_AUTH_SIGNATURE r;
+ ndr_err = ndr_pull_struct_blob(blob, mem_ctx, &r,
+ (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_SIGNATURE);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NDR_PRINT_DEBUG(NL_AUTH_SIGNATURE, &r);
+ }
+ break;
+ }
+ case NL_SIGN_HMAC_SHA256: {
+ struct NL_AUTH_SHA2_SIGNATURE r;
+ ndr_err = ndr_pull_struct_blob(blob, mem_ctx, &r,
+ (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_SHA2_SIGNATURE);
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NDR_PRINT_DEBUG(NL_AUTH_SHA2_SIGNATURE, &r);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
diff --git a/librpc/ndr/ndr_schannel.h b/librpc/ndr/ndr_schannel.h
new file mode 100644
index 0000000..d57278c
--- /dev/null
+++ b/librpc/ndr/ndr_schannel.h
@@ -0,0 +1,25 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special schannel structures
+
+ 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/>.
+*/
+
+void ndr_print_NL_AUTH_MESSAGE_BUFFER(struct ndr_print *ndr, const char *name, const union NL_AUTH_MESSAGE_BUFFER *r);
+void ndr_print_NL_AUTH_MESSAGE_BUFFER_REPLY(struct ndr_print *ndr, const char *name, const union NL_AUTH_MESSAGE_BUFFER_REPLY *r);
+void dump_NL_AUTH_SIGNATURE(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob);
diff --git a/librpc/ndr/ndr_sec_helper.c b/librpc/ndr/ndr_sec_helper.c
new file mode 100644
index 0000000..1a156b0
--- /dev/null
+++ b/librpc/ndr/ndr_sec_helper.c
@@ -0,0 +1,457 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ fast routines for getting the wire size of security objects
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan Metzmacher 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 "librpc/gen_ndr/ndr_security.h"
+#include "../libcli/security/security.h"
+
+
+/*
+ * Find the wire size of a security_ace that has no trailing coda.
+ * This is used in ndr_pull_security_ace() generated from security.idl
+ * to work out where the coda starts (and in ndr_size_security_ace()
+ * just below).
+ */
+static size_t ndr_size_security_ace_core(const struct security_ace *ace, libndr_flags flags)
+{
+ size_t ret;
+
+ if (!ace) return 0;
+
+ ret = 8 + ndr_size_dom_sid(&ace->trustee, flags);
+ if (sec_ace_object(ace->type)) {
+ ret += 4; /* uint32 bitmap ace->object.object.flags */
+ if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
+ ret += 16; /* GUID ace->object.object.type.type */
+ }
+ if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
+ ret += 16; /* GUID ace->object.object.inherited_type.inherited_type */
+ }
+ }
+
+ return ret;
+}
+
+/*
+ return the wire size of a security_ace
+*/
+size_t ndr_size_security_ace(const struct security_ace *ace, libndr_flags flags)
+{
+ size_t base = ndr_size_security_ace_core(ace, flags);
+ size_t ret = base;
+ if (sec_ace_callback(ace->type)) {
+ ret += ace->coda.conditions.length;
+ } else if (ace->type == SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE) {
+ ret += ndr_size_security_ace_coda(&ace->coda, ace->type, flags);
+ } else {
+ /*
+ * Normal ACEs have a coda.ignored blob that is always or
+ * almost always empty. We aren't going to push it (it is
+ * ignored), so we don't add that length to the size.
+ */
+ }
+ /* round up to a multiple of 4 (MS-DTYP 2.4.4.1) */
+ ret = (ret + 3ULL) & ~3ULL;
+ if (unlikely(ret < base)) {
+ /* overflow, and there's not much we can do anyway */
+ return 0;
+ }
+ return ret;
+}
+
+
+static inline enum ndr_err_code ndr_maybe_pull_security_ace_object_ctr(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct security_ace *r)
+{
+ /*
+ * If this is not an object ACE (as is usually common),
+ * ndr_pull_security_ace_object_ctr() will do nothing.
+ *
+ * By avoiding calling the function in that case, we avoid some
+ * tallocing and ndr token busywork.
+ */
+ bool is_object = sec_ace_object(r->type);
+ if (is_object) {
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, is_object));
+ NDR_CHECK(ndr_pull_security_ace_object_ctr(ndr, ndr_flags, &r->object));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+
+_PUBLIC_ enum ndr_err_code ndr_pull_security_ace(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct security_ace *r)
+{
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 5));
+ NDR_CHECK(ndr_pull_security_ace_type(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_security_ace_flags(ndr, NDR_SCALARS, &r->flags));
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->access_mask));
+ NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr, NDR_SCALARS, r));
+ NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->trustee));
+ if (!sec_ace_has_extra_blob(r->type)) {
+ r->coda.ignored.data = NULL;
+ r->coda.ignored.length = 0;
+ } else {
+ struct ndr_pull *_ndr_coda;
+ ssize_t sub_size = ndr_subcontext_size_of_ace_coda(r, r->size, ndr->flags);
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_coda, 0, sub_size));
+ NDR_CHECK(ndr_pull_set_switch_value(_ndr_coda, &r->coda, r->type));
+ NDR_CHECK(ndr_pull_security_ace_coda(_ndr_coda, NDR_SCALARS|NDR_BUFFERS, &r->coda));
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_coda, 0, sub_size));
+ }
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_maybe_pull_security_ace_object_ctr(ndr, NDR_BUFFERS, r));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+
+static inline enum ndr_err_code ndr_maybe_push_security_ace_object_ctr(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct security_ace *r)
+{
+ /*
+ * ndr_push_security_ace_object_ctr() does nothing (except tallocing
+ * and ndr_token fiddling) unless the ACE is an object ACE, which is
+ * usually very unlikely.
+ */
+ bool is_object = sec_ace_object(r->type);
+ if (is_object) {
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->object, is_object));
+ NDR_CHECK(ndr_push_security_ace_object_ctr(ndr, ndr_flags, &r->object));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_security_ace(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct security_ace *r)
+{
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 5));
+ NDR_CHECK(ndr_push_security_ace_type(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_security_ace_flags(ndr, NDR_SCALARS, r->flags));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, ndr_size_security_ace(r, ndr->flags)));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->access_mask));
+ NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr, NDR_SCALARS, r));
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, &r->trustee));
+ if (sec_ace_has_extra_blob(r->type)) {
+ struct ndr_push *_ndr_coda;
+ size_t coda_size = ndr_subcontext_size_of_ace_coda(
+ r,
+ ndr_size_security_ace(r, ndr->flags),
+ ndr->flags);
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_coda, 0, coda_size));
+ NDR_CHECK(ndr_push_set_switch_value(_ndr_coda, &r->coda, r->type));
+ NDR_CHECK(ndr_push_security_ace_coda(_ndr_coda, NDR_SCALARS|NDR_BUFFERS, &r->coda));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_coda, 0, coda_size));
+ }
+ NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ NDR_CHECK(ndr_maybe_push_security_ace_object_ctr(ndr, NDR_BUFFERS, r));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+
+/*
+ * An ACE coda can't be bigger than the space allowed for by
+ * ace->size, so we need to check this from the context of the ACE.
+ *
+ * Usually the coda also can't be any smaller than the remaining
+ * space, because it is defined as a blob consuming everything it can.
+ *
+ * This is only used to find the size for the coda subcontext in
+ * security.idl.
+ */
+size_t ndr_subcontext_size_of_ace_coda(const struct security_ace *ace,
+ size_t ace_size,
+ libndr_flags flags)
+{
+ size_t core_size;
+ if (ace_size == 0) {
+ return 0;
+ }
+ core_size = ndr_size_security_ace_core(ace, flags);
+ if (ace_size < core_size) {
+ return 0;
+ }
+ return ace_size - core_size;
+}
+
+/*
+ return the wire size of a security_acl
+*/
+size_t ndr_size_security_acl(const struct security_acl *theacl, libndr_flags flags)
+{
+ size_t ret;
+ int i;
+ if (!theacl) return 0;
+ ret = 8;
+ for (i=0;i<theacl->num_aces;i++) {
+ ret += ndr_size_security_ace(&theacl->aces[i], flags);
+ }
+ return ret;
+}
+
+/*
+ return the wire size of a security descriptor
+*/
+size_t ndr_size_security_descriptor(const struct security_descriptor *sd, libndr_flags flags)
+{
+ size_t ret;
+ if (!sd) return 0;
+
+ ret = 20;
+ ret += ndr_size_dom_sid(sd->owner_sid, flags);
+ ret += ndr_size_dom_sid(sd->group_sid, flags);
+ ret += ndr_size_security_acl(sd->dacl, flags);
+ ret += ndr_size_security_acl(sd->sacl, flags);
+ return ret;
+}
+
+/*
+ return the wire size of a dom_sid
+*/
+size_t ndr_size_dom_sid(const struct dom_sid *sid, libndr_flags flags)
+{
+ if (!sid) return 0;
+ return 8 + 4*sid->num_auths;
+}
+
+size_t ndr_size_dom_sid28(const struct dom_sid *sid, libndr_flags flags)
+{
+ if (all_zero((const uint8_t *)sid, sizeof(struct dom_sid))) {
+ return 0;
+ }
+ return ndr_size_dom_sid(sid, flags);
+}
+
+size_t ndr_size_dom_sid0(const struct dom_sid *sid, libndr_flags flags)
+{
+ return ndr_size_dom_sid28(sid, flags);
+}
+
+/*
+ print a dom_sid
+*/
+void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
+{
+ struct dom_sid_buf buf;
+ ndr->print(ndr, "%-25s: %s", name, dom_sid_str_buf(sid, &buf));
+}
+
+void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
+{
+ ndr_print_dom_sid(ndr, name, sid);
+}
+
+void ndr_print_dom_sid28(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
+{
+ ndr_print_dom_sid(ndr, name, sid);
+}
+
+void ndr_print_dom_sid0(struct ndr_print *ndr, const char *name, const struct dom_sid *sid)
+{
+ ndr_print_dom_sid(ndr, name, sid);
+}
+
+
+/*
+ parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
+*/
+enum ndr_err_code ndr_pull_dom_sid2(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid)
+{
+ uint32_t num_auths;
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &num_auths));
+ NDR_CHECK(ndr_pull_dom_sid(ndr, ndr_flags, sid));
+ if (sid->num_auths != num_auths) {
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
+ "Bad num_auths %"PRIu32"; should equal %"PRId8,
+ num_auths, sid->num_auths);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field
+*/
+enum ndr_err_code ndr_push_dom_sid2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid)
+{
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, sid->num_auths));
+ return ndr_push_dom_sid(ndr, ndr_flags, sid);
+}
+
+/*
+ parse a dom_sid28 - this is a dom_sid in a fixed 28 byte buffer, so we need to ensure there are only up to 5 sub_auth
+*/
+enum ndr_err_code ndr_pull_dom_sid28(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid)
+{
+ enum ndr_err_code status;
+ struct ndr_pull *subndr;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ subndr = talloc_zero(ndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(subndr);
+ subndr->flags = ndr->flags;
+ subndr->current_mem_ctx = ndr->current_mem_ctx;
+
+ subndr->data = ndr->data + ndr->offset;
+ subndr->data_size = 28;
+ subndr->offset = 0;
+
+ status = ndr_pull_advance(ndr, 28);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(subndr);
+ return status;
+ }
+
+ status = ndr_pull_dom_sid(subndr, ndr_flags, sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ /* handle a w2k bug which send random data in the buffer */
+ ZERO_STRUCTP(sid);
+ } else if (sid->num_auths == 0) {
+ ZERO_STRUCT(sid->sub_auths);
+ }
+
+ talloc_free(subndr);
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ push a dom_sid28 - this is a dom_sid in a 28 byte fixed buffer
+*/
+enum ndr_err_code ndr_push_dom_sid28(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid)
+{
+ uint32_t old_offset;
+ uint32_t padding;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (sid->num_auths > 5) {
+ return ndr_push_error(ndr, NDR_ERR_RANGE,
+ "dom_sid28 allows only up to 5 sub auths [%"PRId8"]",
+ sid->num_auths);
+ }
+
+ old_offset = ndr->offset;
+ NDR_CHECK(ndr_push_dom_sid(ndr, ndr_flags, sid));
+
+ padding = 28 - (ndr->offset - old_offset);
+
+ if (padding > 0) {
+ NDR_CHECK(ndr_push_zero(ndr, padding));
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ parse a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
+*/
+enum ndr_err_code ndr_pull_dom_sid0(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *sid)
+{
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (ndr->data_size == ndr->offset) {
+ ZERO_STRUCTP(sid);
+ return NDR_ERR_SUCCESS;
+ }
+
+ return ndr_pull_dom_sid(ndr, ndr_flags, sid);
+}
+
+/*
+ push a dom_sid0 - this is a dom_sid in a variable byte buffer, which is maybe empty
+*/
+enum ndr_err_code ndr_push_dom_sid0(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *sid)
+{
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (!sid) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (all_zero((const uint8_t *)sid, sizeof(struct dom_sid))) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ return ndr_push_dom_sid(ndr, ndr_flags, sid);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_dom_sid(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct dom_sid *r)
+{
+ uint32_t cntr_sub_auths_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, r->sid_rev_num));
+ NDR_CHECK(ndr_push_int8(ndr, NDR_SCALARS, r->num_auths));
+ NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
+ if (r->num_auths < 0 || r->num_auths > ARRAY_SIZE(r->sub_auths)) {
+ return ndr_push_error(ndr, NDR_ERR_RANGE, "value (%"PRId8") out of range (0 - %zu)", r->num_auths, ARRAY_SIZE(r->sub_auths));
+ }
+ for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->sub_auths[cntr_sub_auths_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_dom_sid(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct dom_sid *r)
+{
+ uint32_t cntr_sub_auths_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sid_rev_num));
+ NDR_CHECK(ndr_pull_int8(ndr, NDR_SCALARS, &r->num_auths));
+ if (r->num_auths < 0 || r->num_auths > ARRAY_SIZE(r->sub_auths)) {
+ return ndr_pull_error(ndr, NDR_ERR_RANGE, "value (%"PRId8") out of range (0 - %zu)", r->num_auths, ARRAY_SIZE(r->sub_auths));
+ }
+ NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6));
+ ZERO_STRUCT(r->sub_auths);
+ for (cntr_sub_auths_0 = 0; cntr_sub_auths_0 < r->num_auths; cntr_sub_auths_0++) {
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->sub_auths[cntr_sub_auths_0]));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_spoolss_buf.c b/librpc/ndr/ndr_spoolss_buf.c
new file mode 100644
index 0000000..abeb884
--- /dev/null
+++ b/librpc/ndr/ndr_spoolss_buf.c
@@ -0,0 +1,1615 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling spoolss subcontext buffer structures
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Tim Potter 2003
+ 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 "includes.h"
+#include "librpc/gen_ndr/ndr_spoolss.h"
+#include "librpc/gen_ndr/ndr_security.h"
+
+#define NDR_SPOOLSS_PUSH_ENUM_IN(fn) do { \
+ if (!r->in.buffer && r->in.offered != 0) {\
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: r->in.offered[%u] but there's no buffer",\
+ (unsigned)r->in.offered);\
+ } else if (r->in.buffer && r->in.buffer->length != r->in.offered) {\
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: r->in.offered[%u] doesn't match length of r->in.buffer[%u]",\
+ (unsigned)r->in.offered, (unsigned)r->in.buffer->length);\
+ }\
+ _r.in.buffer = r->in.buffer;\
+ _r.in.offered = r->in.offered;\
+ NDR_CHECK(ndr_push__##fn(ndr, flags, &_r));\
+} while(0)
+
+#define NDR_SPOOLSS_PUSH_ENUM_IN_LEVEL(fn) do { \
+ _r.in.level = r->in.level;\
+ NDR_SPOOLSS_PUSH_ENUM_IN(fn);\
+} while(0)
+
+#define NDR_SPOOLSS_PUSH_ENUM_OUT_LEVEL(fn) do { \
+ DATA_BLOB _data_blob_info = data_blob_null;\
+ struct ndr_push *_ndr_info = NULL;\
+ _r.in.level = r->in.level;\
+ _r.in.buffer = r->in.buffer;\
+ _r.in.offered = r->in.offered;\
+ _r.out.info = NULL;\
+ _r.out.needed = r->out.needed;\
+ _r.out.count = r->out.count;\
+ _r.out.result = r->out.result;\
+ if (r->out.info && *r->out.info && !r->in.buffer) {\
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: *r->out.info but there's no r->in.buffer");\
+ }\
+ if (r->in.buffer) {\
+ _ndr_info = ndr_push_init_ctx(ndr);\
+ NDR_ERR_HAVE_NO_MEMORY(_ndr_info);\
+ _ndr_info->flags= ndr->flags;\
+ if (r->out.info) {\
+ struct ndr_push *_subndr_info;\
+ struct __##fn __r;\
+ __r.in.level = r->in.level;\
+ __r.in.count = *r->out.count;\
+ __r.out.info = *r->out.info;\
+ NDR_CHECK(ndr_push_subcontext_start(_ndr_info, &_subndr_info, 0, r->in.offered));\
+ NDR_CHECK(ndr_push___##fn(_subndr_info, flags, &__r)); \
+ NDR_CHECK(ndr_push_subcontext_end(_ndr_info, _subndr_info, 0, r->in.offered));\
+ }\
+ if (r->in.offered > _ndr_info->offset) {\
+ uint32_t _padding_len = r->in.offered - _ndr_info->offset;\
+ NDR_CHECK(ndr_push_zero(_ndr_info, _padding_len));\
+ } else if (r->in.offered < _ndr_info->offset) {\
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: r->in.offered[%u] doesn't match length of out buffer[%u]!",\
+ (unsigned)r->in.offered, (unsigned)_ndr_info->offset);\
+ }\
+ _data_blob_info = ndr_push_blob(_ndr_info);\
+ _r.out.info = &_data_blob_info;\
+ }\
+ NDR_CHECK(ndr_push__##fn(ndr, flags, &_r));\
+} while(0)
+
+#define NDR_SPOOLSS_PUSH_ENUM_OUT(fn) do { \
+ DATA_BLOB _data_blob_info = data_blob_null;\
+ struct ndr_push *_ndr_info = NULL;\
+ _r.in.buffer = r->in.buffer;\
+ _r.in.offered = r->in.offered;\
+ _r.out.info = NULL;\
+ _r.out.needed = r->out.needed;\
+ _r.out.count = r->out.count;\
+ _r.out.result = r->out.result;\
+ if (r->out.info && *r->out.info && !r->in.buffer) {\
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: *r->out.info but there's no r->in.buffer");\
+ }\
+ if (r->in.buffer) {\
+ _ndr_info = ndr_push_init_ctx(ndr);\
+ NDR_ERR_HAVE_NO_MEMORY(_ndr_info);\
+ _ndr_info->flags= ndr->flags;\
+ if (r->out.info) {\
+ struct ndr_push *_subndr_info;\
+ struct __##fn __r;\
+ __r.in.count = *r->out.count;\
+ __r.out.info = *r->out.info;\
+ NDR_CHECK(ndr_push_subcontext_start(_ndr_info, &_subndr_info, 0, r->in.offered));\
+ NDR_CHECK(ndr_push___##fn(_subndr_info, flags, &__r)); \
+ NDR_CHECK(ndr_push_subcontext_end(_ndr_info, _subndr_info, 0, r->in.offered));\
+ }\
+ if (r->in.offered > _ndr_info->offset) {\
+ uint32_t _padding_len = r->in.offered - _ndr_info->offset;\
+ NDR_CHECK(ndr_push_zero(_ndr_info, _padding_len));\
+ } else if (r->in.offered < _ndr_info->offset) {\
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: r->in.offered[%u] doesn't match length of out buffer[%u]!",\
+ (unsigned)r->in.offered, (unsigned)_ndr_info->offset);\
+ }\
+ _data_blob_info = ndr_push_blob(_ndr_info);\
+ _r.out.info = &_data_blob_info;\
+ }\
+ NDR_CHECK(ndr_push__##fn(ndr, flags, &_r));\
+} while(0)
+
+#define NDR_SPOOLSS_PUSH_ENUM_LEVEL(fn,in,out) do { \
+ struct _##fn _r;\
+ if (flags & NDR_IN) {\
+ in;\
+ NDR_SPOOLSS_PUSH_ENUM_IN_LEVEL(fn);\
+ }\
+ if (flags & NDR_OUT) {\
+ out;\
+ NDR_SPOOLSS_PUSH_ENUM_OUT_LEVEL(fn);\
+ }\
+} while(0)
+
+#define NDR_SPOOLSS_PUSH_ENUM(fn,in,out) do { \
+ struct _##fn _r;\
+ if (flags & NDR_IN) {\
+ in;\
+ NDR_SPOOLSS_PUSH_ENUM_IN(fn);\
+ }\
+ if (flags & NDR_OUT) {\
+ out;\
+ NDR_SPOOLSS_PUSH_ENUM_OUT(fn);\
+ }\
+} while(0)
+
+#define NDR_SPOOLSS_PULL_ENUM_IN_COMMON(fn) do { \
+ ZERO_STRUCT(r->out);\
+ r->in.buffer = _r.in.buffer;\
+ r->in.offered = _r.in.offered;\
+ r->out.needed = _r.out.needed;\
+ r->out.count = _r.out.count;\
+ if (!r->in.buffer && r->in.offered != 0) {\
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: r->in.offered[%u] but there's no buffer",\
+ (unsigned)r->in.offered);\
+ } else if (r->in.buffer && r->in.buffer->length != r->in.offered) {\
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: r->in.offered[%u] doesn't match length of r->in.buffer[%u]",\
+ (unsigned)r->in.offered, (unsigned)r->in.buffer->length);\
+ }\
+ NDR_PULL_ALLOC(ndr, r->out.info);\
+ ZERO_STRUCTP(r->out.info);\
+} while(0)
+
+#define NDR_SPOOLSS_PULL_ENUM_IN(fn) do { \
+ NDR_CHECK(ndr_pull__##fn(ndr, flags, &_r));\
+ NDR_SPOOLSS_PULL_ENUM_IN_COMMON(fn); \
+} while(0)
+
+#define NDR_SPOOLSS_PULL_ENUM_IN_LEVEL(fn) do { \
+ NDR_CHECK(ndr_pull__##fn(ndr, flags, &_r));\
+ r->in.level = _r.in.level;\
+ NDR_SPOOLSS_PULL_ENUM_IN_COMMON(fn); \
+} while(0)
+
+#define NDR_SPOOLSS_PULL_ENUM_OUT_LEVEL(fn) do { \
+ _r.in.level = r->in.level;\
+ _r.in.buffer = r->in.buffer;\
+ _r.in.offered = r->in.offered;\
+ _r.out.needed = r->out.needed;\
+ _r.out.count = r->out.count;\
+ NDR_CHECK(ndr_pull__##fn(ndr, flags, &_r));\
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {\
+ NDR_PULL_ALLOC(ndr, r->out.info);\
+ }\
+ *r->out.info = NULL;\
+ r->out.needed = _r.out.needed;\
+ r->out.count = _r.out.count;\
+ r->out.result = _r.out.result;\
+ if (_r.out.info) {\
+ struct ndr_pull *_ndr_info;\
+ NDR_PULL_ALLOC(ndr, *r->out.info);\
+ _ndr_info = ndr_pull_init_blob(_r.out.info, *r->out.info);\
+ NDR_ERR_HAVE_NO_MEMORY(_ndr_info);\
+ _ndr_info->flags= ndr->flags;\
+ if (r->in.offered != _ndr_info->data_size) {\
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: offered[%u] doesn't match length of buffer[%u]",\
+ (unsigned)r->in.offered, (unsigned)_ndr_info->data_size);\
+ }\
+ if (*r->out.needed <= _ndr_info->data_size) {\
+ struct __##fn __r;\
+ __r.in.level = r->in.level;\
+ __r.in.count = *r->out.count;\
+ __r.out.info = NULL;\
+ NDR_CHECK(ndr_pull___##fn(_ndr_info, flags, &__r));\
+ *r->out.info = __r.out.info;\
+ }\
+ }\
+} while(0)
+
+#define NDR_SPOOLSS_PULL_ENUM_OUT(fn) do { \
+ _r.in.buffer = r->in.buffer;\
+ _r.in.offered = r->in.offered;\
+ _r.out.needed = r->out.needed;\
+ _r.out.count = r->out.count;\
+ NDR_CHECK(ndr_pull__##fn(ndr, flags, &_r));\
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {\
+ NDR_PULL_ALLOC(ndr, r->out.info);\
+ }\
+ *r->out.info = NULL;\
+ r->out.needed = _r.out.needed;\
+ r->out.count = _r.out.count;\
+ r->out.result = _r.out.result;\
+ if (_r.out.info) {\
+ struct ndr_pull *_ndr_info;\
+ NDR_PULL_ALLOC(ndr, *r->out.info);\
+ _ndr_info = ndr_pull_init_blob(_r.out.info, *r->out.info);\
+ NDR_ERR_HAVE_NO_MEMORY(_ndr_info);\
+ _ndr_info->flags= ndr->flags;\
+ if (r->in.offered != _ndr_info->data_size) {\
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,\
+ "SPOOLSS Buffer: offered[%u] doesn't match length of buffer[%u]",\
+ (unsigned)r->in.offered, (unsigned)_ndr_info->data_size);\
+ }\
+ if (*r->out.needed <= _ndr_info->data_size) {\
+ struct __##fn __r;\
+ __r.in.count = *r->out.count;\
+ __r.out.info = NULL;\
+ NDR_CHECK(ndr_pull___##fn(_ndr_info, flags, &__r));\
+ *r->out.info = __r.out.info;\
+ }\
+ }\
+} while(0)
+
+#define NDR_SPOOLSS_PULL_ENUM_LEVEL(fn,in,out) do { \
+ struct _##fn _r;\
+ if (flags & NDR_IN) {\
+ out;\
+ NDR_SPOOLSS_PULL_ENUM_IN_LEVEL(fn);\
+ in;\
+ }\
+ if (flags & NDR_OUT) {\
+ out;\
+ NDR_SPOOLSS_PULL_ENUM_OUT_LEVEL(fn);\
+ }\
+} while(0)
+
+#define NDR_SPOOLSS_PULL_ENUM(fn,in,out) do { \
+ struct _##fn _r;\
+ if (flags & NDR_IN) {\
+ out;\
+ NDR_SPOOLSS_PULL_ENUM_IN(fn);\
+ in;\
+ }\
+ if (flags & NDR_OUT) {\
+ out;\
+ NDR_SPOOLSS_PULL_ENUM_OUT(fn);\
+ }\
+} while(0)
+
+#define _NDR_CHECK_UINT32(call) do {\
+ enum ndr_err_code _ndr_err; \
+ _ndr_err = call; \
+ if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
+ return 0; \
+ }\
+} while (0)
+
+/* TODO: set _ndr_info->flags correct */
+#define NDR_SPOOLSS_SIZE_ENUM_LEVEL(fn) do { \
+ struct __##fn __r;\
+ DATA_BLOB _data_blob_info;\
+ struct ndr_push *_ndr_info = ndr_push_init_ctx(mem_ctx);\
+ if (!_ndr_info) return 0;\
+ _ndr_info->flags|=LIBNDR_FLAG_NO_NDR_SIZE;\
+ __r.in.level = level;\
+ __r.in.count = count;\
+ __r.out.info = info;\
+ _NDR_CHECK_UINT32(ndr_push___##fn(_ndr_info, NDR_OUT, &__r)); \
+ _data_blob_info = ndr_push_blob(_ndr_info);\
+ return _data_blob_info.length;\
+} while(0)
+
+/* TODO: set _ndr_info->flags correct */
+#define NDR_SPOOLSS_SIZE_ENUM(fn) do { \
+ struct __##fn __r;\
+ DATA_BLOB _data_blob_info;\
+ struct ndr_push *_ndr_info = ndr_push_init_ctx(mem_ctx);\
+ if (!_ndr_info) return 0;\
+ _ndr_info->flags|=LIBNDR_FLAG_NO_NDR_SIZE;\
+ __r.in.count = count;\
+ __r.out.info = info;\
+ _NDR_CHECK_UINT32(ndr_push___##fn(_ndr_info, NDR_OUT, &__r)); \
+ _data_blob_info = ndr_push_blob(_ndr_info);\
+ return _data_blob_info.length;\
+} while(0)
+
+
+/*
+ spoolss_EnumPrinters
+*/
+enum ndr_err_code ndr_push_spoolss_EnumPrinters(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinters *r)
+{
+ NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPrinters,{
+ _r.in.flags = r->in.flags;
+ _r.in.server = r->in.server;
+ },{
+ _r.in.flags = r->in.flags;
+ _r.in.server = r->in.server;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumPrinters(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinters *r)
+{
+ NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPrinters,{
+ r->in.flags = _r.in.flags;
+ r->in.server = _r.in.server;
+ },{
+ _r.in.flags = r->in.flags;
+ _r.in.server = r->in.server;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumPrinters_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_PrinterInfo *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPrinters);
+}
+
+/*
+ spoolss_EnumJobs
+*/
+enum ndr_err_code ndr_push_spoolss_EnumJobs(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumJobs *r)
+{
+ NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumJobs,{
+ _r.in.handle = r->in.handle;
+ _r.in.firstjob = r->in.firstjob;
+ _r.in.numjobs = r->in.numjobs;
+ },{
+ _r.in.handle = r->in.handle;
+ _r.in.firstjob = r->in.firstjob;
+ _r.in.numjobs = r->in.numjobs;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumJobs(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumJobs *r)
+{
+ NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumJobs,{
+ r->in.handle = _r.in.handle;
+ r->in.firstjob = _r.in.firstjob;
+ r->in.numjobs = _r.in.numjobs;
+ },{
+ _r.in.handle = r->in.handle;
+ _r.in.firstjob = r->in.firstjob;
+ _r.in.numjobs = r->in.numjobs;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumJobs_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_JobInfo *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumJobs);
+}
+
+/*
+ spoolss_EnumPrinterDrivers
+*/
+enum ndr_err_code ndr_push_spoolss_EnumPrinterDrivers(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinterDrivers *r)
+{
+ NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPrinterDrivers,{
+ _r.in.server = r->in.server;
+ _r.in.environment = r->in.environment;
+ },{
+ _r.in.server = r->in.server;
+ _r.in.environment = r->in.environment;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumPrinterDrivers(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinterDrivers *r)
+{
+ NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPrinterDrivers,{
+ r->in.server = _r.in.server;
+ r->in.environment = _r.in.environment;
+ },{
+ _r.in.server = r->in.server;
+ _r.in.environment = r->in.environment;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumPrinterDrivers_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_DriverInfo *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPrinterDrivers);
+}
+
+/*
+ spoolss_EnumForms
+*/
+enum ndr_err_code ndr_push_spoolss_EnumForms(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumForms *r)
+{
+ NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumForms,{
+ _r.in.handle = r->in.handle;
+ },{
+ _r.in.handle = r->in.handle;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumForms(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumForms *r)
+{
+ NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumForms,{
+ r->in.handle = _r.in.handle;
+ },{
+ _r.in.handle = r->in.handle;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumForms_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_FormInfo *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumForms);
+}
+
+/*
+ spoolss_EnumPorts
+*/
+enum ndr_err_code ndr_push_spoolss_EnumPorts(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPorts *r)
+{
+ NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPorts,{
+ _r.in.servername= r->in.servername;
+ },{
+ _r.in.servername= r->in.servername;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumPorts(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPorts *r)
+{
+ NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPorts,{
+ r->in.servername= _r.in.servername;
+ },{
+ _r.in.servername= r->in.servername;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumPorts_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_PortInfo *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPorts);
+}
+
+/*
+ spoolss_EnumMonitors
+*/
+enum ndr_err_code ndr_push_spoolss_EnumMonitors(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumMonitors *r)
+{
+ NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumMonitors,{
+ _r.in.servername= r->in.servername;
+ },{
+ _r.in.servername= r->in.servername;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumMonitors(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumMonitors *r)
+{
+ NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumMonitors,{
+ r->in.servername= _r.in.servername;
+ },{
+ _r.in.servername= r->in.servername;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumMonitors_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_MonitorInfo *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumMonitors);
+}
+
+/*
+ spoolss_EnumPrintProcessors
+*/
+enum ndr_err_code ndr_push_spoolss_EnumPrintProcessors(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrintProcessors *r)
+{
+ NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPrintProcessors,{
+ _r.in.servername = r->in.servername;
+ _r.in.environment = r->in.environment;
+ },{
+ _r.in.servername = r->in.servername;
+ _r.in.environment = r->in.environment;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumPrintProcessors(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrintProcessors *r)
+{
+ NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPrintProcessors,{
+ r->in.servername = _r.in.servername;
+ r->in.environment = _r.in.environment;
+ },{
+ _r.in.servername = r->in.servername;
+ _r.in.environment = r->in.environment;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumPrintProcessors_info(TALLOC_CTX *mem_ctx,
+ uint32_t level, uint32_t count, union spoolss_PrintProcessorInfo *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessors);
+}
+
+/*
+ spoolss_EnumPrintProcessors
+*/
+enum ndr_err_code ndr_push_spoolss_EnumPrintProcessorDataTypes(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrintProcessorDataTypes *r)
+{
+ NDR_SPOOLSS_PUSH_ENUM_LEVEL(spoolss_EnumPrintProcessorDataTypes,{
+ _r.in.servername = r->in.servername;
+ _r.in.print_processor_name = r->in.print_processor_name;
+ },{
+ _r.in.servername = r->in.servername;
+ _r.in.print_processor_name = r->in.print_processor_name;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumPrintProcessorDataTypes(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrintProcessorDataTypes *r)
+{
+ NDR_SPOOLSS_PULL_ENUM_LEVEL(spoolss_EnumPrintProcessorDataTypes,{
+ r->in.servername = _r.in.servername;
+ r->in.print_processor_name = _r.in.print_processor_name;
+ },{
+ _r.in.servername = r->in.servername;
+ _r.in.print_processor_name = r->in.print_processor_name;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumPrintProcessorDataTypes_info(TALLOC_CTX *mem_ctx,
+ uint32_t level, uint32_t count, union spoolss_PrintProcDataTypesInfo *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM_LEVEL(spoolss_EnumPrintProcessorDataTypes);
+}
+
+/*
+ spoolss_EnumPerMachineConnections
+*/
+enum ndr_err_code ndr_push_spoolss_EnumPerMachineConnections(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPerMachineConnections *r)
+{
+ NDR_SPOOLSS_PUSH_ENUM(spoolss_EnumPerMachineConnections,{
+ _r.in.server = r->in.server;
+ },{
+ _r.in.server = r->in.server;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumPerMachineConnections(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPerMachineConnections *r)
+{
+ NDR_SPOOLSS_PULL_ENUM(spoolss_EnumPerMachineConnections,{
+ r->in.server = _r.in.server;
+ },{
+ _r.in.server = r->in.server;
+ });
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumPerMachineConnections_info(TALLOC_CTX *mem_ctx, uint32_t count, struct spoolss_PrinterInfo4 *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM(spoolss_EnumPerMachineConnections);
+}
+
+/*
+ spoolss_EnumPrinterDataEx
+*/
+
+enum ndr_err_code ndr_push_spoolss_EnumPrinterDataEx(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinterDataEx *r)
+{
+ struct _spoolss_EnumPrinterDataEx _r;
+ if (flags & NDR_IN) {
+ _r.in.handle = r->in.handle;
+ _r.in.key_name = r->in.key_name;
+ _r.in.offered = r->in.offered;
+ NDR_CHECK(ndr_push__spoolss_EnumPrinterDataEx(ndr, flags, &_r));
+ }
+ if (flags & NDR_OUT) {
+ struct ndr_push *_ndr_info;
+ _r.in.handle = r->in.handle;
+ _r.in.key_name = r->in.key_name;
+ _r.in.offered = r->in.offered;
+ _r.out.count = r->out.count;
+ _r.out.needed = r->out.needed;
+ _r.out.result = r->out.result;
+ _r.out.info = data_blob(NULL, 0);
+ if (r->in.offered >= *r->out.needed) {
+ struct ndr_push *_subndr_info;
+ struct __spoolss_EnumPrinterDataEx __r;
+ _ndr_info = ndr_push_init_ctx(ndr);
+ NDR_ERR_HAVE_NO_MEMORY(_ndr_info);
+ _ndr_info->flags= ndr->flags;
+ __r.in.count = *r->out.count;
+ __r.out.info = *r->out.info;
+ NDR_CHECK(ndr_push_subcontext_start(_ndr_info, &_subndr_info, 0, r->in.offered));
+ NDR_CHECK(ndr_push___spoolss_EnumPrinterDataEx(_subndr_info, flags, &__r));
+ NDR_CHECK(ndr_push_subcontext_end(_ndr_info, _subndr_info, 0, r->in.offered));
+ if (r->in.offered > _ndr_info->offset) {
+ uint32_t _padding_len = r->in.offered - _ndr_info->offset;
+ NDR_CHECK(ndr_push_zero(_ndr_info, _padding_len));
+ }
+ _r.out.info = ndr_push_blob(_ndr_info);
+ }
+ NDR_CHECK(ndr_push__spoolss_EnumPrinterDataEx(ndr, flags, &_r));
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_spoolss_EnumPrinterDataEx(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinterDataEx *r)
+{
+ struct _spoolss_EnumPrinterDataEx _r;
+ if (flags & NDR_IN) {
+ _r.in.handle = r->in.handle;
+ _r.in.key_name = r->in.key_name;
+ ZERO_STRUCT(r->out);
+ NDR_CHECK(ndr_pull__spoolss_EnumPrinterDataEx(ndr, flags, &_r));
+ r->in.handle = _r.in.handle;
+ r->in.key_name = _r.in.key_name;
+ r->in.offered = _r.in.offered;
+ r->out.needed = _r.out.needed;
+ r->out.count = _r.out.count;
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ ZERO_STRUCTP(r->out.info);
+ }
+ if (flags & NDR_OUT) {
+ _r.in.handle = r->in.handle;
+ _r.in.key_name = r->in.key_name;
+ _r.in.offered = r->in.offered;
+ _r.out.count = r->out.count;
+ _r.out.needed = r->out.needed;
+ NDR_CHECK(ndr_pull__spoolss_EnumPrinterDataEx(ndr, flags, &_r));
+ if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {
+ NDR_PULL_ALLOC(ndr, r->out.info);
+ }
+ *r->out.info = NULL;
+ r->out.needed = _r.out.needed;
+ r->out.count = _r.out.count;
+ r->out.result = _r.out.result;
+ if (_r.out.info.length) {
+ struct ndr_pull *_ndr_info;
+ NDR_PULL_ALLOC(ndr, *r->out.info);
+ _ndr_info = ndr_pull_init_blob(&_r.out.info, *r->out.info);
+ NDR_ERR_HAVE_NO_MEMORY(_ndr_info);
+ _ndr_info->flags= ndr->flags;
+ if (r->in.offered != _ndr_info->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "SPOOLSS Buffer: offered[%u] doesn't match length of buffer[%u]",
+ (unsigned)r->in.offered, (unsigned)_ndr_info->data_size);
+ }
+ if (*r->out.needed <= _ndr_info->data_size) {
+ struct __spoolss_EnumPrinterDataEx __r;
+ __r.in.count = *r->out.count;
+ __r.out.info = NULL;
+ NDR_CHECK(ndr_pull___spoolss_EnumPrinterDataEx(_ndr_info, flags, &__r));
+ *r->out.info = __r.out.info;
+ }
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+uint32_t ndr_size_spoolss_EnumPrinterDataEx_info(TALLOC_CTX *mem_ctx,
+ uint32_t count, struct spoolss_PrinterEnumValues *info)
+{
+ NDR_SPOOLSS_SIZE_ENUM(spoolss_EnumPrinterDataEx);
+}
+
+uint32_t _ndr_size_spoolss_DeviceMode(struct spoolss_DeviceMode *devmode, libndr_flags flags)
+{
+ if (!devmode) return 0;
+ return ndr_size_spoolss_DeviceMode(devmode, flags);
+}
+
+_PUBLIC_ size_t ndr_size_spoolss_StringArray(const struct spoolss_StringArray *r, libndr_flags flags)
+{
+ if (!r) {
+ return 4;
+ }
+
+ return ndr_size_struct(r, flags, (ndr_push_flags_fn_t)ndr_push_spoolss_StringArray);
+}
+
+/* hand marshall as pidl cannot (yet) generate a relative pointer to a fixed array of
+ * structs */
+
+_PUBLIC_ enum ndr_err_code ndr_push_spoolss_DriverInfo101(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct spoolss_DriverInfo101 *r)
+{
+ uint32_t cntr_file_info_1;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 8));
+ NDR_CHECK(ndr_push_spoolss_DriverOSVersion(ndr, NDR_SCALARS, r->version));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->driver_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->architecture));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->file_info));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->file_count));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->monitor_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->default_datatype));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string_array = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->previous_names));
+ ndr->flags = _flags_save_string_array;
+ }
+ NDR_CHECK(ndr_push_NTTIME(ndr, NDR_SCALARS, r->driver_date));
+ NDR_CHECK(ndr_push_hyper(ndr, NDR_SCALARS, r->driver_version));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->manufacturer_name));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->manufacturer_url));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->hardware_id));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->provider));
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_push_trailer_align(ndr, 8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->driver_name) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->driver_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->driver_name));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->driver_name));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->architecture) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->architecture));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->architecture));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->architecture));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ if (r->file_info) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->file_info));
+#if 0
+ NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, r->file_count));
+#endif
+ for (cntr_file_info_1 = 0; cntr_file_info_1 < r->file_count; cntr_file_info_1++) {
+ NDR_CHECK(ndr_push_spoolss_DriverFileInfo(ndr, NDR_SCALARS, &r->file_info[cntr_file_info_1]));
+ }
+ for (cntr_file_info_1 = 0; cntr_file_info_1 < r->file_count; cntr_file_info_1++) {
+ NDR_CHECK(ndr_push_spoolss_DriverFileInfo(ndr, NDR_BUFFERS, &r->file_info[cntr_file_info_1]));
+ }
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->file_info));
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->monitor_name) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->monitor_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->monitor_name));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->monitor_name));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->default_datatype) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->default_datatype));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->default_datatype));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->default_datatype));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string_array = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->previous_names) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->previous_names));
+ NDR_CHECK(ndr_push_string_array(ndr, NDR_SCALARS, r->previous_names));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->previous_names));
+ }
+ ndr->flags = _flags_save_string_array;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->manufacturer_name) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->manufacturer_name));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->manufacturer_name));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->manufacturer_name));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->manufacturer_url) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->manufacturer_url));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->manufacturer_url));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->manufacturer_url));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->hardware_id) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->hardware_id));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->hardware_id));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->hardware_id));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->provider) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->provider));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->provider));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->provider));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_spoolss_DriverInfo101(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct spoolss_DriverInfo101 *r)
+{
+ uint32_t _ptr_driver_name;
+ TALLOC_CTX *_mem_save_driver_name_0;
+ uint32_t _ptr_architecture;
+ TALLOC_CTX *_mem_save_architecture_0;
+ uint32_t _ptr_file_info;
+ uint32_t cntr_file_info_1;
+ TALLOC_CTX *_mem_save_file_info_0;
+ TALLOC_CTX *_mem_save_file_info_1;
+ uint32_t _ptr_monitor_name;
+ TALLOC_CTX *_mem_save_monitor_name_0;
+ uint32_t _ptr_default_datatype;
+ TALLOC_CTX *_mem_save_default_datatype_0;
+ uint32_t _ptr_previous_names;
+ TALLOC_CTX *_mem_save_previous_names_0;
+ uint32_t _ptr_manufacturer_name;
+ TALLOC_CTX *_mem_save_manufacturer_name_0;
+ uint32_t _ptr_manufacturer_url;
+ TALLOC_CTX *_mem_save_manufacturer_url_0;
+ uint32_t _ptr_hardware_id;
+ TALLOC_CTX *_mem_save_hardware_id_0;
+ uint32_t _ptr_provider;
+ TALLOC_CTX *_mem_save_provider_0;
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 8));
+ NDR_CHECK(ndr_pull_spoolss_DriverOSVersion(ndr, NDR_SCALARS, &r->version));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_driver_name));
+ if (_ptr_driver_name) {
+ NDR_PULL_ALLOC(ndr, r->driver_name);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->driver_name, _ptr_driver_name));
+ } else {
+ r->driver_name = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_architecture));
+ if (_ptr_architecture) {
+ NDR_PULL_ALLOC(ndr, r->architecture);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->architecture, _ptr_architecture));
+ } else {
+ r->architecture = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_file_info));
+ if (_ptr_file_info) {
+ NDR_PULL_ALLOC(ndr, r->file_info);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->file_info, _ptr_file_info));
+ } else {
+ r->file_info = NULL;
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->file_count));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_monitor_name));
+ if (_ptr_monitor_name) {
+ NDR_PULL_ALLOC(ndr, r->monitor_name);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->monitor_name, _ptr_monitor_name));
+ } else {
+ r->monitor_name = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_default_datatype));
+ if (_ptr_default_datatype) {
+ NDR_PULL_ALLOC(ndr, r->default_datatype);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->default_datatype, _ptr_default_datatype));
+ } else {
+ r->default_datatype = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string_array = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_previous_names));
+ if (_ptr_previous_names) {
+ NDR_PULL_ALLOC(ndr, r->previous_names);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->previous_names, _ptr_previous_names));
+ } else {
+ r->previous_names = NULL;
+ }
+ ndr->flags = _flags_save_string_array;
+ }
+ NDR_CHECK(ndr_pull_NTTIME(ndr, NDR_SCALARS, &r->driver_date));
+ NDR_CHECK(ndr_pull_hyper(ndr, NDR_SCALARS, &r->driver_version));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_manufacturer_name));
+ if (_ptr_manufacturer_name) {
+ NDR_PULL_ALLOC(ndr, r->manufacturer_name);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->manufacturer_name, _ptr_manufacturer_name));
+ } else {
+ r->manufacturer_name = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_manufacturer_url));
+ if (_ptr_manufacturer_url) {
+ NDR_PULL_ALLOC(ndr, r->manufacturer_url);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->manufacturer_url, _ptr_manufacturer_url));
+ } else {
+ r->manufacturer_url = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_hardware_id));
+ if (_ptr_hardware_id) {
+ NDR_PULL_ALLOC(ndr, r->hardware_id);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->hardware_id, _ptr_hardware_id));
+ } else {
+ r->hardware_id = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_provider));
+ if (_ptr_provider) {
+ NDR_PULL_ALLOC(ndr, r->provider);
+ NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->provider, _ptr_provider));
+ } else {
+ r->provider = NULL;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 8));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->driver_name) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->driver_name));
+ _mem_save_driver_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->driver_name, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->driver_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_driver_name_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->architecture) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->architecture));
+ _mem_save_architecture_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->architecture, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->architecture));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_architecture_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ if (r->file_info) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->file_info));
+ _mem_save_file_info_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->file_info, 0);
+#if 0
+ NDR_CHECK(ndr_pull_array_size(ndr, &r->file_info));
+#else
+ NDR_CHECK(ndr_token_store(ndr, &ndr->array_size_list, &r->file_info, r->file_count));
+#endif
+ NDR_PULL_ALLOC_N(ndr, r->file_info, r->file_count);
+ _mem_save_file_info_1 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->file_info, 0);
+ for (cntr_file_info_1 = 0; cntr_file_info_1 < r->file_count; cntr_file_info_1++) {
+ NDR_CHECK(ndr_pull_spoolss_DriverFileInfo(ndr, NDR_SCALARS, &r->file_info[cntr_file_info_1]));
+ }
+ for (cntr_file_info_1 = 0; cntr_file_info_1 < r->file_count; cntr_file_info_1++) {
+ NDR_CHECK(ndr_pull_spoolss_DriverFileInfo(ndr, NDR_BUFFERS, &r->file_info[cntr_file_info_1]));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_file_info_1, 0);
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_file_info_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->monitor_name) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->monitor_name));
+ _mem_save_monitor_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->monitor_name, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->monitor_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_monitor_name_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->default_datatype) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->default_datatype));
+ _mem_save_default_datatype_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->default_datatype, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->default_datatype));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_default_datatype_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string_array = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->previous_names) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->previous_names));
+ _mem_save_previous_names_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->previous_names, 0);
+ NDR_CHECK(ndr_pull_string_array(ndr, NDR_SCALARS, &r->previous_names));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_previous_names_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string_array;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->manufacturer_name) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->manufacturer_name));
+ _mem_save_manufacturer_name_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->manufacturer_name, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->manufacturer_name));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_manufacturer_name_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->manufacturer_url) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->manufacturer_url));
+ _mem_save_manufacturer_url_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->manufacturer_url, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->manufacturer_url));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_manufacturer_url_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->hardware_id) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->hardware_id));
+ _mem_save_hardware_id_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->hardware_id, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->hardware_id));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_hardware_id_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->provider) {
+ uint32_t _relative_save_offset;
+ _relative_save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->provider));
+ _mem_save_provider_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->provider, 0);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->provider));
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_provider_0, 0);
+ if (ndr->offset > ndr->relative_highest_offset) {
+ ndr->relative_highest_offset = ndr->offset;
+ }
+ ndr->offset = _relative_save_offset;
+ }
+ ndr->flags = _flags_save_string;
+ }
+ if (r->file_info) {
+ NDR_CHECK(ndr_check_steal_array_size(ndr, (void*)&r->file_info, r->file_count));
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+void ndr_print_spoolss_Field(struct ndr_print *ndr, const char *name, const union spoolss_Field *r)
+{
+ int level;
+ level = ndr_print_steal_switch_value(ndr, r);
+ ndr_print_union(ndr, name, level, "spoolss_Field");
+ switch (level) {
+ case PRINTER_NOTIFY_TYPE:
+ ndr_print_spoolss_PrintNotifyField(ndr, "field", r->field);
+ break;
+
+ case JOB_NOTIFY_TYPE:
+ ndr_print_spoolss_JobNotifyField(ndr, "field", r->field);
+ break;
+
+ default:
+ ndr_print_uint16(ndr, "field", r->field);
+ break;
+
+ }
+}
+
+_PUBLIC_ size_t ndr_size_spoolss_PrinterData(const union spoolss_PrinterData *r, uint32_t level, libndr_flags flags)
+{
+ if (!r) {
+ return 0;
+ }
+ return ndr_size_union(r, flags, level, (ndr_push_flags_fn_t)ndr_push_spoolss_PrinterData);
+}
+
+void ndr_print_spoolss_security_descriptor(struct ndr_print *ndr, const char *name, const struct security_descriptor *r)
+{
+ ndr_print_security_descriptor(ndr, name, r);
+}
+
+enum ndr_err_code ndr_pull_spoolss_security_descriptor(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct security_descriptor *r)
+{
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NO_RELATIVE_REVERSE);
+ NDR_CHECK(ndr_pull_security_descriptor(ndr, ndr_flags, r));
+ ndr->flags = _flags_save_STRUCT;
+ return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_push_spoolss_security_descriptor(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct security_descriptor *r)
+{
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN|LIBNDR_FLAG_NO_RELATIVE_REVERSE);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 5));
+ NDR_CHECK(ndr_push_security_descriptor_revision(ndr, NDR_SCALARS, r->revision));
+ NDR_CHECK(ndr_push_security_descriptor_type(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->owner_sid));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->group_sid));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->sacl));
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->dacl));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ if (r->sacl) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->sacl));
+ NDR_CHECK(ndr_push_security_acl(ndr, NDR_SCALARS|NDR_BUFFERS, r->sacl));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->sacl));
+ }
+ if (r->dacl) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->dacl));
+ NDR_CHECK(ndr_push_security_acl(ndr, NDR_SCALARS|NDR_BUFFERS, r->dacl));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->dacl));
+ }
+ if (r->owner_sid) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->owner_sid));
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, r->owner_sid));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->owner_sid));
+ }
+ if (r->group_sid) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->group_sid));
+ NDR_CHECK(ndr_push_dom_sid(ndr, NDR_SCALARS, r->group_sid));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->group_sid));
+ }
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_spoolss_PrinterInfo2(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct spoolss_PrinterInfo2 *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 5));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->servername));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->printername));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->sharename));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->portname));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->drivername));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->comment));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->location));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_spoolss_DeviceMode = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->devmode));
+ ndr->flags = _flags_save_spoolss_DeviceMode;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->sepfile));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->printprocessor));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->datatype));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->parameters));
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_spoolss_security_descriptor = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ NDR_CHECK(ndr_push_relative_ptr1(ndr, r->secdesc));
+ ndr->flags = _flags_save_spoolss_security_descriptor;
+ }
+ NDR_CHECK(ndr_push_spoolss_PrinterAttributes(ndr, NDR_SCALARS, r->attributes));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->priority));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->defaultpriority));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->starttime));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->untiltime));
+ NDR_CHECK(ndr_push_spoolss_PrinterStatus(ndr, NDR_SCALARS, r->status));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->cjobs));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->averageppm));
+ NDR_CHECK(ndr_push_trailer_align(ndr, 5));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->servername) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->servername));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->servername));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->servername));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->printername) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->printername));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->printername));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->printername));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->sharename) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->sharename));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sharename));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->sharename));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->portname) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->portname));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->portname));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->portname));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->drivername) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->drivername));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->drivername));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->drivername));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->comment) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->comment));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->comment));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->comment));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->location) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->location));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->location));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->location));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->sepfile) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->sepfile));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->sepfile));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->sepfile));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->printprocessor) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->printprocessor));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->printprocessor));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->printprocessor));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->datatype) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->datatype));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->datatype));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->datatype));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_NULLTERM);
+ if (r->parameters) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->parameters));
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->parameters));
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->parameters));
+ }
+ ndr->flags = _flags_save_string;
+ }
+ {
+ libndr_flags _flags_save_spoolss_DeviceMode = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ if (r->devmode) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->devmode));
+ {
+ struct ndr_push *_ndr_devmode;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_devmode, 0, -1));
+ NDR_CHECK(ndr_push_spoolss_DeviceMode(_ndr_devmode, NDR_SCALARS, r->devmode));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_devmode, 0, -1));
+ }
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->devmode));
+ }
+ ndr->flags = _flags_save_spoolss_DeviceMode;
+ }
+ {
+ libndr_flags _flags_save_spoolss_security_descriptor = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN4);
+ if (r->secdesc) {
+ NDR_CHECK(ndr_push_relative_ptr2_start(ndr, r->secdesc));
+ {
+ struct ndr_push *_ndr_secdesc;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_secdesc, 0, -1));
+ NDR_CHECK(ndr_push_spoolss_security_descriptor(_ndr_secdesc, NDR_SCALARS|NDR_BUFFERS, r->secdesc));
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_secdesc, 0, -1));
+ }
+ NDR_CHECK(ndr_push_relative_ptr2_end(ndr, r->secdesc));
+ }
+ ndr->flags = _flags_save_spoolss_security_descriptor;
+ }
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_spoolss_Time(struct ndr_print *ndr, const char *name, const struct spoolss_Time *r)
+{
+ struct tm tm;
+ time_t t;
+ char *str;
+
+ tm.tm_sec = r->second;
+ tm.tm_min = r->minute;
+ tm.tm_hour = r->hour;
+ tm.tm_mday = r->day;
+ tm.tm_mon = r->month - 1;
+ tm.tm_year = r->year - 1900;
+ tm.tm_wday = r->day_of_week;
+ tm.tm_yday = 0;
+ tm.tm_isdst = -1;
+
+ t = mktime(&tm);
+
+ str = timestring(ndr, t);
+
+ ndr_print_struct(ndr, name, "spoolss_Time");
+ ndr->depth++;
+ ndr_print_string(ndr, "", str);
+ ndr->depth--;
+ talloc_free(str);
+}
+
+_PUBLIC_ libndr_flags ndr_spoolss_PrinterEnumValues_align(enum winreg_Type type)
+{
+ switch(type) {
+ case REG_NONE:
+ return 0;
+ case REG_SZ:
+ return LIBNDR_FLAG_ALIGN2;
+ case REG_EXPAND_SZ:
+ return LIBNDR_FLAG_ALIGN2;
+ case REG_BINARY:
+ return 0;
+ case REG_DWORD:
+ return LIBNDR_FLAG_ALIGN4;
+ case REG_DWORD_BIG_ENDIAN:
+ return LIBNDR_FLAG_ALIGN4;
+ case REG_LINK:
+ return 0;
+ case REG_MULTI_SZ:
+ return LIBNDR_FLAG_ALIGN2;
+ case REG_RESOURCE_LIST:
+ return LIBNDR_FLAG_ALIGN2;
+ case REG_FULL_RESOURCE_DESCRIPTOR:
+ return LIBNDR_FLAG_ALIGN4;
+ case REG_RESOURCE_REQUIREMENTS_LIST:
+ return LIBNDR_FLAG_ALIGN2;
+ case REG_QWORD:
+ return LIBNDR_FLAG_ALIGN8;
+ }
+
+ return 0;
+}
diff --git a/librpc/ndr/ndr_spoolss_buf.h b/librpc/ndr/ndr_spoolss_buf.h
new file mode 100644
index 0000000..aeb071d
--- /dev/null
+++ b/librpc/ndr/ndr_spoolss_buf.h
@@ -0,0 +1,84 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling spoolss subcontext buffer structures
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Tim Potter 2003
+ 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/>.
+*/
+
+#ifndef ___SPACE_SRC_SAMBA_SOURCES_SAMBA_GIT_SOURCE3____SOURCE4_LIBRPC_NDR_NDR_SPOOLSS_BUF_H__
+#define ___SPACE_SRC_SAMBA_SOURCES_SAMBA_GIT_SOURCE3____SOURCE4_LIBRPC_NDR_NDR_SPOOLSS_BUF_H__
+
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2) PRINTF_ATTRIBUTE(a1, a2)
+/* This file was automatically generated by mkproto.pl. DO NOT EDIT */
+
+/* this file contains prototypes for functions that are private
+ * to this subsystem or library. These functions should not be
+ * used outside this particular subsystem! */
+
+
+/* The following definitions come from /space/src/samba/SOURCES/samba.git/source3/../source4/librpc/ndr/ndr_spoolss_buf.c */
+
+enum ndr_err_code ndr_push_spoolss_EnumPrinters(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinters *r);
+enum ndr_err_code ndr_pull_spoolss_EnumPrinters(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinters *r);
+uint32_t ndr_size_spoolss_EnumPrinters_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_PrinterInfo *info);
+enum ndr_err_code ndr_push_spoolss_EnumJobs(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumJobs *r);
+enum ndr_err_code ndr_pull_spoolss_EnumJobs(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumJobs *r);
+uint32_t ndr_size_spoolss_EnumJobs_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_JobInfo *info);
+enum ndr_err_code ndr_push_spoolss_EnumPrinterDrivers(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinterDrivers *r);
+enum ndr_err_code ndr_pull_spoolss_EnumPrinterDrivers(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinterDrivers *r);
+uint32_t ndr_size_spoolss_EnumPrinterDrivers_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_DriverInfo *info);
+enum ndr_err_code ndr_push_spoolss_EnumForms(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumForms *r);
+enum ndr_err_code ndr_pull_spoolss_EnumForms(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumForms *r);
+uint32_t ndr_size_spoolss_EnumForms_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_FormInfo *info);
+enum ndr_err_code ndr_push_spoolss_EnumPorts(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPorts *r);
+enum ndr_err_code ndr_pull_spoolss_EnumPorts(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPorts *r);
+uint32_t ndr_size_spoolss_EnumPorts_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_PortInfo *info);
+enum ndr_err_code ndr_push_spoolss_EnumMonitors(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumMonitors *r);
+enum ndr_err_code ndr_pull_spoolss_EnumMonitors(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumMonitors *r);
+uint32_t ndr_size_spoolss_EnumMonitors_info(TALLOC_CTX *mem_ctx, uint32_t level, uint32_t count, union spoolss_MonitorInfo *info);
+enum ndr_err_code ndr_push_spoolss_EnumPrintProcessors(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrintProcessors *r);
+enum ndr_err_code ndr_pull_spoolss_EnumPrintProcessors(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrintProcessors *r);
+uint32_t ndr_size_spoolss_EnumPrintProcessors_info(TALLOC_CTX *mem_ctx,
+ uint32_t level, uint32_t count, union spoolss_PrintProcessorInfo *info);
+enum ndr_err_code ndr_push_spoolss_EnumPrintProcessorDataTypes(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrintProcessorDataTypes *r);
+enum ndr_err_code ndr_pull_spoolss_EnumPrintProcessorDataTypes(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrintProcessorDataTypes *r);
+uint32_t ndr_size_spoolss_EnumPrintProcessorDataTypes_info(TALLOC_CTX *mem_ctx,
+ uint32_t level, uint32_t count, union spoolss_PrintProcDataTypesInfo *info);
+enum ndr_err_code ndr_push_spoolss_EnumPrinterDataEx(struct ndr_push *ndr, ndr_flags_type flags, const struct spoolss_EnumPrinterDataEx *r);
+enum ndr_err_code ndr_pull_spoolss_EnumPrinterDataEx(struct ndr_pull *ndr, ndr_flags_type flags, struct spoolss_EnumPrinterDataEx *r);
+uint32_t ndr_size_spoolss_EnumPrinterDataEx_info(TALLOC_CTX *mem_ctx,
+ uint32_t count, struct spoolss_PrinterEnumValues *info);
+uint32_t _ndr_size_spoolss_DeviceMode(struct spoolss_DeviceMode *devmode, libndr_flags flags);
+size_t ndr_size_spoolss_StringArray(const struct spoolss_StringArray *r, libndr_flags flags);
+_PUBLIC_ enum ndr_err_code ndr_push_spoolss_DriverInfo101(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct spoolss_DriverInfo101 *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_spoolss_DriverInfo101(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct spoolss_DriverInfo101 *r);
+void ndr_print_spoolss_Field(struct ndr_print *ndr, const char *name, const union spoolss_Field *r);
+size_t ndr_size_spoolss_PrinterData(const union spoolss_PrinterData *r, uint32_t level, libndr_flags flags);
+void ndr_print_spoolss_security_descriptor(struct ndr_print *ndr, const char *name, const struct security_descriptor *r);
+enum ndr_err_code ndr_pull_spoolss_security_descriptor(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct security_descriptor *r);
+enum ndr_err_code ndr_push_spoolss_security_descriptor(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct security_descriptor *r);
+_PUBLIC_ void ndr_print_spoolss_Time(struct ndr_print *ndr, const char *name, const struct spoolss_Time *r);
+_PUBLIC_ libndr_flags ndr_spoolss_PrinterEnumValues_align(enum winreg_Type type);
+
+uint32_t ndr_size_spoolss_EnumPerMachineConnections_info(TALLOC_CTX *mem_ctx, uint32_t count, struct spoolss_PrinterInfo4 *info);
+#undef _PRINTF_ATTRIBUTE
+#define _PRINTF_ATTRIBUTE(a1, a2)
+
+#endif /* ___SPACE_SRC_SAMBA_SOURCES_SAMBA_GIT_SOURCE3____SOURCE4_LIBRPC_NDR_NDR_SPOOLSS_BUF_H__ */
diff --git a/librpc/ndr/ndr_string.c b/librpc/ndr/ndr_string.c
new file mode 100644
index 0000000..323886b
--- /dev/null
+++ b/librpc/ndr/ndr_string.c
@@ -0,0 +1,1109 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling string types
+
+ 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 "librpc/ndr/libndr.h"
+
+/**
+ pull a general string from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_string(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **s)
+{
+ char *as=NULL;
+ uint32_t len1, ofs, len2;
+ uint16_t len3;
+ size_t conv_src_len = 0, converted_size;
+ int do_convert = 1, chset = CH_UTF16;
+ unsigned byte_mul = 2;
+ libndr_flags flags = ndr->flags;
+ unsigned c_len_term = 0;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (NDR_BE(ndr)) {
+ chset = CH_UTF16BE;
+ }
+
+ /*
+ * We will check this flag, but from the unmodified
+ * ndr->flags, so just remove it from flags
+ */
+ flags &= ~LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ switch (flags & LIBNDR_ENCODING_FLAGS) {
+ case 0:
+ break;
+
+ case LIBNDR_FLAG_STR_ASCII:
+ chset = CH_DOS;
+ byte_mul = 1;
+ break;
+
+ case LIBNDR_FLAG_STR_UTF8:
+ chset = CH_UTF8;
+ byte_mul = 1;
+ break;
+
+ case LIBNDR_FLAG_STR_RAW8:
+ do_convert = 0;
+ byte_mul = 1;
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+ flags &= ~LIBNDR_ENCODING_FLAGS;
+
+ flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
+ if (flags & LIBNDR_FLAG_STR_CHARLEN) {
+ c_len_term = 1;
+ flags &= ~LIBNDR_FLAG_STR_CHARLEN;
+ }
+
+ switch (flags & LIBNDR_STRING_FLAGS) {
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
+ if (ofs != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%"PRI_LIBNDR_FLAGS"\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len2));
+ if (len2 > len1) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "Bad string lengths len1=%"PRIu32" ofs=%"PRIu32" len2=%"PRIu32"\n",
+ len1, ofs, len2);
+ } else if (len1 != len2) {
+ DEBUG(6,("len1[%"PRIu32"] != len2[%"PRIu32"]\n", len1, len2));
+ }
+ conv_src_len = len2 + c_len_term;
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE4:
+ case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
+ conv_src_len = len1 + c_len_term;
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
+ conv_src_len = len1;
+ byte_mul = 1; /* the length is now absolute */
+ break;
+
+ case LIBNDR_FLAG_STR_LEN4:
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &ofs));
+ if (ofs != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "non-zero array offset with string flags 0x%"PRI_LIBNDR_FLAGS"\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &len1));
+ conv_src_len = len1 + c_len_term;
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE2:
+ case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
+ conv_src_len = len3 + c_len_term;
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_STR_BYTESIZE:
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &len3));
+ conv_src_len = len3;
+ byte_mul = 1; /* the length is now absolute */
+ break;
+
+ case LIBNDR_FLAG_STR_NULLTERM:
+ /*
+ * We ensure that conv_src_len cannot equal 0 by
+ * requiring that there be enough bytes for at least
+ * the NULL terminator
+ */
+ if (byte_mul == 1) {
+ NDR_PULL_NEED_BYTES(ndr, 1);
+ conv_src_len = ascii_len_n((const char *)(ndr->data+ndr->offset), ndr->data_size - ndr->offset);
+ } else {
+ NDR_PULL_NEED_BYTES(ndr, 2);
+ conv_src_len = utf16_null_terminated_len_n(ndr->data+ndr->offset, ndr->data_size - ndr->offset);
+ }
+ byte_mul = 1; /* the length is now absolute */
+ break;
+
+ case LIBNDR_FLAG_STR_NOTERM:
+ if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS" (missing NDR_REMAINING)\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+ conv_src_len = ndr->data_size - ndr->offset;
+ byte_mul = 1; /* the length is now absolute */
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ NDR_PULL_NEED_BYTES(ndr, conv_src_len * byte_mul);
+ if (conv_src_len == 0) {
+ as = talloc_strdup(ndr->current_mem_ctx, "");
+ converted_size = 0;
+ if (!as) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC,
+ "Failed to talloc_strndup() in zero-length ndr_pull_string()");
+ }
+ } else {
+ if (!do_convert) {
+ as = talloc_strndup(ndr->current_mem_ctx,
+ (char *)ndr->data + ndr->offset,
+ conv_src_len);
+ if (!as) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC,
+ "Failed to talloc_strndup() in RAW8 ndr_pull_string()");
+ }
+ converted_size = MIN(strlen(as)+1, conv_src_len);
+ } else if (!convert_string_talloc(ndr->current_mem_ctx, chset,
+ CH_UNIX, ndr->data + ndr->offset,
+ conv_src_len * byte_mul,
+ &as,
+ &converted_size)) {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad character conversion with flags 0x%"PRI_LIBNDR_FLAGS, flags);
+ }
+ }
+
+ /* this is a way of detecting if a string is sent with the wrong
+ termination */
+ if (ndr->flags & LIBNDR_FLAG_STR_NOTERM) {
+ if (converted_size > 0 && as[converted_size-1] == '\0') {
+ DEBUG(6,("short string '%s', sent with NULL termination despite NOTERM flag in IDL\n", as));
+ }
+ /*
+ * We check the original ndr->flags as it has already
+ * been removed from the local variable flags
+ */
+ if (ndr->flags & LIBNDR_FLAG_STR_NO_EMBEDDED_NUL) {
+ size_t strlen_of_unix_string = strlen(as);
+ if (strlen_of_unix_string != converted_size) {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Embedded NUL at position %zu in "
+ "converted string "
+ "(and therefore source string) "
+ "despite "
+ "LIBNDR_FLAG_STR_NO_EMBEDDED_NUL\n",
+ strlen_of_unix_string);
+ }
+ }
+ } else {
+ /*
+ * We check the original ndr->flags as it has already
+ * been removed from the local variable flags
+ */
+ if (ndr->flags & LIBNDR_FLAG_STR_NO_EMBEDDED_NUL) {
+ size_t strlen_of_unix_string = strlen(as);
+ if (converted_size > 0 && strlen_of_unix_string != converted_size - 1) {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Embedded NUL at position %zu in "
+ "converted string "
+ "(and therefore source string) "
+ "despite "
+ "LIBNDR_FLAG_STR_NO_EMBEDDED_NUL\n",
+ strlen_of_unix_string);
+ }
+ }
+ if (converted_size > 0 && as[converted_size-1] != '\0') {
+ DEBUG(6,("long string '%s', sent without NULL termination (which was expected)\n", as));
+ }
+ }
+
+ NDR_CHECK(ndr_pull_advance(ndr, conv_src_len * byte_mul));
+ *s = as;
+
+ return NDR_ERR_SUCCESS;
+}
+
+
+/**
+ push a general string onto the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_string(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *s)
+{
+ ssize_t s_len, c_len;
+ size_t d_len;
+ int do_convert = 1, chset = CH_UTF16;
+ libndr_flags flags = ndr->flags;
+ unsigned byte_mul = 2;
+ const uint8_t *dest = NULL;
+ uint8_t *dest_to_free = NULL;
+ static const uint8_t null_byte[] = {0};
+ enum ndr_err_code ndr_err = NDR_ERR_SUCCESS;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (NDR_BE(ndr)) {
+ chset = CH_UTF16BE;
+ }
+
+ s_len = s?strlen(s):0;
+
+ /*
+ * We will check this flag, but from the unmodified
+ * ndr->flags, so just remove it from flags
+ */
+ flags &= ~LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ switch (flags & LIBNDR_ENCODING_FLAGS) {
+ case 0:
+ break;
+
+ case LIBNDR_FLAG_STR_ASCII:
+ chset = CH_DOS;
+ byte_mul = 1;
+ break;
+
+ case LIBNDR_FLAG_STR_UTF8:
+ chset = CH_UTF8;
+ byte_mul = 1;
+ break;
+
+ case LIBNDR_FLAG_STR_RAW8:
+ do_convert = 0;
+ byte_mul = 1;
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+ flags &= ~LIBNDR_ENCODING_FLAGS;
+
+ flags &= ~LIBNDR_FLAG_STR_CONFORMANT;
+
+ if (!(flags & LIBNDR_FLAG_STR_NOTERM)) {
+ s_len++;
+ }
+
+ if (s_len == 0) {
+ d_len = 0;
+ dest = null_byte;
+ } else if (!do_convert) {
+ d_len = s_len;
+ dest = (const uint8_t *)s;
+ } else {
+ bool ok;
+
+ ok = convert_string_talloc(ndr, CH_UNIX, chset, s, s_len,
+ &dest_to_free, &d_len);
+ if (!ok) {
+ return ndr_push_error(ndr, NDR_ERR_CHARCNV,
+ "Bad character push conversion with flags 0x%"PRI_LIBNDR_FLAGS, flags);
+ }
+
+ dest = dest_to_free;
+ }
+
+ if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
+ c_len = d_len;
+ flags &= ~LIBNDR_FLAG_STR_BYTESIZE;
+ } else if (flags & LIBNDR_FLAG_STR_CHARLEN) {
+ c_len = (d_len / byte_mul)-1;
+ flags &= ~LIBNDR_FLAG_STR_CHARLEN;
+ } else {
+ c_len = d_len / byte_mul;
+ }
+
+ switch (flags & LIBNDR_STRING_FLAGS) {
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4:
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
+ ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, 0);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ ndr_err = ndr_push_bytes(ndr, dest, d_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ break;
+
+ case LIBNDR_FLAG_STR_LEN4:
+ case LIBNDR_FLAG_STR_LEN4|LIBNDR_FLAG_STR_NOTERM:
+ ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, 0);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ ndr_err = ndr_push_bytes(ndr, dest, d_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE4:
+ case LIBNDR_FLAG_STR_SIZE4|LIBNDR_FLAG_STR_NOTERM:
+ ndr_err = ndr_push_uint32(ndr, NDR_SCALARS, c_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ ndr_err = ndr_push_bytes(ndr, dest, d_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ break;
+
+ case LIBNDR_FLAG_STR_SIZE2:
+ case LIBNDR_FLAG_STR_SIZE2|LIBNDR_FLAG_STR_NOTERM:
+ ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, c_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ ndr_err = ndr_push_bytes(ndr, dest, d_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ break;
+
+ case LIBNDR_FLAG_STR_NULLTERM:
+ ndr_err = ndr_push_bytes(ndr, dest, d_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ break;
+
+ default:
+ if (ndr->flags & LIBNDR_FLAG_REMAINING) {
+ ndr_err = ndr_push_bytes(ndr, dest, d_len);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ goto out;
+ }
+ break;
+ }
+
+ ndr_err = ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ goto out;
+ }
+
+out:
+ talloc_free(dest_to_free);
+ return ndr_err;
+}
+
+/**
+ push a general string onto the wire
+*/
+_PUBLIC_ size_t ndr_string_array_size(struct ndr_push *ndr, const char *s)
+{
+ size_t c_len;
+ libndr_flags flags = ndr->flags;
+ unsigned byte_mul = 2;
+ unsigned c_len_term = 1;
+
+ if (flags & LIBNDR_FLAG_STR_RAW8) {
+ c_len = s?strlen(s):0;
+ } else {
+ c_len = s?strlen_m(s):0;
+ }
+
+ if (flags & (LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_RAW8|LIBNDR_FLAG_STR_UTF8)) {
+ byte_mul = 1;
+ }
+
+ if (flags & LIBNDR_FLAG_STR_NOTERM) {
+ c_len_term = 0;
+ }
+
+ c_len = c_len + c_len_term;
+
+ if (flags & LIBNDR_FLAG_STR_BYTESIZE) {
+ c_len = c_len * byte_mul;
+ }
+
+ return c_len;
+}
+
+_PUBLIC_ void ndr_print_string(struct ndr_print *ndr, const char *name, const char *s)
+{
+ if (NDR_HIDE_SECRET(ndr)) {
+ ndr->print(ndr, "%-25s: <REDACTED SECRET VALUE>", name);
+ return;
+ }
+ if (s) {
+ ndr->print(ndr, "%-25s: '%s'", name, s);
+ } else {
+ ndr->print(ndr, "%-25s: NULL", name);
+ }
+}
+
+_PUBLIC_ uint32_t ndr_size_string(int ret, const char * const* string, ndr_flags_type flags)
+{
+ /* FIXME: Is this correct for all strings ? */
+ if(!(*string)) return ret;
+ return ret+strlen(*string)+1;
+}
+
+/**
+ pull a UTF‐16 string from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_u16string(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ const unsigned char **s)
+{
+ unsigned char *as = NULL;
+ const char *const src_str = (char *)ndr->data + ndr->offset;
+ size_t src_len = 0;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (NDR_BE(ndr)) {
+ /*
+ * It isn’t clear how this type should be encoded in a
+ * big‐endian context.
+ */
+ return ndr_pull_error(
+ ndr,
+ NDR_ERR_STRING,
+ "u16string does not support big‐endian encoding\n");
+ }
+
+ if (ndr->flags & LIBNDR_ENCODING_FLAGS) {
+ return ndr_pull_error(
+ ndr,
+ NDR_ERR_STRING,
+ "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS
+ " passed to ndr_pull_u16string()\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ switch (ndr->flags & LIBNDR_STRING_FLAGS) {
+ case LIBNDR_FLAG_STR_NULLTERM:
+ /*
+ * We ensure that src_len cannot equal 0 by
+ * requiring that there be enough bytes for at least
+ * the NULL terminator
+ */
+ NDR_PULL_NEED_BYTES(ndr, 2);
+ src_len = utf16_null_terminated_len_n(src_str,
+ ndr->data_size -
+ ndr->offset);
+ break;
+
+ default:
+ return ndr_pull_error(
+ ndr,
+ NDR_ERR_STRING,
+ "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS
+ " passed to ndr_pull_u16string()\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ NDR_PULL_NEED_BYTES(ndr, src_len);
+ as = talloc_utf16_strlendup(ndr->current_mem_ctx,
+ src_str,
+ src_len);
+ if (as == NULL) {
+ return ndr_pull_error(ndr,
+ NDR_ERR_ALLOC,
+ "Failed to talloc_utf16_strlendup() in "
+ "ndr_pull_u16string()");
+ }
+
+ NDR_CHECK(ndr_pull_advance(ndr, src_len));
+ *s = as;
+
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a UTF‐16 string onto the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_u16string(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const unsigned char *s)
+{
+ size_t s_len;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (NDR_BE(ndr)) {
+ /*
+ * It isn’t clear how this type should be encoded in a
+ * big‐endian context.
+ */
+ return ndr_push_error(
+ ndr,
+ NDR_ERR_STRING,
+ "u16string does not support big‐endian encoding\n");
+ }
+
+ if (s == NULL) {
+ return ndr_push_error(
+ ndr,
+ NDR_ERR_INVALID_POINTER,
+ "NULL pointer passed to ndr_push_u16string()");
+ }
+
+ s_len = utf16_null_terminated_len(s);
+ if (s_len > UINT32_MAX) {
+ return ndr_push_error(
+ ndr,
+ NDR_ERR_LENGTH,
+ "length overflow in ndr_push_u16string()");
+ }
+
+ if (ndr->flags & LIBNDR_ENCODING_FLAGS) {
+ return ndr_push_error(
+ ndr,
+ NDR_ERR_STRING,
+ "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS
+ " passed to ndr_push_u16string()\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ switch (ndr->flags & LIBNDR_STRING_FLAGS) {
+ case LIBNDR_FLAG_STR_NULLTERM:
+ NDR_CHECK(ndr_push_bytes(ndr, s, s_len));
+ break;
+
+ default:
+ if (ndr->flags & LIBNDR_FLAG_REMAINING) {
+ NDR_CHECK(ndr_push_bytes(ndr, s, s_len));
+ break;
+ }
+
+ return ndr_push_error(
+ ndr,
+ NDR_ERR_STRING,
+ "Unsupported string flags 0x%" PRI_LIBNDR_FLAGS
+ " passed to ndr_push_u16string()\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_u16string(struct ndr_print *ndr,
+ const char *name,
+ const unsigned char *s)
+{
+ return ndr_print_array_uint8(ndr,
+ name,
+ s,
+ utf16_len(s));
+}
+
+static uint32_t guess_string_array_size(struct ndr_pull *ndr, ndr_flags_type ndr_flags)
+{
+ /*
+ * Here we could do something clever like count the number of zeros in
+ * the ndr data, but it is probably sufficient to pick a lowish number
+ * (compared to the overhead of the talloc header) and let the
+ * exponential resizing deal with longer arrays.
+ */
+ return 5;
+}
+
+static enum ndr_err_code extend_string_array(struct ndr_pull *ndr,
+ const char ***_a,
+ uint32_t *count)
+{
+ const char **a = *_a;
+ uint32_t inc = *count / 4 + 3;
+ uint32_t alloc_size = *count + inc;
+
+ if (alloc_size < *count) {
+ /* overflow ! */
+ return NDR_ERR_ALLOC;
+ }
+ /*
+ * We allocate and zero two more bytes than we report back, so that
+ * the string array will always be NULL terminated.
+ */
+ a = talloc_realloc(ndr->current_mem_ctx, a,
+ const char *,
+ alloc_size);
+ NDR_ERR_HAVE_NO_MEMORY(a);
+
+ memset(a + *count, 0, inc * sizeof(a[0]));
+ *_a = a;
+ *count = alloc_size - 2;
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ pull a general string array from the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_string_array(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char ***_a)
+{
+ const char **a = NULL;
+ uint32_t count;
+ libndr_flags flags = ndr->flags;
+ libndr_flags saved_flags = ndr->flags;
+ uint32_t alloc_size;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ alloc_size = guess_string_array_size(ndr, ndr_flags);
+ a = talloc_zero_array(ndr->current_mem_ctx, const char *, alloc_size + 2);
+ NDR_ERR_HAVE_NO_MEMORY(a);
+
+ switch (flags & (LIBNDR_FLAG_STR_NULLTERM|LIBNDR_FLAG_STR_NOTERM)) {
+ case LIBNDR_FLAG_STR_NULLTERM:
+ /*
+ * here the strings are null terminated
+ * but also the array is null terminated if LIBNDR_FLAG_REMAINING
+ * is specified
+ */
+ for (count = 0;; count++) {
+ TALLOC_CTX *tmp_ctx;
+ const char *s = NULL;
+ if (count == alloc_size) {
+ NDR_CHECK(extend_string_array(ndr,
+ &a,
+ &alloc_size));
+ }
+
+ tmp_ctx = ndr->current_mem_ctx;
+ ndr->current_mem_ctx = a;
+ NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
+ ndr->current_mem_ctx = tmp_ctx;
+ if ((ndr->data_size - ndr->offset) == 0 && ndr->flags & LIBNDR_FLAG_REMAINING)
+ {
+ a[count] = s;
+ break;
+ }
+ if (strcmp("", s)==0) {
+ a[count] = NULL;
+ break;
+ } else {
+ a[count] = s;
+ }
+ }
+
+ *_a =a;
+ break;
+
+ case LIBNDR_FLAG_STR_NOTERM:
+ if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS" (missing NDR_REMAINING)\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+ /*
+ * here the strings are not null terminated
+ * but separated by a null terminator
+ *
+ * which means the same as:
+ * Every string is null terminated except the last
+ * string is terminated by the end of the buffer
+ *
+ * as LIBNDR_FLAG_STR_NULLTERM also end at the end
+ * of the buffer, we can pull each string with this flag
+ *
+ * The big difference with the case LIBNDR_FLAG_STR_NOTERM +
+ * LIBNDR_FLAG_REMAINING is that the last string will not be null terminated
+ */
+ ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
+
+ for (count = 0; ((ndr->data_size - ndr->offset) > 0); count++) {
+ TALLOC_CTX *tmp_ctx;
+ const char *s = NULL;
+ if (count == alloc_size) {
+ NDR_CHECK(extend_string_array(ndr,
+ &a,
+ &alloc_size));
+ }
+
+ tmp_ctx = ndr->current_mem_ctx;
+ ndr->current_mem_ctx = a;
+ NDR_CHECK(ndr_pull_string(ndr, ndr_flags, &s));
+ ndr->current_mem_ctx = tmp_ctx;
+ a[count] = s;
+ }
+
+ a = talloc_realloc(ndr->current_mem_ctx, a, const char *, count + 1);
+ NDR_ERR_HAVE_NO_MEMORY(a);
+ *_a = a;
+ break;
+
+ default:
+ return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ ndr->flags = saved_flags;
+ return NDR_ERR_SUCCESS;
+}
+
+/**
+ push a general string array onto the wire
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_string_array(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char **a)
+{
+ uint32_t count;
+ libndr_flags flags = ndr->flags;
+ libndr_flags saved_flags = ndr->flags;
+
+ if (!(ndr_flags & NDR_SCALARS)) {
+ return NDR_ERR_SUCCESS;
+ }
+
+ switch (flags & LIBNDR_STRING_FLAGS) {
+ case LIBNDR_FLAG_STR_NULLTERM:
+ for (count = 0; a && a[count]; count++) {
+ NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
+ }
+ /* If LIBNDR_FLAG_REMAINING then we do not add a null terminator to the array */
+ if (!(flags & LIBNDR_FLAG_REMAINING))
+ {
+ NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
+ }
+ break;
+
+ case LIBNDR_FLAG_STR_NOTERM:
+ if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) {
+ return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS" (missing NDR_REMAINING)\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ for (count = 0; a && a[count]; count++) {
+ if (count > 0) {
+ ndr->flags &= ~(LIBNDR_FLAG_STR_NOTERM|LIBNDR_FLAG_REMAINING);
+ ndr->flags |= LIBNDR_FLAG_STR_NULLTERM;
+ NDR_CHECK(ndr_push_string(ndr, ndr_flags, ""));
+ ndr->flags = saved_flags;
+ }
+ NDR_CHECK(ndr_push_string(ndr, ndr_flags, a[count]));
+ }
+
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%"PRI_LIBNDR_FLAGS"\n",
+ ndr->flags & LIBNDR_STRING_FLAGS);
+ }
+
+ ndr->flags = saved_flags;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_string_array(struct ndr_print *ndr, const char *name, const char **a)
+{
+ uint32_t count;
+ uint32_t i;
+
+ for (count = 0; a && a[count]; count++) {}
+
+ ndr->print(ndr, "%s: ARRAY(%"PRIu32")", name, count);
+ ndr->depth++;
+ for (i=0;i<count;i++) {
+ char *idx=NULL;
+ if (asprintf(&idx, "[%"PRIu32"]", i) != -1) {
+ ndr_print_string(ndr, idx, a[i]);
+ free(idx);
+ }
+ }
+ ndr->depth--;
+}
+
+_PUBLIC_ size_t ndr_size_string_array(const char **a, uint32_t count, libndr_flags flags)
+{
+ uint32_t i;
+ size_t size = 0;
+ int rawbytes = 0;
+
+ if (flags & LIBNDR_FLAG_STR_RAW8) {
+ rawbytes = 1;
+ flags &= ~LIBNDR_FLAG_STR_RAW8;
+ }
+
+ switch (flags & LIBNDR_STRING_FLAGS) {
+ case LIBNDR_FLAG_STR_NULLTERM:
+ for (i = 0; i < count; i++) {
+ size += rawbytes?strlen(a[i]) + 1:strlen_m_term(a[i]);
+ }
+ break;
+ case LIBNDR_FLAG_STR_NOTERM:
+ for (i = 0; i < count; i++) {
+ size += rawbytes?strlen(a[i]):strlen_m(a[i]);
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ return size;
+}
+
+/**
+ * Return number of elements in a string including the last (zeroed) element
+ */
+_PUBLIC_ uint32_t ndr_string_length(const void *_var, uint32_t element_size)
+{
+ uint32_t i;
+ uint8_t zero[4] = {0,0,0,0};
+ const char *var = (const char *)_var;
+
+ for (i = 0; memcmp(var+i*element_size,zero,element_size) != 0; i++);
+
+ return i+1;
+}
+
+/**
+ * @brief Get the string length including the null terminator if available.
+ *
+ * This checks the string length based on the elements. The returned number
+ * includes the terminating null byte(s) if found.
+ *
+ * @param[in] _var The string to calculate the length for.
+ *
+ * @param[in] length The length of the buffer passed by _var.
+ *
+ * @param[in] element_size The element_size of a string char in bytes.
+ *
+ * @return The length of the strings or 0.
+ */
+static uint32_t ndr_string_n_length(const void *_var,
+ size_t length,
+ uint32_t element_size)
+{
+ size_t i = 0;
+ uint8_t zero[4] = {0,0,0,0};
+ const char *var = (const char *)_var;
+ int cmp;
+
+ if (element_size > 4) {
+ return 0;
+ }
+
+ for (i = 0; i < length; i++, var += element_size) {
+ cmp = memcmp(var, zero, element_size);
+ if (cmp == 0) {
+ break;
+ }
+ }
+
+ if (i == length) {
+ return length;
+ }
+
+ return i + 1;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_check_string_terminator(struct ndr_pull *ndr, uint32_t count, uint32_t element_size)
+{
+ uint32_t i;
+ uint32_t save_offset;
+
+ if (count == 0) {
+ return NDR_ERR_RANGE;
+ }
+
+ if (element_size && count - 1 > UINT32_MAX / element_size) {
+ return NDR_ERR_RANGE;
+ }
+
+ save_offset = ndr->offset;
+ NDR_CHECK(ndr_pull_advance(ndr, (count - 1) * element_size));
+ NDR_PULL_NEED_BYTES(ndr, element_size);
+
+ for (i = 0; i < element_size; i++) {
+ if (ndr->data[ndr->offset+i] != 0) {
+ ndr->offset = save_offset;
+
+ return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, "String terminator not present or outside string boundaries");
+ }
+ }
+
+ ndr->offset = save_offset;
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_charset(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset)
+{
+ size_t converted_size;
+
+ if (length == 0) {
+ *var = talloc_strdup(ndr->current_mem_ctx, "");
+ if (*var == NULL) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC,
+ "Failed to talloc_strdup() in ndr_pull_charset()");
+ }
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (NDR_BE(ndr) && chset == CH_UTF16) {
+ chset = CH_UTF16BE;
+ }
+
+ if ((byte_mul != 0) && (length > UINT32_MAX/byte_mul)) {
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "length overflow");
+ }
+ NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
+
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
+ ndr->data+ndr->offset, length*byte_mul,
+ var,
+ &converted_size))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad character conversion");
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_charset_to_null(struct ndr_pull *ndr, ndr_flags_type ndr_flags, const char **var, uint32_t length, uint8_t byte_mul, charset_t chset)
+{
+ size_t converted_size;
+ uint32_t str_len;
+
+ if (length == 0) {
+ *var = talloc_strdup(ndr->current_mem_ctx, "");
+ if (*var == NULL) {
+ return ndr_pull_error(ndr, NDR_ERR_ALLOC,
+ "Failed to talloc_strdup() in ndr_pull_charset_to_null()");
+ }
+ return NDR_ERR_SUCCESS;
+ }
+
+ if (NDR_BE(ndr) && chset == CH_UTF16) {
+ chset = CH_UTF16BE;
+ }
+
+ if ((byte_mul != 0) && (length > UINT32_MAX/byte_mul)) {
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "length overflow");
+ }
+ NDR_PULL_NEED_BYTES(ndr, length*byte_mul);
+
+ str_len = ndr_string_n_length(ndr->data+ndr->offset, length, byte_mul);
+ if (str_len == 0) {
+ return ndr_pull_error(ndr, NDR_ERR_LENGTH,
+ "Invalid length");
+ }
+
+ if (!convert_string_talloc(ndr->current_mem_ctx, chset, CH_UNIX,
+ ndr->data+ndr->offset, str_len*byte_mul,
+ var,
+ &converted_size))
+ {
+ return ndr_pull_error(ndr, NDR_ERR_CHARCNV,
+ "Bad character conversion");
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, length*byte_mul));
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_charset(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset)
+{
+ size_t required;
+
+ if (NDR_BE(ndr) && chset == CH_UTF16) {
+ chset = CH_UTF16BE;
+ }
+
+ if ((byte_mul != 0) && (length > SIZE_MAX/byte_mul)) {
+ return ndr_push_error(ndr, NDR_ERR_LENGTH, "length overflow");
+ }
+ required = byte_mul * length;
+
+ NDR_PUSH_NEED_BYTES(ndr, required);
+
+ if (required) {
+ size_t size = 0;
+
+ if (var == NULL) {
+ return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, "NULL [ref] pointer");
+ }
+
+ if (!convert_string(CH_UNIX, chset,
+ var, strlen(var),
+ ndr->data+ndr->offset, required, &size)) {
+ return ndr_push_error(ndr, NDR_ERR_CHARCNV,
+ "Bad character conversion");
+ }
+
+ /* Make sure the remaining part of the string is filled with zeroes */
+ if (size < required) {
+ memset(ndr->data+ndr->offset+size, 0, required-size);
+ }
+ }
+
+ ndr->offset += required;
+
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_charset_to_null(struct ndr_push *ndr, ndr_flags_type ndr_flags, const char *var, uint32_t length, uint8_t byte_mul, charset_t chset)
+{
+ const char *str = var;
+
+ if (str == NULL) {
+ str = "\0"; /* i.e. two zero bytes, for UTF16 null word. */
+ length = 1;
+ }
+
+ return ndr_push_charset(ndr, ndr_flags, str, length, byte_mul, chset);
+}
+
+/* Return number of elements in a string in the specified charset */
+_PUBLIC_ uint32_t ndr_charset_length(const void *var, charset_t chset)
+{
+ switch (chset) {
+ /* case CH_UTF16: this has the same value as CH_UTF16LE */
+ case CH_UTF16LE:
+ case CH_UTF16BE:
+ case CH_UTF16MUNGED:
+ case CH_UTF8:
+ return strlen_m_ext_term((const char *)var, CH_UNIX, chset);
+ case CH_DOS:
+ case CH_UNIX:
+ return strlen((const char *)var)+1;
+ default:
+ /* Fallback, this should never happen */
+ return strlen((const char *)var)+1;
+ }
+}
diff --git a/librpc/ndr/ndr_svcctl.c b/librpc/ndr/ndr_svcctl.c
new file mode 100644
index 0000000..83e581b
--- /dev/null
+++ b/librpc/ndr/ndr_svcctl.c
@@ -0,0 +1,52 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special svcctl types
+
+ 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 "includes.h"
+#include "librpc/gen_ndr/ndr_svcctl.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_ENUM_SERVICE_STATUSW_array(struct ndr_push *ndr, uint32_t count, struct ENUM_SERVICE_STATUSW *r)
+{
+ uint32_t cntr_array_1;
+
+ for (cntr_array_1 = 0; cntr_array_1 < count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_ENUM_SERVICE_STATUSW(ndr, NDR_SCALARS, &r[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < count; cntr_array_1++) {
+ NDR_CHECK(ndr_push_ENUM_SERVICE_STATUSW(ndr, NDR_BUFFERS, &r[cntr_array_1]));
+ }
+
+ return NDR_ERR_SUCCESS;
+
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_ENUM_SERVICE_STATUSW_array(struct ndr_pull *ndr, uint32_t count, struct ENUM_SERVICE_STATUSW *r)
+{
+ uint32_t cntr_array_1;
+
+ for (cntr_array_1 = 0; cntr_array_1 < count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_ENUM_SERVICE_STATUSW(ndr, NDR_SCALARS, &r[cntr_array_1]));
+ }
+ for (cntr_array_1 = 0; cntr_array_1 < count; cntr_array_1++) {
+ NDR_CHECK(ndr_pull_ENUM_SERVICE_STATUSW(ndr, NDR_BUFFERS, &r[cntr_array_1]));
+ }
+
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_svcctl.h b/librpc/ndr/ndr_svcctl.h
new file mode 100644
index 0000000..e11ff69
--- /dev/null
+++ b/librpc/ndr/ndr_svcctl.h
@@ -0,0 +1,24 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling special svcctl types
+
+ 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/>.
+*/
+
+_PUBLIC_ enum ndr_err_code ndr_push_ENUM_SERVICE_STATUSW_array(struct ndr_push *ndr, uint32_t count, struct ENUM_SERVICE_STATUSW *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_ENUM_SERVICE_STATUSW_array(struct ndr_pull *ndr, uint32_t count, struct ENUM_SERVICE_STATUSW *r);
+
diff --git a/librpc/ndr/ndr_table.c b/librpc/ndr/ndr_table.c
new file mode 100644
index 0000000..69a3eda
--- /dev/null
+++ b/librpc/ndr/ndr_table.c
@@ -0,0 +1,182 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc utility functions
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 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/util/dlinklist.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/ndr/ndr_table.h"
+#undef strcasecmp
+
+static struct ndr_interface_list *ndr_interfaces;
+
+/*
+ register a ndr interface table
+*/
+NTSTATUS ndr_table_register(const struct ndr_interface_table *table)
+{
+ struct ndr_interface_list *l;
+
+ for (l = ndr_interfaces; l; l = l->next) {
+ /*
+ * If no GUID is supplied, use the name to determine
+ * uniqueness.
+ */
+ if (GUID_all_zero(&table->syntax_id.uuid)) {
+ if (strcmp(table->name,
+ l->table->name) != 0) {
+ continue;
+ }
+ DBG_ERR("Attempt to register interface %s which has the "
+ "same name as already registered interface\n",
+ table->name);
+ } else {
+ if (!GUID_equal(&table->syntax_id.uuid,
+ &l->table->syntax_id.uuid)) {
+ continue;
+ }
+ DBG_ERR("Attempt to register interface %s which has the "
+ "same UUID as already registered interface %s\n",
+ table->name, l->table->name);
+ }
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ /*
+ * This is a singleton instance guaranteed
+ * by the above check to be only added once
+ * into the list so we can allocate off the NULL
+ * context. We never want this to be freed
+ * until process shutdown. If needed we could
+ * add a deregister function that walks and
+ * frees the list.
+ */
+
+ l = talloc(NULL, struct ndr_interface_list);
+ l->table = table;
+
+ DLIST_ADD(ndr_interfaces, l);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ find the pipe name for a local IDL interface
+*/
+const char *ndr_interface_name(const struct GUID *uuid, uint32_t if_version)
+{
+ const struct ndr_interface_list *l;
+ for (l=ndr_table_list();l;l=l->next) {
+ if (GUID_equal(&l->table->syntax_id.uuid, uuid) &&
+ l->table->syntax_id.if_version == if_version) {
+ return l->table->name;
+ }
+ }
+ return "UNKNOWN";
+}
+
+/*
+ find the number of calls defined by local IDL
+*/
+int ndr_interface_num_calls(const struct GUID *uuid, uint32_t if_version)
+{
+ const struct ndr_interface_list *l;
+ for (l=ndr_table_list();l;l=l->next){
+ if (GUID_equal(&l->table->syntax_id.uuid, uuid) &&
+ l->table->syntax_id.if_version == if_version) {
+ return l->table->num_calls;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ find a dcerpc interface by name
+*/
+const struct ndr_interface_table *ndr_table_by_name(const char *name)
+{
+ const struct ndr_interface_list *l;
+ for (l=ndr_table_list();l;l=l->next) {
+ if (strcasecmp(l->table->name, name) == 0) {
+ return l->table;
+ }
+ }
+ return NULL;
+}
+
+/*
+ find a dcerpc interface by syntax
+*/
+const struct ndr_interface_table *ndr_table_by_syntax(const struct ndr_syntax_id *syntax)
+{
+ const struct ndr_interface_list *l;
+ if (GUID_all_zero(&syntax->uuid)) {
+ /* These are not unique */
+ return NULL;
+ }
+ for (l=ndr_table_list();l;l=l->next) {
+ if (ndr_syntax_id_equal(&l->table->syntax_id, syntax)) {
+ return l->table;
+ }
+ }
+ return NULL;
+}
+
+/*
+ find a dcerpc interface by uuid
+*/
+const struct ndr_interface_table *ndr_table_by_uuid(const struct GUID *uuid)
+{
+ const struct ndr_interface_list *l;
+ if (GUID_all_zero(uuid)) {
+ /* These are not unique */
+ return NULL;
+ }
+ for (l=ndr_table_list();l;l=l->next) {
+ if (GUID_equal(&l->table->syntax_id.uuid, uuid)) {
+ return l->table;
+ }
+ }
+ return NULL;
+}
+
+/*
+ return the list of registered dcerpc_pipes
+*/
+const struct ndr_interface_list *ndr_table_list(void)
+{
+ ndr_table_init();
+ return ndr_interfaces;
+}
+
+
+NTSTATUS ndr_table_init(void)
+{
+ static bool initialized = false;
+
+ if (initialized) return NT_STATUS_OK;
+ initialized = true;
+
+ ndr_table_register_builtin_tables();
+
+ return NT_STATUS_OK;
+}
diff --git a/librpc/ndr/ndr_table.h b/librpc/ndr/ndr_table.h
new file mode 100644
index 0000000..1f6858a
--- /dev/null
+++ b/librpc/ndr/ndr_table.h
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc utility functions
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 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 _NDR_TABLE_PROTO_H_
+#define _NDR_TABLE_PROTO_H_
+
+NTSTATUS ndr_table_register(const struct ndr_interface_table *table);
+const char *ndr_interface_name(const struct GUID *uuid, uint32_t if_version);
+int ndr_interface_num_calls(const struct GUID *uuid, uint32_t if_version);
+const struct ndr_interface_table *ndr_table_by_name(const char *name);
+const struct ndr_interface_table *ndr_table_by_syntax(const struct ndr_syntax_id *syntax);
+const struct ndr_interface_table *ndr_table_by_uuid(const struct GUID *uuid);
+const struct ndr_interface_list *ndr_table_list(void);
+NTSTATUS ndr_table_init(void);
+NTSTATUS ndr_table_register_builtin_tables(void);
+
+#endif /* _NDR_TABLE_PROTO_H_ */
+
diff --git a/librpc/ndr/ndr_witness.c b/librpc/ndr/ndr_witness.c
new file mode 100644
index 0000000..85ba62e
--- /dev/null
+++ b/librpc/ndr/ndr_witness.c
@@ -0,0 +1,110 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling witness structures
+
+ Copyright (C) Guenther Deschner 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 "includes.h"
+#include "librpc/gen_ndr/ndr_witness.h"
+
+_PUBLIC_ enum ndr_err_code ndr_push_witness_notifyResponse(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct witness_notifyResponse *r)
+{
+ uint32_t cntr_messages_0;
+ {
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_PUSH_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_push_witness_notifyResponse_type(ndr, NDR_SCALARS, r->type));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr_size_witness_notifyResponse(r, ndr->flags) - 20));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num));
+ NDR_CHECK(ndr_push_unique_ptr(ndr, r->messages));
+ if (r->messages) {
+ libndr_flags _flags_save_witness_notifyResponse_message = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ {
+ struct ndr_push *_ndr_messages;
+ NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_messages, 4, ndr_size_witness_notifyResponse(r, ndr->flags) - 20));
+ for (cntr_messages_0 = 0; cntr_messages_0 < (r->num); cntr_messages_0++) {
+ NDR_CHECK(ndr_push_set_switch_value(_ndr_messages, &r->messages[cntr_messages_0], r->type));
+ NDR_CHECK(ndr_push_witness_notifyResponse_message(_ndr_messages, NDR_SCALARS, &r->messages[cntr_messages_0]));
+ }
+ NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_messages, 4, ndr_size_witness_notifyResponse(r, ndr->flags) - 20));
+ }
+ ndr->flags = _flags_save_witness_notifyResponse_message;
+ }
+ NDR_CHECK(ndr_push_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_witness_notifyResponse(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct witness_notifyResponse *r)
+{
+ libndr_flags _flags_save_STRUCT = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX);
+ NDR_PULL_CHECK_FLAGS(ndr, ndr_flags);
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ NDR_CHECK(ndr_pull_witness_notifyResponse_type(ndr, NDR_SCALARS, &r->type));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->length));
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num));
+ {
+ libndr_flags _flags_save_witness_notifyResponse_message = ndr->flags;
+ uint32_t _ptr_messages;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_REMAINING);
+ NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_messages));
+ if (_ptr_messages) {
+ NDR_PULL_ALLOC(ndr, r->messages);
+ } else {
+ r->messages = NULL;
+ }
+ if (r->messages) {
+ uint32_t size_messages_0 = 0;
+ uint32_t cntr_messages_0;
+ TALLOC_CTX *_mem_save_messages_0;
+
+ size_messages_0 = r->num;
+ NDR_PULL_ALLOC_N(ndr, r->messages, size_messages_0);
+ _mem_save_messages_0 = NDR_PULL_GET_MEM_CTX(ndr);
+ NDR_PULL_SET_MEM_CTX(ndr, r->messages, 0);
+ {
+ struct ndr_pull *_ndr_messages;
+ NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_messages, 4, r->length));
+ for (cntr_messages_0 = 0; cntr_messages_0 < (size_messages_0); cntr_messages_0++) {
+ NDR_CHECK(ndr_pull_set_switch_value(_ndr_messages, &r->messages[cntr_messages_0], r->type));
+ NDR_CHECK(ndr_pull_witness_notifyResponse_message(_ndr_messages, NDR_SCALARS, &r->messages[cntr_messages_0]));
+ }
+ NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_messages, 4, r->length));
+ }
+ NDR_PULL_SET_MEM_CTX(ndr, _mem_save_messages_0, 0);
+ }
+ ndr->flags = _flags_save_witness_notifyResponse_message;
+ }
+ NDR_CHECK(ndr_pull_trailer_align(ndr, 4));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ ndr->flags = _flags_save_STRUCT;
+
+ return NDR_ERR_SUCCESS;
+}
diff --git a/librpc/ndr/ndr_witness.h b/librpc/ndr/ndr_witness.h
new file mode 100644
index 0000000..1a129e6
--- /dev/null
+++ b/librpc/ndr/ndr_witness.h
@@ -0,0 +1,23 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling witness structures
+
+ Copyright (C) Guenther Deschner 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/>.
+*/
+
+_PUBLIC_ enum ndr_err_code ndr_push_witness_notifyResponse(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct witness_notifyResponse *r);
+_PUBLIC_ enum ndr_err_code ndr_pull_witness_notifyResponse(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct witness_notifyResponse *r);
diff --git a/librpc/ndr/ndr_wmi.h b/librpc/ndr/ndr_wmi.h
new file mode 100644
index 0000000..7787bb1
--- /dev/null
+++ b/librpc/ndr/ndr_wmi.h
@@ -0,0 +1,24 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling DCOM string arrays
+
+ Copyright (C) Jelmer Vernooij 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 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.
+*/
+
+enum ndr_err_code ndr_push_BSTR(struct ndr_push *ndr, ndr_flags_type ndr_flags, const struct BSTR *r);
+enum ndr_err_code ndr_pull_BSTR(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct BSTR *r);
diff --git a/librpc/ndr/ndr_xattr.c b/librpc/ndr/ndr_xattr.c
new file mode 100644
index 0000000..0ffdce9
--- /dev/null
+++ b/librpc/ndr/ndr_xattr.c
@@ -0,0 +1,148 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ helper routines for XATTR marshalling
+
+ Copyright (C) Stefan (metze) Metzmacher 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 "librpc/gen_ndr/ndr_xattr.h"
+
+static char *ndr_compat_xattr_attrib_hex(TALLOC_CTX *mem_ctx,
+ const struct xattr_DOSATTRIB *r)
+{
+ char *attrib_hex = NULL;
+
+ switch (r->version) {
+ case 0xFFFF:
+ attrib_hex = talloc_asprintf(mem_ctx, "0x%"PRIx32,
+ r->info.compatinfoFFFF.attrib);
+ break;
+ case 1:
+ attrib_hex = talloc_asprintf(mem_ctx, "0x%"PRIx32,
+ r->info.info1.attrib);
+ break;
+ case 2:
+ attrib_hex = talloc_asprintf(mem_ctx, "0x%"PRIx32,
+ r->info.oldinfo2.attrib);
+ break;
+ case 3:
+ if (!(r->info.info3.valid_flags & XATTR_DOSINFO_ATTRIB)) {
+ attrib_hex = talloc_strdup(mem_ctx, "");
+ break;
+ }
+ attrib_hex = talloc_asprintf(mem_ctx, "0x%"PRIx32,
+ r->info.info3.attrib);
+ break;
+ default:
+ attrib_hex = talloc_strdup(mem_ctx, "");
+ break;
+ }
+
+ return attrib_hex;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_xattr_DOSATTRIB(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct xattr_DOSATTRIB *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ char *attrib_hex = NULL;
+
+ attrib_hex = ndr_compat_xattr_attrib_hex(ndr, r);
+ NDR_ERR_HAVE_NO_MEMORY(attrib_hex);
+
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, attrib_hex));
+ ndr->flags = _flags_save_string;
+ }
+ if (r->version == 0xFFFF) {
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r->version));
+ NDR_CHECK(ndr_push_set_switch_value(ndr, &r->info, r->version));
+ NDR_CHECK(ndr_push_xattr_DosInfo(ndr, NDR_SCALARS, &r->info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_xattr_DOSATTRIB(struct ndr_pull *ndr, ndr_flags_type ndr_flags, struct xattr_DOSATTRIB *r)
+{
+ if (ndr_flags & NDR_SCALARS) {
+ NDR_CHECK(ndr_pull_align(ndr, 4));
+ {
+ libndr_flags _flags_save_string = ndr->flags;
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
+ NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->attrib_hex));
+ ndr->flags = _flags_save_string;
+ }
+ if (ndr->offset >= ndr->data_size) {
+ unsigned int dosattr;
+ int ret;
+
+ if (r->attrib_hex[0] != '0') {
+
+ }
+ if (r->attrib_hex[1] != 'x') {
+
+ }
+ ret = sscanf(r->attrib_hex, "%x", &dosattr);
+ if (ret != 1) {
+ }
+ r->version = 0xFFFF;
+ r->info.compatinfoFFFF.attrib = dosattr;
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->version));
+ if (r->version == 0xFFFF) {
+ return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH,
+ "ndr_pull_xattr_DOSATTRIB: "
+ "invalid level 0x%02"PRIX16,
+ r->version);
+ }
+ NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->info, r->version));
+ NDR_CHECK(ndr_pull_xattr_DosInfo(ndr, NDR_SCALARS, &r->info));
+ }
+ if (ndr_flags & NDR_BUFFERS) {
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_xattr_DOSATTRIB(struct ndr_print *ndr, const char *name, const struct xattr_DOSATTRIB *r)
+{
+ char *attrib_hex;
+
+ ndr_print_struct(ndr, name, "xattr_DOSATTRIB");
+ ndr->depth++;
+
+ if (ndr->flags & LIBNDR_PRINT_SET_VALUES) {
+ attrib_hex = ndr_compat_xattr_attrib_hex(ndr, r);
+ } else {
+ attrib_hex = talloc_strdup(ndr, r->attrib_hex);
+ }
+ ndr_print_string(ndr, "attrib_hex", attrib_hex);
+
+ ndr_print_uint16(ndr, "version", r->version);
+ ndr_print_set_switch_value(ndr, &r->info, r->version);
+ ndr_print_xattr_DosInfo(ndr, "info", &r->info);
+ ndr->depth--;
+}
diff --git a/librpc/ndr/ndr_xattr.h b/librpc/ndr/ndr_xattr.h
new file mode 100644
index 0000000..893ac88
--- /dev/null
+++ b/librpc/ndr/ndr_xattr.h
@@ -0,0 +1,37 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ helper routines for XATTR marshalling
+
+ Copyright (C) Stefan (metze) Metzmacher 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 _LIBRPC_NDR_NDR_XATTR_H
+#define _LIBRPC_NDR_NDR_XATTR_H
+
+_PUBLIC_ enum ndr_err_code ndr_push_xattr_DOSATTRIB(struct ndr_push *ndr,
+ ndr_flags_type ndr_flags,
+ const struct xattr_DOSATTRIB *r);
+
+_PUBLIC_ enum ndr_err_code ndr_pull_xattr_DOSATTRIB(struct ndr_pull *ndr,
+ ndr_flags_type ndr_flags,
+ struct xattr_DOSATTRIB *r);
+
+_PUBLIC_ void ndr_print_xattr_DOSATTRIB(struct ndr_print *ndr,
+ const char *name,
+ const struct xattr_DOSATTRIB *r);
+
+#endif /* _LIBRPC_NDR_NDR_XATTR_H */
diff --git a/librpc/ndr/util.c b/librpc/ndr/util.c
new file mode 100644
index 0000000..0eb7eba
--- /dev/null
+++ b/librpc/ndr/util.c
@@ -0,0 +1,36 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libndr interface
+
+ 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 "../librpc/ndr/libndr.h"
+#include "system/network.h"
+#include "lib/util/util_net.h"
+
+_PUBLIC_ void ndr_print_sockaddr_storage(struct ndr_print *ndr, const char *name, const struct sockaddr_storage *ss)
+{
+ char addr[INET6_ADDRSTRLEN];
+ ndr->print(ndr, "%-25s: %s", name, print_sockaddr(addr, sizeof(addr), ss));
+}
+
+_PUBLIC_ void ndr_zero_memory(void *ptr, size_t len)
+{
+ memset_s(ptr, len, 0, len);
+}
diff --git a/librpc/ndr/uuid.c b/librpc/ndr/uuid.c
new file mode 100644
index 0000000..a759900
--- /dev/null
+++ b/librpc/ndr/uuid.c
@@ -0,0 +1,258 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ UUID/GUID functions
+
+ Copyright (C) Theodore Ts'o 1996, 1997,
+ Copyright (C) Jim McDonough 2002.
+ 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 "replace.h"
+#include "lib/util/samba_util.h"
+#include "lib/util/genrand.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "lib/util/util_str_hex.h"
+
+_PUBLIC_ NTSTATUS GUID_to_ndr_buf(
+ const struct GUID *guid, struct GUID_ndr_buf *buf)
+{
+ DATA_BLOB b = { .data = buf->buf, .length = sizeof(buf->buf), };
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_into_fixed_blob(
+ &b, guid, (ndr_push_flags_fn_t)ndr_push_GUID);
+ return ndr_map_error2ntstatus(ndr_err);
+}
+
+/**
+ build a NDR blob from a GUID
+*/
+_PUBLIC_ NTSTATUS GUID_to_ndr_blob(const struct GUID *guid, TALLOC_CTX *mem_ctx, DATA_BLOB *b)
+{
+ struct GUID_ndr_buf buf = { .buf = {0}, };
+ NTSTATUS status;
+
+ status = GUID_to_ndr_buf(guid, &buf);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *b = data_blob_talloc(mem_ctx, buf.buf, sizeof(buf.buf));
+ if (b->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+
+/**
+ build a GUID from a NDR data blob
+*/
+_PUBLIC_ NTSTATUS GUID_from_ndr_blob(const DATA_BLOB *b, struct GUID *guid)
+{
+ enum ndr_err_code ndr_err =
+ ndr_pull_struct_blob_all_noalloc(b, guid,
+ (ndr_pull_flags_fn_t)ndr_pull_GUID);
+ return ndr_map_error2ntstatus(ndr_err);
+}
+
+
+/**
+ build a GUID from a string
+*/
+_PUBLIC_ NTSTATUS GUID_from_data_blob(const DATA_BLOB *s, struct GUID *guid)
+{
+ bool ok;
+
+ if (s->data == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (s->length == 36) {
+ ok = parse_guid_string((char *)s->data, guid);
+ return ok ? NT_STATUS_OK : NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (s->length == 38) {
+ if (s->data[0] != '{' || s->data[37] != '}') {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ok = parse_guid_string((char *)s->data + 1, guid);
+ return ok ? NT_STATUS_OK : NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (s->length == 32) {
+ uint8_t buf16[16] = {0};
+ DATA_BLOB blob16 = { .data = buf16, .length = sizeof(buf16) };
+ size_t rlen = strhex_to_str((char *)blob16.data, blob16.length,
+ (const char *)s->data, s->length);
+ if (rlen != blob16.length) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return GUID_from_ndr_blob(&blob16, guid);
+ }
+
+ if (s->length == 16) {
+ return GUID_from_ndr_blob(s, guid);
+ }
+
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+/**
+ build a GUID from a string
+*/
+_PUBLIC_ NTSTATUS GUID_from_string(const char *s, struct GUID *guid)
+{
+ DATA_BLOB blob = data_blob_string_const(s);
+ return GUID_from_data_blob(&blob, guid);
+}
+
+/**
+ * generate a random GUID
+ */
+_PUBLIC_ struct GUID GUID_random(void)
+{
+ struct GUID guid;
+
+ generate_random_buffer((uint8_t *)&guid, sizeof(guid));
+ guid.clock_seq[0] = (guid.clock_seq[0] & 0x3F) | 0x80;
+ guid.time_hi_and_version = (guid.time_hi_and_version & 0x0FFF) | 0x4000;
+
+ return guid;
+}
+
+/**
+ * generate an empty GUID
+ */
+_PUBLIC_ struct GUID GUID_zero(void)
+{
+ return (struct GUID) { .time_low = 0 };
+}
+
+_PUBLIC_ bool GUID_all_zero(const struct GUID *u)
+{
+ if (u->time_low != 0 ||
+ u->time_mid != 0 ||
+ u->time_hi_and_version != 0 ||
+ u->clock_seq[0] != 0 ||
+ u->clock_seq[1] != 0 ||
+ !all_zero(u->node, 6)) {
+ return false;
+ }
+ return true;
+}
+
+_PUBLIC_ bool GUID_equal(const struct GUID *u1, const struct GUID *u2)
+{
+ return (GUID_compare(u1, u2) == 0);
+}
+
+_PUBLIC_ int GUID_compare(const struct GUID *u1, const struct GUID *u2)
+{
+ if (u1->time_low != u2->time_low) {
+ return u1->time_low > u2->time_low ? 1 : -1;
+ }
+
+ if (u1->time_mid != u2->time_mid) {
+ return u1->time_mid > u2->time_mid ? 1 : -1;
+ }
+
+ if (u1->time_hi_and_version != u2->time_hi_and_version) {
+ return u1->time_hi_and_version > u2->time_hi_and_version ? 1 : -1;
+ }
+
+ if (u1->clock_seq[0] != u2->clock_seq[0]) {
+ return u1->clock_seq[0] > u2->clock_seq[0] ? 1 : -1;
+ }
+
+ if (u1->clock_seq[1] != u2->clock_seq[1]) {
+ return u1->clock_seq[1] > u2->clock_seq[1] ? 1 : -1;
+ }
+
+ return memcmp(u1->node, u2->node, 6);
+}
+
+/**
+ its useful to be able to display these in debugging messages
+*/
+_PUBLIC_ char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid)
+{
+ struct GUID_txt_buf buf;
+ return talloc_strdup(mem_ctx, GUID_buf_string(guid, &buf));
+}
+
+/**
+ * Does the same without allocating memory, using the structure buffer.
+ * Useful for debug messages, so that you do not have to talloc_free the result
+ */
+_PUBLIC_ char* GUID_buf_string(const struct GUID *guid,
+ struct GUID_txt_buf *dst)
+{
+ if (!guid) {
+ return NULL;
+ }
+ snprintf(dst->buf, sizeof(dst->buf),
+ "%08"PRIx32"-%04"PRIx16"-%04"PRIx16"-%02"PRIx8"%02"PRIx8"-%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8,
+ guid->time_low, guid->time_mid,
+ guid->time_hi_and_version,
+ guid->clock_seq[0],
+ guid->clock_seq[1],
+ guid->node[0], guid->node[1],
+ guid->node[2], guid->node[3],
+ guid->node[4], guid->node[5]);
+ return dst->buf;
+}
+
+_PUBLIC_ char *GUID_string2(TALLOC_CTX *mem_ctx, const struct GUID *guid)
+{
+ struct GUID_txt_buf buf;
+ char *ret = talloc_asprintf(
+ mem_ctx, "{%s}", GUID_buf_string(guid, &buf));
+ return ret;
+}
+
+_PUBLIC_ char *GUID_hexstring(TALLOC_CTX *mem_ctx, const struct GUID *guid)
+{
+ char *ret = NULL;
+ DATA_BLOB guid_blob = { .data = NULL };
+ NTSTATUS status;
+
+ status = GUID_to_ndr_blob(guid, mem_ctx, &guid_blob);
+ if (NT_STATUS_IS_OK(status)) {
+ ret = data_blob_hex_string_upper(mem_ctx, &guid_blob);
+ }
+ TALLOC_FREE(guid_blob.data);
+ return ret;
+}
+
+_PUBLIC_ bool ndr_policy_handle_empty(const struct policy_handle *h)
+{
+ return (h->handle_type == 0 && GUID_all_zero(&h->uuid));
+}
+
+_PUBLIC_ bool ndr_policy_handle_equal(const struct policy_handle *hnd1,
+ const struct policy_handle *hnd2)
+{
+ if (!hnd1 || !hnd2) {
+ return false;
+ }
+
+ return (memcmp(hnd1, hnd2, sizeof(*hnd1)) == 0);
+}
diff --git a/librpc/ndr_krb5pac.pc.in b/librpc/ndr_krb5pac.pc.in
new file mode 100644
index 0000000..581b7e5
--- /dev/null
+++ b/librpc/ndr_krb5pac.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ndr-krb5pac
+Description: NDR marshallers for the KRB5 PAC formats
+Requires: ndr ndr_standard
+Version: @PACKAGE_VERSION@
+Libs: @LIB_RPATH@ -L${libdir} -lndr-krb5pac
+Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 -D_GNU_SOURCE=1
diff --git a/librpc/ndr_nbt.pc.in b/librpc/ndr_nbt.pc.in
new file mode 100644
index 0000000..2083e2d
--- /dev/null
+++ b/librpc/ndr_nbt.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ndr-nbt
+Description: NDR marshallers for nbt formats
+Requires: ndr
+Version: @PACKAGE_VERSION@
+Libs: @LIB_RPATH@ -L${libdir} -lndr-nbt
+Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 -D_GNU_SOURCE=1
diff --git a/librpc/ndr_standard.pc.in b/librpc/ndr_standard.pc.in
new file mode 100644
index 0000000..97687ba
--- /dev/null
+++ b/librpc/ndr_standard.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ndr-standard
+Description: NDR marshallers for the standard set of DCE/RPC interfaces
+Requires: ndr
+Version: @PACKAGE_VERSION@
+Libs: @LIB_RPATH@ -L${libdir} -lndr-standard
+Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 -D_GNU_SOURCE=1
diff --git a/librpc/rpc/binding.c b/librpc/rpc/binding.c
new file mode 100644
index 0000000..eaf3430
--- /dev/null
+++ b/librpc/rpc/binding.c
@@ -0,0 +1,1502 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc utility functions
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Rafal Szczesniak 2006
+ Copyright (C) Stefan Metzmacher 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 "includes.h"
+#include "../../lib/util/util_net.h"
+#include "librpc/gen_ndr/ndr_epmapper.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "librpc/rpc/dcerpc.h"
+#include "rpc_common.h"
+
+#undef strcasecmp
+#undef strncasecmp
+
+#define MAX_PROTSEQ 10
+
+struct dcerpc_binding {
+ enum dcerpc_transport_t transport;
+ struct GUID object;
+ const char *object_string;
+ const char *host;
+ const char *target_hostname;
+ const char *target_principal;
+ const char *endpoint;
+ const char **options;
+ uint32_t flags;
+ uint32_t assoc_group_id;
+ char assoc_group_string[11]; /* 0x3456789a + '\0' */
+};
+
+static const struct {
+ const char *name;
+ enum dcerpc_transport_t transport;
+ int num_protocols;
+ enum epm_protocol protseq[MAX_PROTSEQ];
+} transports[] = {
+ { "ncacn_np", NCACN_NP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NETBIOS }},
+ { "ncacn_ip_tcp", NCACN_IP_TCP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP, EPM_PROTOCOL_IP } },
+ { "ncacn_http", NCACN_HTTP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP, EPM_PROTOCOL_IP } },
+ { "ncadg_ip_udp", NCACN_IP_UDP, 3,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UDP, EPM_PROTOCOL_IP } },
+ { "ncalrpc", NCALRPC, 2,
+ { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_NAMED_PIPE } },
+ { "ncacn_unix_stream", NCACN_UNIX_STREAM, 2,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } },
+ { "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UNIX_DS } },
+ { "ncacn_at_dsp", NCACN_AT_DSP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DSP } },
+ { "ncadg_at_ddp", NCADG_AT_DDP, 3,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DDP } },
+ { "ncacn_vns_ssp", NCACN_VNS_SPP, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_SPP } },
+ { "ncacn_vns_ipc", NCACN_VNS_IPC, 3,
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_IPC }, },
+ { "ncadg_ipx", NCADG_IPX, 2,
+ { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_IPX },
+ },
+ { "ncacn_spx", NCACN_SPX, 3,
+ /* I guess some MS programmer confused the identifier for
+ * EPM_PROTOCOL_UUID (0x0D or 13) with the one for
+ * EPM_PROTOCOL_SPX (0x13) here. -- jelmer*/
+ { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID },
+ },
+};
+
+static const struct ncacn_option {
+ const char *name;
+ uint32_t flag;
+} ncacn_options[] = {
+ {"sign", DCERPC_SIGN},
+ {"seal", DCERPC_SEAL},
+ {"connect", DCERPC_CONNECT},
+ {"spnego", DCERPC_AUTH_SPNEGO},
+ {"ntlm", DCERPC_AUTH_NTLM},
+ {"krb5", DCERPC_AUTH_KRB5},
+ {"schannel", DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO},
+ {"validate", DCERPC_DEBUG_VALIDATE_BOTH},
+ {"print", DCERPC_DEBUG_PRINT_BOTH},
+ {"padcheck", DCERPC_DEBUG_PAD_CHECK},
+ {"bigendian", DCERPC_PUSH_BIGENDIAN},
+ {"smb1", DCERPC_SMB1},
+ {"smb2", DCERPC_SMB2},
+ {"ndr64", DCERPC_NDR64},
+ {"packet", DCERPC_PACKET},
+};
+
+static const struct ncacn_option *ncacn_option_by_name(const char *name)
+{
+ size_t i;
+
+ for (i=0; i<ARRAY_SIZE(ncacn_options); i++) {
+ int ret;
+
+ ret = strcasecmp(ncacn_options[i].name, name);
+ if (ret != 0) {
+ continue;
+ }
+
+ return &ncacn_options[i];
+ }
+
+ return NULL;
+}
+
+const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
+{
+ struct ndr_syntax_id syntax;
+ NTSTATUS status;
+
+ switch(epm_floor->lhs.protocol) {
+ case EPM_PROTOCOL_UUID:
+ status = dcerpc_floor_get_uuid_full(epm_floor, &syntax);
+ if (NT_STATUS_IS_OK(status)) {
+ /* lhs is used: UUID */
+ struct GUID_txt_buf buf;
+
+ if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr.uuid)) {
+ return "NDR";
+ }
+
+ if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr64.uuid)) {
+ return "NDR64";
+ }
+
+ return talloc_asprintf(
+ mem_ctx,
+ " uuid %s/0x%02x",
+ GUID_buf_string(&syntax.uuid, &buf),
+ syntax.if_version);
+ } else { /* IPX */
+ return talloc_asprintf(mem_ctx, "IPX:%s",
+ data_blob_hex_string_upper(mem_ctx, &epm_floor->rhs.uuid.unknown));
+ }
+
+ case EPM_PROTOCOL_NCACN:
+ return "RPC-C";
+
+ case EPM_PROTOCOL_NCADG:
+ return "RPC";
+
+ case EPM_PROTOCOL_NCALRPC:
+ return "NCALRPC";
+
+ case EPM_PROTOCOL_DNET_NSP:
+ return "DNET/NSP";
+
+ case EPM_PROTOCOL_IP:
+ return talloc_asprintf(mem_ctx, "IP:%s", epm_floor->rhs.ip.ipaddr);
+
+ case EPM_PROTOCOL_NAMED_PIPE:
+ return talloc_asprintf(mem_ctx, "NAMED-PIPE:%s", epm_floor->rhs.named_pipe.path);
+
+ case EPM_PROTOCOL_SMB:
+ return talloc_asprintf(mem_ctx, "SMB:%s", epm_floor->rhs.smb.unc);
+
+ case EPM_PROTOCOL_UNIX_DS:
+ return talloc_asprintf(mem_ctx, "Unix:%s", epm_floor->rhs.unix_ds.path);
+
+ case EPM_PROTOCOL_NETBIOS:
+ return talloc_asprintf(mem_ctx, "NetBIOS:%s", epm_floor->rhs.netbios.name);
+
+ case EPM_PROTOCOL_NETBEUI:
+ return "NETBeui";
+
+ case EPM_PROTOCOL_SPX:
+ return "SPX";
+
+ case EPM_PROTOCOL_NB_IPX:
+ return "NB_IPX";
+
+ case EPM_PROTOCOL_HTTP:
+ return talloc_asprintf(mem_ctx, "HTTP:%"PRIu16, epm_floor->rhs.http.port);
+
+ case EPM_PROTOCOL_TCP:
+ return talloc_asprintf(mem_ctx, "TCP:%"PRIu16, epm_floor->rhs.tcp.port);
+
+ case EPM_PROTOCOL_UDP:
+ return talloc_asprintf(mem_ctx, "UDP:%"PRIu16, epm_floor->rhs.udp.port);
+
+ default:
+ return talloc_asprintf(mem_ctx, "UNK(%02x):", epm_floor->lhs.protocol);
+ }
+}
+
+
+/*
+ form a binding string from a binding structure
+*/
+_PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
+{
+ char *s = NULL;
+ size_t i;
+ const char *t_name = NULL;
+ bool option_section = false;
+ const char *target_hostname = NULL;
+
+ if (b->transport != NCA_UNKNOWN) {
+ t_name = derpc_transport_string_by_transport(b->transport);
+ if (!t_name) {
+ return NULL;
+ }
+ }
+
+ s = talloc_strdup(mem_ctx, "");
+
+ if (!GUID_all_zero(&b->object)) {
+ struct GUID_txt_buf buf;
+ talloc_asprintf_addbuf(
+ &s, "%s@", GUID_buf_string(&b->object, &buf));
+ }
+
+ if (t_name != NULL) {
+ talloc_asprintf_addbuf(&s, "%s:", t_name);
+ }
+
+ if (b->host) {
+ talloc_asprintf_addbuf(&s, "%s", b->host);
+ }
+
+ target_hostname = b->target_hostname;
+ if (target_hostname != NULL && b->host != NULL) {
+ if (strcmp(target_hostname, b->host) == 0) {
+ target_hostname = NULL;
+ }
+ }
+
+ option_section =
+ (b->endpoint != NULL) ||
+ (target_hostname != NULL) ||
+ (b->target_principal != NULL) ||
+ (b->assoc_group_id != 0) ||
+ (b->options != NULL) ||
+ (b->flags != 0);
+
+ if (!option_section) {
+ return s;
+ }
+
+ talloc_asprintf_addbuf(&s, "[");
+
+ if (b->endpoint) {
+ talloc_asprintf_addbuf(&s, "%s", b->endpoint);
+ }
+
+ for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
+ if (!(b->flags & ncacn_options[i].flag)) {
+ continue;
+ }
+
+ talloc_asprintf_addbuf(&s, ",%s", ncacn_options[i].name);
+ }
+
+ if (target_hostname) {
+ talloc_asprintf_addbuf(
+ &s, ",target_hostname=%s", b->target_hostname);
+ }
+
+ if (b->target_principal) {
+ talloc_asprintf_addbuf(
+ &s, ",target_principal=%s", b->target_principal);
+ }
+
+ if (b->assoc_group_id != 0) {
+ talloc_asprintf_addbuf(
+ &s, ",assoc_group_id=0x%08x", b->assoc_group_id);
+ }
+
+ for (i=0;b->options && b->options[i];i++) {
+ talloc_asprintf_addbuf(&s, ",%s", b->options[i]);
+ }
+
+ talloc_asprintf_addbuf(&s, "]");
+
+ return s;
+}
+
+/*
+ parse a binding string into a dcerpc_binding structure
+*/
+_PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *_s, struct dcerpc_binding **b_out)
+{
+ char *_t;
+ struct dcerpc_binding *b;
+ char *s;
+ char *options = NULL;
+ char *p;
+ size_t i;
+ NTSTATUS status;
+
+ b = talloc_zero(mem_ctx, struct dcerpc_binding);
+ if (!b) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ _t = talloc_strdup(b, _s);
+ if (_t == NULL) {
+ talloc_free(b);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ s = _t;
+
+ p = strchr(s, '[');
+ if (p) {
+ char *q = p + strlen(p) - 1;
+ if (*q != ']') {
+ talloc_free(b);
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ *p = '\0';
+ *q = '\0';
+ options = p + 1;
+ }
+
+ p = strchr(s, '@');
+
+ if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
+ *p = '\0';
+
+ status = dcerpc_binding_set_string_option(b, "object", s);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+
+ s = p + 1;
+ }
+
+ p = strchr(s, ':');
+
+ if (p == NULL) {
+ b->transport = NCA_UNKNOWN;
+ } else if (is_ipaddress_v6(s)) {
+ b->transport = NCA_UNKNOWN;
+ } else {
+ *p = '\0';
+
+ status = dcerpc_binding_set_string_option(b, "transport", s);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+
+ s = p + 1;
+ }
+
+ if (strlen(s) > 0) {
+ status = dcerpc_binding_set_string_option(b, "host", s);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+
+ b->target_hostname = talloc_strdup(b, b->host);
+ if (b->target_hostname == NULL) {
+ talloc_free(b);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ for (i=0; options != NULL; i++) {
+ const char *name = options;
+ const char *value = NULL;
+
+ p = strchr(options, ',');
+ if (p != NULL) {
+ *p = '\0';
+ options = p+1;
+ } else {
+ options = NULL;
+ }
+
+ p = strchr(name, '=');
+ if (p != NULL) {
+ *p = '\0';
+ value = p + 1;
+ }
+
+ if (value == NULL) {
+ /*
+ * If it's not a key=value pair
+ * it might be a ncacn_option
+ * or if it's the first option
+ * it's the endpoint.
+ */
+ const struct ncacn_option *no = NULL;
+
+ value = name;
+
+ no = ncacn_option_by_name(name);
+ if (no == NULL) {
+ if (i > 0) {
+ /*
+ * we don't allow unknown options
+ */
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ /*
+ * This is the endpoint
+ */
+ name = "endpoint";
+ if (strlen(value) == 0) {
+ value = NULL;
+ }
+ }
+ }
+
+ status = dcerpc_binding_set_string_option(b, name, value);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+ }
+
+ talloc_free(_t);
+ *b_out = b;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ struct GUID dcerpc_binding_get_object(const struct dcerpc_binding *b)
+{
+ return b->object;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_set_object(struct dcerpc_binding *b,
+ struct GUID object)
+{
+ char *tmp = discard_const_p(char, b->object_string);
+
+ if (GUID_all_zero(&object)) {
+ talloc_free(tmp);
+ b->object_string = NULL;
+ ZERO_STRUCT(b->object);
+ return NT_STATUS_OK;
+ }
+
+ b->object_string = GUID_string(b, &object);
+ if (b->object_string == NULL) {
+ b->object_string = tmp;
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_free(tmp);
+
+ b->object = object;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ enum dcerpc_transport_t dcerpc_binding_get_transport(const struct dcerpc_binding *b)
+{
+ return b->transport;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_set_transport(struct dcerpc_binding *b,
+ enum dcerpc_transport_t transport)
+{
+ NTSTATUS status;
+
+ /*
+ * TODO: we may want to check the transport value is
+ * wellknown.
+ */
+ if (b->transport == transport) {
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * This implicitly resets the endpoint
+ * as the endpoint is transport specific.
+ *
+ * It also resets the assoc group as it's
+ * also endpoint specific.
+ *
+ * TODO: in future we may reset more options
+ * here.
+ */
+ status = dcerpc_binding_set_string_option(b, "endpoint", NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ b->assoc_group_id = 0;
+
+ b->transport = transport;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
+ enum dcerpc_AuthType *_auth_type,
+ enum dcerpc_AuthLevel *_auth_level)
+{
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ if (b->flags & DCERPC_AUTH_SPNEGO) {
+ auth_type = DCERPC_AUTH_TYPE_SPNEGO;
+ } else if (b->flags & DCERPC_AUTH_KRB5) {
+ auth_type = DCERPC_AUTH_TYPE_KRB5;
+ } else if (b->flags & DCERPC_SCHANNEL) {
+ auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
+ } else if (b->flags & DCERPC_AUTH_NTLM) {
+ auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
+ } else {
+ auth_type = DCERPC_AUTH_TYPE_NONE;
+ }
+
+ if (b->flags & DCERPC_SEAL) {
+ auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ } else if (b->flags & DCERPC_SIGN) {
+ auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ } else if (b->flags & DCERPC_CONNECT) {
+ auth_level = DCERPC_AUTH_LEVEL_CONNECT;
+ } else if (b->flags & DCERPC_PACKET) {
+ auth_level = DCERPC_AUTH_LEVEL_PACKET;
+ } else if (auth_type != DCERPC_AUTH_TYPE_NONE) {
+ auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ } else {
+ auth_level = DCERPC_AUTH_LEVEL_NONE;
+ }
+
+ if (_auth_type != NULL) {
+ *_auth_type = auth_type;
+ }
+
+ if (_auth_level != NULL) {
+ *_auth_level = auth_level;
+ }
+}
+
+_PUBLIC_ uint32_t dcerpc_binding_get_assoc_group_id(const struct dcerpc_binding *b)
+{
+ return b->assoc_group_id;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_set_assoc_group_id(struct dcerpc_binding *b,
+ uint32_t assoc_group_id)
+{
+ b->assoc_group_id = assoc_group_id;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ struct ndr_syntax_id dcerpc_binding_get_abstract_syntax(const struct dcerpc_binding *b)
+{
+ const char *s = dcerpc_binding_get_string_option(b, "abstract_syntax");
+ bool ok;
+ struct ndr_syntax_id id;
+
+ if (s == NULL) {
+ return ndr_syntax_id_null;
+ }
+
+ ok = ndr_syntax_id_from_string(s, &id);
+ if (!ok) {
+ return ndr_syntax_id_null;
+ }
+
+ return id;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_set_abstract_syntax(struct dcerpc_binding *b,
+ const struct ndr_syntax_id *syntax)
+{
+ NTSTATUS status;
+ struct ndr_syntax_id_buf buf;
+
+ if (syntax == NULL) {
+ status = dcerpc_binding_set_string_option(b, "abstract_syntax", NULL);
+ return status;
+ }
+
+ if (ndr_syntax_id_equal(&ndr_syntax_id_null, syntax)) {
+ status = dcerpc_binding_set_string_option(b, "abstract_syntax", NULL);
+ return status;
+ }
+
+ status = dcerpc_binding_set_string_option(
+ b, "abstract_syntax", ndr_syntax_id_buf_string(syntax, &buf));
+ return status;
+}
+
+_PUBLIC_ const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
+ const char *name)
+{
+ struct {
+ const char *name;
+ const char *value;
+#define _SPECIAL(x) { .name = #x, .value = b->x, }
+ } specials[] = {
+ { .name = "object", .value = b->object_string, },
+ _SPECIAL(host),
+ _SPECIAL(endpoint),
+ _SPECIAL(target_hostname),
+ _SPECIAL(target_principal),
+#undef _SPECIAL
+ };
+ const struct ncacn_option *no = NULL;
+ size_t name_len = strlen(name);
+ size_t i;
+ int ret;
+
+ ret = strcmp(name, "transport");
+ if (ret == 0) {
+ return derpc_transport_string_by_transport(b->transport);
+ }
+
+ ret = strcmp(name, "assoc_group_id");
+ if (ret == 0) {
+ char *tmp = discard_const_p(char, b->assoc_group_string);
+
+ if (b->assoc_group_id == 0) {
+ return NULL;
+ }
+
+ snprintf(tmp, sizeof(b->assoc_group_string),
+ "0x%08x", b->assoc_group_id);
+ return (const char *)b->assoc_group_string;
+ }
+
+ for (i=0; i < ARRAY_SIZE(specials); i++) {
+ ret = strcmp(specials[i].name, name);
+ if (ret != 0) {
+ continue;
+ }
+
+ return specials[i].value;
+ }
+
+ no = ncacn_option_by_name(name);
+ if (no != NULL) {
+ if (b->flags & no->flag) {
+ return no->name;
+ }
+
+ return NULL;
+ }
+
+ if (b->options == NULL) {
+ return NULL;
+ }
+
+ for (i=0; b->options[i]; i++) {
+ const char *o = b->options[i];
+ const char *vs = NULL;
+
+ ret = strncmp(name, o, name_len);
+ if (ret != 0) {
+ continue;
+ }
+
+ if (o[name_len] != '=') {
+ continue;
+ }
+
+ vs = &o[name_len + 1];
+
+ return vs;
+ }
+
+ return NULL;
+}
+
+_PUBLIC_ char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
+ const struct dcerpc_binding *b,
+ const char *name)
+{
+ const char *c = dcerpc_binding_get_string_option(b, name);
+ char *v;
+
+ if (c == NULL) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ v = talloc_strdup(mem_ctx, c);
+ if (v == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ return v;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
+ const char *name,
+ const char *value)
+{
+ struct {
+ const char *name;
+ const char **ptr;
+#define _SPECIAL(x) { .name = #x, .ptr = &b->x, }
+ } specials[] = {
+ _SPECIAL(host),
+ _SPECIAL(endpoint),
+ _SPECIAL(target_hostname),
+ _SPECIAL(target_principal),
+#undef _SPECIAL
+ };
+ const struct ncacn_option *no = NULL;
+ size_t name_len = strlen(name);
+ const char *opt = NULL;
+ char *tmp;
+ size_t i;
+ int ret;
+
+ /*
+ * Note: value == NULL, means delete it.
+ * value != NULL means add or reset.
+ */
+
+ ret = strcmp(name, "transport");
+ if (ret == 0) {
+ enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
+
+ if (t == NCA_UNKNOWN && value != NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ return dcerpc_binding_set_transport(b, t);
+ }
+
+ ret = strcmp(name, "object");
+ if (ret == 0) {
+ NTSTATUS status;
+ struct GUID uuid = GUID_zero();
+
+ if (value != NULL) {
+ DATA_BLOB blob;
+ blob = data_blob_string_const(value);
+ if (blob.length != 36) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ status = GUID_from_data_blob(&blob, &uuid);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return dcerpc_binding_set_object(b, uuid);
+ }
+
+ ret = strcmp(name, "assoc_group_id");
+ if (ret == 0) {
+ uint32_t assoc_group_id = 0;
+
+ if (value != NULL) {
+ char c;
+
+ ret = sscanf(value, "0x%08x%c", &assoc_group_id, &c);
+ if (ret != 1) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+ }
+
+ return dcerpc_binding_set_assoc_group_id(b, assoc_group_id);
+ }
+
+ for (i=0; i < ARRAY_SIZE(specials); i++) {
+ ret = strcmp(specials[i].name, name);
+ if (ret != 0) {
+ continue;
+ }
+
+ tmp = discard_const_p(char, *specials[i].ptr);
+
+ if (value == NULL) {
+ talloc_free(tmp);
+ *specials[i].ptr = NULL;
+ return NT_STATUS_OK;
+ }
+
+ if (value[0] == '\0') {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ *specials[i].ptr = talloc_strdup(b, value);
+ if (*specials[i].ptr == NULL) {
+ *specials[i].ptr = tmp;
+ return NT_STATUS_NO_MEMORY;
+ }
+ talloc_free(tmp);
+
+ return NT_STATUS_OK;
+ }
+
+ no = ncacn_option_by_name(name);
+ if (no != NULL) {
+ if (value == NULL) {
+ b->flags &= ~no->flag;
+ return NT_STATUS_OK;
+ }
+
+ ret = strcasecmp(no->name, value);
+ if (ret != 0) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ b->flags |= no->flag;
+ return NT_STATUS_OK;
+ }
+
+ for (i=0; b->options && b->options[i]; i++) {
+ const char *o = b->options[i];
+
+ ret = strncmp(name, o, name_len);
+ if (ret != 0) {
+ continue;
+ }
+
+ if (o[name_len] != '=') {
+ continue;
+ }
+
+ opt = o;
+ break;
+ }
+
+ if (opt == NULL) {
+ const char **n;
+
+ if (value == NULL) {
+ return NT_STATUS_OK;
+ }
+
+ n = talloc_realloc(b, b->options, const char *, i + 2);
+ if (n == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ n[i] = NULL;
+ n[i + 1] = NULL;
+ b->options = n;
+ }
+
+ tmp = discard_const_p(char, opt);
+
+ if (value == NULL) {
+ for (;b->options[i];i++) {
+ b->options[i] = b->options[i+1];
+ }
+ talloc_free(tmp);
+ return NT_STATUS_OK;
+ }
+
+ b->options[i] = talloc_asprintf(b->options, "%s=%s",
+ name, value);
+ if (b->options[i] == NULL) {
+ b->options[i] = tmp;
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
+{
+ return b->flags;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
+ uint32_t additional,
+ uint32_t clear)
+{
+ /*
+ * TODO: in future we may want to reject invalid combinations
+ */
+ b->flags &= ~clear;
+ b->flags |= additional;
+
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_floor_get_uuid_full(const struct epm_floor *epm_floor,
+ struct ndr_syntax_id *syntax)
+{
+ TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
+ struct ndr_pull *ndr;
+ enum ndr_err_code ndr_err;
+ uint16_t if_version=0;
+
+ *syntax = (struct ndr_syntax_id) { .if_version = 0, };
+
+ if (epm_floor->lhs.protocol != EPM_PROTOCOL_UUID) {
+ talloc_free(mem_ctx);
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
+ if (ndr == NULL) {
+ talloc_free(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ndr->flags |= LIBNDR_FLAG_NOALIGN;
+
+ ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(mem_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(mem_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ syntax->if_version = if_version;
+
+ TALLOC_FREE(ndr);
+
+ ndr = ndr_pull_init_blob(&epm_floor->rhs.uuid.unknown, mem_ctx);
+ if (ndr == NULL) {
+ talloc_free(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ ndr->flags |= LIBNDR_FLAG_NOALIGN;
+
+ ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(mem_ctx);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ syntax->if_version |= (((uint32_t)if_version) << 16) & 0xffff0000;
+
+ talloc_free(mem_ctx);
+
+ return NT_STATUS_OK;
+}
+
+static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ struct ndr_push *ndr;
+
+ ndr = ndr_push_init_ctx(mem_ctx);
+ if (ndr == NULL) {
+ return data_blob_null;
+ }
+
+ ndr->flags |= LIBNDR_FLAG_NOALIGN;
+
+ ndr_err = ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return data_blob_null;
+ }
+ ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return data_blob_null;
+ }
+
+ blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob.data);
+ talloc_free(ndr);
+ return blob;
+}
+
+static bool dcerpc_floor_pack_rhs_if_version_data(
+ TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax,
+ DATA_BLOB *pblob)
+{
+ DATA_BLOB blob;
+ struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
+ enum ndr_err_code ndr_err;
+
+ if (ndr == NULL) {
+ return false;
+ }
+
+ ndr->flags |= LIBNDR_FLAG_NOALIGN;
+
+ ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version >> 16);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return false;
+ }
+
+ blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob.data);
+ talloc_free(ndr);
+ *pblob = blob;
+ return true;
+}
+
+static NTSTATUS dcerpc_floor_pack_uuid_full(TALLOC_CTX *mem_ctx,
+ struct epm_floor *floor,
+ const struct ndr_syntax_id *syntax)
+{
+ bool ok;
+
+ floor->lhs.protocol = EPM_PROTOCOL_UUID;
+
+ floor->lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx, syntax);
+ if (floor->lhs.lhs_data.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ok = dcerpc_floor_pack_rhs_if_version_data(mem_ctx, syntax,
+ &floor->rhs.uuid.unknown);
+ if (!ok) {
+ data_blob_free(&floor->lhs.lhs_data);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ return NT_STATUS_OK;
+}
+
+char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
+{
+ switch (epm_floor->lhs.protocol) {
+ case EPM_PROTOCOL_TCP:
+ if (epm_floor->rhs.tcp.port == 0) return NULL;
+ return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.tcp.port);
+
+ case EPM_PROTOCOL_UDP:
+ if (epm_floor->rhs.udp.port == 0) return NULL;
+ return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.udp.port);
+
+ case EPM_PROTOCOL_HTTP:
+ if (epm_floor->rhs.http.port == 0) return NULL;
+ return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.http.port);
+
+ case EPM_PROTOCOL_IP:
+ return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
+
+ case EPM_PROTOCOL_NCACN:
+ return NULL;
+
+ case EPM_PROTOCOL_NCADG:
+ return NULL;
+
+ case EPM_PROTOCOL_SMB:
+ if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
+
+ case EPM_PROTOCOL_NAMED_PIPE:
+ if (strlen(epm_floor->rhs.named_pipe.path) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.named_pipe.path);
+
+ case EPM_PROTOCOL_NETBIOS:
+ if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
+
+ case EPM_PROTOCOL_NCALRPC:
+ return NULL;
+
+ case EPM_PROTOCOL_VINES_SPP:
+ return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.vines_spp.port);
+
+ case EPM_PROTOCOL_VINES_IPC:
+ return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.vines_ipc.port);
+
+ case EPM_PROTOCOL_STREETTALK:
+ return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
+
+ case EPM_PROTOCOL_UNIX_DS:
+ if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
+ return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
+
+ case EPM_PROTOCOL_NULL:
+ return NULL;
+
+ default:
+ DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
+ break;
+ }
+
+ return NULL;
+}
+
+static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx,
+ struct epm_floor *epm_floor,
+ const char *data)
+{
+ if (data == NULL) {
+ data = "";
+ }
+
+ switch (epm_floor->lhs.protocol) {
+ case EPM_PROTOCOL_TCP:
+ epm_floor->rhs.tcp.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_UDP:
+ epm_floor->rhs.udp.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_HTTP:
+ epm_floor->rhs.http.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_IP:
+ if (!is_ipaddress_v4(data)) {
+ data = "0.0.0.0";
+ }
+ epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NCACN:
+ epm_floor->rhs.ncacn.minor_version = 0;
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NCADG:
+ epm_floor->rhs.ncadg.minor_version = 0;
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_SMB:
+ epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NAMED_PIPE:
+ epm_floor->rhs.named_pipe.path = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.named_pipe.path);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NETBIOS:
+ epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NCALRPC:
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_VINES_SPP:
+ epm_floor->rhs.vines_spp.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_VINES_IPC:
+ epm_floor->rhs.vines_ipc.port = atoi(data);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_STREETTALK:
+ epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_UNIX_DS:
+ epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
+ NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
+ return NT_STATUS_OK;
+
+ case EPM_PROTOCOL_NULL:
+ return NT_STATUS_OK;
+
+ default:
+ DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
+ break;
+ }
+
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
+{
+ size_t i;
+
+ /* Find a transport that has 'prot' as 4th protocol */
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (transports[i].num_protocols >= 2 &&
+ transports[i].protseq[1] == prot) {
+ return transports[i].transport;
+ }
+ }
+
+ /* Unknown transport */
+ return (unsigned int)-1;
+}
+
+_PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower)
+{
+ size_t i;
+
+ /* Find a transport that matches this tower */
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ int j;
+ if (transports[i].num_protocols != tower->num_floors - 2) {
+ continue;
+ }
+
+ for (j = 0; j < transports[i].num_protocols && j < MAX_PROTSEQ; j++) {
+ if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
+ break;
+ }
+ }
+
+ if (j == transports[i].num_protocols) {
+ return transports[i].transport;
+ }
+ }
+
+ /* Unknown transport */
+ return (unsigned int)-1;
+}
+
+_PUBLIC_ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t)
+{
+ size_t i;
+
+ for (i=0; i<ARRAY_SIZE(transports); i++) {
+ if (t == transports[i].transport) {
+ return transports[i].name;
+ }
+ }
+ return NULL;
+}
+
+_PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_name(const char *name)
+{
+ size_t i;
+
+ if (name == NULL) {
+ return NCA_UNKNOWN;
+ }
+
+ for (i=0; i<ARRAY_SIZE(transports);i++) {
+ if (strcasecmp(name, transports[i].name) == 0) {
+ return transports[i].transport;
+ }
+ }
+
+ return NCA_UNKNOWN;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
+ struct epm_tower *tower,
+ struct dcerpc_binding **b_out)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *b;
+ enum dcerpc_transport_t transport;
+ struct ndr_syntax_id abstract_syntax;
+ char *endpoint = NULL;
+ char *host = NULL;
+
+ /*
+ * A tower needs to have at least 4 floors to carry useful
+ * information. Floor 3 is the transport identifier which defines
+ * how many floors are required at least.
+ */
+ if (tower->num_floors < 4) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = dcerpc_parse_binding(mem_ctx, "", &b);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ transport = dcerpc_transport_by_tower(tower);
+ if (transport == NCA_UNKNOWN) {
+ talloc_free(b);
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ status = dcerpc_binding_set_transport(b, transport);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+
+ /* Set abstract syntax */
+ status = dcerpc_floor_get_uuid_full(&tower->floors[0], &abstract_syntax);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+
+ status = dcerpc_binding_set_abstract_syntax(b, &abstract_syntax);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+
+ /* Ignore floor 1, it contains the NDR version info */
+
+ /* Set endpoint */
+ errno = 0;
+ if (tower->num_floors >= 4) {
+ endpoint = dcerpc_floor_get_rhs_data(b, &tower->floors[3]);
+ }
+ if (errno != 0) {
+ int saved_errno = errno;
+ talloc_free(b);
+ return map_nt_error_from_unix_common(saved_errno);
+ }
+
+ status = dcerpc_binding_set_string_option(b, "endpoint", endpoint);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+ TALLOC_FREE(endpoint);
+
+ /* Set network address */
+ errno = 0;
+ if (tower->num_floors >= 5) {
+ host = dcerpc_floor_get_rhs_data(b, &tower->floors[4]);
+ }
+ if (errno != 0) {
+ int saved_errno = errno;
+ talloc_free(b);
+ return map_nt_error_from_unix_common(saved_errno);
+ }
+
+ status = dcerpc_binding_set_string_option(b, "host", host);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+ status = dcerpc_binding_set_string_option(b, "target_hostname", host);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(b);
+ return status;
+ }
+ TALLOC_FREE(host);
+
+ *b_out = b;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
+ const struct dcerpc_binding *b)
+{
+ struct dcerpc_binding *n;
+ uint32_t count;
+
+ n = talloc_zero(mem_ctx, struct dcerpc_binding);
+ if (n == NULL) {
+ return NULL;
+ }
+
+ n->transport = b->transport;
+ n->object = b->object;
+ n->flags = b->flags;
+ n->assoc_group_id = b->assoc_group_id;
+
+ if (b->object_string != NULL) {
+ n->object_string = talloc_strdup(n, b->object_string);
+ if (n->object_string == NULL) {
+ goto nomem;
+ }
+ }
+ if (b->host != NULL) {
+ n->host = talloc_strdup(n, b->host);
+ if (n->host == NULL) {
+ goto nomem;
+ }
+ }
+
+ if (b->target_hostname != NULL) {
+ n->target_hostname = talloc_strdup(n, b->target_hostname);
+ if (n->target_hostname == NULL) {
+ goto nomem;
+ }
+ }
+
+ if (b->target_principal != NULL) {
+ n->target_principal = talloc_strdup(n, b->target_principal);
+ if (n->target_principal == NULL) {
+ goto nomem;
+ }
+ }
+
+ if (b->endpoint != NULL) {
+ n->endpoint = talloc_strdup(n, b->endpoint);
+ if (n->endpoint == NULL) {
+ goto nomem;
+ }
+ }
+
+ for (count = 0; b->options && b->options[count]; count++);
+
+ if (count > 0) {
+ uint32_t i;
+
+ n->options = talloc_array(n, const char *, count + 1);
+ if (n->options == NULL) {
+ goto nomem;
+ }
+
+ for (i = 0; i < count; i++) {
+ n->options[i] = talloc_strdup(n->options, b->options[i]);
+ if (n->options[i] == NULL) {
+ goto nomem;
+ }
+ }
+ n->options[count] = NULL;
+ }
+
+ return n;
+nomem:
+ TALLOC_FREE(n);
+ return NULL;
+}
+
+_PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
+ const struct dcerpc_binding *binding,
+ struct epm_tower *tower)
+{
+ const enum epm_protocol *protseq = NULL;
+ size_t i, num_protocols = 0;
+ struct ndr_syntax_id abstract_syntax;
+ NTSTATUS status;
+
+ /* Find transport */
+ for (i=0;i<ARRAY_SIZE(transports);i++) {
+ if (transports[i].transport == binding->transport) {
+ protseq = transports[i].protseq;
+ num_protocols = transports[i].num_protocols;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(transports)) {
+ DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ tower->num_floors = 2 + num_protocols;
+ tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
+ if (tower->floors == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Floor 0 */
+ abstract_syntax = dcerpc_binding_get_abstract_syntax(binding);
+ status = dcerpc_floor_pack_uuid_full(tower->floors,
+ &tower->floors[0],
+ &abstract_syntax);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Floor 1 */
+ status = dcerpc_floor_pack_uuid_full(tower->floors,
+ &tower->floors[1],
+ &ndr_transfer_syntax_ndr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Floor 2 to num_protocols */
+ for (i = 0; i < num_protocols; i++) {
+ tower->floors[2 + i].lhs.protocol = protseq[i];
+ tower->floors[2 + i].lhs.lhs_data = data_blob_null;
+ ZERO_STRUCT(tower->floors[2 + i].rhs);
+ status = dcerpc_floor_set_rhs_data(tower->floors,
+ &tower->floors[2 + i],
+ NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ /* The 4th floor contains the endpoint */
+ if (num_protocols >= 2 && binding->endpoint) {
+ status = dcerpc_floor_set_rhs_data(tower->floors,
+ &tower->floors[3],
+ binding->endpoint);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ /* The 5th contains the network address */
+ if (num_protocols >= 3 && binding->host) {
+ status = dcerpc_floor_set_rhs_data(tower->floors,
+ &tower->floors[4],
+ binding->host);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
diff --git a/librpc/rpc/binding_handle.c b/librpc/rpc/binding_handle.c
new file mode 100644
index 0000000..41675e1
--- /dev/null
+++ b/librpc/rpc/binding_handle.c
@@ -0,0 +1,568 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc binding handle functions
+
+ Copyright (C) Stefan Metzmacher 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 <tevent.h>
+#include "../lib/util/tevent_ntstatus.h"
+#include "librpc/rpc/dcerpc.h"
+#include "rpc_common.h"
+
+struct dcerpc_binding_handle {
+ void *private_data;
+ const struct dcerpc_binding_handle_ops *ops;
+ const char *location;
+ const struct GUID *object;
+ const struct ndr_interface_table *table;
+ struct tevent_context *sync_ev;
+};
+
+static int dcerpc_binding_handle_destructor(struct dcerpc_binding_handle *b)
+{
+ return 0;
+}
+
+struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
+ const struct dcerpc_binding_handle_ops *ops,
+ const struct GUID *object,
+ const struct ndr_interface_table *table,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location)
+{
+ struct dcerpc_binding_handle *h;
+ void **ppstate = (void **)pstate;
+ void *state;
+
+ h = talloc_zero(mem_ctx, struct dcerpc_binding_handle);
+ if (h == NULL) {
+ return NULL;
+ }
+ h->ops = ops;
+ h->location = location;
+ h->object = object;
+ h->table = table;
+
+ state = talloc_zero_size(h, psize);
+ if (state == NULL) {
+ talloc_free(h);
+ return NULL;
+ }
+ talloc_set_name_const(state, type);
+
+ h->private_data = state;
+
+ talloc_set_destructor(h, dcerpc_binding_handle_destructor);
+
+ *ppstate = state;
+ return h;
+}
+
+void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h)
+{
+ return h->private_data;
+}
+
+void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
+ struct tevent_context *ev)
+{
+ h->sync_ev = ev;
+}
+
+bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h)
+{
+ return h->ops->is_connected(h);
+}
+
+uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
+ uint32_t timeout)
+{
+ return h->ops->set_timeout(h, timeout);
+}
+
+void dcerpc_binding_handle_auth_info(struct dcerpc_binding_handle *h,
+ enum dcerpc_AuthType *auth_type,
+ enum dcerpc_AuthLevel *auth_level)
+{
+ enum dcerpc_AuthType _auth_type;
+ enum dcerpc_AuthLevel _auth_level;
+
+ if (auth_type == NULL) {
+ auth_type = &_auth_type;
+ }
+
+ if (auth_level == NULL) {
+ auth_level = &_auth_level;
+ }
+
+ *auth_type = DCERPC_AUTH_TYPE_NONE;
+ *auth_level = DCERPC_AUTH_LEVEL_NONE;
+
+ if (h->ops->auth_info == NULL) {
+ return;
+ }
+
+ h->ops->auth_info(h, auth_type, auth_level);
+}
+
+struct dcerpc_binding_handle_raw_call_state {
+ const struct dcerpc_binding_handle_ops *ops;
+ uint8_t *out_data;
+ size_t out_length;
+ uint32_t out_flags;
+};
+
+static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq);
+
+struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ uint32_t opnum,
+ uint32_t in_flags,
+ const uint8_t *in_data,
+ size_t in_length)
+{
+ struct tevent_req *req;
+ struct dcerpc_binding_handle_raw_call_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dcerpc_binding_handle_raw_call_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ops = h->ops;
+ state->out_data = NULL;
+ state->out_length = 0;
+ state->out_flags = 0;
+
+ if (h->object != NULL) {
+ /*
+ * If an object is set on the binding handle,
+ * per request object passing is not allowed.
+ */
+ if (object != NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * We use the object from the binding handle
+ */
+ object = h->object;
+ }
+
+ subreq = state->ops->raw_call_send(state, ev, h,
+ object, opnum,
+ in_flags, in_data, in_length);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, dcerpc_binding_handle_raw_call_done, req);
+
+ return req;
+}
+
+static void dcerpc_binding_handle_raw_call_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct dcerpc_binding_handle_raw_call_state *state =
+ tevent_req_data(req,
+ struct dcerpc_binding_handle_raw_call_state);
+ NTSTATUS error;
+
+ error = state->ops->raw_call_recv(subreq, state,
+ &state->out_data,
+ &state->out_length,
+ &state->out_flags);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, error)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **out_data,
+ size_t *out_length,
+ uint32_t *out_flags)
+{
+ struct dcerpc_binding_handle_raw_call_state *state =
+ tevent_req_data(req,
+ struct dcerpc_binding_handle_raw_call_state);
+ NTSTATUS error;
+
+ if (tevent_req_is_nterror(req, &error)) {
+ tevent_req_received(req);
+ return error;
+ }
+
+ *out_data = talloc_move(mem_ctx, &state->out_data);
+ *out_length = state->out_length;
+ *out_flags = state->out_flags;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ uint32_t opnum,
+ uint32_t in_flags,
+ const uint8_t *in_data,
+ size_t in_length,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **out_data,
+ size_t *out_length,
+ uint32_t *out_flags)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *subreq;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ /*
+ * TODO: allow only one sync call
+ */
+
+ if (h->sync_ev) {
+ ev = h->sync_ev;
+ } else {
+ ev = samba_tevent_context_init(frame);
+ }
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ subreq = dcerpc_binding_handle_raw_call_send(frame, ev,
+ h, object, opnum,
+ in_flags,
+ in_data,
+ in_length);
+ if (subreq == NULL) {
+ goto fail;
+ }
+
+ if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
+ goto fail;
+ }
+
+ status = dcerpc_binding_handle_raw_call_recv(subreq,
+ mem_ctx,
+ out_data,
+ out_length,
+ out_flags);
+fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct dcerpc_binding_handle_disconnect_state {
+ const struct dcerpc_binding_handle_ops *ops;
+};
+
+static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq);
+
+struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h)
+{
+ struct tevent_req *req;
+ struct dcerpc_binding_handle_disconnect_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dcerpc_binding_handle_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = h->ops;
+
+ subreq = state->ops->disconnect_send(state, ev, h);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, dcerpc_binding_handle_disconnect_done, req);
+
+ return req;
+}
+
+static void dcerpc_binding_handle_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct dcerpc_binding_handle_disconnect_state *state =
+ tevent_req_data(req,
+ struct dcerpc_binding_handle_disconnect_state);
+ NTSTATUS error;
+
+ error = state->ops->disconnect_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, error)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req)
+{
+ NTSTATUS error;
+
+ if (tevent_req_is_nterror(req, &error)) {
+ tevent_req_received(req);
+ return error;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+struct dcerpc_binding_handle_call_state {
+ struct dcerpc_binding_handle *h;
+ const struct ndr_interface_call *call;
+ TALLOC_CTX *r_mem;
+ void *r_ptr;
+ struct ndr_push *push;
+ DATA_BLOB request;
+ DATA_BLOB response;
+ struct ndr_pull *pull;
+};
+
+static void dcerpc_binding_handle_call_done(struct tevent_req *subreq);
+
+struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ const struct ndr_interface_table *table,
+ uint32_t opnum,
+ TALLOC_CTX *r_mem,
+ void *r_ptr)
+{
+ struct tevent_req *req;
+ struct dcerpc_binding_handle_call_state *state;
+ struct tevent_req *subreq;
+ enum ndr_err_code ndr_err;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dcerpc_binding_handle_call_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (table != h->table) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_HANDLE);
+ return tevent_req_post(req, ev);
+ }
+
+ if (opnum >= table->num_calls) {
+ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+ return tevent_req_post(req, ev);
+ }
+
+ state->h = h;
+ state->call = &table->calls[opnum];
+
+ state->r_mem = r_mem;
+ state->r_ptr = r_ptr;
+
+ /* setup for a ndr_push_* call */
+ state->push = ndr_push_init_ctx(state);
+ if (tevent_req_nomem(state->push, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ if (h->ops->ref_alloc && h->ops->ref_alloc(h)) {
+ state->push->flags |= LIBNDR_FLAG_REF_ALLOC;
+ }
+
+ if (h->ops->push_bigendian && h->ops->push_bigendian(h)) {
+ state->push->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ if (h->ops->use_ndr64 && h->ops->use_ndr64(h)) {
+ state->push->flags |= LIBNDR_FLAG_NDR64;
+ }
+
+ if (h->ops->do_ndr_print) {
+ h->ops->do_ndr_print(h, NDR_IN | NDR_SET_VALUES,
+ state->r_ptr, state->call);
+ }
+
+ /* push the structure into a blob */
+ ndr_err = state->call->ndr_push(state->push, NDR_IN, state->r_ptr);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ NTSTATUS error;
+ error = ndr_map_error2ntstatus(ndr_err);
+ if (h->ops->ndr_push_failed) {
+ h->ops->ndr_push_failed(h, error,
+ state->r_ptr,
+ state->call);
+ }
+ tevent_req_nterror(req, error);
+ return tevent_req_post(req, ev);
+ }
+
+ /* retrieve the blob */
+ state->request = ndr_push_blob(state->push);
+
+ if (h->ops->ndr_validate_in) {
+ NTSTATUS error;
+ error = h->ops->ndr_validate_in(h, state,
+ &state->request,
+ state->call);
+ if (!NT_STATUS_IS_OK(error)) {
+ tevent_req_nterror(req, error);
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ subreq = dcerpc_binding_handle_raw_call_send(state, ev,
+ h, object, opnum,
+ state->push->flags,
+ state->request.data,
+ state->request.length);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, dcerpc_binding_handle_call_done, req);
+
+ return req;
+}
+
+static void dcerpc_binding_handle_call_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct dcerpc_binding_handle_call_state *state =
+ tevent_req_data(req,
+ struct dcerpc_binding_handle_call_state);
+ struct dcerpc_binding_handle *h = state->h;
+ NTSTATUS error;
+ uint32_t out_flags = 0;
+ enum ndr_err_code ndr_err;
+
+ error = dcerpc_binding_handle_raw_call_recv(subreq, state,
+ &state->response.data,
+ &state->response.length,
+ &out_flags);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, error)) {
+ return;
+ }
+
+ state->pull = ndr_pull_init_blob(&state->response, state);
+ if (tevent_req_nomem(state->pull, req)) {
+ return;
+ }
+ state->pull->flags = state->push->flags;
+
+ if (out_flags & LIBNDR_FLAG_BIGENDIAN) {
+ state->pull->flags |= LIBNDR_FLAG_BIGENDIAN;
+ } else {
+ state->pull->flags &= ~LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ state->pull->current_mem_ctx = state->r_mem;
+
+ /* pull the structure from the blob */
+ ndr_err = state->call->ndr_pull(state->pull, NDR_OUT, state->r_ptr);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ error = ndr_map_error2ntstatus(ndr_err);
+ if (h->ops->ndr_pull_failed) {
+ h->ops->ndr_pull_failed(h, error,
+ &state->response,
+ state->call);
+ }
+ tevent_req_nterror(req, error);
+ return;
+ }
+
+ if (h->ops->do_ndr_print) {
+ h->ops->do_ndr_print(h, NDR_OUT,
+ state->r_ptr, state->call);
+ }
+
+ if (h->ops->ndr_validate_out) {
+ error = h->ops->ndr_validate_out(h,
+ state->pull,
+ state->r_ptr,
+ state->call);
+ if (!NT_STATUS_IS_OK(error)) {
+ tevent_req_nterror(req, error);
+ return;
+ }
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ const struct ndr_interface_table *table,
+ uint32_t opnum,
+ TALLOC_CTX *r_mem,
+ void *r_ptr)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *subreq;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ /*
+ * TODO: allow only one sync call
+ */
+
+ if (h->sync_ev) {
+ ev = h->sync_ev;
+ } else {
+ ev = samba_tevent_context_init(frame);
+ }
+ if (ev == NULL) {
+ goto fail;
+ }
+
+ subreq = dcerpc_binding_handle_call_send(frame, ev,
+ h, object, table,
+ opnum, r_mem, r_ptr);
+ if (subreq == NULL) {
+ goto fail;
+ }
+
+ if (!tevent_req_poll_ntstatus(subreq, ev, &status)) {
+ goto fail;
+ }
+
+ status = dcerpc_binding_handle_call_recv(subreq);
+fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/librpc/rpc/dcerpc_error.c b/librpc/rpc/dcerpc_error.c
new file mode 100644
index 0000000..d5b5b66
--- /dev/null
+++ b/librpc/rpc/dcerpc_error.c
@@ -0,0 +1,153 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc fault functions
+
+ Copyright (C) Stefan Metzmacher 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 "librpc/rpc/dcerpc.h"
+#include "rpc_common.h"
+
+struct dcerpc_fault_table {
+ const char *errstr;
+ uint32_t faultcode;
+ NTSTATUS nt_status;
+};
+
+static const struct dcerpc_fault_table dcerpc_faults[] =
+{
+#define _FAULT_STR(x, s) { .errstr = #x , .faultcode = x, .nt_status = s }
+#define _FAULT_STR_NO_NT_MAPPING(x) _FAULT_STR(x, NT_STATUS_RPC_NOT_RPC_ERROR)
+ _FAULT_STR(DCERPC_NCA_S_COMM_FAILURE, NT_STATUS_RPC_COMM_FAILURE),
+ _FAULT_STR(DCERPC_NCA_S_OP_RNG_ERROR, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE),
+ _FAULT_STR(DCERPC_NCA_S_UNKNOWN_IF, NT_STATUS_RPC_UNKNOWN_IF),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_WRONG_BOOT_TIME),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_YOU_CRASHED),
+ _FAULT_STR(DCERPC_NCA_S_PROTO_ERROR, NT_STATUS_RPC_PROTOCOL_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_OUT_ARGS_TOO_BIG),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_SERVER_TOO_BUSY),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_STRING_TOO_LARGE),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_UNSUPPORTED_TYPE),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_ADDR_ERROR),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_FP_DIV_BY_ZERO, NT_STATUS_RPC_FP_DIV_ZERO),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_FP_UNDERFLOW, NT_STATUS_RPC_FP_UNDERFLOW),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_FP_OVERRFLOW, NT_STATUS_RPC_FP_OVERFLOW),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INT_DIV_BY_ZERO, NT_STATUS_RPC_FP_DIV_ZERO),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INT_OVERFLOW, NT_STATUS_RPC_FP_OVERFLOW),
+ /*
+ * Our callers expect NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
+ * instead of NT_STATUS_RPC_INVALID_TAG.
+ */
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_TAG, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_TAG, NT_STATUS_RPC_INVALID_TAG),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_INVALID_BOUND, NT_STATUS_RPC_INVALID_BOUND),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_RPC_VERSION_MISMATCH, NT_STATUS_RPC_PROTOCOL_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_UNSPEC_REJECT),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_BAD_ACTID),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_WHO_ARE_YOU_FAILED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_MANAGER_NOT_ENTERED),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_CANCEL, NT_STATUS_RPC_CALL_CANCELLED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_ILL_INST),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_FP_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_UNUSED_1C000011),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_UNSPEC),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_REMOTE_COMM_FAILURE),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_EMPTY),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_CLOSED, NT_STATUS_RPC_PIPE_CLOSED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_ORDER),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_PIPE_DISCIPLINE, NT_STATUS_RPC_PIPE_DISCIPLINE_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_COMM_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_PIPE_MEMORY),
+ _FAULT_STR(DCERPC_NCA_S_FAULT_CONTEXT_MISMATCH, NT_STATUS_RPC_SS_CONTEXT_MISMATCH),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_INVALID_PRES_CONTEXT_ID),
+ _FAULT_STR(DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL, NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_UNUSED_1C00001E),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_INVALID_CHECKSUM),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_INVALID_CRC),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_USER_DEFINED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_TX_OPEN_FAILED),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_CODESET_CONV_ERROR),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_OBJECT_NOT_FOUND),
+ _FAULT_STR_NO_NT_MAPPING(DCERPC_NCA_S_FAULT_NO_CLIENT_STUB),
+ _FAULT_STR(DCERPC_FAULT_OTHER, NT_STATUS_RPC_CALL_FAILED),
+ _FAULT_STR(DCERPC_FAULT_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED),
+ _FAULT_STR(DCERPC_FAULT_SERVER_UNAVAILABLE, NT_STATUS_RPC_SERVER_UNAVAILABLE),
+ _FAULT_STR(DCERPC_FAULT_NO_CALL_ACTIVE, NT_STATUS_RPC_NO_CALL_ACTIVE),
+ _FAULT_STR(DCERPC_FAULT_CANT_PERFORM, NT_STATUS_EPT_CANT_PERFORM_OP),
+ _FAULT_STR(DCERPC_FAULT_OUT_OF_RESOURCES, NT_STATUS_RPC_OUT_OF_RESOURCES),
+ _FAULT_STR(DCERPC_FAULT_BAD_STUB_DATA, NT_STATUS_RPC_BAD_STUB_DATA),
+ _FAULT_STR(DCERPC_FAULT_SEC_PKG_ERROR, NT_STATUS_RPC_SEC_PKG_ERROR),
+ { .faultcode = 0 }
+#undef _FAULT_STR
+};
+
+_PUBLIC_ const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code)
+{
+ int idx = 0;
+ WERROR werr = W_ERROR(fault_code);
+
+ while (dcerpc_faults[idx].errstr != NULL) {
+ if (dcerpc_faults[idx].faultcode == fault_code) {
+ return dcerpc_faults[idx].errstr;
+ }
+ idx++;
+ }
+
+ return win_errstr(werr);
+}
+
+_PUBLIC_ NTSTATUS dcerpc_fault_to_nt_status(uint32_t fault_code)
+{
+ int idx = 0;
+ WERROR werr = W_ERROR(fault_code);
+
+ if (fault_code == 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ while (dcerpc_faults[idx].errstr != NULL) {
+ if (dcerpc_faults[idx].faultcode == fault_code) {
+ return dcerpc_faults[idx].nt_status;
+ }
+ idx++;
+ }
+
+ return werror_to_ntstatus(werr);
+}
+
+_PUBLIC_ uint32_t dcerpc_fault_from_nt_status(NTSTATUS nt_status)
+{
+ int idx = 0;
+ WERROR werr;
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ return DCERPC_NCA_S_PROTO_ERROR;
+ }
+
+ while (dcerpc_faults[idx].errstr != NULL) {
+ if (NT_STATUS_EQUAL(dcerpc_faults[idx].nt_status, nt_status)) {
+ return dcerpc_faults[idx].faultcode;
+ }
+ idx++;
+ }
+
+ werr = ntstatus_to_werror(nt_status);
+
+ return W_ERROR_V(werr);
+}
diff --git a/librpc/rpc/dcerpc_helper.c b/librpc/rpc/dcerpc_helper.c
new file mode 100644
index 0000000..e1589f9
--- /dev/null
+++ b/librpc/rpc/dcerpc_helper.c
@@ -0,0 +1,132 @@
+/*
+ * 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 "librpc/gen_ndr/security.h"
+#include "librpc/gen_ndr/auth.h"
+#include "lib/crypto/gnutls_helpers.h"
+#include "libcli/security/dom_sid.h"
+#include "libcli/security/security_token.h"
+#include "libcli/smb/smb2_constants.h"
+
+#include "dcerpc_helper.h"
+
+static bool smb3_sid_parse(const struct dom_sid *sid,
+ uint16_t *pdialect,
+ uint16_t *pencrypt,
+ uint16_t *pcipher)
+{
+ uint16_t dialect;
+ uint16_t encrypt;
+ uint16_t cipher;
+
+ if (sid->sub_auths[0] != global_sid_Samba_SMB3.sub_auths[0]) {
+ return false;
+ }
+
+ dialect = sid->sub_auths[1];
+ if (dialect > 0x03ff) {
+ return false;
+ }
+
+ encrypt = sid->sub_auths[2];
+ if (encrypt > 0x0002) {
+ return false;
+ }
+
+ cipher = sid->sub_auths[3];
+ if (cipher > 256) {
+ /*
+ * It is unlikely that we
+ * ever have more then 256
+ * encryption algorithms
+ */
+ return false;
+ }
+
+ if (pdialect != NULL) {
+ *pdialect = dialect;
+ }
+
+ if (pencrypt != NULL) {
+ *pencrypt = encrypt;
+ }
+
+ if (pcipher != NULL) {
+ *pcipher = cipher;
+ }
+
+ return true;
+}
+
+bool dcerpc_is_transport_encrypted(struct auth_session_info *session_info)
+{
+ struct security_token *token = session_info->security_token;
+ struct dom_sid smb3_dom_sid = global_sid_Samba_SMB3;
+ const struct dom_sid *smb3_sid = NULL;
+ uint16_t dialect = 0;
+ uint16_t encrypt = 0;
+ uint16_t cipher = 0;
+ size_t num_smb3_sids;
+ bool ok;
+
+ num_smb3_sids = security_token_count_flag_sids(token,
+ &smb3_dom_sid,
+ 3,
+ &smb3_sid);
+ if (num_smb3_sids > 1) {
+ DBG_ERR("ERROR: The SMB3 SID has been detected %zu times\n",
+ num_smb3_sids);
+ return false;
+ }
+
+ if (smb3_sid == NULL) {
+ return false;
+ }
+
+ ok = smb3_sid_parse(smb3_sid, &dialect, &encrypt, &cipher);
+ if (!ok) {
+ DBG_ERR("Failed to parse SMB3 SID!\n");
+ return false;
+ }
+
+ DBG_DEBUG("SMB SID - dialect: %#04x, encrypt: %#04x, cipher: %#04x\n",
+ dialect,
+ encrypt,
+ cipher);
+
+ if (dialect < SMB3_DIALECT_REVISION_300) {
+ DBG_DEBUG("Invalid SMB3 dialect!\n");
+ return false;
+ }
+
+ if (encrypt != DCERPC_SMB_ENCRYPTION_REQUIRED) {
+ DBG_DEBUG("Invalid SMB3 encryption!\n");
+ return false;
+ }
+
+ switch (cipher) {
+ case SMB2_ENCRYPTION_AES128_CCM:
+ case SMB2_ENCRYPTION_AES128_GCM:
+ break;
+ default:
+ DBG_DEBUG("Invalid SMB3 cipher!\n");
+ return false;
+ }
+
+ return true;
+}
diff --git a/librpc/rpc/dcerpc_helper.h b/librpc/rpc/dcerpc_helper.h
new file mode 100644
index 0000000..c0f09ee
--- /dev/null
+++ b/librpc/rpc/dcerpc_helper.h
@@ -0,0 +1,26 @@
+/*
+ * 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 _DCERPC_HELPER_H
+#define _DCERPC_HELPER_H
+
+#define DCERPC_SMB_ENCRYPTION_OFF 0x0000
+#define DCERPC_SMB_ENCRYPTION_REQUIRED 0x0002
+
+bool dcerpc_is_transport_encrypted(struct auth_session_info *session_info);
+
+#endif /* _DCERPC_HELPER_H */
diff --git a/librpc/rpc/dcerpc_pkt_auth.c b/librpc/rpc/dcerpc_pkt_auth.c
new file mode 100644
index 0000000..5eb9c44
--- /dev/null
+++ b/librpc/rpc/dcerpc_pkt_auth.c
@@ -0,0 +1,500 @@
+/*
+ Unix SMB/CIFS implementation.
+ raw dcerpc operations
+
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Jelmer Vernooij 2004-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/network.h"
+#include <tevent.h>
+#include "lib/util/talloc_stack.h"
+#include "lib/util/debug.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/samba_util.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_util.h"
+#include "librpc/rpc/dcerpc_pkt_auth.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "rpc_common.h"
+#include "lib/util/bitmap.h"
+#include "auth/gensec/gensec.h"
+#include "lib/util/mkdir_p.h"
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/crypto.h>
+
+NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ bool check_pkt_auth_fields,
+ TALLOC_CTX *mem_ctx,
+ enum dcerpc_pkt_type ptype,
+ uint8_t required_flags,
+ uint8_t optional_flags,
+ uint8_t payload_offset,
+ DATA_BLOB *payload_and_verifier,
+ DATA_BLOB *raw_packet,
+ const struct ncacn_packet *pkt)
+{
+ NTSTATUS status;
+ struct dcerpc_auth auth;
+ uint32_t auth_length;
+
+ if (auth_state == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ status = dcerpc_verify_ncacn_packet_header(pkt, ptype,
+ payload_and_verifier->length,
+ required_flags, optional_flags);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ if (pkt->auth_length != 0) {
+ break;
+ }
+ return NT_STATUS_OK;
+ case DCERPC_AUTH_LEVEL_NONE:
+ if (pkt->auth_length != 0) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ return NT_STATUS_OK;
+
+ default:
+ return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
+ }
+
+ if (pkt->auth_length == 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (gensec == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
+ payload_and_verifier,
+ &auth, &auth_length, false);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (payload_and_verifier->length < auth_length) {
+ /*
+ * should be checked in dcerpc_pull_auth_trailer()
+ */
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ payload_and_verifier->length -= auth_length;
+
+ if (payload_and_verifier->length < auth.auth_pad_length) {
+ /*
+ * should be checked in dcerpc_pull_auth_trailer()
+ */
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (check_pkt_auth_fields) {
+ if (auth.auth_type != auth_state->auth_type) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (auth.auth_level != auth_state->auth_level) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ if (auth.auth_context_id != auth_state->auth_context_id) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+
+ /* check signature or unseal the packet */
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ status = gensec_unseal_packet(gensec,
+ raw_packet->data + payload_offset,
+ payload_and_verifier->length,
+ raw_packet->data,
+ raw_packet->length -
+ auth.credentials.length,
+ &auth.credentials);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_RPC_SEC_PKG_ERROR;
+ }
+ memcpy(payload_and_verifier->data,
+ raw_packet->data + payload_offset,
+ payload_and_verifier->length);
+ break;
+
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ status = gensec_check_packet(gensec,
+ payload_and_verifier->data,
+ payload_and_verifier->length,
+ raw_packet->data,
+ raw_packet->length -
+ auth.credentials.length,
+ &auth.credentials);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_RPC_SEC_PKG_ERROR;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ /* for now we ignore possible signatures here */
+ break;
+
+ default:
+ return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
+ }
+
+ /*
+ * remove the indicated amount of padding
+ *
+ * A possible overflow is checked above.
+ */
+ payload_and_verifier->length -= auth.auth_pad_length;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *raw_packet,
+ size_t sig_size,
+ uint8_t payload_offset,
+ const DATA_BLOB *payload,
+ const struct ncacn_packet *pkt)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ struct ndr_push *ndr = NULL;
+ uint32_t payload_length;
+ uint32_t whole_length;
+ DATA_BLOB blob = data_blob_null;
+ DATA_BLOB sig = data_blob_null;
+ struct dcerpc_auth _out_auth_info;
+ struct dcerpc_auth *out_auth_info = NULL;
+
+ *raw_packet = data_blob_null;
+
+ if (auth_state == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ if (sig_size == 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (gensec == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ _out_auth_info = (struct dcerpc_auth) {
+ .auth_type = auth_state->auth_type,
+ .auth_level = auth_state->auth_level,
+ .auth_context_id = auth_state->auth_context_id,
+ };
+ out_auth_info = &_out_auth_info;
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ /*
+ * TODO: let the gensec mech decide if it wants to generate a
+ * signature that might be needed for schannel...
+ */
+ if (sig_size != 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (gensec == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_NONE:
+ if (sig_size != 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ break;
+
+ default:
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ ndr = ndr_push_init_ctx(frame);
+ if (ndr == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (out_auth_info != NULL) {
+ /*
+ * pad to 16 byte multiple in the payload portion of the
+ * packet. This matches what w2k3 does. Note that we can't use
+ * ndr_push_align() as that is relative to the start of the
+ * whole packet, whereas w2k8 wants it relative to the start
+ * of the stub.
+ */
+ out_auth_info->auth_pad_length =
+ DCERPC_AUTH_PAD_LENGTH(payload->length);
+ ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ payload_length = payload->length +
+ out_auth_info->auth_pad_length;
+
+ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
+ out_auth_info);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ whole_length = ndr->offset;
+
+ ndr_err = ndr_push_zero(ndr, sig_size);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(frame);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ } else {
+ payload_length = payload->length;
+ whole_length = ndr->offset;
+ }
+
+ /* extract the whole packet as a blob */
+ blob = ndr_push_blob(ndr);
+
+ /*
+ * Setup the frag and auth length in the packet buffer.
+ * This is needed if the GENSEC mech does AEAD signing
+ * of the packet headers. The signature itself will be
+ * appended later.
+ */
+ dcerpc_set_frag_length(&blob, blob.length);
+ dcerpc_set_auth_length(&blob, sig_size);
+
+ /* sign or seal the packet */
+ switch (auth_state->auth_level) {
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ status = gensec_seal_packet(gensec,
+ frame,
+ blob.data + payload_offset,
+ payload_length,
+ blob.data,
+ whole_length,
+ &sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ status = gensec_sign_packet(gensec,
+ frame,
+ blob.data + payload_offset,
+ payload_length,
+ blob.data,
+ whole_length,
+ &sig);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
+ break;
+
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ case DCERPC_AUTH_LEVEL_NONE:
+ break;
+
+ default:
+ TALLOC_FREE(frame);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (sig.length != sig_size) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_RPC_SEC_PKG_ERROR;
+ }
+
+ if (sig_size != 0) {
+ memcpy(blob.data + whole_length, sig.data, sig_size);
+ }
+
+ *raw_packet = blob;
+ talloc_steal(mem_ctx, raw_packet->data);
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+}
+
+#ifdef DEVELOPER
+
+/*
+ * Save valid, well-formed DCE/RPC stubs to use as a seed for
+ * ndr_fuzz_X
+ */
+void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx,
+ DATA_BLOB raw_blob,
+ const char *dump_dir,
+ const char *iface_name,
+ ndr_flags_type flags,
+ int opnum,
+ bool ndr64)
+{
+ char *fname = NULL;
+ const char *sub_dir = NULL;
+ TALLOC_CTX *temp_ctx = talloc_new(mem_ctx);
+ DATA_BLOB blob;
+ int ret, rc;
+ uint8_t digest[20];
+ DATA_BLOB digest_blob;
+ char *digest_hex;
+ uint16_t fuzz_flags = 0;
+
+ /*
+ * We want to save the 'stub' in a per-pipe subdirectory, with
+ * the ndr_fuzz_X header 4 byte header. For the sake of
+ * convenience (this is a developer only function), we mkdir
+ * -p the sub-directories when they are needed.
+ */
+
+ if (dump_dir == NULL) {
+ return;
+ }
+
+ temp_ctx = talloc_stackframe();
+
+ sub_dir = talloc_asprintf(temp_ctx, "%s/%s",
+ dump_dir,
+ iface_name);
+ if (sub_dir == NULL) {
+ talloc_free(temp_ctx);
+ return;
+ }
+ ret = mkdir_p(sub_dir, 0755);
+ if (ret && errno != EEXIST) {
+ DBG_ERR("could not create %s\n", sub_dir);
+ talloc_free(temp_ctx);
+ return;
+ }
+
+ blob.length = raw_blob.length + 4;
+ blob.data = talloc_array(sub_dir,
+ uint8_t,
+ blob.length);
+ if (blob.data == NULL) {
+ DBG_ERR("could not allocate for fuzz seeds! (%s)\n",
+ iface_name);
+ talloc_free(temp_ctx);
+ return;
+ }
+
+ if (ndr64) {
+ fuzz_flags = 4;
+ }
+ if (flags & NDR_IN) {
+ fuzz_flags |= 1;
+ } else if (flags & NDR_OUT) {
+ fuzz_flags |= 2;
+ }
+
+ SSVAL(blob.data, 0, fuzz_flags);
+ SSVAL(blob.data, 2, opnum);
+
+ memcpy(&blob.data[4],
+ raw_blob.data,
+ raw_blob.length);
+
+ /*
+ * This matches how oss-fuzz names the corpus input files, due
+ * to a preference from libFuzzer
+ */
+ rc = gnutls_hash_fast(GNUTLS_DIG_SHA1,
+ blob.data,
+ blob.length,
+ digest);
+ if (rc < 0) {
+ /*
+ * This prints a better error message, eg if SHA1 is
+ * disabled
+ */
+ NTSTATUS status = gnutls_error_to_ntstatus(rc,
+ NT_STATUS_HASH_NOT_SUPPORTED);
+ DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s\n",
+ nt_errstr(status));
+ talloc_free(temp_ctx);
+ return;
+ }
+
+ digest_blob.data = digest;
+ digest_blob.length = sizeof(digest);
+ digest_hex = data_blob_hex_string_lower(temp_ctx, &digest_blob);
+
+ fname = talloc_asprintf(temp_ctx, "%s/%s",
+ sub_dir,
+ digest_hex);
+ if (fname == NULL) {
+ talloc_free(temp_ctx);
+ return;
+ }
+
+ /*
+ * If this fails, it is most likely because that file already
+ * exists. This is fine, it means we already have this
+ * sample
+ */
+ file_save(fname,
+ blob.data,
+ blob.length);
+
+ talloc_free(temp_ctx);
+}
+
+#endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */
diff --git a/librpc/rpc/dcerpc_pkt_auth.h b/librpc/rpc/dcerpc_pkt_auth.h
new file mode 100644
index 0000000..1dcee12
--- /dev/null
+++ b/librpc/rpc/dcerpc_pkt_auth.h
@@ -0,0 +1,59 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2010-2011
+ Copyright (C) Andrew Tridgell 2010-2011
+ Copyright (C) Simo Sorce 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 __LIBRPC_RPC_DCERPC_PKT_AUTH_H__
+#define __LIBRPC_RPC_DCERPC_PKT_AUTH_H__
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+#include "libcli/util/ntstatus.h"
+#include "librpc/rpc/rpc_common.h"
+#include "librpc/gen_ndr/dcerpc.h"
+
+NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ bool check_pkt_auth_fields,
+ TALLOC_CTX *mem_ctx,
+ enum dcerpc_pkt_type ptype,
+ uint8_t required_flags,
+ uint8_t optional_flags,
+ uint8_t payload_offset,
+ DATA_BLOB *payload_and_verifier,
+ DATA_BLOB *raw_packet,
+ const struct ncacn_packet *pkt);
+NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
+ struct gensec_security *gensec,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *raw_packet,
+ size_t sig_size,
+ uint8_t payload_offset,
+ const DATA_BLOB *payload,
+ const struct ncacn_packet *pkt);
+struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct ncacn_packet **pkt,
+ DATA_BLOB *buffer);
+
+#endif
diff --git a/librpc/rpc/dcerpc_samr.h b/librpc/rpc/dcerpc_samr.h
new file mode 100644
index 0000000..dac89a9
--- /dev/null
+++ b/librpc/rpc/dcerpc_samr.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 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/>.
+ */
+
+#ifndef _DCERPC_SAMR_H
+#define _DCERPC_SAMR_H
+
+#include <util/discard.h>
+#include "lib/util/data_blob.h"
+
+#define SAMR_AES256_ENC_KEY_STRING \
+ "Microsoft SAM encryption key AEAD-AES-256-CBC-HMAC-SHA512 16"
+#define SAMR_AES256_ENC_KEY_STRING_LEN 61 /* Including terminating null byte */
+
+#define SAMR_AES256_MAC_KEY_STRING \
+ "Microsoft SAM MAC key AEAD-AES-256-CBC-HMAC-SHA512 16"
+#define SAMR_AES256_MAC_KEY_STRING_LEN 54 /* Including terminating null byte */
+
+static const DATA_BLOB samr_aes256_enc_key_salt = {
+ .data = discard_const_p(uint8_t, SAMR_AES256_ENC_KEY_STRING),
+ .length = SAMR_AES256_ENC_KEY_STRING_LEN,
+};
+
+static const DATA_BLOB samr_aes256_mac_key_salt = {
+ .data = discard_const_p(uint8_t, SAMR_AES256_MAC_KEY_STRING),
+ .length = SAMR_AES256_MAC_KEY_STRING_LEN,
+};
+
+#endif /* _DCERPC_SAMR_H */
diff --git a/librpc/rpc/dcerpc_util.c b/librpc/rpc/dcerpc_util.c
new file mode 100644
index 0000000..e6f7fa6
--- /dev/null
+++ b/librpc/rpc/dcerpc_util.c
@@ -0,0 +1,1140 @@
+/*
+ Unix SMB/CIFS implementation.
+ raw dcerpc operations
+
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Jelmer Vernooij 2004-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/network.h"
+#include <tevent.h>
+#include "lib/tsocket/tsocket.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_util.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "rpc_common.h"
+#include "lib/util/bitmap.h"
+
+#undef strncasecmp
+
+/* we need to be able to get/set the fragment length without doing a full
+ decode */
+void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
+{
+ SMB_ASSERT(blob->length >= DCERPC_NCACN_PAYLOAD_OFFSET);
+
+ if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
+ SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
+ } else {
+ RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
+ }
+}
+
+uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
+{
+ SMB_ASSERT(blob->length >= DCERPC_NCACN_PAYLOAD_OFFSET);
+
+ if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
+ return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
+ } else {
+ return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
+ }
+}
+
+void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
+{
+ SMB_ASSERT(blob->length >= DCERPC_NCACN_PAYLOAD_OFFSET);
+
+ if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
+ SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
+ } else {
+ RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
+ }
+}
+
+uint16_t dcerpc_get_auth_length(const DATA_BLOB *blob)
+{
+ SMB_ASSERT(blob->length >= DCERPC_NCACN_PAYLOAD_OFFSET);
+
+ if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
+ return SVAL(blob->data, DCERPC_AUTH_LEN_OFFSET);
+ } else {
+ return RSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET);
+ }
+}
+
+uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob)
+{
+ SMB_ASSERT(blob->length >= DCERPC_NCACN_PAYLOAD_OFFSET);
+
+ return blob->data[DCERPC_DREP_OFFSET];
+}
+
+static uint16_t dcerpc_get_auth_context_offset(const DATA_BLOB *blob)
+{
+ uint16_t frag_len = dcerpc_get_frag_length(blob);
+ uint16_t auth_len = dcerpc_get_auth_length(blob);
+ uint16_t min_offset;
+ uint16_t offset;
+
+ if (auth_len == 0) {
+ return 0;
+ }
+
+ if (frag_len > blob->length) {
+ return 0;
+ }
+
+ if (auth_len > frag_len) {
+ return 0;
+ }
+
+ min_offset = DCERPC_NCACN_PAYLOAD_OFFSET + DCERPC_AUTH_TRAILER_LENGTH;
+ offset = frag_len - auth_len;
+ if (offset < min_offset) {
+ return 0;
+ }
+ offset -= DCERPC_AUTH_TRAILER_LENGTH;
+
+ return offset;
+}
+
+uint8_t dcerpc_get_auth_type(const DATA_BLOB *blob)
+{
+ uint16_t offset;
+
+ offset = dcerpc_get_auth_context_offset(blob);
+ if (offset == 0) {
+ return 0;
+ }
+
+ /*
+ * auth_typw is in the 1st byte
+ * of the auth trailer
+ */
+ offset += 0;
+
+ return blob->data[offset];
+}
+
+uint8_t dcerpc_get_auth_level(const DATA_BLOB *blob)
+{
+ uint16_t offset;
+
+ offset = dcerpc_get_auth_context_offset(blob);
+ if (offset == 0) {
+ return 0;
+ }
+
+ /*
+ * auth_level is in 2nd byte
+ * of the auth trailer
+ */
+ offset += 1;
+
+ return blob->data[offset];
+}
+
+uint32_t dcerpc_get_auth_context_id(const DATA_BLOB *blob)
+{
+ uint16_t offset;
+
+ offset = dcerpc_get_auth_context_offset(blob);
+ if (offset == 0) {
+ return 0;
+ }
+
+ /*
+ * auth_context_id is in the last 4 byte
+ * of the auth trailer
+ */
+ offset += 4;
+
+ if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
+ return IVAL(blob->data, offset);
+ } else {
+ return RIVAL(blob->data, offset);
+ }
+}
+
+/**
+* @brief Decodes a ncacn_packet
+*
+* @param mem_ctx The memory context on which to allocate the packet
+* elements
+* @param blob The blob of data to decode
+* @param r An empty ncacn_packet, must not be NULL
+*
+* @return a NTSTATUS error code
+*/
+NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ struct ncacn_packet *r)
+{
+ enum ndr_err_code ndr_err;
+ struct ndr_pull *ndr;
+
+ ndr = ndr_pull_init_blob(blob, mem_ctx);
+ if (!ndr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, r);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(ndr);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ talloc_free(ndr);
+
+ if (r->frag_length != blob->length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+* @brief Pull a dcerpc_auth structure, taking account of any auth
+* padding in the blob. For request/response packets we pass
+* the whole data blob, so auth_data_only must be set to false
+* as the blob contains data+pad+auth and no just pad+auth.
+*
+* @param pkt - The ncacn_packet structure
+* @param mem_ctx - The mem_ctx used to allocate dcerpc_auth elements
+* @param pkt_trailer - The packet trailer data, usually the trailing
+* auth_info blob, but in the request/response case
+* this is the stub_and_verifier blob.
+* @param auth - A preallocated dcerpc_auth *empty* structure
+* @param auth_length - The length of the auth trail, sum of auth header
+* length and pkt->auth_length
+* @param auth_data_only - Whether the pkt_trailer includes only the auth_blob
+* (+ padding) or also other data.
+*
+* @return - A NTSTATUS error code.
+*/
+NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *pkt_trailer,
+ struct dcerpc_auth *auth,
+ uint32_t *_auth_length,
+ bool auth_data_only)
+{
+ struct ndr_pull *ndr;
+ enum ndr_err_code ndr_err;
+ uint16_t data_and_pad;
+ uint16_t auth_length;
+ uint32_t tmp_length;
+ uint32_t max_pad_len = 0;
+
+ ZERO_STRUCTP(auth);
+ if (_auth_length != NULL) {
+ *_auth_length = 0;
+
+ if (auth_data_only) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ } else {
+ if (!auth_data_only) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ }
+
+ /* Paranoia checks for auth_length. The caller should check this... */
+ if (pkt->auth_length == 0) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ /* Paranoia checks for auth_length. The caller should check this... */
+ if (pkt->auth_length > pkt->frag_length) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET;
+ tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
+ tmp_length += pkt->auth_length;
+ if (tmp_length > pkt->frag_length) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ if (pkt_trailer->length > UINT16_MAX) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length;
+ if (pkt_trailer->length < auth_length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ data_and_pad = pkt_trailer->length - auth_length;
+
+ ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx);
+ if (!ndr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
+ ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ ndr_err = ndr_pull_advance(ndr, data_and_pad);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(ndr);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(ndr);
+ ZERO_STRUCTP(auth);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ /*
+ * Make sure the padding would not exceed
+ * the frag_length.
+ *
+ * Here we assume at least 24 bytes for the
+ * payload specific header the value of
+ * DCERPC_{REQUEST,RESPONSE}_LENGTH.
+ *
+ * We use this also for BIND_*, ALTER_* and AUTH3 pdus.
+ *
+ * We need this check before we ignore possible
+ * invalid values. See also bug #11982.
+ *
+ * This check is mainly used to generate the correct
+ * error for BIND_*, ALTER_* and AUTH3 pdus.
+ *
+ * We always have the 'if (data_and_pad < auth->auth_pad_length)'
+ * protection for REQUEST and RESPONSE pdus, where the
+ * auth_pad_length field is actually used by the caller.
+ */
+ tmp_length = DCERPC_REQUEST_LENGTH;
+ tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
+ tmp_length += pkt->auth_length;
+ if (tmp_length < pkt->frag_length) {
+ max_pad_len = pkt->frag_length - tmp_length;
+ }
+ if (max_pad_len < auth->auth_pad_length) {
+ DEBUG(1, (__location__ ": ERROR: pad length too large. "
+ "max %"PRIu32" got %"PRIu8"\n",
+ max_pad_len,
+ auth->auth_pad_length));
+ talloc_free(ndr);
+ ZERO_STRUCTP(auth);
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ /*
+ * This is a workaround for a bug in old
+ * Samba releases. For BIND_ACK <= 3.5.x
+ * and for ALTER_RESP <= 4.2.x (see bug #11061)
+ *
+ * See also bug #11982.
+ */
+ if (auth_data_only && data_and_pad == 0 &&
+ auth->auth_pad_length > 0) {
+ /*
+ * we need to ignore invalid auth_pad_length
+ * values for BIND_*, ALTER_* and AUTH3 pdus.
+ */
+ auth->auth_pad_length = 0;
+ }
+
+ if (data_and_pad < auth->auth_pad_length) {
+ DBG_WARNING(__location__ ": ERROR: pad length too long. "
+ "Calculated %"PRIu16" (pkt_trailer->length=%zu - auth_length=%"PRIu16") "
+ "was less than auth_pad_length=%"PRIu8"\n",
+ data_and_pad,
+ pkt_trailer->length,
+ auth_length,
+ auth->auth_pad_length);
+ talloc_free(ndr);
+ ZERO_STRUCTP(auth);
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (auth_data_only && data_and_pad > auth->auth_pad_length) {
+ DBG_WARNING(__location__ ": ERROR: auth_data_only pad length mismatch. "
+ "Client sent a longer BIND packet than expected by %"PRIu16" bytes "
+ "(pkt_trailer->length=%zu - auth_length=%"PRIu16") "
+ "= %"PRIu16" auth_pad_length=%"PRIu8"\n",
+ data_and_pad - auth->auth_pad_length,
+ pkt_trailer->length,
+ auth_length,
+ data_and_pad,
+ auth->auth_pad_length);
+ talloc_free(ndr);
+ ZERO_STRUCTP(auth);
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (auth_data_only && data_and_pad != auth->auth_pad_length) {
+ DBG_WARNING(__location__ ": ERROR: auth_data_only pad length mismatch. "
+ "Calculated %"PRIu16" (pkt_trailer->length=%zu - auth_length=%"PRIu16") "
+ "but auth_pad_length=%"PRIu8"\n",
+ data_and_pad,
+ pkt_trailer->length,
+ auth_length,
+ auth->auth_pad_length);
+ talloc_free(ndr);
+ ZERO_STRUCTP(auth);
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ DBG_DEBUG("auth_pad_length %"PRIu8"\n",
+ auth->auth_pad_length);
+
+ talloc_steal(mem_ctx, auth->credentials.data);
+ talloc_free(ndr);
+
+ if (_auth_length != NULL) {
+ *_auth_length = auth_length;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+* @brief Verify the fields in ncacn_packet header.
+*
+* @param pkt - The ncacn_packet structure
+* @param ptype - The expected PDU type
+* @param max_auth_info - The maximum size of a possible auth trailer
+* @param required_flags - The required flags for the pdu.
+* @param optional_flags - The possible optional flags for the pdu.
+*
+* @return - A NTSTATUS error code.
+*/
+NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
+ enum dcerpc_pkt_type ptype,
+ size_t max_auth_info,
+ uint8_t required_flags,
+ uint8_t optional_flags)
+{
+ if (pkt->rpc_vers != 5) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (pkt->rpc_vers_minor != 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (pkt->auth_length > pkt->frag_length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (pkt->ptype != ptype) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (max_auth_info > UINT16_MAX) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (pkt->auth_length > 0) {
+ size_t max_auth_length;
+
+ if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH;
+
+ if (pkt->auth_length > max_auth_length) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ }
+
+ if ((pkt->pfc_flags & required_flags) != required_flags) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ if (pkt->pfc_flags & ~(optional_flags|required_flags)) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (pkt->drep[0] & ~DCERPC_DREP_LE) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ if (pkt->drep[1] != 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ if (pkt->drep[2] != 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+ if (pkt->drep[3] != 0) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct dcerpc_read_ncacn_packet_state {
+#if 0
+ struct {
+ } caller;
+#endif
+ DATA_BLOB buffer;
+ struct ncacn_packet *pkt;
+};
+
+static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count);
+static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq);
+
+struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream)
+{
+ struct tevent_req *req;
+ struct dcerpc_read_ncacn_packet_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dcerpc_read_ncacn_packet_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->pkt = talloc_zero(state, struct ncacn_packet);
+ if (tevent_req_nomem(state->pkt, req)) {
+ goto post;
+ }
+
+ subreq = tstream_readv_pdu_send(state, ev,
+ stream,
+ dcerpc_read_ncacn_packet_next_vector,
+ state);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, dcerpc_read_ncacn_packet_done, req);
+
+ return req;
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct iovec **_vector,
+ size_t *_count)
+{
+ struct dcerpc_read_ncacn_packet_state *state =
+ talloc_get_type_abort(private_data,
+ struct dcerpc_read_ncacn_packet_state);
+ struct iovec *vector;
+ off_t ofs = 0;
+
+ if (state->buffer.length == 0) {
+ /*
+ * first get enough to read the fragment length
+ *
+ * We read the full fixed ncacn_packet header
+ * in order to make wireshark happy with
+ * pcap files from socket_wrapper.
+ */
+ ofs = 0;
+ state->buffer.length = DCERPC_NCACN_PAYLOAD_OFFSET;
+ state->buffer.data = talloc_array(state, uint8_t,
+ state->buffer.length);
+ if (!state->buffer.data) {
+ return -1;
+ }
+ } else if (state->buffer.length == DCERPC_NCACN_PAYLOAD_OFFSET) {
+ /* now read the fragment length and allocate the full buffer */
+ size_t frag_len = dcerpc_get_frag_length(&state->buffer);
+
+ ofs = state->buffer.length;
+
+ if (frag_len <= ofs) {
+ /*
+ * With frag_len == ofs, we are done, this is likely
+ * a DCERPC_PKT_CO_CANCEL and DCERPC_PKT_ORPHANED
+ * without any payload.
+ *
+ * Otherwise it's a broken packet and we
+ * let the caller deal with it.
+ */
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
+ }
+
+ state->buffer.data = talloc_realloc(state,
+ state->buffer.data,
+ uint8_t, frag_len);
+ if (!state->buffer.data) {
+ return -1;
+ }
+ state->buffer.length = frag_len;
+ } else {
+ /* if we reach this we have a full fragment */
+ *_vector = NULL;
+ *_count = 0;
+ return 0;
+ }
+
+ /* now create the vector that we want to be filled */
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (!vector) {
+ return -1;
+ }
+
+ vector[0].iov_base = (void *) (state->buffer.data + ofs);
+ vector[0].iov_len = state->buffer.length - ofs;
+
+ *_vector = vector;
+ *_count = 1;
+ return 0;
+}
+
+static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct dcerpc_read_ncacn_packet_state *state = tevent_req_data(req,
+ struct dcerpc_read_ncacn_packet_state);
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+
+ ret = tstream_readv_pdu_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix_common(sys_errno);
+ tevent_req_nterror(req, status);
+ return;
+ }
+
+ status = dcerpc_pull_ncacn_packet(state->pkt,
+ &state->buffer,
+ state->pkt);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct ncacn_packet **pkt,
+ DATA_BLOB *buffer)
+{
+ struct dcerpc_read_ncacn_packet_state *state = tevent_req_data(req,
+ struct dcerpc_read_ncacn_packet_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *pkt = talloc_move(mem_ctx, &state->pkt);
+ if (buffer) {
+ buffer->data = talloc_move(mem_ctx, &state->buffer.data);
+ buffer->length = state->buffer.length;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx,
+ enum dcerpc_transport_t transport,
+ const struct ndr_interface_table *table)
+{
+ NTSTATUS status;
+ const char *p = NULL;
+ const char *endpoint = NULL;
+ uint32_t i;
+ struct dcerpc_binding *default_binding = NULL;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ /* Find one of the default pipes for this interface */
+
+ for (i = 0; i < table->endpoints->count; i++) {
+ enum dcerpc_transport_t dtransport;
+ const char *dendpoint;
+
+ status = dcerpc_parse_binding(frame, table->endpoints->names[i],
+ &default_binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ continue;
+ }
+
+ dtransport = dcerpc_binding_get_transport(default_binding);
+ dendpoint = dcerpc_binding_get_string_option(default_binding,
+ "endpoint");
+ if (dendpoint == NULL) {
+ TALLOC_FREE(default_binding);
+ continue;
+ }
+
+ if (transport == NCA_UNKNOWN) {
+ transport = dtransport;
+ }
+
+ if (transport != dtransport) {
+ TALLOC_FREE(default_binding);
+ continue;
+ }
+
+ p = dendpoint;
+ break;
+ }
+
+ if (p == NULL) {
+ goto done;
+ }
+
+ /*
+ * extract the pipe name without \\pipe from for example
+ * ncacn_np:[\\pipe\\epmapper]
+ */
+ if (transport == NCACN_NP) {
+ if (strncasecmp(p, "\\pipe\\", 6) == 0) {
+ p += 6;
+ }
+ if (p[0] == '\\') {
+ p += 1;
+ }
+ }
+
+ endpoint = talloc_strdup(mem_ctx, p);
+
+ done:
+ talloc_free(frame);
+ return endpoint;
+}
+
+struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struct ncacn_packet *pkt)
+{
+ struct dcerpc_sec_vt_header2 ret;
+
+ ZERO_STRUCT(ret);
+ ret.ptype = pkt->ptype;
+ memcpy(&ret.drep, pkt->drep, sizeof(ret.drep));
+ ret.call_id = pkt->call_id;
+
+ switch (pkt->ptype) {
+ case DCERPC_PKT_REQUEST:
+ ret.context_id = pkt->u.request.context_id;
+ ret.opnum = pkt->u.request.opnum;
+ break;
+
+ case DCERPC_PKT_RESPONSE:
+ ret.context_id = pkt->u.response.context_id;
+ break;
+
+ case DCERPC_PKT_FAULT:
+ ret.context_id = pkt->u.fault.context_id;
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
+ const struct dcerpc_sec_vt_header2 *v2)
+{
+ if (v1->ptype != v2->ptype) {
+ return false;
+ }
+
+ if (memcmp(v1->drep, v2->drep, sizeof(v1->drep)) != 0) {
+ return false;
+ }
+
+ if (v1->call_id != v2->call_id) {
+ return false;
+ }
+
+ if (v1->context_id != v2->context_id) {
+ return false;
+ }
+
+ if (v1->opnum != v2->opnum) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool dcerpc_sec_vt_is_valid(const struct dcerpc_sec_verification_trailer *r)
+{
+ bool ret = false;
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct bitmap *commands_seen;
+ int i;
+
+ if (r->count.count == 0) {
+ ret = true;
+ goto done;
+ }
+
+ if (memcmp(r->magic, DCERPC_SEC_VT_MAGIC, sizeof(r->magic)) != 0) {
+ goto done;
+ }
+
+ commands_seen = bitmap_talloc(frame, DCERPC_SEC_VT_COMMAND_ENUM + 1);
+ if (commands_seen == NULL) {
+ goto done;
+ }
+
+ for (i=0; i < r->count.count; i++) {
+ enum dcerpc_sec_vt_command_enum cmd =
+ r->commands[i].command & DCERPC_SEC_VT_COMMAND_ENUM;
+
+ if (bitmap_query(commands_seen, cmd)) {
+ /* Each command must appear at most once. */
+ goto done;
+ }
+ bitmap_set(commands_seen, cmd);
+
+ switch (cmd) {
+ case DCERPC_SEC_VT_COMMAND_BITMASK1:
+ case DCERPC_SEC_VT_COMMAND_PCONTEXT:
+ case DCERPC_SEC_VT_COMMAND_HEADER2:
+ break;
+ default:
+ if ((r->commands[i].u._unknown.length % 4) != 0) {
+ goto done;
+ }
+ break;
+ }
+ }
+ ret = true;
+done:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+static bool dcerpc_sec_vt_bitmask_check(const uint32_t *bitmask1,
+ struct dcerpc_sec_vt *c)
+{
+ if (bitmask1 == NULL) {
+ if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
+ DEBUG(10, ("SEC_VT check Bitmask1 must_process_command "
+ "failed\n"));
+ return false;
+ }
+
+ return true;
+ }
+
+ if ((c->u.bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING)
+ && (!(*bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING))) {
+ DEBUG(10, ("SEC_VT check Bitmask1 client_header_signing "
+ "failed\n"));
+ return false;
+ }
+ return true;
+}
+
+static bool dcerpc_sec_vt_pctx_check(const struct dcerpc_sec_vt_pcontext *pcontext,
+ struct dcerpc_sec_vt *c)
+{
+ bool ok;
+
+ if (pcontext == NULL) {
+ if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
+ DEBUG(10, ("SEC_VT check Pcontext must_process_command "
+ "failed\n"));
+ return false;
+ }
+
+ return true;
+ }
+
+ ok = ndr_syntax_id_equal(&pcontext->abstract_syntax,
+ &c->u.pcontext.abstract_syntax);
+ if (!ok) {
+ struct ndr_syntax_id_buf buf1, buf2;
+ DEBUG(10, ("SEC_VT check pcontext abstract_syntax failed: "
+ "%s vs. %s\n",
+ ndr_syntax_id_buf_string(
+ &pcontext->abstract_syntax, &buf1),
+ ndr_syntax_id_buf_string(
+ &c->u.pcontext.abstract_syntax, &buf2)));
+ return false;
+ }
+ ok = ndr_syntax_id_equal(&pcontext->transfer_syntax,
+ &c->u.pcontext.transfer_syntax);
+ if (!ok) {
+ struct ndr_syntax_id_buf buf1, buf2;
+ DEBUG(10, ("SEC_VT check pcontext transfer_syntax failed: "
+ "%s vs. %s\n",
+ ndr_syntax_id_buf_string(
+ &pcontext->transfer_syntax, &buf1),
+ ndr_syntax_id_buf_string(
+ &c->u.pcontext.transfer_syntax, &buf2)));
+ return false;
+ }
+
+ return true;
+}
+
+static bool dcerpc_sec_vt_hdr2_check(const struct dcerpc_sec_vt_header2 *header2,
+ struct dcerpc_sec_vt *c)
+{
+ if (header2 == NULL) {
+ if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
+ DEBUG(10, ("SEC_VT check Header2 must_process_command failed\n"));
+ return false;
+ }
+
+ return true;
+ }
+
+ if (!dcerpc_sec_vt_header2_equal(header2, &c->u.header2)) {
+ DEBUG(10, ("SEC_VT check Header2 failed\n"));
+ return false;
+ }
+
+ return true;
+}
+
+bool dcerpc_sec_verification_trailer_check(
+ const struct dcerpc_sec_verification_trailer *vt,
+ const uint32_t *bitmask1,
+ const struct dcerpc_sec_vt_pcontext *pcontext,
+ const struct dcerpc_sec_vt_header2 *header2)
+{
+ size_t i;
+
+ if (!dcerpc_sec_vt_is_valid(vt)) {
+ return false;
+ }
+
+ for (i=0; i < vt->count.count; i++) {
+ bool ok;
+ struct dcerpc_sec_vt *c = &vt->commands[i];
+
+ switch (c->command & DCERPC_SEC_VT_COMMAND_ENUM) {
+ case DCERPC_SEC_VT_COMMAND_BITMASK1:
+ ok = dcerpc_sec_vt_bitmask_check(bitmask1, c);
+ if (!ok) {
+ return false;
+ }
+ break;
+
+ case DCERPC_SEC_VT_COMMAND_PCONTEXT:
+ ok = dcerpc_sec_vt_pctx_check(pcontext, c);
+ if (!ok) {
+ return false;
+ }
+ break;
+
+ case DCERPC_SEC_VT_COMMAND_HEADER2: {
+ ok = dcerpc_sec_vt_hdr2_check(header2, c);
+ if (!ok) {
+ return false;
+ }
+ break;
+ }
+
+ default:
+ if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
+ DEBUG(10, ("SEC_VT check Unknown must_process_command failed\n"));
+ return false;
+ }
+
+ break;
+ }
+ }
+
+ return true;
+}
+
+static const struct ndr_syntax_id dcerpc_bind_time_features_prefix = {
+ .uuid = {
+ .time_low = 0x6cb71c2c,
+ .time_mid = 0x9812,
+ .time_hi_and_version = 0x4540,
+ .clock_seq = {0x00, 0x00},
+ .node = {0x00,0x00,0x00,0x00,0x00,0x00}
+ },
+ .if_version = 1,
+};
+
+bool dcerpc_extract_bind_time_features(struct ndr_syntax_id s, uint64_t *_features)
+{
+ uint8_t values[8];
+ uint64_t features = 0;
+
+ values[0] = s.uuid.clock_seq[0];
+ values[1] = s.uuid.clock_seq[1];
+ values[2] = s.uuid.node[0];
+ values[3] = s.uuid.node[1];
+ values[4] = s.uuid.node[2];
+ values[5] = s.uuid.node[3];
+ values[6] = s.uuid.node[4];
+ values[7] = s.uuid.node[5];
+
+ ZERO_STRUCT(s.uuid.clock_seq);
+ ZERO_STRUCT(s.uuid.node);
+
+ if (!ndr_syntax_id_equal(&s, &dcerpc_bind_time_features_prefix)) {
+ if (_features != NULL) {
+ *_features = 0;
+ }
+ return false;
+ }
+
+ features = BVAL(values, 0);
+
+ if (_features != NULL) {
+ *_features = features;
+ }
+
+ return true;
+}
+
+struct ndr_syntax_id dcerpc_construct_bind_time_features(uint64_t features)
+{
+ struct ndr_syntax_id s = dcerpc_bind_time_features_prefix;
+ uint8_t values[8];
+
+ SBVAL(values, 0, features);
+
+ s.uuid.clock_seq[0] = values[0];
+ s.uuid.clock_seq[1] = values[1];
+ s.uuid.node[0] = values[2];
+ s.uuid.node[1] = values[3];
+ s.uuid.node[2] = values[4];
+ s.uuid.node[3] = values[5];
+ s.uuid.node[4] = values[6];
+ s.uuid.node[5] = values[7];
+
+ return s;
+}
+
+NTSTATUS dcerpc_generic_session_key(DATA_BLOB *session_key)
+{
+ *session_key = data_blob_null;
+
+ /* this took quite a few CPU cycles to find ... */
+ session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC");
+ session_key->length = 16;
+ return NT_STATUS_OK;
+}
+
+/*
+ push a ncacn_packet into a blob, potentially with auth info
+*/
+NTSTATUS dcerpc_ncacn_push_auth(DATA_BLOB *blob,
+ TALLOC_CTX *mem_ctx,
+ struct ncacn_packet *pkt,
+ struct dcerpc_auth *auth_info)
+{
+ struct ndr_push *ndr;
+ enum ndr_err_code ndr_err;
+
+ ndr = ndr_push_init_ctx(mem_ctx);
+ if (!ndr) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (auth_info) {
+ pkt->auth_length = auth_info->credentials.length;
+ } else {
+ pkt->auth_length = 0;
+ }
+
+ ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+
+ if (auth_info) {
+#if 0
+ /* the s3 rpc server doesn't handle auth padding in
+ bind requests. Use zero auth padding to keep us
+ working with old servers */
+ uint32_t offset = ndr->offset;
+ ndr_err = ndr_push_align(ndr, 16);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ auth_info->auth_pad_length = ndr->offset - offset;
+#else
+ auth_info->auth_pad_length = 0;
+#endif
+ ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ }
+
+ *blob = ndr_push_blob(ndr);
+
+ /* fill in the frag length */
+ dcerpc_set_frag_length(blob, blob->length);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ log a rpc packet in a format suitable for ndrdump. This is especially useful
+ for sealed packets, where ethereal cannot easily see the contents
+
+ this triggers if "dcesrv:stubs directory" is set and present
+ for all packets that fail to parse
+*/
+void dcerpc_log_packet(const char *packet_log_dir,
+ const char *interface_name,
+ uint32_t opnum, ndr_flags_type flags,
+ const DATA_BLOB *pkt,
+ const char *why)
+{
+ const int num_examples = 20;
+ int i;
+
+ if (packet_log_dir == NULL) {
+ return;
+ }
+
+ for (i=0;i<num_examples;i++) {
+ char *name=NULL;
+ int ret;
+ bool saved;
+ ret = asprintf(&name, "%s/%s-%"PRIu32".%d.%s.%s",
+ packet_log_dir, interface_name, opnum, i,
+ (flags&NDR_IN)?"in":"out",
+ why);
+ if (ret == -1) {
+ return;
+ }
+
+ saved = file_save(name, pkt->data, pkt->length);
+ if (saved) {
+ DBG_DEBUG("Logged rpc packet to %s\n", name);
+ free(name);
+ break;
+ }
+ free(name);
+ }
+}
diff --git a/librpc/rpc/dcerpc_util.h b/librpc/rpc/dcerpc_util.h
new file mode 100644
index 0000000..4e49e3e
--- /dev/null
+++ b/librpc/rpc/dcerpc_util.h
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2010-2011
+ Copyright (C) Andrew Tridgell 2010-2011
+ Copyright (C) Simo Sorce 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 __LIBRPC_RPC_DCERPC_UTIL_H__
+#define __LIBRPC_RPC_DCERPC_UTIL_H__
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+#include "librpc/rpc/rpc_common.h"
+#include "librpc/gen_ndr/dcerpc.h"
+
+void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v);
+uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob);
+void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v);
+uint16_t dcerpc_get_auth_length(const DATA_BLOB *blob);
+uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob);
+uint8_t dcerpc_get_auth_type(const DATA_BLOB *blob);
+uint8_t dcerpc_get_auth_level(const DATA_BLOB *blob);
+uint32_t dcerpc_get_auth_context_id(const DATA_BLOB *blob);
+const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx,
+ enum dcerpc_transport_t transport,
+ const struct ndr_interface_table *table);
+
+NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ struct ncacn_packet *r);
+
+/**
+* @brief Pull a dcerpc_auth structure, taking account of any auth
+* padding in the blob. For request/response packets we pass
+* the whole data blob, so auth_data_only must be set to false
+* as the blob contains data+pad+auth and no just pad+auth.
+*
+* @param pkt - The ncacn_packet structure
+* @param mem_ctx - The mem_ctx used to allocate dcerpc_auth elements
+* @param pkt_trailer - The packet trailer data, usually the trailing
+* auth_info blob, but in the request/response case
+* this is the stub_and_verifier blob.
+* @param auth - A preallocated dcerpc_auth *empty* structure
+* @param auth_length - The length of the auth trail, sum of auth header
+* length and pkt->auth_length
+* @param auth_data_only - Whether the pkt_trailer includes only the auth_blob
+* (+ padding) or also other data.
+*
+* @return - A NTSTATUS error code.
+*/
+NTSTATUS dcerpc_pull_auth_trailer(const struct ncacn_packet *pkt,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *pkt_trailer,
+ struct dcerpc_auth *auth,
+ uint32_t *auth_length,
+ bool auth_data_only);
+NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
+ enum dcerpc_pkt_type ptype,
+ size_t max_auth_info,
+ uint8_t required_flags,
+ uint8_t optional_flags);
+struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tstream_context *stream);
+NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ struct ncacn_packet **pkt,
+ DATA_BLOB *buffer);
+
+#endif
diff --git a/librpc/rpc/dcesrv_auth.c b/librpc/rpc/dcesrv_auth.c
new file mode 100644
index 0000000..1fc6255
--- /dev/null
+++ b/librpc/rpc/dcesrv_auth.c
@@ -0,0 +1,703 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ server side dcerpc authentication code
+
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan (metze) Metzmacher 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 "librpc/rpc/dcesrv_core.h"
+#include "librpc/rpc/dcesrv_core_proto.h"
+#include "librpc/rpc/dcerpc_util.h"
+#include "librpc/rpc/dcerpc_pkt_auth.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "auth/auth.h"
+#include "param/param.h"
+
+static NTSTATUS dcesrv_auth_negotiate_hdr_signing(struct dcesrv_call_state *call,
+ struct ncacn_packet *pkt)
+{
+ struct dcesrv_connection *dce_conn = call->conn;
+ struct dcesrv_auth *a = NULL;
+
+ if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
+ return NT_STATUS_OK;
+ }
+
+ if (dce_conn->client_hdr_signing) {
+ if (dce_conn->negotiated_hdr_signing && pkt != NULL) {
+ pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+ }
+ return NT_STATUS_OK;
+ }
+
+ dce_conn->client_hdr_signing = true;
+ dce_conn->negotiated_hdr_signing = dce_conn->support_hdr_signing;
+
+ if (!dce_conn->negotiated_hdr_signing) {
+ return NT_STATUS_OK;
+ }
+
+ if (pkt != NULL) {
+ pkt->pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
+ }
+
+ a = call->conn->default_auth_state;
+ if (a->gensec_security != NULL) {
+ gensec_want_feature(a->gensec_security,
+ GENSEC_FEATURE_SIGN_PKT_HEADER);
+ }
+
+ for (a = call->conn->auth_states; a != NULL; a = a->next) {
+ if (a->gensec_security == NULL) {
+ continue;
+ }
+
+ gensec_want_feature(a->gensec_security,
+ GENSEC_FEATURE_SIGN_PKT_HEADER);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static bool dcesrv_auth_prepare_gensec(struct dcesrv_call_state *call)
+{
+ struct dcesrv_connection *dce_conn = call->conn;
+ struct dcesrv_auth *auth = call->auth_state;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+ NTSTATUS status;
+
+ if (auth->auth_started) {
+ return false;
+ }
+
+ auth->auth_started = true;
+
+ if (auth->auth_invalid) {
+ return false;
+ }
+
+ if (auth->auth_finished) {
+ return false;
+ }
+
+ if (auth->gensec_security != NULL) {
+ return false;
+ }
+
+ switch (call->in_auth_info.auth_level) {
+ case DCERPC_AUTH_LEVEL_CONNECT:
+ case DCERPC_AUTH_LEVEL_CALL:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ /*
+ * We evaluate auth_type only if auth_level was valid
+ */
+ break;
+ default:
+ /*
+ * Setting DCERPC_AUTH_LEVEL_NONE,
+ * gives the caller the reject_reason
+ * as auth_context_id.
+ *
+ * Note: DCERPC_AUTH_LEVEL_NONE == 1
+ */
+ auth->auth_type = DCERPC_AUTH_TYPE_NONE;
+ auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ auth->auth_context_id = DCERPC_BIND_NAK_REASON_NOT_SPECIFIED;
+ return false;
+ }
+
+ auth->auth_type = call->in_auth_info.auth_type;
+ auth->auth_level = call->in_auth_info.auth_level;
+ auth->auth_context_id = call->in_auth_info.auth_context_id;
+
+ cb->auth.become_root();
+ status = cb->auth.gensec_prepare(
+ auth,
+ call,
+ &auth->gensec_security,
+ cb->auth.private_data);
+ cb->auth.unbecome_root();
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to call samba_server_gensec_start %s\n",
+ nt_errstr(status)));
+ return false;
+ }
+
+ /*
+ * We have to call this because we set the target_service for
+ * Kerberos to NULL above, and in any case we wish to log a
+ * more specific service target.
+ *
+ */
+ status = gensec_set_target_service_description(auth->gensec_security,
+ "DCE/RPC");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to call gensec_set_target_service_description %s\n",
+ nt_errstr(status)));
+ return false;
+ }
+
+ if (call->conn->remote_address != NULL) {
+ status = gensec_set_remote_address(auth->gensec_security,
+ call->conn->remote_address);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to call gensec_set_remote_address() %s\n",
+ nt_errstr(status)));
+ return false;
+ }
+ }
+
+ if (call->conn->local_address != NULL) {
+ status = gensec_set_local_address(auth->gensec_security,
+ call->conn->local_address);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to call gensec_set_local_address() %s\n",
+ nt_errstr(status)));
+ return false;
+ }
+ }
+
+ status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_type,
+ auth->auth_level);
+ if (!NT_STATUS_IS_OK(status)) {
+ const char *backend_name =
+ gensec_get_name_by_authtype(auth->gensec_security,
+ auth->auth_type);
+
+ DEBUG(3, ("Failed to start GENSEC mechanism for DCERPC server: "
+ "auth_type=%d (%s), auth_level=%d: %s\n",
+ (int)auth->auth_type, backend_name,
+ (int)auth->auth_level,
+ nt_errstr(status)));
+
+ /*
+ * Setting DCERPC_AUTH_LEVEL_NONE,
+ * gives the caller the reject_reason
+ * as auth_context_id.
+ *
+ * Note: DCERPC_AUTH_LEVEL_NONE == 1
+ */
+ auth->auth_type = DCERPC_AUTH_TYPE_NONE;
+ auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ if (backend_name != NULL) {
+ auth->auth_context_id =
+ DCERPC_BIND_NAK_REASON_INVALID_CHECKSUM;
+ } else {
+ auth->auth_context_id =
+ DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE;
+ }
+ return false;
+ }
+
+ if (dce_conn->negotiated_hdr_signing) {
+ gensec_want_feature(auth->gensec_security,
+ GENSEC_FEATURE_SIGN_PKT_HEADER);
+ }
+
+ return true;
+}
+
+static void dcesrv_default_auth_state_finish_bind(struct dcesrv_call_state *call)
+{
+ SMB_ASSERT(call->pkt.ptype == DCERPC_PKT_BIND);
+
+ if (call->auth_state == call->conn->default_auth_state) {
+ return;
+ }
+
+ if (call->conn->default_auth_state->auth_started) {
+ return;
+ }
+
+ if (call->conn->default_auth_state->auth_invalid) {
+ return;
+ }
+
+ call->conn->default_auth_state->auth_type = DCERPC_AUTH_TYPE_NONE;
+ call->conn->default_auth_state->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ call->conn->default_auth_state->auth_context_id = 0;
+ call->conn->default_auth_state->auth_started = true;
+ call->conn->default_auth_state->auth_finished = true;
+
+ /*
+ *
+ * We defer log_successful_dcesrv_authz_event()
+ * to dcesrv_default_auth_state_prepare_request()
+ *
+ * As we don't want to trigger authz_events
+ * just for alter_context requests without authentication
+ */
+}
+
+void dcesrv_default_auth_state_prepare_request(struct dcesrv_call_state *call)
+{
+ struct dcesrv_connection *dce_conn = call->conn;
+ struct dcesrv_auth *auth = call->auth_state;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+
+ if (auth->auth_audited) {
+ return;
+ }
+
+ if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
+ return;
+ }
+
+ if (auth != dce_conn->default_auth_state) {
+ return;
+ }
+
+ if (auth->auth_invalid) {
+ return;
+ }
+
+ if (!auth->auth_finished) {
+ return;
+ }
+
+ if (cb->log.successful_authz == NULL) {
+ return;
+ }
+
+ cb->log.successful_authz(call, cb->log.private_data);
+}
+
+/*
+ parse any auth information from a dcerpc bind request
+ return false if we can't handle the auth request for some
+ reason (in which case we send a bind_nak)
+*/
+bool dcesrv_auth_bind(struct dcesrv_call_state *call)
+{
+ struct ncacn_packet *pkt = &call->pkt;
+ struct dcesrv_auth *auth = call->auth_state;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+ NTSTATUS status;
+
+ if (pkt->auth_length == 0) {
+ auth->auth_type = DCERPC_AUTH_TYPE_NONE;
+ auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ auth->auth_context_id = 0;
+ auth->auth_started = true;
+
+ if (cb->log.successful_authz != NULL) {
+ cb->log.successful_authz(call, cb->log.private_data);
+ }
+
+ return true;
+ }
+
+ status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info,
+ &call->in_auth_info,
+ NULL, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * Setting DCERPC_AUTH_LEVEL_NONE,
+ * gives the caller the reject_reason
+ * as auth_context_id.
+ *
+ * Note: DCERPC_AUTH_LEVEL_NONE == 1
+ */
+ auth->auth_type = DCERPC_AUTH_TYPE_NONE;
+ auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
+ auth->auth_context_id =
+ DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED;
+ return false;
+ }
+
+ return dcesrv_auth_prepare_gensec(call);
+}
+
+NTSTATUS dcesrv_auth_complete(struct dcesrv_call_state *call, NTSTATUS status)
+{
+ struct dcesrv_auth *auth = call->auth_state;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+ const char *pdu = "<unknown>";
+
+ switch (call->pkt.ptype) {
+ case DCERPC_PKT_BIND:
+ pdu = "BIND";
+ break;
+ case DCERPC_PKT_ALTER:
+ pdu = "ALTER";
+ break;
+ case DCERPC_PKT_AUTH3:
+ pdu = "AUTH3";
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(4, ("GENSEC not finished at %s\n", pdu));
+ return NT_STATUS_RPC_SEC_PKG_ERROR;
+ }
+ break;
+ default:
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(4, ("GENSEC mech rejected the incoming authentication "
+ "at %s: %s\n", pdu, nt_errstr(status)));
+ return status;
+ }
+
+ cb->auth.become_root();
+ status = gensec_session_info(auth->gensec_security,
+ auth,
+ &auth->session_info);
+ cb->auth.unbecome_root();
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to establish session_info: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+ auth->auth_finished = true;
+
+ if (auth->auth_level == DCERPC_AUTH_LEVEL_CONNECT &&
+ !call->conn->got_explicit_auth_level_connect)
+ {
+ call->conn->default_auth_level_connect = auth;
+ }
+
+ if (call->pkt.ptype != DCERPC_PKT_AUTH3) {
+ return NT_STATUS_OK;
+ }
+
+ if (call->out_auth_info->credentials.length != 0) {
+ DEBUG(4, ("GENSEC produced output token (len=%zu) at %s\n",
+ call->out_auth_info->credentials.length, pdu));
+ return NT_STATUS_RPC_SEC_PKG_ERROR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ add any auth information needed in a bind ack, and process the authentication
+ information found in the bind.
+*/
+NTSTATUS dcesrv_auth_prepare_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
+{
+ struct dcesrv_connection *dce_conn = call->conn;
+ struct dcesrv_auth *auth = call->auth_state;
+ NTSTATUS status;
+
+ status = dcesrv_auth_negotiate_hdr_signing(call, pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dce_conn->allow_alter = true;
+ dcesrv_default_auth_state_finish_bind(call);
+
+ if (call->pkt.auth_length == 0) {
+ auth->auth_finished = true;
+ return NT_STATUS_OK;
+ }
+
+ /* We can't work without an existing gensec state */
+ if (auth->gensec_security == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ call->_out_auth_info = (struct dcerpc_auth) {
+ .auth_type = auth->auth_type,
+ .auth_level = auth->auth_level,
+ .auth_context_id = auth->auth_context_id,
+ };
+ call->out_auth_info = &call->_out_auth_info;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ process the final stage of a auth request
+*/
+bool dcesrv_auth_prepare_auth3(struct dcesrv_call_state *call)
+{
+ struct ncacn_packet *pkt = &call->pkt;
+ struct dcesrv_auth *auth = call->auth_state;
+ NTSTATUS status;
+
+ if (pkt->auth_length == 0) {
+ return false;
+ }
+
+ if (auth->auth_finished) {
+ return false;
+ }
+
+ if (auth->auth_invalid) {
+ return false;
+ }
+
+ /* We can't work without an existing gensec state */
+ if (auth->gensec_security == NULL) {
+ return false;
+ }
+
+ status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info,
+ &call->in_auth_info, NULL, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * Windows returns DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY
+ * instead of DCERPC_NCA_S_PROTO_ERROR.
+ */
+ call->fault_code = DCERPC_NCA_S_FAULT_REMOTE_NO_MEMORY;
+ return false;
+ }
+
+ if (call->in_auth_info.auth_type != auth->auth_type) {
+ return false;
+ }
+
+ if (call->in_auth_info.auth_level != auth->auth_level) {
+ return false;
+ }
+
+ if (call->in_auth_info.auth_context_id != auth->auth_context_id) {
+ return false;
+ }
+
+ call->_out_auth_info = (struct dcerpc_auth) {
+ .auth_type = auth->auth_type,
+ .auth_level = auth->auth_level,
+ .auth_context_id = auth->auth_context_id,
+ };
+ call->out_auth_info = &call->_out_auth_info;
+
+ return true;
+}
+
+/*
+ parse any auth information from a dcerpc alter request
+ return false if we can't handle the auth request for some
+ reason (in which case we send a bind_nak (is this true for here?))
+*/
+bool dcesrv_auth_alter(struct dcesrv_call_state *call)
+{
+ struct ncacn_packet *pkt = &call->pkt;
+ struct dcesrv_auth *auth = call->auth_state;
+ NTSTATUS status;
+
+ /* on a pure interface change there is no auth blob */
+ if (pkt->auth_length == 0) {
+ if (!auth->auth_finished) {
+ return false;
+ }
+ return true;
+ }
+
+ if (auth->auth_finished) {
+ call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
+ return false;
+ }
+
+ status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.alter.auth_info,
+ &call->in_auth_info, NULL, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
+ return false;
+ }
+
+ if (!auth->auth_started) {
+ bool ok;
+
+ ok = dcesrv_auth_prepare_gensec(call);
+ if (!ok) {
+ call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
+ return false;
+ }
+
+ return true;
+ }
+
+ if (call->in_auth_info.auth_type == DCERPC_AUTH_TYPE_NONE) {
+ call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
+ return false;
+ }
+
+ if (auth->auth_invalid) {
+ return false;
+ }
+
+ if (call->in_auth_info.auth_type != auth->auth_type) {
+ return false;
+ }
+
+ if (call->in_auth_info.auth_level != auth->auth_level) {
+ return false;
+ }
+
+ if (call->in_auth_info.auth_context_id != auth->auth_context_id) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ add any auth information needed in a alter ack, and process the authentication
+ information found in the alter.
+*/
+NTSTATUS dcesrv_auth_prepare_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
+{
+ struct dcesrv_auth *auth = call->auth_state;
+ NTSTATUS status;
+
+ status = dcesrv_auth_negotiate_hdr_signing(call, pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* on a pure interface change there is no auth_info structure
+ setup */
+ if (call->pkt.auth_length == 0) {
+ return NT_STATUS_OK;
+ }
+
+ if (auth->gensec_security == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ call->_out_auth_info = (struct dcerpc_auth) {
+ .auth_type = auth->auth_type,
+ .auth_level = auth->auth_level,
+ .auth_context_id = auth->auth_context_id,
+ };
+ call->out_auth_info = &call->_out_auth_info;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ check credentials on a packet
+*/
+bool dcesrv_auth_pkt_pull(struct dcesrv_call_state *call,
+ DATA_BLOB *full_packet,
+ uint8_t required_flags,
+ uint8_t optional_flags,
+ uint8_t payload_offset,
+ DATA_BLOB *payload_and_verifier)
+{
+ struct ncacn_packet *pkt = &call->pkt;
+ struct dcesrv_auth *auth = call->auth_state;
+ const struct dcerpc_auth tmp_auth = {
+ .auth_type = auth->auth_type,
+ .auth_level = auth->auth_level,
+ .auth_context_id = auth->auth_context_id,
+ };
+ bool check_pkt_auth_fields;
+ NTSTATUS status;
+
+ if (!auth->auth_started) {
+ return false;
+ }
+
+ if (!auth->auth_finished) {
+ call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
+ return false;
+ }
+
+ if (auth->auth_invalid) {
+ return false;
+ }
+
+ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
+ /*
+ * The caller most likely checked this
+ * already, but we better double check.
+ */
+ check_pkt_auth_fields = true;
+ } else {
+ /*
+ * The caller already found first fragment
+ * and is passing the auth_state of it.
+ * A server is supposed to use the
+ * setting of the first fragment and
+ * completely ignore the values
+ * on the remaining fragments
+ */
+ check_pkt_auth_fields = false;
+ }
+
+ status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
+ auth->gensec_security,
+ check_pkt_auth_fields,
+ call,
+ pkt->ptype,
+ required_flags,
+ optional_flags,
+ payload_offset,
+ payload_and_verifier,
+ full_packet,
+ pkt);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
+ call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
+ return false;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL)) {
+ call->fault_code = DCERPC_NCA_S_UNSUPPORTED_AUTHN_LEVEL;
+ return false;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
+ call->fault_code = DCERPC_FAULT_SEC_PKG_ERROR;
+ return false;
+ }
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
+ return false;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ push a signed or sealed dcerpc request packet into a blob
+*/
+bool dcesrv_auth_pkt_push(struct dcesrv_call_state *call,
+ DATA_BLOB *blob, size_t sig_size,
+ uint8_t payload_offset,
+ const DATA_BLOB *payload,
+ const struct ncacn_packet *pkt)
+{
+ struct dcesrv_auth *auth = call->auth_state;
+ const struct dcerpc_auth tmp_auth = {
+ .auth_type = auth->auth_type,
+ .auth_level = auth->auth_level,
+ .auth_context_id = auth->auth_context_id,
+ };
+ NTSTATUS status;
+
+ status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
+ auth->gensec_security,
+ call, blob, sig_size,
+ payload_offset,
+ payload,
+ pkt);
+ return NT_STATUS_IS_OK(status);
+}
diff --git a/librpc/rpc/dcesrv_core.c b/librpc/rpc/dcesrv_core.c
new file mode 100644
index 0000000..c0a4150
--- /dev/null
+++ b/librpc/rpc/dcesrv_core.c
@@ -0,0 +1,3369 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ server side dcerpc core code
+
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Stefan (metze) Metzmacher 2004-2005
+ Copyright (C) Samuel Cabrero <scabrero@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/>.
+*/
+
+#include "includes.h"
+#include "librpc/rpc/dcesrv_core.h"
+#include "librpc/rpc/dcesrv_core_proto.h"
+#include "librpc/rpc/dcerpc_util.h"
+#include "librpc/gen_ndr/auth.h"
+#include "auth/gensec/gensec.h"
+#include "lib/util/dlinklist.h"
+#include "libcli/security/security.h"
+#include "param/param.h"
+#include "lib/tsocket/tsocket.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "system/network.h"
+#include "lib/util/idtree_random.h"
+#include "nsswitch/winbind_client.h"
+
+/**
+ * @file
+ * @brief DCERPC server
+ */
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+#undef strcasecmp
+
+static NTSTATUS dcesrv_negotiate_contexts(struct dcesrv_call_state *call,
+ const struct dcerpc_bind *b,
+ struct dcerpc_ack_ctx *ack_ctx_list);
+
+/*
+ see if two endpoints match
+*/
+static bool endpoints_match(const struct dcerpc_binding *ep1,
+ const struct dcerpc_binding *ep2)
+{
+ enum dcerpc_transport_t t1;
+ enum dcerpc_transport_t t2;
+ const char *e1;
+ const char *e2;
+
+ t1 = dcerpc_binding_get_transport(ep1);
+ t2 = dcerpc_binding_get_transport(ep2);
+
+ e1 = dcerpc_binding_get_string_option(ep1, "endpoint");
+ e2 = dcerpc_binding_get_string_option(ep2, "endpoint");
+
+ if (t1 != t2) {
+ return false;
+ }
+
+ if (!e1 || !e2) {
+ return e1 == e2;
+ }
+
+ if (strcasecmp(e1, e2) != 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ find an endpoint in the dcesrv_context
+*/
+_PUBLIC_ NTSTATUS dcesrv_find_endpoint(struct dcesrv_context *dce_ctx,
+ const struct dcerpc_binding *ep_description,
+ struct dcesrv_endpoint **_out)
+{
+ struct dcesrv_endpoint *ep = NULL;
+ for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
+ if (endpoints_match(ep->ep_description, ep_description)) {
+ *_out = ep;
+ return NT_STATUS_OK;
+ }
+ }
+ return NT_STATUS_NOT_FOUND;
+}
+
+/*
+ find a registered context_id from a bind or alter_context
+*/
+static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn,
+ uint16_t context_id)
+{
+ struct dcesrv_connection_context *c;
+ for (c=conn->contexts;c;c=c->next) {
+ if (c->context_id == context_id) return c;
+ }
+ return NULL;
+}
+
+/*
+ find the interface operations on any endpoint with this binding
+*/
+static const struct dcesrv_interface *find_interface_by_binding(struct dcesrv_context *dce_ctx,
+ struct dcerpc_binding *binding,
+ const struct dcesrv_interface *iface)
+{
+ struct dcesrv_endpoint *ep;
+ for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
+ if (endpoints_match(ep->ep_description, binding)) {
+ const struct dcesrv_interface *ret = NULL;
+
+ ret = find_interface_by_syntax_id(
+ ep, &iface->syntax_id);
+ if (ret != NULL) {
+ return ret;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ find the interface operations on an endpoint by uuid
+*/
+_PUBLIC_ const struct dcesrv_interface *find_interface_by_syntax_id(
+ const struct dcesrv_endpoint *endpoint,
+ const struct ndr_syntax_id *interface)
+{
+ struct dcesrv_if_list *ifl;
+ for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
+ if (ndr_syntax_id_equal(&ifl->iface->syntax_id, interface)) {
+ return ifl->iface;
+ }
+ }
+ return NULL;
+}
+
+/*
+ find the earlier parts of a fragmented call awaiting reassembly
+*/
+static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint32_t call_id)
+{
+ struct dcesrv_call_state *c;
+ for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
+ if (c->pkt.call_id == call_id) {
+ return c;
+ }
+ }
+ return NULL;
+}
+
+/*
+ find a pending request
+*/
+static struct dcesrv_call_state *dcesrv_find_pending_call(
+ struct dcesrv_connection *dce_conn,
+ uint32_t call_id)
+{
+ struct dcesrv_call_state *c = NULL;
+
+ for (c = dce_conn->pending_call_list; c != NULL; c = c->next) {
+ if (c->pkt.call_id == call_id) {
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * register a principal for an auth_type
+ *
+ * In order to get used in dcesrv_mgmt_inq_princ_name()
+ */
+_PUBLIC_ NTSTATUS dcesrv_auth_type_principal_register(struct dcesrv_context *dce_ctx,
+ enum dcerpc_AuthType auth_type,
+ const char *principal_name)
+{
+ const char *existing = NULL;
+ struct dcesrv_ctx_principal *p = NULL;
+
+ existing = dcesrv_auth_type_principal_find(dce_ctx, auth_type);
+ if (existing != NULL) {
+ DBG_ERR("auth_type[%u] already registered with principal_name[%s]\n",
+ auth_type, existing);
+ return NT_STATUS_ALREADY_REGISTERED;
+ }
+
+ p = talloc_zero(dce_ctx, struct dcesrv_ctx_principal);
+ if (p == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ p->auth_type = auth_type;
+ p->principal_name = talloc_strdup(p, principal_name);
+ if (p->principal_name == NULL) {
+ TALLOC_FREE(p);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DLIST_ADD_END(dce_ctx->principal_list, p);
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ const char *dcesrv_auth_type_principal_find(struct dcesrv_context *dce_ctx,
+ enum dcerpc_AuthType auth_type)
+{
+ struct dcesrv_ctx_principal *p = NULL;
+
+ for (p = dce_ctx->principal_list; p != NULL; p = p->next) {
+ if (p->auth_type == auth_type) {
+ return p->principal_name;
+ }
+ }
+
+ return NULL;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_register_default_auth_types(struct dcesrv_context *dce_ctx,
+ const char *principal)
+{
+ const char *realm = lpcfg_realm(dce_ctx->lp_ctx);
+ NTSTATUS status;
+
+ status = dcesrv_auth_type_principal_register(dce_ctx,
+ DCERPC_AUTH_TYPE_NTLMSSP,
+ principal);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ status = dcesrv_auth_type_principal_register(dce_ctx,
+ DCERPC_AUTH_TYPE_SPNEGO,
+ principal);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (realm == NULL || realm[0] == '\0') {
+ return NT_STATUS_OK;
+ }
+
+ status = dcesrv_auth_type_principal_register(dce_ctx,
+ DCERPC_AUTH_TYPE_KRB5,
+ principal);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_register_default_auth_types_machine_principal(struct dcesrv_context *dce_ctx)
+{
+ const char *realm = lpcfg_realm(dce_ctx->lp_ctx);
+ const char *nb = lpcfg_netbios_name(dce_ctx->lp_ctx);
+ char *principal = NULL;
+ NTSTATUS status;
+
+ if (realm == NULL || realm[0] == '\0') {
+ return dcesrv_register_default_auth_types(dce_ctx, "");
+ }
+
+ principal = talloc_asprintf(talloc_tos(), "%s$@%s", nb, realm);
+ if (principal == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dcesrv_register_default_auth_types(dce_ctx, principal);
+ TALLOC_FREE(principal);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ register an interface on an endpoint
+
+ An endpoint is one unix domain socket (for ncalrpc), one TCP port
+ (for ncacn_ip_tcp) or one (forwarded) named pipe (for ncacn_np).
+
+ Each endpoint can have many interfaces such as netlogon, lsa or
+ samr. Some have essentially the full set.
+
+ This is driven from the set of interfaces listed in each IDL file
+ via the PIDL generated *__op_init_server() functions.
+*/
+_PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
+ const char *ep_name,
+ const char *ncacn_np_secondary_endpoint,
+ const struct dcesrv_interface *iface,
+ const struct security_descriptor *sd)
+{
+ struct dcerpc_binding *binding = NULL;
+ struct dcerpc_binding *binding2 = NULL;
+ NTSTATUS ret;
+
+ ret = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
+ if (NT_STATUS_IS_ERR(ret)) {
+ DBG_ERR("Trouble parsing binding string '%s'\n", ep_name);
+ goto out;
+ }
+
+ if (ncacn_np_secondary_endpoint != NULL) {
+ ret = dcerpc_parse_binding(dce_ctx,
+ ncacn_np_secondary_endpoint,
+ &binding2);
+ if (NT_STATUS_IS_ERR(ret)) {
+ DBG_ERR("Trouble parsing 2nd binding string '%s'\n",
+ ncacn_np_secondary_endpoint);
+ goto out;
+ }
+ }
+
+ ret = dcesrv_interface_register_b(dce_ctx,
+ binding,
+ binding2,
+ iface,
+ sd);
+out:
+ TALLOC_FREE(binding);
+ TALLOC_FREE(binding2);
+ return ret;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_interface_register_b(struct dcesrv_context *dce_ctx,
+ struct dcerpc_binding *binding,
+ struct dcerpc_binding *binding2,
+ const struct dcesrv_interface *iface,
+ const struct security_descriptor *sd)
+{
+ struct dcesrv_endpoint *ep;
+ struct dcesrv_if_list *ifl;
+ bool add_ep = false;
+ NTSTATUS status;
+ enum dcerpc_transport_t transport;
+ char *ep_string = NULL;
+ bool use_single_process = true;
+ const char *ep_process_string;
+
+ /*
+ * If we are not using handles, there is no need for force
+ * this service into using a single process.
+ *
+ * However, due to the way we listen for RPC packets, we can
+ * only do this if we have a single service per pipe or TCP
+ * port, so we still force a single combined process for
+ * ncalrpc.
+ */
+ if (iface->flags & DCESRV_INTERFACE_FLAGS_HANDLES_NOT_USED) {
+ use_single_process = false;
+ }
+
+ transport = dcerpc_binding_get_transport(binding);
+ if (transport == NCACN_IP_TCP) {
+ int port;
+
+ /*
+ * First check if there is already a port specified, eg
+ * for epmapper on ncacn_ip_tcp:[135]
+ */
+ const char *endpoint
+ = dcerpc_binding_get_string_option(binding,
+ "endpoint");
+ if (endpoint == NULL) {
+ port = lpcfg_parm_int(dce_ctx->lp_ctx, NULL,
+ "rpc server port", iface->name, 0);
+
+ /*
+ * For RPC services that are not set to use a single
+ * process, we do not default to using the 'rpc server
+ * port' because that would cause a double-bind on
+ * that port.
+ */
+ if (port == 0 && !use_single_process) {
+ port = lpcfg_rpc_server_port(dce_ctx->lp_ctx);
+ }
+ if (port != 0) {
+ char port_str[6];
+ snprintf(port_str, sizeof(port_str), "%u", port);
+ status = dcerpc_binding_set_string_option(binding,
+ "endpoint",
+ port_str);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+ }
+ }
+
+ if (transport == NCACN_NP && binding2 != NULL) {
+ enum dcerpc_transport_t transport2;
+
+ transport2 = dcerpc_binding_get_transport(binding2);
+ SMB_ASSERT(transport2 == transport);
+ }
+
+ /* see if the interface is already registered on the endpoint */
+ if (find_interface_by_binding(dce_ctx, binding, iface)!=NULL) {
+ char *binding_string = dcerpc_binding_string(dce_ctx, binding);
+ DBG_ERR("Interface '%s' already registered on endpoint '%s'\n",
+ iface->name, binding_string);
+ TALLOC_FREE(binding_string);
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ /* check if this endpoint exists
+ */
+ status = dcesrv_find_endpoint(dce_ctx, binding, &ep);
+ if (NT_STATUS_IS_OK(status)) {
+ /*
+ * We want a new port on ncacn_ip_tcp for NETLOGON, so
+ * it can be multi-process. Other processes can also
+ * listen on distinct ports, if they have one forced
+ * in the code above with eg 'rpc server port:drsuapi = 1027'
+ *
+ * If we have multiple endpoints on port 0, they each
+ * get an epemeral port (currently by walking up from
+ * 1024).
+ *
+ * Because one endpoint can only have one process
+ * model, we add a new IP_TCP endpoint for each model.
+ *
+ * This works in conjunction with the forced overwrite
+ * of ep->use_single_process below.
+ */
+ if (ep->use_single_process != use_single_process
+ && transport == NCACN_IP_TCP) {
+ add_ep = true;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) || add_ep) {
+ ep = talloc_zero(dce_ctx, struct dcesrv_endpoint);
+ if (!ep) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ep->ep_description = dcerpc_binding_dup(ep, binding);
+ if (transport == NCACN_NP && binding2 != NULL) {
+ ep->ep_2nd_description =
+ dcerpc_binding_dup(ep, binding2);
+ }
+ add_ep = true;
+
+ /* add mgmt interface */
+ ifl = talloc_zero(ep, struct dcesrv_if_list);
+ if (!ifl) {
+ TALLOC_FREE(ep);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ifl->iface = talloc_memdup(ifl,
+ dcesrv_get_mgmt_interface(),
+ sizeof(struct dcesrv_interface));
+ if (ifl->iface == NULL) {
+ talloc_free(ep);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ DLIST_ADD(ep->interface_list, ifl);
+ } else if (!NT_STATUS_IS_OK(status)) {
+ DBG_NOTICE("Failed to find endpoint: %s\n", nt_errstr(status));
+ return status;
+ }
+
+ /*
+ * By default don't force into a single process, but if any
+ * interface on this endpoint on this service uses handles
+ * (most do), then we must force into single process mode
+ *
+ * By overwriting this each time a new interface is added to
+ * this endpoint, we end up with the most restrictive setting.
+ */
+ if (use_single_process) {
+ ep->use_single_process = true;
+ }
+
+ /* talloc a new interface list element */
+ ifl = talloc_zero(ep, struct dcesrv_if_list);
+ if (!ifl) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* copy the given interface struct to the one on the endpoints interface list */
+ ifl->iface = talloc_memdup(ifl,
+ iface,
+ sizeof(struct dcesrv_interface));
+ if (ifl->iface == NULL) {
+ talloc_free(ep);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* if we have a security descriptor given,
+ * we should see if we can set it up on the endpoint
+ */
+ if (sd != NULL) {
+ /* if there's currently no security descriptor given on the endpoint
+ * we try to set it
+ */
+ if (ep->sd == NULL) {
+ ep->sd = security_descriptor_copy(ep, sd);
+ }
+
+ /* if now there's no security descriptor given on the endpoint
+ * something goes wrong, either we failed to copy the security descriptor
+ * or there was already one on the endpoint
+ */
+ if (ep->sd != NULL) {
+ char *binding_string =
+ dcerpc_binding_string(dce_ctx, binding);
+ DBG_ERR("Interface '%s' failed to setup a security "
+ "descriptor on endpoint '%s'\n",
+ iface->name, binding_string);
+ TALLOC_FREE(binding_string);
+ if (add_ep) free(ep);
+ free(ifl);
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+ }
+
+ /* finally add the interface on the endpoint */
+ DLIST_ADD(ep->interface_list, ifl);
+
+ /* if it's a new endpoint add it to the dcesrv_context */
+ if (add_ep) {
+ DLIST_ADD(dce_ctx->endpoint_list, ep);
+ }
+
+ /* Re-get the string as we may have set a port */
+ ep_string = dcerpc_binding_string(dce_ctx, ep->ep_description);
+
+ if (use_single_process) {
+ ep_process_string = "single process required";
+ } else {
+ ep_process_string = "multi process compatible";
+ }
+
+ DBG_INFO("Interface '%s' registered on endpoint '%s' (%s)\n",
+ iface->name, ep_string, ep_process_string);
+ TALLOC_FREE(ep_string);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS dcesrv_session_info_session_key(struct dcesrv_auth *auth,
+ DATA_BLOB *session_key)
+{
+ if (auth->session_info == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ if (auth->session_info->session_key.length == 0) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ *session_key = auth->session_info->session_key;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS dcesrv_remote_session_key(struct dcesrv_auth *auth,
+ DATA_BLOB *session_key)
+{
+ if (auth->auth_type != DCERPC_AUTH_TYPE_NONE) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ return dcesrv_session_info_session_key(auth, session_key);
+}
+
+static NTSTATUS dcesrv_local_fixed_session_key(struct dcesrv_auth *auth,
+ DATA_BLOB *session_key)
+{
+ return dcerpc_generic_session_key(session_key);
+}
+
+/*
+ * Fetch the authentication session key if available.
+ *
+ * This is the key generated by a gensec authentication.
+ *
+ */
+_PUBLIC_ NTSTATUS dcesrv_auth_session_key(struct dcesrv_call_state *call,
+ DATA_BLOB *session_key)
+{
+ struct dcesrv_auth *auth = call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
+ return dcesrv_session_info_session_key(auth, session_key);
+}
+
+/*
+ * Fetch the transport session key if available.
+ * Typically this is the SMB session key
+ * or a fixed key for local transports.
+ *
+ * The key is always truncated to 16 bytes.
+*/
+_PUBLIC_ NTSTATUS dcesrv_transport_session_key(struct dcesrv_call_state *call,
+ DATA_BLOB *session_key)
+{
+ struct dcesrv_auth *auth = call->auth_state;
+ NTSTATUS status;
+
+ SMB_ASSERT(auth->auth_finished);
+
+ if (auth->session_key_fn == NULL) {
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
+ status = auth->session_key_fn(auth, session_key);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ session_key->length = MIN(session_key->length, 16);
+
+ return NT_STATUS_OK;
+}
+
+static struct dcesrv_auth *dcesrv_auth_create(struct dcesrv_connection *conn)
+{
+ const struct dcesrv_endpoint *ep = conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(ep->ep_description);
+ struct dcesrv_auth *auth = NULL;
+
+ auth = talloc_zero(conn, struct dcesrv_auth);
+ if (auth == NULL) {
+ return NULL;
+ }
+
+ switch (transport) {
+ case NCACN_NP:
+ auth->session_key_fn = dcesrv_remote_session_key;
+ break;
+ case NCALRPC:
+ case NCACN_UNIX_STREAM:
+ auth->session_key_fn = dcesrv_local_fixed_session_key;
+ break;
+ default:
+ /*
+ * All other's get a NULL pointer, which
+ * results in NT_STATUS_NO_USER_SESSION_KEY
+ */
+ break;
+ }
+
+ return auth;
+}
+
+/*
+ connect to a dcerpc endpoint
+*/
+_PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
+ TALLOC_CTX *mem_ctx,
+ const struct dcesrv_endpoint *ep,
+ struct auth_session_info *session_info,
+ struct tevent_context *event_ctx,
+ uint32_t state_flags,
+ struct dcesrv_connection **_p)
+{
+ struct dcesrv_auth *auth = NULL;
+ struct dcesrv_connection *p = NULL;
+
+ if (!session_info) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ p = talloc_zero(mem_ctx, struct dcesrv_connection);
+ if (p == NULL) {
+ goto nomem;
+ }
+
+ p->dce_ctx = dce_ctx;
+ p->endpoint = ep;
+ p->packet_log_dir = lpcfg_parm_string(dce_ctx->lp_ctx,
+ NULL,
+ "dcesrv",
+ "stubs directory");
+ p->event_ctx = event_ctx;
+ p->state_flags = state_flags;
+ p->allow_bind = true;
+ p->max_recv_frag = 5840;
+ p->max_xmit_frag = 5840;
+ p->max_total_request_size = DCERPC_NCACN_REQUEST_DEFAULT_MAX_SIZE;
+
+ p->support_hdr_signing = lpcfg_parm_bool(dce_ctx->lp_ctx,
+ NULL,
+ "dcesrv",
+ "header signing",
+ true);
+ p->max_auth_states = lpcfg_parm_ulong(dce_ctx->lp_ctx,
+ NULL,
+ "dcesrv",
+ "max auth states",
+ 2049);
+
+ auth = dcesrv_auth_create(p);
+ if (auth == NULL) {
+ goto nomem;
+ }
+
+ auth->session_info = talloc_reference(auth, session_info);
+ if (auth->session_info == NULL) {
+ goto nomem;
+ }
+
+ p->default_auth_state = auth;
+
+ p->preferred_transfer = dce_ctx->preferred_transfer;
+
+ *_p = p;
+ return NT_STATUS_OK;
+nomem:
+ TALLOC_FREE(p);
+ return NT_STATUS_NO_MEMORY;
+}
+
+/*
+ move a call from an existing linked list to the specified list. This
+ prevents bugs where we forget to remove the call from a previous
+ list when moving it.
+ */
+static void dcesrv_call_set_list(struct dcesrv_call_state *call,
+ enum dcesrv_call_list list)
+{
+ switch (call->list) {
+ case DCESRV_LIST_NONE:
+ break;
+ case DCESRV_LIST_CALL_LIST:
+ DLIST_REMOVE(call->conn->call_list, call);
+ break;
+ case DCESRV_LIST_FRAGMENTED_CALL_LIST:
+ DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
+ break;
+ case DCESRV_LIST_PENDING_CALL_LIST:
+ DLIST_REMOVE(call->conn->pending_call_list, call);
+ break;
+ }
+ call->list = list;
+ switch (list) {
+ case DCESRV_LIST_NONE:
+ break;
+ case DCESRV_LIST_CALL_LIST:
+ DLIST_ADD_END(call->conn->call_list, call);
+ break;
+ case DCESRV_LIST_FRAGMENTED_CALL_LIST:
+ DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call);
+ break;
+ case DCESRV_LIST_PENDING_CALL_LIST:
+ DLIST_ADD_END(call->conn->pending_call_list, call);
+ break;
+ }
+}
+
+static void dcesrv_call_disconnect_after(struct dcesrv_call_state *call,
+ const char *reason)
+{
+ struct dcesrv_auth *a = NULL;
+
+ if (call->conn->terminate != NULL) {
+ return;
+ }
+
+ call->conn->allow_bind = false;
+ call->conn->allow_alter = false;
+
+ call->conn->default_auth_state->auth_invalid = true;
+
+ for (a = call->conn->auth_states; a != NULL; a = a->next) {
+ a->auth_invalid = true;
+ }
+
+ call->terminate_reason = talloc_strdup(call, reason);
+ if (call->terminate_reason == NULL) {
+ call->terminate_reason = __location__;
+ }
+}
+
+/*
+ return a dcerpc bind_nak
+*/
+static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
+{
+ struct ncacn_packet pkt;
+ struct dcerpc_bind_nak_version version;
+ struct data_blob_list_item *rep;
+ NTSTATUS status;
+ static const uint8_t _pad[3] = { 0, };
+
+ /*
+ * We add the call to the pending_call_list
+ * in order to defer the termination.
+ */
+ dcesrv_call_disconnect_after(call, "dcesrv_bind_nak");
+
+ /* setup a bind_nak */
+ dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
+ pkt.auth_length = 0;
+ pkt.call_id = call->pkt.call_id;
+ pkt.ptype = DCERPC_PKT_BIND_NAK;
+ pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+ pkt.u.bind_nak.reject_reason = reason;
+ version.rpc_vers = 5;
+ version.rpc_vers_minor = 0;
+ pkt.u.bind_nak.num_versions = 1;
+ pkt.u.bind_nak.versions = &version;
+ pkt.u.bind_nak._pad = data_blob_const(_pad, sizeof(_pad));
+
+ rep = talloc_zero(call, struct data_blob_list_item);
+ if (!rep) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dcerpc_ncacn_push_auth(&rep->blob, call, &pkt, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dcerpc_set_frag_length(&rep->blob, rep->blob.length);
+
+ DLIST_ADD_END(call->replies, rep);
+ dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
+
+ if (call->conn->call_list && call->conn->call_list->replies) {
+ if (call->conn->transport.report_output_data) {
+ call->conn->transport.report_output_data(call->conn);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS _dcesrv_fault_disconnect_flags(struct dcesrv_call_state *call,
+ uint32_t fault_code,
+ uint8_t extra_flags,
+ const char *func,
+ const char *location)
+{
+ const char *reason = NULL;
+
+ reason = talloc_asprintf(call, "%s:%s: fault=%u (%s) flags=0x%x",
+ func, location,
+ fault_code,
+ dcerpc_errstr(call, fault_code),
+ extra_flags);
+ if (reason == NULL) {
+ reason = location;
+ }
+
+ /*
+ * We add the call to the pending_call_list
+ * in order to defer the termination.
+ */
+
+ dcesrv_call_disconnect_after(call, reason);
+
+ return dcesrv_fault_with_flags(call, fault_code, extra_flags);
+}
+
+#define dcesrv_fault_disconnect(call, fault_code) \
+ _dcesrv_fault_disconnect_flags(call, fault_code, \
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE, \
+ __func__, __location__)
+#define dcesrv_fault_disconnect0(call, fault_code) \
+ _dcesrv_fault_disconnect_flags(call, fault_code, 0, \
+ __func__, __location__)
+
+static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
+{
+ DLIST_REMOVE(c->conn->contexts, c);
+
+ if (c->iface && c->iface->unbind) {
+ c->iface->unbind(c, c->iface);
+ c->iface = NULL;
+ }
+
+ return 0;
+}
+
+static void dcesrv_prepare_context_auth(struct dcesrv_call_state *dce_call)
+{
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ const struct dcesrv_endpoint *endpoint = dce_call->conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
+ struct dcesrv_connection_context *context = dce_call->context;
+ const struct dcesrv_interface *iface = context->iface;
+
+ context->min_auth_level = DCERPC_AUTH_LEVEL_NONE;
+
+ if (transport == NCALRPC) {
+ context->allow_connect = true;
+ return;
+ }
+
+ /*
+ * allow overwrite per interface
+ * allow dcerpc auth level connect:<interface>
+ */
+ context->allow_connect = lpcfg_allow_dcerpc_auth_level_connect(lp_ctx);
+ context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
+ "allow dcerpc auth level connect",
+ iface->name,
+ context->allow_connect);
+}
+
+NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface)
+{
+ /*
+ * For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
+ * has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
+ */
+ context->min_auth_level = DCERPC_AUTH_LEVEL_PACKET;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface)
+{
+ context->min_auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface)
+{
+ struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx;
+ const struct dcesrv_endpoint *endpoint = context->conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
+
+ if (transport == NCALRPC) {
+ context->allow_connect = true;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * allow overwrite per interface
+ * allow dcerpc auth level connect:<interface>
+ */
+ context->allow_connect = false;
+ context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
+ "allow dcerpc auth level connect",
+ iface->name,
+ context->allow_connect);
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface)
+{
+ struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx;
+ const struct dcesrv_endpoint *endpoint = context->conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
+
+ if (transport == NCALRPC) {
+ context->allow_connect = true;
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * allow overwrite per interface
+ * allow dcerpc auth level connect:<interface>
+ */
+ context->allow_connect = true;
+ context->allow_connect = lpcfg_parm_bool(lp_ctx, NULL,
+ "allow dcerpc auth level connect",
+ iface->name,
+ context->allow_connect);
+ return NT_STATUS_OK;
+}
+
+struct dcesrv_conn_auth_wait_context {
+ struct tevent_req *req;
+ bool done;
+ NTSTATUS status;
+};
+
+struct dcesrv_conn_auth_wait_state {
+ uint8_t dummy;
+};
+
+static struct tevent_req *dcesrv_conn_auth_wait_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ void *private_data)
+{
+ struct dcesrv_conn_auth_wait_context *auth_wait =
+ talloc_get_type_abort(private_data,
+ struct dcesrv_conn_auth_wait_context);
+ struct tevent_req *req = NULL;
+ struct dcesrv_conn_auth_wait_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct dcesrv_conn_auth_wait_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ auth_wait->req = req;
+
+ tevent_req_defer_callback(req, ev);
+
+ if (!auth_wait->done) {
+ return req;
+ }
+
+ if (tevent_req_nterror(req, auth_wait->status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS dcesrv_conn_auth_wait_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS dcesrv_conn_auth_wait_setup(struct dcesrv_connection *conn)
+{
+ struct dcesrv_conn_auth_wait_context *auth_wait = NULL;
+
+ if (conn->wait_send != NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ auth_wait = talloc_zero(conn, struct dcesrv_conn_auth_wait_context);
+ if (auth_wait == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ conn->wait_private = auth_wait;
+ conn->wait_send = dcesrv_conn_auth_wait_send;
+ conn->wait_recv = dcesrv_conn_auth_wait_recv;
+ return NT_STATUS_OK;
+}
+
+static void dcesrv_conn_auth_wait_finished(struct dcesrv_connection *conn,
+ NTSTATUS status)
+{
+ struct dcesrv_conn_auth_wait_context *auth_wait =
+ talloc_get_type_abort(conn->wait_private,
+ struct dcesrv_conn_auth_wait_context);
+
+ auth_wait->done = true;
+ auth_wait->status = status;
+
+ if (auth_wait->req == NULL) {
+ return;
+ }
+
+ if (tevent_req_nterror(auth_wait->req, status)) {
+ return;
+ }
+
+ tevent_req_done(auth_wait->req);
+}
+
+static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call);
+
+static void dcesrv_bind_done(struct tevent_req *subreq);
+
+/*
+ handle a bind request
+*/
+static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
+{
+ struct dcesrv_connection *conn = call->conn;
+ struct dcesrv_context *dce_ctx = conn->dce_ctx;
+ struct ncacn_packet *pkt = &call->ack_pkt;
+ NTSTATUS status;
+ uint32_t extra_flags = 0;
+ uint16_t max_req = 0;
+ uint16_t max_rep = 0;
+ struct dcerpc_binding *ep_2nd_description = NULL;
+ const char *endpoint = NULL;
+ struct dcesrv_auth *auth = call->auth_state;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+ struct dcerpc_ack_ctx *ack_ctx_list = NULL;
+ struct dcerpc_ack_ctx *ack_features = NULL;
+ struct tevent_req *subreq = NULL;
+ size_t i;
+
+ status = dcerpc_verify_ncacn_packet_header(&call->pkt,
+ DCERPC_PKT_BIND,
+ call->pkt.u.bind.auth_info.length,
+ 0, /* required flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_bind_nak(call,
+ DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED);
+ }
+
+ /* max_recv_frag and max_xmit_frag result always in the same value! */
+ max_req = MIN(call->pkt.u.bind.max_xmit_frag,
+ call->pkt.u.bind.max_recv_frag);
+ /*
+ * The values are between 2048 and 5840 tested against Windows 2012R2
+ * via ncacn_ip_tcp on port 135.
+ */
+ max_req = MAX(2048, max_req);
+ max_rep = MIN(max_req, conn->max_recv_frag);
+ /* They are truncated to an 8 byte boundary. */
+ max_rep &= 0xFFF8;
+
+ /* max_recv_frag and max_xmit_frag result always in the same value! */
+ conn->max_recv_frag = max_rep;
+ conn->max_xmit_frag = max_rep;
+
+ status = dce_ctx->callbacks->assoc_group.find(
+ call, dce_ctx->callbacks->assoc_group.private_data);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_NOTICE("Failed to find assoc_group 0x%08x: %s\n",
+ call->pkt.u.bind.assoc_group_id, nt_errstr(status));
+ return dcesrv_bind_nak(call, 0);
+ }
+
+ if (call->pkt.u.bind.num_contexts < 1) {
+ return dcesrv_bind_nak(call, 0);
+ }
+
+ ack_ctx_list = talloc_zero_array(call, struct dcerpc_ack_ctx,
+ call->pkt.u.bind.num_contexts);
+ if (ack_ctx_list == NULL) {
+ return dcesrv_bind_nak(call, 0);
+ }
+
+ /*
+ * Set some sane defaults (required by dcesrv_negotiate_contexts()/
+ * dcesrv_check_or_create_context()) and do some protocol validation
+ * and set sane defaults.
+ */
+ for (i = 0; i < call->pkt.u.bind.num_contexts; i++) {
+ const struct dcerpc_ctx_list *c = &call->pkt.u.bind.ctx_list[i];
+ struct dcerpc_ack_ctx *a = &ack_ctx_list[i];
+ bool is_feature = false;
+ uint64_t features = 0;
+
+ if (c->num_transfer_syntaxes == 0) {
+ return dcesrv_bind_nak(call, 0);
+ }
+
+ a->result = DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION;
+ a->reason.value = DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
+
+ /*
+ * It's only treated as bind time feature request, if the first
+ * transfer_syntax matches, all others are ignored.
+ */
+ is_feature = dcerpc_extract_bind_time_features(c->transfer_syntaxes[0],
+ &features);
+ if (!is_feature) {
+ continue;
+ }
+
+ if (ack_features != NULL) {
+ /*
+ * Only one bind time feature context is allowed.
+ */
+ return dcesrv_bind_nak(call, 0);
+ }
+ ack_features = a;
+
+ a->result = DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK;
+ a->reason.negotiate = 0;
+ if (features & DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING) {
+ if (conn->max_auth_states != 0) {
+ a->reason.negotiate |=
+ DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING;
+ }
+ }
+ if (features & DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN) {
+ a->reason.negotiate |=
+ DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN;
+ }
+
+ conn->assoc_group->bind_time_features = a->reason.negotiate;
+ }
+
+ /*
+ * Try to negotiate one new presentation context.
+ *
+ * Deep in here we locate the iface (by uuid) that the client
+ * requested, from the list of interfaces on the
+ * call->conn->endpoint, and call iface->bind() on that iface.
+ *
+ * call->conn was set up at the accept() of the socket, and
+ * call->conn->endpoint has a list of interfaces restricted to
+ * this port or pipe.
+ */
+ status = dcesrv_negotiate_contexts(call, &call->pkt.u.bind, ack_ctx_list);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
+ return dcesrv_bind_nak(call, 0);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * At this point we still don't know which interface (eg
+ * netlogon, lsa, drsuapi) the caller requested in this bind!
+ * The most recently added context is available as the first
+ * element in the linked list at call->conn->contexts, that is
+ * call->conn->contexts->iface, but they may not have
+ * requested one at all!
+ */
+
+ if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
+ (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
+ call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
+ extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
+ }
+
+ if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
+ conn->state_flags |= DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
+ }
+
+ /*
+ * After finding the interface and setting up the NDR
+ * transport negotiation etc, handle any authentication that
+ * is being requested.
+ */
+ if (!dcesrv_auth_bind(call)) {
+
+ if (auth->auth_level == DCERPC_AUTH_LEVEL_NONE) {
+ /*
+ * With DCERPC_AUTH_LEVEL_NONE, we get the
+ * reject_reason in auth->auth_context_id.
+ */
+ return dcesrv_bind_nak(call, auth->auth_context_id);
+ }
+
+ /*
+ * This must a be a temporary failure e.g. talloc or invalid
+ * configuration, e.g. no machine account.
+ */
+ return dcesrv_bind_nak(call,
+ DCERPC_BIND_NAK_REASON_TEMPORARY_CONGESTION);
+ }
+
+ /* setup a bind_ack */
+ dcesrv_init_hdr(pkt, lpcfg_rpc_big_endian(dce_ctx->lp_ctx));
+ pkt->auth_length = 0;
+ pkt->call_id = call->pkt.call_id;
+ pkt->ptype = DCERPC_PKT_BIND_ACK;
+ pkt->pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
+ pkt->u.bind_ack.max_xmit_frag = conn->max_xmit_frag;
+ pkt->u.bind_ack.max_recv_frag = conn->max_recv_frag;
+ pkt->u.bind_ack.assoc_group_id = conn->assoc_group->id;
+
+ ep_2nd_description = conn->endpoint->ep_2nd_description;
+ if (ep_2nd_description == NULL) {
+ ep_2nd_description = conn->endpoint->ep_description;
+ }
+
+ endpoint = dcerpc_binding_get_string_option(
+ ep_2nd_description,
+ "endpoint");
+ if (endpoint == NULL) {
+ endpoint = "";
+ }
+
+ pkt->u.bind_ack.secondary_address = endpoint;
+ pkt->u.bind_ack.num_results = call->pkt.u.bind.num_contexts;
+ pkt->u.bind_ack.ctx_list = ack_ctx_list;
+ pkt->u.bind_ack.auth_info = data_blob_null;
+
+ status = dcesrv_auth_prepare_bind_ack(call, pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_bind_nak(call, 0);
+ }
+
+ if (auth->auth_finished) {
+ return dcesrv_auth_reply(call);
+ }
+
+ cb->auth.become_root();
+ subreq = gensec_update_send(call, call->event_ctx,
+ auth->gensec_security,
+ call->in_auth_info.credentials);
+ cb->auth.unbecome_root();
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, dcesrv_bind_done, call);
+
+ return dcesrv_conn_auth_wait_setup(conn);
+}
+
+static void dcesrv_bind_done(struct tevent_req *subreq)
+{
+ struct dcesrv_call_state *call =
+ tevent_req_callback_data(subreq,
+ struct dcesrv_call_state);
+ struct dcesrv_connection *conn = call->conn;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+ NTSTATUS status;
+
+ cb->auth.become_root();
+ status = gensec_update_recv(subreq, call,
+ &call->out_auth_info->credentials);
+ cb->auth.unbecome_root();
+ TALLOC_FREE(subreq);
+
+ status = dcesrv_auth_complete(call, status);
+ if (!NT_STATUS_IS_OK(status)) {
+ status = dcesrv_bind_nak(call, 0);
+ dcesrv_conn_auth_wait_finished(conn, status);
+ return;
+ }
+
+ status = dcesrv_auth_reply(call);
+ dcesrv_conn_auth_wait_finished(conn, status);
+ return;
+}
+
+static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call)
+{
+ struct ncacn_packet *pkt = &call->ack_pkt;
+ struct data_blob_list_item *rep = NULL;
+ NTSTATUS status;
+
+ rep = talloc_zero(call, struct data_blob_list_item);
+ if (!rep) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dcerpc_ncacn_push_auth(&rep->blob,
+ call,
+ pkt,
+ call->out_auth_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dcerpc_set_frag_length(&rep->blob, rep->blob.length);
+
+ DLIST_ADD_END(call->replies, rep);
+ dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
+
+ if (call->conn->call_list && call->conn->call_list->replies) {
+ if (call->conn->transport.report_output_data) {
+ call->conn->transport.report_output_data(call->conn);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+static void dcesrv_auth3_done(struct tevent_req *subreq);
+
+/*
+ handle a auth3 request
+*/
+static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
+{
+ struct dcesrv_connection *conn = call->conn;
+ struct dcesrv_auth *auth = call->auth_state;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+ struct tevent_req *subreq = NULL;
+ NTSTATUS status;
+
+ if (!auth->auth_started) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ if (auth->auth_finished) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ status = dcerpc_verify_ncacn_packet_header(&call->pkt,
+ DCERPC_PKT_AUTH3,
+ call->pkt.u.auth3.auth_info.length,
+ 0, /* required flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ /* handle the auth3 in the auth code */
+ if (!dcesrv_auth_prepare_auth3(call)) {
+ /*
+ * we don't send a reply to a auth3 request,
+ * except by a fault.
+ *
+ * In anycase we mark the connection as
+ * invalid.
+ */
+ auth->auth_invalid = true;
+ if (call->fault_code != 0) {
+ return dcesrv_fault_disconnect(call, call->fault_code);
+ }
+ TALLOC_FREE(call);
+ return NT_STATUS_OK;
+ }
+
+ cb->auth.become_root();
+ subreq = gensec_update_send(call, call->event_ctx,
+ auth->gensec_security,
+ call->in_auth_info.credentials);
+ cb->auth.unbecome_root();
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, dcesrv_auth3_done, call);
+
+ return dcesrv_conn_auth_wait_setup(conn);
+}
+
+static void dcesrv_auth3_done(struct tevent_req *subreq)
+{
+ struct dcesrv_call_state *call =
+ tevent_req_callback_data(subreq,
+ struct dcesrv_call_state);
+ struct dcesrv_connection *conn = call->conn;
+ struct dcesrv_auth *auth = call->auth_state;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+ NTSTATUS status;
+
+ cb->auth.become_root();
+ status = gensec_update_recv(subreq, call,
+ &call->out_auth_info->credentials);
+ cb->auth.unbecome_root();
+ TALLOC_FREE(subreq);
+
+ status = dcesrv_auth_complete(call, status);
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * we don't send a reply to a auth3 request,
+ * except by a fault.
+ *
+ * In anycase we mark the connection as
+ * invalid.
+ */
+ auth->auth_invalid = true;
+ if (call->fault_code != 0) {
+ status = dcesrv_fault_disconnect(call, call->fault_code);
+ dcesrv_conn_auth_wait_finished(conn, status);
+ return;
+ }
+ TALLOC_FREE(call);
+ dcesrv_conn_auth_wait_finished(conn, NT_STATUS_OK);
+ return;
+ }
+
+ /*
+ * we don't send a reply to a auth3 request.
+ */
+ TALLOC_FREE(call);
+ dcesrv_conn_auth_wait_finished(conn, NT_STATUS_OK);
+ return;
+}
+
+
+static NTSTATUS dcesrv_check_or_create_context(struct dcesrv_call_state *call,
+ const struct dcerpc_bind *b,
+ const struct dcerpc_ctx_list *ctx,
+ struct dcerpc_ack_ctx *ack,
+ bool validate_only,
+ const struct ndr_syntax_id *supported_transfer)
+{
+ struct dcesrv_connection_context *context;
+ const struct dcesrv_interface *iface;
+ NTSTATUS status;
+ const struct ndr_syntax_id *selected_transfer = NULL;
+ size_t i;
+ bool ok;
+
+ if (b == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ if (ctx == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ if (ctx->num_transfer_syntaxes < 1) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ if (ack == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ if (supported_transfer == NULL) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ switch (ack->result) {
+ case DCERPC_BIND_ACK_RESULT_ACCEPTANCE:
+ case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
+ /*
+ * We is already completed.
+ */
+ return NT_STATUS_OK;
+ default:
+ break;
+ }
+
+ ack->result = DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION;
+ ack->reason.value = DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
+
+ iface = find_interface_by_syntax_id(
+ call->conn->endpoint, &ctx->abstract_syntax);
+ if (iface == NULL) {
+ struct ndr_syntax_id_buf buf;
+ DBG_NOTICE("Request for unknown dcerpc interface %s\n",
+ ndr_syntax_id_buf_string(
+ &ctx->abstract_syntax, &buf));
+ /*
+ * We report this only via ack->result
+ */
+ return NT_STATUS_OK;
+ }
+
+ ack->result = DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION;
+ ack->reason.value = DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED;
+
+ if (validate_only) {
+ /*
+ * We report this only via ack->result
+ */
+ return NT_STATUS_OK;
+ }
+
+ for (i = 0; i < ctx->num_transfer_syntaxes; i++) {
+ /*
+ * we only do NDR encoded dcerpc for now.
+ */
+ ok = ndr_syntax_id_equal(&ctx->transfer_syntaxes[i],
+ supported_transfer);
+ if (ok) {
+ selected_transfer = supported_transfer;
+ break;
+ }
+ }
+
+ context = dcesrv_find_context(call->conn, ctx->context_id);
+ if (context != NULL) {
+ ok = ndr_syntax_id_equal(&context->iface->syntax_id,
+ &ctx->abstract_syntax);
+ if (!ok) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ if (selected_transfer != NULL) {
+ ok = ndr_syntax_id_equal(&context->transfer_syntax,
+ selected_transfer);
+ if (!ok) {
+ return NT_STATUS_RPC_PROTOCOL_ERROR;
+ }
+
+ ack->result = DCERPC_BIND_ACK_RESULT_ACCEPTANCE;
+ ack->reason.value = DCERPC_BIND_ACK_REASON_NOT_SPECIFIED;
+ ack->syntax = context->transfer_syntax;
+ }
+
+ /*
+ * We report this only via ack->result
+ */
+ return NT_STATUS_OK;
+ }
+
+ if (selected_transfer == NULL) {
+ /*
+ * We report this only via ack->result
+ */
+ return NT_STATUS_OK;
+ }
+
+ ack->result = DCERPC_BIND_ACK_RESULT_USER_REJECTION;
+ ack->reason.value = DCERPC_BIND_ACK_REASON_LOCAL_LIMIT_EXCEEDED;
+
+ /* add this context to the list of available context_ids */
+ context = talloc_zero(call->conn, struct dcesrv_connection_context);
+ if (context == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ context->conn = call->conn;
+ context->context_id = ctx->context_id;
+ context->iface = iface;
+ context->transfer_syntax = *selected_transfer;
+ context->ndr64 = ndr_syntax_id_equal(&context->transfer_syntax,
+ &ndr_transfer_syntax_ndr64);
+ DLIST_ADD(call->conn->contexts, context);
+ call->context = context;
+ talloc_set_destructor(context, dcesrv_connection_context_destructor);
+
+ dcesrv_prepare_context_auth(call);
+
+ /*
+ * Multiplex is supported by default
+ */
+ call->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
+
+ status = iface->bind(context, iface);
+ call->context = NULL;
+ if (!NT_STATUS_IS_OK(status)) {
+ /* we don't want to trigger the iface->unbind() hook */
+ context->iface = NULL;
+ talloc_free(context);
+ /*
+ * We report this only via ack->result
+ */
+ return NT_STATUS_OK;
+ }
+
+ ack->result = DCERPC_BIND_ACK_RESULT_ACCEPTANCE;
+ ack->reason.value = DCERPC_BIND_ACK_REASON_NOT_SPECIFIED;
+ ack->syntax = context->transfer_syntax;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS dcesrv_negotiate_contexts(struct dcesrv_call_state *call,
+ const struct dcerpc_bind *b,
+ struct dcerpc_ack_ctx *ack_ctx_list)
+{
+ NTSTATUS status;
+ size_t i;
+ bool validate_only = false;
+ bool preferred_ndr32;
+
+ /*
+ * Try to negotiate one new presentation context,
+ * using our preferred transfer syntax.
+ */
+ for (i = 0; i < b->num_contexts; i++) {
+ const struct dcerpc_ctx_list *c = &b->ctx_list[i];
+ struct dcerpc_ack_ctx *a = &ack_ctx_list[i];
+
+ status = dcesrv_check_or_create_context(call, b, c, a,
+ validate_only,
+ call->conn->preferred_transfer);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (a->result == DCERPC_BIND_ACK_RESULT_ACCEPTANCE) {
+ /*
+ * We managed to negotiate one context.
+ *
+ * => we're done.
+ */
+ validate_only = true;
+ }
+ }
+
+ preferred_ndr32 = ndr_syntax_id_equal(&ndr_transfer_syntax_ndr,
+ call->conn->preferred_transfer);
+ if (preferred_ndr32) {
+ /*
+ * We're done.
+ */
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Try to negotiate one new presentation context,
+ * using NDR 32 as fallback.
+ */
+ for (i = 0; i < b->num_contexts; i++) {
+ const struct dcerpc_ctx_list *c = &b->ctx_list[i];
+ struct dcerpc_ack_ctx *a = &ack_ctx_list[i];
+
+ status = dcesrv_check_or_create_context(call, b, c, a,
+ validate_only,
+ &ndr_transfer_syntax_ndr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (a->result == DCERPC_BIND_ACK_RESULT_ACCEPTANCE) {
+ /*
+ * We managed to negotiate one context.
+ *
+ * => we're done.
+ */
+ validate_only = true;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void dcesrv_alter_done(struct tevent_req *subreq);
+
+/*
+ handle a alter context request
+*/
+static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
+{
+ struct dcesrv_connection *conn = call->conn;
+ NTSTATUS status;
+ bool auth_ok = false;
+ struct ncacn_packet *pkt = &call->ack_pkt;
+ uint32_t extra_flags = 0;
+ struct dcesrv_auth *auth = call->auth_state;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+ struct dcerpc_ack_ctx *ack_ctx_list = NULL;
+ struct tevent_req *subreq = NULL;
+ size_t i;
+
+ if (!call->conn->allow_alter) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ status = dcerpc_verify_ncacn_packet_header(&call->pkt,
+ DCERPC_PKT_ALTER,
+ call->pkt.u.alter.auth_info.length,
+ 0, /* required flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ auth_ok = dcesrv_auth_alter(call);
+ if (!auth_ok) {
+ if (call->fault_code != 0) {
+ return dcesrv_fault_disconnect(call, call->fault_code);
+ }
+ }
+
+ if (call->pkt.u.alter.num_contexts < 1) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ ack_ctx_list = talloc_zero_array(call, struct dcerpc_ack_ctx,
+ call->pkt.u.alter.num_contexts);
+ if (ack_ctx_list == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /*
+ * Set some sane defaults (required by dcesrv_negotiate_contexts()/
+ * dcesrv_check_or_create_context()) and do some protocol validation
+ * and set sane defaults.
+ */
+ for (i = 0; i < call->pkt.u.alter.num_contexts; i++) {
+ const struct dcerpc_ctx_list *c = &call->pkt.u.alter.ctx_list[i];
+ struct dcerpc_ack_ctx *a = &ack_ctx_list[i];
+
+ if (c->num_transfer_syntaxes == 0) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ a->result = DCERPC_BIND_ACK_RESULT_PROVIDER_REJECTION;
+ a->reason.value = DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
+ }
+
+ /*
+ * Try to negotiate one new presentation context.
+ */
+ status = dcesrv_negotiate_contexts(call, &call->pkt.u.alter, ack_ctx_list);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) &&
+ (call->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
+ call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_MULTIPLEXED;
+ extra_flags |= DCERPC_PFC_FLAG_CONC_MPX;
+ }
+
+ if (call->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
+ call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL;
+ }
+
+ /* handle any authentication that is being requested */
+ if (!auth_ok) {
+ if (call->in_auth_info.auth_type != auth->auth_type) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_FAULT_SEC_PKG_ERROR);
+ }
+ return dcesrv_fault_disconnect(call, DCERPC_FAULT_ACCESS_DENIED);
+ }
+
+ dcesrv_init_hdr(pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
+ pkt->auth_length = 0;
+ pkt->call_id = call->pkt.call_id;
+ pkt->ptype = DCERPC_PKT_ALTER_RESP;
+ pkt->pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
+ pkt->u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag;
+ pkt->u.alter_resp.max_recv_frag = call->conn->max_recv_frag;
+ pkt->u.alter_resp.assoc_group_id = call->conn->assoc_group->id;
+ pkt->u.alter_resp.secondary_address = "";
+ pkt->u.alter_resp.num_results = call->pkt.u.alter.num_contexts;
+ pkt->u.alter_resp.ctx_list = ack_ctx_list;
+ pkt->u.alter_resp.auth_info = data_blob_null;
+
+ status = dcesrv_auth_prepare_alter_ack(call, pkt);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
+ }
+
+ if (auth->auth_finished) {
+ return dcesrv_auth_reply(call);
+ }
+
+ cb->auth.become_root();
+ subreq = gensec_update_send(call, call->event_ctx,
+ auth->gensec_security,
+ call->in_auth_info.credentials);
+ cb->auth.unbecome_root();
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, dcesrv_alter_done, call);
+
+ return dcesrv_conn_auth_wait_setup(conn);
+}
+
+static void dcesrv_alter_done(struct tevent_req *subreq)
+{
+ struct dcesrv_call_state *call =
+ tevent_req_callback_data(subreq,
+ struct dcesrv_call_state);
+ struct dcesrv_connection *conn = call->conn;
+ struct dcesrv_context_callbacks *cb = call->conn->dce_ctx->callbacks;
+ NTSTATUS status;
+
+ cb->auth.become_root();
+ status = gensec_update_recv(subreq, call,
+ &call->out_auth_info->credentials);
+ cb->auth.unbecome_root();
+ TALLOC_FREE(subreq);
+
+ status = dcesrv_auth_complete(call, status);
+ if (!NT_STATUS_IS_OK(status)) {
+ status = dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
+ dcesrv_conn_auth_wait_finished(conn, status);
+ return;
+ }
+
+ status = dcesrv_auth_reply(call);
+ dcesrv_conn_auth_wait_finished(conn, status);
+ return;
+}
+
+/*
+ possibly save the call for inspection with ndrdump
+ */
+static void dcesrv_save_call(struct dcesrv_call_state *call, const char *why)
+{
+#ifdef DEVELOPER
+ dcerpc_log_packet(call->conn->packet_log_dir,
+ call->context->iface->name,
+ call->pkt.u.request.opnum,
+ NDR_IN,
+ &call->pkt.u.request.stub_and_verifier,
+ why);
+#endif
+}
+
+#ifdef DEVELOPER
+/*
+ Save the call for use as a seed for fuzzing.
+
+ This is only enabled in a developer build, and only has effect if the
+ "dcesrv fuzz directory" param is set.
+*/
+void _dcesrv_save_ndr_fuzz_seed(DATA_BLOB call_blob,
+ struct dcesrv_call_state *call,
+ ndr_flags_type flags)
+{
+ const char *dump_dir = lpcfg_parm_string(call->conn->dce_ctx->lp_ctx,
+ NULL,
+ "dcesrv", "fuzz directory");
+
+ dcerpc_save_ndr_fuzz_seed(call,
+ call_blob,
+ dump_dir,
+ call->context->iface->name,
+ flags,
+ call->pkt.u.request.opnum,
+ call->ndr_pull->flags & LIBNDR_FLAG_NDR64);
+}
+#endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */
+
+
+static NTSTATUS dcesrv_check_verification_trailer(struct dcesrv_call_state *call)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const uint32_t bitmask1 = call->conn->client_hdr_signing ?
+ DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING : 0;
+ const struct dcerpc_sec_vt_pcontext pcontext = {
+ .abstract_syntax = call->context->iface->syntax_id,
+ .transfer_syntax = call->context->transfer_syntax,
+ };
+ const struct dcerpc_sec_vt_header2 header2 =
+ dcerpc_sec_vt_header2_from_ncacn_packet(&call->pkt);
+ enum ndr_err_code ndr_err;
+ struct dcerpc_sec_verification_trailer *vt = NULL;
+ NTSTATUS status = NT_STATUS_OK;
+ bool ok;
+
+ SMB_ASSERT(call->pkt.ptype == DCERPC_PKT_REQUEST);
+
+ ndr_err = ndr_pop_dcerpc_sec_verification_trailer(call->ndr_pull,
+ frame, &vt);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ goto done;
+ }
+
+ ok = dcerpc_sec_verification_trailer_check(vt, &bitmask1,
+ &pcontext, &header2);
+ if (!ok) {
+ status = NT_STATUS_ACCESS_DENIED;
+ goto done;
+ }
+done:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/*
+ handle a dcerpc request packet
+*/
+static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
+{
+ const struct dcesrv_endpoint *endpoint = call->conn->endpoint;
+ struct dcesrv_auth *auth = call->auth_state;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
+ struct ndr_pull *pull;
+ bool turn_winbind_on = false;
+ NTSTATUS status;
+
+ if (auth->auth_invalid) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ if (!auth->auth_finished) {
+ return dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ /* if authenticated, and the mech we use can't do async replies, don't use them... */
+ if (auth->gensec_security != NULL &&
+ !gensec_have_feature(auth->gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
+ call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
+ }
+
+ if (call->context == NULL) {
+ return dcesrv_fault_with_flags(call, DCERPC_NCA_S_UNKNOWN_IF,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+ }
+
+ switch (auth->auth_level) {
+ case DCERPC_AUTH_LEVEL_NONE:
+ case DCERPC_AUTH_LEVEL_PACKET:
+ case DCERPC_AUTH_LEVEL_INTEGRITY:
+ case DCERPC_AUTH_LEVEL_PRIVACY:
+ break;
+ default:
+ if (!call->context->allow_connect) {
+ char *addr;
+
+ addr = tsocket_address_string(call->conn->remote_address,
+ call);
+
+ DEBUG(2, ("%s: restrict auth_level_connect access "
+ "to [%s] with auth[type=0x%x,level=0x%x] "
+ "on [%s] from [%s]\n",
+ __func__, call->context->iface->name,
+ auth->auth_type,
+ auth->auth_level,
+ derpc_transport_string_by_transport(transport),
+ addr));
+ return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
+ }
+ break;
+ }
+
+ if (auth->auth_level < call->context->min_auth_level) {
+ char *addr;
+
+ addr = tsocket_address_string(call->conn->remote_address, call);
+
+ DEBUG(2, ("%s: restrict access by min_auth_level[0x%x] "
+ "to [%s] with auth[type=0x%x,level=0x%x] "
+ "on [%s] from [%s]\n",
+ __func__,
+ call->context->min_auth_level,
+ call->context->iface->name,
+ auth->auth_type,
+ auth->auth_level,
+ derpc_transport_string_by_transport(transport),
+ addr));
+ return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
+ }
+
+ pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
+ NT_STATUS_HAVE_NO_MEMORY(pull);
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ call->ndr_pull = pull;
+
+ if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
+ pull->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ status = dcesrv_check_verification_trailer(call);
+ if (!NT_STATUS_IS_OK(status)) {
+ uint32_t faultcode = DCERPC_FAULT_OTHER;
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
+ faultcode = DCERPC_FAULT_ACCESS_DENIED;
+ }
+ DEBUG(10, ("dcesrv_check_verification_trailer failed: %s\n",
+ nt_errstr(status)));
+ return dcesrv_fault(call, faultcode);
+ }
+
+ if (call->context->ndr64) {
+ call->ndr_pull->flags |= LIBNDR_FLAG_NDR64;
+ }
+
+ /* unravel the NDR for the packet */
+ status = call->context->iface->ndr_pull(call, call, pull, &call->r);
+ if (!NT_STATUS_IS_OK(status)) {
+ uint8_t extra_flags = 0;
+ if (call->fault_code == DCERPC_FAULT_OP_RNG_ERROR) {
+ /* we got an unknown call */
+ DEBUG(3,(__location__ ": Unknown RPC call %"PRIu16" on %s\n",
+ call->pkt.u.request.opnum,
+ call->context->iface->name));
+ dcesrv_save_call(call, "unknown");
+ extra_flags |= DCERPC_PFC_FLAG_DID_NOT_EXECUTE;
+ } else {
+ dcesrv_save_call(call, "pullfail");
+ }
+
+ return dcesrv_fault_with_flags(call, call->fault_code, extra_flags);
+ }
+
+ dcesrv_save_ndr_fuzz_seed(call->pkt.u.request.stub_and_verifier,
+ call,
+ NDR_IN);
+
+ if (pull->offset != pull->data_size) {
+ dcesrv_save_call(call, "extrabytes");
+ DEBUG(3,("Warning: %"PRIu32" extra bytes in incoming RPC request\n",
+ pull->data_size - pull->offset));
+ }
+
+ if (call->state_flags & DCESRV_CALL_STATE_FLAG_WINBIND_OFF) {
+ bool winbind_active = !winbind_env_set();
+ if (winbind_active) {
+ DBG_DEBUG("turning winbind off\n");
+ (void)winbind_off();
+ turn_winbind_on = true;
+ }
+ }
+
+ /* call the dispatch function */
+ status = call->context->iface->dispatch(call, call, call->r);
+
+ if (turn_winbind_on) {
+ DBG_DEBUG("turning winbind on\n");
+ (void)winbind_on();
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
+ call->context->iface->name,
+ call->pkt.u.request.opnum,
+ dcerpc_errstr(pull, call->fault_code)));
+ return dcesrv_fault(call, call->fault_code);
+ }
+
+ /* add the call to the pending list */
+ dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
+
+ if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
+ return NT_STATUS_OK;
+ }
+
+ return dcesrv_reply(call);
+}
+
+
+/*
+ remove the call from the right list when freed
+ */
+static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
+{
+ dcesrv_call_set_list(call, DCESRV_LIST_NONE);
+ return 0;
+}
+
+_PUBLIC_ const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn)
+{
+ return conn->local_address;
+}
+
+_PUBLIC_ const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn)
+{
+ return conn->remote_address;
+}
+
+/*
+ process some input to a dcerpc endpoint server.
+*/
+static NTSTATUS dcesrv_process_ncacn_packet(struct dcesrv_connection *dce_conn,
+ struct ncacn_packet *pkt,
+ DATA_BLOB blob)
+{
+ NTSTATUS status;
+ struct dcesrv_call_state *call;
+ struct dcesrv_call_state *existing = NULL;
+ size_t num_auth_ctx = 0;
+ enum dcerpc_AuthType auth_type = 0;
+ enum dcerpc_AuthLevel auth_level = 0;
+ uint32_t auth_context_id = 0;
+ bool auth_invalid = false;
+
+ call = talloc_zero(dce_conn, struct dcesrv_call_state);
+ if (!call) {
+ data_blob_free(&blob);
+ talloc_free(pkt);
+ return NT_STATUS_NO_MEMORY;
+ }
+ call->conn = dce_conn;
+ call->event_ctx = dce_conn->event_ctx;
+ call->state_flags = call->conn->state_flags;
+ call->time = timeval_current();
+ call->list = DCESRV_LIST_NONE;
+
+ talloc_steal(call, pkt);
+ talloc_steal(call, blob.data);
+ call->pkt = *pkt;
+
+ if (dce_conn->max_auth_states == 0) {
+ call->auth_state = dce_conn->default_auth_state;
+ } else if (call->pkt.auth_length == 0) {
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
+ dce_conn->default_auth_level_connect != NULL)
+ {
+ call->auth_state = dce_conn->default_auth_level_connect;
+ } else {
+ call->auth_state = dce_conn->default_auth_state;
+ }
+ }
+
+ if (call->auth_state == NULL) {
+ struct dcesrv_auth *a = NULL;
+ bool check_type_level = true;
+
+ auth_type = dcerpc_get_auth_type(&blob);
+ auth_level = dcerpc_get_auth_level(&blob);
+ auth_context_id = dcerpc_get_auth_context_id(&blob);
+
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
+ if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
+ check_type_level = false;
+ }
+ dce_conn->default_auth_level_connect = NULL;
+ if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
+ dce_conn->got_explicit_auth_level_connect = true;
+ }
+ }
+
+ for (a = dce_conn->auth_states; a != NULL; a = a->next) {
+ num_auth_ctx++;
+
+ if (a->auth_context_id != auth_context_id) {
+ continue;
+ }
+
+ if (a->auth_type != auth_type) {
+ auth_invalid = true;
+ }
+ if (a->auth_level != auth_level) {
+ auth_invalid = true;
+ }
+
+ if (check_type_level && auth_invalid) {
+ a->auth_invalid = true;
+ }
+
+ DLIST_PROMOTE(dce_conn->auth_states, a);
+ call->auth_state = a;
+ break;
+ }
+ }
+
+ if (call->auth_state == NULL) {
+ struct dcesrv_auth *a = NULL;
+
+ if (num_auth_ctx >= dce_conn->max_auth_states) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ a = dcesrv_auth_create(dce_conn);
+ if (a == NULL) {
+ talloc_free(call);
+ return NT_STATUS_NO_MEMORY;
+ }
+ DLIST_ADD(dce_conn->auth_states, a);
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
+ /*
+ * This can never be valid.
+ */
+ auth_invalid = true;
+ a->auth_invalid = true;
+ }
+ call->auth_state = a;
+ }
+
+ talloc_set_destructor(call, dcesrv_call_dequeue);
+
+ if (call->conn->allow_bind) {
+ /*
+ * Only one bind is possible per connection
+ */
+ call->conn->allow_bind = false;
+ return dcesrv_bind(call);
+ }
+
+ /* we have to check the signing here, before combining the
+ pdus */
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
+ dcesrv_default_auth_state_prepare_request(call);
+
+ if (call->auth_state->auth_started &&
+ !call->auth_state->auth_finished) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ status = dcerpc_verify_ncacn_packet_header(&call->pkt,
+ DCERPC_PKT_REQUEST,
+ call->pkt.u.request.stub_and_verifier.length,
+ 0, /* required_flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_PENDING_CANCEL |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ if (call->pkt.frag_length > DCERPC_FRAG_MAX_SIZE) {
+ /*
+ * We don't use dcesrv_fault_disconnect()
+ * here, because we don't want to set
+ * DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+ *
+ * Note that we don't check against the negotiated
+ * max_recv_frag, but a hard coded value.
+ */
+ return dcesrv_fault_disconnect0(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
+ if (dce_conn->pending_call_list != NULL) {
+ /*
+ * concurrent requests are only allowed
+ * if DCERPC_PFC_FLAG_CONC_MPX was negotiated.
+ */
+ if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ }
+ /* only one request is possible in the fragmented list */
+ if (dce_conn->incoming_fragmented_call_list != NULL) {
+ call->fault_code = DCERPC_NCA_S_PROTO_ERROR;
+
+ existing = dcesrv_find_fragmented_call(dce_conn,
+ call->pkt.call_id);
+ if (existing != NULL && call->auth_state != existing->auth_state) {
+ call->context = dcesrv_find_context(call->conn,
+ call->pkt.u.request.context_id);
+
+ if (call->pkt.auth_length != 0 && existing->context == call->context) {
+ call->fault_code = DCERPC_FAULT_SEC_PKG_ERROR;
+ }
+ }
+ if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
+ /*
+ * Without DCERPC_PFC_FLAG_CONC_MPX
+ * we need to return the FAULT on the
+ * already existing call.
+ *
+ * This is important to get the
+ * call_id and context_id right.
+ */
+ dce_conn->incoming_fragmented_call_list->fault_code = call->fault_code;
+ TALLOC_FREE(call);
+ call = dce_conn->incoming_fragmented_call_list;
+ }
+ if (existing != NULL) {
+ call->context = existing->context;
+ }
+ return dcesrv_fault_disconnect0(call, call->fault_code);
+ }
+ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_PENDING_CANCEL) {
+ return dcesrv_fault_disconnect(call,
+ DCERPC_FAULT_NO_CALL_ACTIVE);
+ }
+ call->context = dcesrv_find_context(call->conn,
+ call->pkt.u.request.context_id);
+ if (call->context == NULL) {
+ return dcesrv_fault_with_flags(call, DCERPC_NCA_S_UNKNOWN_IF,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+ }
+ } else {
+ int cmp;
+
+ existing = dcesrv_find_fragmented_call(dce_conn,
+ call->pkt.call_id);
+ if (existing == NULL) {
+ if (!(dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_MULTIPLEXED)) {
+ /*
+ * Without DCERPC_PFC_FLAG_CONC_MPX
+ * we need to return the FAULT on the
+ * already existing call.
+ *
+ * This is important to get the
+ * call_id and context_id right.
+ */
+ if (dce_conn->incoming_fragmented_call_list != NULL) {
+ TALLOC_FREE(call);
+ call = dce_conn->incoming_fragmented_call_list;
+ }
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ if (dce_conn->incoming_fragmented_call_list != NULL) {
+ return dcesrv_fault_disconnect0(call, DCERPC_NCA_S_PROTO_ERROR);
+ }
+ call->context = dcesrv_find_context(call->conn,
+ call->pkt.u.request.context_id);
+ if (call->context == NULL) {
+ return dcesrv_fault_with_flags(call, DCERPC_NCA_S_UNKNOWN_IF,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+ }
+ if (auth_invalid) {
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_FAULT_ACCESS_DENIED);
+ }
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+
+ if (call->pkt.ptype != existing->pkt.ptype) {
+ /* trying to play silly buggers are we? */
+ return dcesrv_fault_disconnect(existing,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ cmp = memcmp(call->pkt.drep, existing->pkt.drep,
+ sizeof(pkt->drep));
+ if (cmp != 0) {
+ return dcesrv_fault_disconnect(existing,
+ DCERPC_NCA_S_PROTO_ERROR);
+ }
+ call->auth_state = existing->auth_state;
+ call->context = existing->context;
+ }
+ }
+
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST) {
+ bool ok;
+ uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
+
+ if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
+ payload_offset += 16;
+ }
+
+ ok = dcesrv_auth_pkt_pull(call, &blob,
+ 0, /* required_flags */
+ DCERPC_PFC_FLAG_FIRST |
+ DCERPC_PFC_FLAG_LAST |
+ DCERPC_PFC_FLAG_PENDING_CANCEL |
+ 0x08 | /* this is not defined, but should be ignored */
+ DCERPC_PFC_FLAG_CONC_MPX |
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE |
+ DCERPC_PFC_FLAG_MAYBE |
+ DCERPC_PFC_FLAG_OBJECT_UUID,
+ payload_offset,
+ &call->pkt.u.request.stub_and_verifier);
+ if (!ok) {
+ /*
+ * We don't use dcesrv_fault_disconnect()
+ * here, because we don't want to set
+ * DCERPC_PFC_FLAG_DID_NOT_EXECUTE
+ */
+ if (call->fault_code == 0) {
+ call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
+ }
+ return dcesrv_fault_disconnect0(call, call->fault_code);
+ }
+ }
+
+ /* see if this is a continued packet */
+ if (existing != NULL) {
+ struct dcerpc_request *er = &existing->pkt.u.request;
+ const struct dcerpc_request *nr = &call->pkt.u.request;
+ size_t available;
+ size_t alloc_size;
+ size_t alloc_hint;
+
+ /*
+ * Up to 4 MByte are allowed by all fragments
+ */
+ available = dce_conn->max_total_request_size;
+ if (er->stub_and_verifier.length > available) {
+ return dcesrv_fault_disconnect0(existing,
+ DCERPC_FAULT_ACCESS_DENIED);
+ }
+ available -= er->stub_and_verifier.length;
+ if (nr->alloc_hint > available) {
+ return dcesrv_fault_disconnect0(existing,
+ DCERPC_FAULT_ACCESS_DENIED);
+ }
+ if (nr->stub_and_verifier.length > available) {
+ return dcesrv_fault_disconnect0(existing,
+ DCERPC_FAULT_ACCESS_DENIED);
+ }
+ alloc_hint = er->stub_and_verifier.length + nr->alloc_hint;
+ /* allocate at least 1 byte */
+ alloc_hint = MAX(alloc_hint, 1);
+ alloc_size = er->stub_and_verifier.length +
+ nr->stub_and_verifier.length;
+ alloc_size = MAX(alloc_size, alloc_hint);
+
+ er->stub_and_verifier.data =
+ talloc_realloc(existing,
+ er->stub_and_verifier.data,
+ uint8_t, alloc_size);
+ if (er->stub_and_verifier.data == NULL) {
+ TALLOC_FREE(call);
+ return dcesrv_fault_with_flags(existing,
+ DCERPC_FAULT_OUT_OF_RESOURCES,
+ DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
+ }
+ memcpy(er->stub_and_verifier.data +
+ er->stub_and_verifier.length,
+ nr->stub_and_verifier.data,
+ nr->stub_and_verifier.length);
+ er->stub_and_verifier.length += nr->stub_and_verifier.length;
+
+ existing->pkt.pfc_flags |= (call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
+
+ TALLOC_FREE(call);
+ call = existing;
+ }
+
+ /* this may not be the last pdu in the chain - if its isn't then
+ just put it on the incoming_fragmented_call_list and wait for the rest */
+ if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
+ !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+ /*
+ * Up to 4 MByte are allowed by all fragments
+ */
+ if (call->pkt.u.request.alloc_hint > dce_conn->max_total_request_size) {
+ return dcesrv_fault_disconnect0(call,
+ DCERPC_FAULT_ACCESS_DENIED);
+ }
+ dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
+ return NT_STATUS_OK;
+ }
+
+ /* This removes any fragments we may have had stashed away */
+ dcesrv_call_set_list(call, DCESRV_LIST_NONE);
+
+ switch (call->pkt.ptype) {
+ case DCERPC_PKT_BIND:
+ status = dcesrv_bind_nak(call,
+ DCERPC_BIND_NAK_REASON_NOT_SPECIFIED);
+ break;
+ case DCERPC_PKT_AUTH3:
+ status = dcesrv_auth3(call);
+ break;
+ case DCERPC_PKT_ALTER:
+ status = dcesrv_alter(call);
+ break;
+ case DCERPC_PKT_REQUEST:
+ status = dcesrv_request(call);
+ break;
+ case DCERPC_PKT_CO_CANCEL:
+ existing = dcesrv_find_fragmented_call(dce_conn,
+ call->pkt.call_id);
+ if (existing != NULL) {
+ /*
+ * If the call is still waiting for
+ * more fragments, it's not pending yet,
+ * for now we just remember we got CO_CANCEL,
+ * but ignore it otherwise.
+ *
+ * This matches what windows is doing...
+ */
+ existing->got_co_cancel = true;
+ SMB_ASSERT(existing->subreq == NULL);
+ existing = NULL;
+ }
+ existing = dcesrv_find_pending_call(dce_conn,
+ call->pkt.call_id);
+ if (existing != NULL) {
+ /*
+ * Give the backend a chance to react
+ * on CO_CANCEL, but note it's ignored
+ * by default.
+ */
+ existing->got_co_cancel = true;
+ if (existing->subreq != NULL) {
+ tevent_req_cancel(existing->subreq);
+ }
+ existing = NULL;
+ }
+ status = NT_STATUS_OK;
+ TALLOC_FREE(call);
+ break;
+ case DCERPC_PKT_ORPHANED:
+ existing = dcesrv_find_fragmented_call(dce_conn,
+ call->pkt.call_id);
+ if (existing != NULL) {
+ /*
+ * If the call is still waiting for
+ * more fragments, it's not pending yet,
+ * for now we just remember we got ORPHANED,
+ * but ignore it otherwise.
+ *
+ * This matches what windows is doing...
+ */
+ existing->got_orphaned = true;
+ SMB_ASSERT(existing->subreq == NULL);
+ existing = NULL;
+ }
+ existing = dcesrv_find_pending_call(dce_conn,
+ call->pkt.call_id);
+ if (existing != NULL) {
+ /*
+ * Give the backend a chance to react
+ * on ORPHANED, but note it's ignored
+ * by default.
+ */
+ existing->got_orphaned = true;
+ if (existing->subreq != NULL) {
+ tevent_req_cancel(existing->subreq);
+ }
+ existing = NULL;
+ }
+ status = NT_STATUS_OK;
+ TALLOC_FREE(call);
+ break;
+ case DCERPC_PKT_BIND_ACK:
+ case DCERPC_PKT_BIND_NAK:
+ case DCERPC_PKT_ALTER_RESP:
+ case DCERPC_PKT_RESPONSE:
+ case DCERPC_PKT_FAULT:
+ case DCERPC_PKT_SHUTDOWN:
+ default:
+ status = dcesrv_fault_disconnect(call, DCERPC_NCA_S_PROTO_ERROR);
+ break;
+ }
+
+ /* if we are going to be sending a reply then add
+ it to the list of pending calls. We add it to the end to keep the call
+ list in the order we will answer */
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(call);
+ }
+
+ return status;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct dcesrv_context_callbacks *cb,
+ struct dcesrv_context **_dce_ctx)
+{
+ struct dcesrv_context *dce_ctx;
+
+ if (cb == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ dce_ctx = talloc_zero(mem_ctx, struct dcesrv_context);
+ NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
+
+ if (uid_wrapper_enabled()) {
+ setenv("UID_WRAPPER_MYUID", "1", 1);
+ }
+ dce_ctx->initial_euid = geteuid();
+ if (uid_wrapper_enabled()) {
+ unsetenv("UID_WRAPPER_MYUID");
+ }
+
+ dce_ctx->endpoint_list = NULL;
+ dce_ctx->lp_ctx = lp_ctx;
+ dce_ctx->assoc_groups_idr = idr_init(dce_ctx);
+ if (dce_ctx->assoc_groups_idr == NULL) {
+ TALLOC_FREE(dce_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ dce_ctx->broken_connections = NULL;
+ dce_ctx->callbacks = cb;
+
+ /*
+ * For now we only support NDR32.
+ */
+ dce_ctx->preferred_transfer = &ndr_transfer_syntax_ndr;
+
+ *_dce_ctx = dce_ctx;
+ return NT_STATUS_OK;
+}
+
+/**
+ * @brief Set callback functions on an existing dcesrv_context
+ *
+ * This allows to reset callbacks initially set via
+ * dcesrv_init_context()
+ *
+ * @param[in] dce_ctx The context to set the callbacks on
+ * @param[in] cb The callbacks to set on dce_ctx
+ */
+_PUBLIC_ void dcesrv_context_set_callbacks(
+ struct dcesrv_context *dce_ctx,
+ struct dcesrv_context_callbacks *cb)
+{
+ dce_ctx->callbacks = cb;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_init_ep_servers(struct dcesrv_context *dce_ctx,
+ const char **endpoint_servers)
+{
+ NTSTATUS status;
+ int i;
+
+ if (endpoint_servers == NULL) {
+ DBG_ERR("No endpoint servers configured\n");
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ for (i=0;endpoint_servers[i];i++) {
+ status = dcesrv_init_ep_server(dce_ctx, endpoint_servers[i]);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("failed to init endpoint server = '%s': %s\n",
+ endpoint_servers[i], nt_errstr(status));
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+/* the list of currently registered DCERPC endpoint servers.
+ */
+static struct ep_server {
+ struct dcesrv_endpoint_server *ep_server;
+} *ep_servers = NULL;
+static int num_ep_servers = 0;
+
+_PUBLIC_ NTSTATUS dcesrv_init_registered_ep_servers(
+ struct dcesrv_context *dce_ctx)
+{
+ NTSTATUS status;
+ int i;
+
+ for (i = 0; i < num_ep_servers; i++) {
+ status = dcesrv_init_ep_server(dce_ctx,
+ ep_servers[i].ep_server->name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_init_ep_server(struct dcesrv_context *dce_ctx,
+ const char *ep_server_name)
+{
+ struct dcesrv_endpoint_server *ep_server = NULL;
+ NTSTATUS status;
+
+ ep_server = discard_const_p(struct dcesrv_endpoint_server,
+ dcesrv_ep_server_byname(ep_server_name));
+ if (ep_server == NULL) {
+ DBG_ERR("Failed to find endpoint server '%s'\n",
+ ep_server_name);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (ep_server->initialized) {
+ return NT_STATUS_OK;
+ }
+
+ status = ep_server->init_server(dce_ctx, ep_server);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Failed to init endpoint server '%s': %s\n",
+ ep_server_name, nt_errstr(status));
+ return status;
+ }
+
+ ep_server->initialized = true;
+
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_shutdown_registered_ep_servers(
+ struct dcesrv_context *dce_ctx)
+{
+ NTSTATUS status;
+ int i;
+
+ for (i = 0; i < num_ep_servers; i++) {
+ status = dcesrv_shutdown_ep_server(dce_ctx,
+ ep_servers[i].ep_server->name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_shutdown_ep_server(struct dcesrv_context *dce_ctx,
+ const char *ep_server_name)
+{
+ struct dcesrv_endpoint_server *ep_server = NULL;
+ NTSTATUS status;
+
+ ep_server = discard_const_p(struct dcesrv_endpoint_server,
+ dcesrv_ep_server_byname(ep_server_name));
+ if (ep_server == NULL) {
+ DBG_ERR("Failed to find endpoint server '%s'\n",
+ ep_server_name);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ if (!ep_server->initialized) {
+ return NT_STATUS_OK;
+ }
+
+ DBG_INFO("Shutting down DCE/RPC endpoint server '%s'\n",
+ ep_server_name);
+
+ status = ep_server->shutdown_server(dce_ctx, ep_server);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Failed to shutdown endpoint server '%s': %s\n",
+ ep_server_name, nt_errstr(status));
+ return status;
+ }
+
+ ep_server->initialized = false;
+
+ return NT_STATUS_OK;
+}
+
+/*
+ register a DCERPC endpoint server.
+
+ The 'name' can be later used by other backends to find the operations
+ structure for this backend.
+
+*/
+_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const struct dcesrv_endpoint_server *ep_server)
+{
+
+ if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
+ /* its already registered! */
+ DEBUG(0,("DCERPC endpoint server '%s' already registered\n",
+ ep_server->name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
+ if (!ep_servers) {
+ smb_panic("out of memory in dcerpc_register");
+ }
+
+ ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
+ ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
+
+ num_ep_servers++;
+
+ DEBUG(3,("DCERPC endpoint server '%s' registered\n",
+ ep_server->name));
+
+ return NT_STATUS_OK;
+}
+
+/*
+ return the operations structure for a named backend of the specified type
+*/
+_PUBLIC_ const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
+{
+ int i;
+
+ for (i=0;i<num_ep_servers;i++) {
+ if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
+ return ep_servers[i].ep_server;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ return the DCERPC module version, and the size of some critical types
+ This can be used by endpoint server modules to either detect compilation errors, or provide
+ multiple implementations for different smbd compilation options in one module
+*/
+const struct dcesrv_critical_sizes *dcerpc_module_version(void)
+{
+ static const struct dcesrv_critical_sizes critical_sizes = {
+ DCERPC_MODULE_VERSION,
+ sizeof(struct dcesrv_context),
+ sizeof(struct dcesrv_endpoint),
+ sizeof(struct dcesrv_endpoint_server),
+ sizeof(struct dcesrv_interface),
+ sizeof(struct dcesrv_if_list),
+ sizeof(struct dcesrv_connection),
+ sizeof(struct dcesrv_call_state),
+ sizeof(struct dcesrv_auth),
+ sizeof(struct dcesrv_handle)
+ };
+
+ return &critical_sizes;
+}
+
+_PUBLIC_ void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
+{
+ struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
+ struct dcesrv_call_state *c = NULL, *n = NULL;
+ struct dcesrv_auth *a = NULL;
+
+ dce_conn->wait_send = NULL;
+ dce_conn->wait_recv = NULL;
+ dce_conn->wait_private = NULL;
+
+ dce_conn->allow_bind = false;
+ dce_conn->allow_alter = false;
+
+ dce_conn->default_auth_state->auth_invalid = true;
+
+ for (a = dce_conn->auth_states; a != NULL; a = a->next) {
+ a->auth_invalid = true;
+ }
+
+no_pending:
+ if (dce_conn->pending_call_list == NULL) {
+ char *full_reason = talloc_asprintf(dce_conn, "dcesrv: %s", reason);
+
+ DLIST_REMOVE(dce_ctx->broken_connections, dce_conn);
+ dce_conn->transport.terminate_connection(dce_conn,
+ full_reason ? full_reason : reason);
+ return;
+ }
+
+ if (dce_conn->terminate != NULL) {
+ return;
+ }
+
+ DEBUG(3,("dcesrv: terminating connection due to '%s' deferred due to pending calls\n",
+ reason));
+ dce_conn->terminate = talloc_strdup(dce_conn, reason);
+ if (dce_conn->terminate == NULL) {
+ dce_conn->terminate = "dcesrv: deferred terminating connection - no memory";
+ }
+ DLIST_ADD_END(dce_ctx->broken_connections, dce_conn);
+
+ for (c = dce_conn->pending_call_list; c != NULL; c = n) {
+ n = c->next;
+
+ c->got_disconnect = true;
+ if (c->subreq != NULL) {
+ tevent_req_cancel(c->subreq);
+ }
+ }
+
+ if (dce_conn->pending_call_list == NULL) {
+ /*
+ * tevent_req_cancel() was able to made progress
+ * and we don't have pending calls anymore.
+ */
+ goto no_pending;
+ }
+}
+
+_PUBLIC_ void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx)
+{
+ struct dcesrv_connection *cur, *next;
+
+ next = dce_ctx->broken_connections;
+ while (next != NULL) {
+ cur = next;
+ next = cur->next;
+
+ if (cur->state_flags & DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL) {
+ struct dcesrv_connection_context *context_cur, *context_next;
+
+ context_next = cur->contexts;
+ while (context_next != NULL) {
+ context_cur = context_next;
+ context_next = context_cur->next;
+
+ dcesrv_connection_context_destructor(context_cur);
+ }
+ }
+
+ dcesrv_terminate_connection(cur, cur->terminate);
+ }
+}
+
+struct dcesrv_sock_reply_state {
+ struct dcesrv_connection *dce_conn;
+ struct dcesrv_call_state *call;
+ struct iovec iov;
+};
+
+static void dcesrv_sock_reply_done(struct tevent_req *subreq);
+static void dcesrv_call_terminate_step1(struct tevent_req *subreq);
+
+_PUBLIC_ void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn)
+{
+ struct dcesrv_call_state *call;
+
+ call = dce_conn->call_list;
+ if (!call || !call->replies) {
+ return;
+ }
+
+ while (call->replies) {
+ struct data_blob_list_item *rep = call->replies;
+ struct dcesrv_sock_reply_state *substate;
+ struct tevent_req *subreq;
+
+ substate = talloc_zero(call, struct dcesrv_sock_reply_state);
+ if (!substate) {
+ dcesrv_terminate_connection(dce_conn, "no memory");
+ return;
+ }
+
+ substate->dce_conn = dce_conn;
+ substate->call = NULL;
+
+ DLIST_REMOVE(call->replies, rep);
+
+ if (call->replies == NULL && call->terminate_reason == NULL) {
+ substate->call = call;
+ }
+
+ substate->iov.iov_base = (void *) rep->blob.data;
+ substate->iov.iov_len = rep->blob.length;
+
+ subreq = tstream_writev_queue_send(substate,
+ dce_conn->event_ctx,
+ dce_conn->stream,
+ dce_conn->send_queue,
+ &substate->iov, 1);
+ if (!subreq) {
+ dcesrv_terminate_connection(dce_conn, "no memory");
+ return;
+ }
+ tevent_req_set_callback(subreq, dcesrv_sock_reply_done,
+ substate);
+ }
+
+ if (call->terminate_reason != NULL) {
+ struct tevent_req *subreq;
+
+ subreq = tevent_queue_wait_send(call,
+ dce_conn->event_ctx,
+ dce_conn->send_queue);
+ if (!subreq) {
+ dcesrv_terminate_connection(dce_conn, __location__);
+ return;
+ }
+ tevent_req_set_callback(subreq, dcesrv_call_terminate_step1,
+ call);
+ }
+
+ DLIST_REMOVE(call->conn->call_list, call);
+ call->list = DCESRV_LIST_NONE;
+}
+
+static void dcesrv_sock_reply_done(struct tevent_req *subreq)
+{
+ struct dcesrv_sock_reply_state *substate = tevent_req_callback_data(subreq,
+ struct dcesrv_sock_reply_state);
+ int ret;
+ int sys_errno;
+ NTSTATUS status;
+ struct dcesrv_call_state *call = substate->call;
+
+ ret = tstream_writev_queue_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ status = map_nt_error_from_unix_common(sys_errno);
+ dcesrv_terminate_connection(substate->dce_conn, nt_errstr(status));
+ return;
+ }
+
+ talloc_free(substate);
+ if (call) {
+ talloc_free(call);
+ }
+}
+
+static void dcesrv_call_terminate_step2(struct tevent_req *subreq);
+
+static void dcesrv_call_terminate_step1(struct tevent_req *subreq)
+{
+ struct dcesrv_call_state *call = tevent_req_callback_data(subreq,
+ struct dcesrv_call_state);
+ bool ok;
+ struct timeval tv;
+
+ /* make sure we stop send queue before removing subreq */
+ tevent_queue_stop(call->conn->send_queue);
+
+ ok = tevent_queue_wait_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ dcesrv_terminate_connection(call->conn, __location__);
+ return;
+ }
+
+ /* disconnect after 200 usecs */
+ tv = timeval_current_ofs_usec(200);
+ subreq = tevent_wakeup_send(call, call->conn->event_ctx, tv);
+ if (subreq == NULL) {
+ dcesrv_terminate_connection(call->conn, __location__);
+ return;
+ }
+ tevent_req_set_callback(subreq, dcesrv_call_terminate_step2,
+ call);
+}
+
+static void dcesrv_call_terminate_step2(struct tevent_req *subreq)
+{
+ struct dcesrv_call_state *call = tevent_req_callback_data(subreq,
+ struct dcesrv_call_state);
+ bool ok;
+
+ ok = tevent_wakeup_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ dcesrv_terminate_connection(call->conn, __location__);
+ return;
+ }
+
+ dcesrv_terminate_connection(call->conn, call->terminate_reason);
+}
+
+static void dcesrv_conn_wait_done(struct tevent_req *subreq);
+
+static void dcesrv_read_fragment_done(struct tevent_req *subreq)
+{
+ struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
+ struct dcesrv_connection);
+ struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
+ struct ncacn_packet *pkt;
+ DATA_BLOB buffer;
+ NTSTATUS status;
+
+ if (dce_conn->terminate) {
+ /*
+ * if the current connection is broken
+ * we need to clean it up before any other connection
+ */
+ dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
+ dcesrv_cleanup_broken_connections(dce_ctx);
+ return;
+ }
+
+ dcesrv_cleanup_broken_connections(dce_ctx);
+
+ status = dcerpc_read_ncacn_packet_recv(subreq, dce_conn,
+ &pkt, &buffer);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ dcesrv_terminate_connection(dce_conn, nt_errstr(status));
+ return;
+ }
+
+ dcesrv_loop_next_packet(dce_conn, pkt, buffer);
+}
+
+/**
+ * @brief Start the dcesrv loop, inducing the bind as a blob
+ *
+ * Like dcesrv_connection_loop_start() but used from connections
+ * where the caller has already read the dcerpc bind packet from
+ * the socket and is available as a DATA_BLOB.
+ *
+ * @param[in] dce_conn The connection to start
+ * @param[in] pkt The parsed bind packet
+ * @param[in] buffer The full binary bind including auth data
+ */
+void dcesrv_loop_next_packet(
+ struct dcesrv_connection *dce_conn,
+ struct ncacn_packet *pkt,
+ DATA_BLOB buffer)
+{
+ struct tevent_req *subreq = NULL;
+ NTSTATUS status;
+
+ status = dcesrv_process_ncacn_packet(dce_conn, pkt, buffer);
+ if (!NT_STATUS_IS_OK(status)) {
+ dcesrv_terminate_connection(dce_conn, nt_errstr(status));
+ return;
+ }
+
+ /*
+ * This is used to block the connection during
+ * pending authentication.
+ */
+ if (dce_conn->wait_send != NULL) {
+ subreq = dce_conn->wait_send(dce_conn,
+ dce_conn->event_ctx,
+ dce_conn->wait_private);
+ if (!subreq) {
+ status = NT_STATUS_NO_MEMORY;
+ dcesrv_terminate_connection(dce_conn, nt_errstr(status));
+ return;
+ }
+ tevent_req_set_callback(subreq, dcesrv_conn_wait_done, dce_conn);
+ return;
+ }
+
+ subreq = dcerpc_read_ncacn_packet_send(dce_conn,
+ dce_conn->event_ctx,
+ dce_conn->stream);
+ if (!subreq) {
+ status = NT_STATUS_NO_MEMORY;
+ dcesrv_terminate_connection(dce_conn, nt_errstr(status));
+ return;
+ }
+ tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
+}
+
+static void dcesrv_conn_wait_done(struct tevent_req *subreq)
+{
+ struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
+ struct dcesrv_connection);
+ struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
+ NTSTATUS status;
+
+ if (dce_conn->terminate) {
+ /*
+ * if the current connection is broken
+ * we need to clean it up before any other connection
+ */
+ dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
+ dcesrv_cleanup_broken_connections(dce_ctx);
+ return;
+ }
+
+ dcesrv_cleanup_broken_connections(dce_ctx);
+
+ status = dce_conn->wait_recv(subreq);
+ dce_conn->wait_send = NULL;
+ dce_conn->wait_recv = NULL;
+ dce_conn->wait_private = NULL;
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ dcesrv_terminate_connection(dce_conn, nt_errstr(status));
+ return;
+ }
+
+ status = dcesrv_connection_loop_start(dce_conn);
+ if (!NT_STATUS_IS_OK(status)) {
+ dcesrv_terminate_connection(dce_conn, nt_errstr(status));
+ return;
+ }
+}
+
+/**
+ * retrieve credentials from a dce_call
+ */
+_PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call)
+{
+ struct dcesrv_auth *auth = dce_call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
+ return auth->session_info->credentials;
+}
+
+/**
+ * returns true if this is an authenticated call
+ */
+_PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call)
+{
+ struct dcesrv_auth *auth = dce_call->auth_state;
+ enum security_user_level level;
+ SMB_ASSERT(auth->auth_finished);
+ level = security_session_user_level(auth->session_info, NULL);
+ return level >= SECURITY_USER;
+}
+
+/**
+ * retrieve account_name for a dce_call
+ */
+_PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call)
+{
+ struct dcesrv_auth *auth = dce_call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
+ return auth->session_info->info->account_name;
+}
+
+/**
+ * retrieve session_info from a dce_call
+ */
+_PUBLIC_ struct auth_session_info *dcesrv_call_session_info(struct dcesrv_call_state *dce_call)
+{
+ struct dcesrv_auth *auth = dce_call->auth_state;
+ SMB_ASSERT(auth->auth_finished);
+ return auth->session_info;
+}
+
+/**
+ * retrieve auth type/level from a dce_call
+ */
+_PUBLIC_ void dcesrv_call_auth_info(struct dcesrv_call_state *dce_call,
+ enum dcerpc_AuthType *auth_type,
+ enum dcerpc_AuthLevel *auth_level)
+{
+ struct dcesrv_auth *auth = dce_call->auth_state;
+
+ SMB_ASSERT(auth->auth_finished);
+
+ if (auth_type != NULL) {
+ *auth_type = auth->auth_type;
+ }
+ if (auth_level != NULL) {
+ *auth_level = auth->auth_level;
+ }
+}
+
+_PUBLIC_ NTSTATUS dcesrv_connection_loop_start(struct dcesrv_connection *conn)
+{
+ struct tevent_req *subreq;
+
+ subreq = dcerpc_read_ncacn_packet_send(conn,
+ conn->event_ctx,
+ conn->stream);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, dcesrv_read_fragment_done, conn);
+
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS dcesrv_call_dispatch_local(struct dcesrv_call_state *call)
+{
+ NTSTATUS status;
+ struct ndr_pull *pull = NULL;
+ struct ndr_push *push = NULL;
+ struct data_blob_list_item *rep = NULL;
+
+ pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier,
+ call);
+ if (pull == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ call->ndr_pull = pull;
+
+ /* unravel the NDR for the packet */
+ status = call->context->iface->ndr_pull(call, call, pull, &call->r);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_INFO("DCE/RPC fault in call %s:%02X - %s\n",
+ call->context->iface->name,
+ call->pkt.u.request.opnum,
+ dcerpc_errstr(call, call->fault_code));
+ return dcerpc_fault_to_nt_status(call->fault_code);
+ }
+
+ status = call->context->iface->local(call, call, call->r);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_INFO("DCE/RPC fault in call %s:%02X - %s\n",
+ call->context->iface->name,
+ call->pkt.u.request.opnum,
+ dcerpc_errstr(call, call->fault_code));
+ return dcerpc_fault_to_nt_status(call->fault_code);
+ }
+
+ /* This can never go async for now! */
+ SMB_ASSERT(!(call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC));
+
+ /* call the reply function */
+ status = call->context->iface->reply(call, call, call->r);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_INFO("DCE/RPC fault in call %s:%02X - %s\n",
+ call->context->iface->name,
+ call->pkt.u.request.opnum,
+ dcerpc_errstr(call, call->fault_code));
+ return dcerpc_fault_to_nt_status(call->fault_code);
+ }
+
+ push = ndr_push_init_ctx(call);
+ if (push == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ push->ptr_count = call->ndr_pull->ptr_count;
+
+ status = call->context->iface->ndr_push(call, call, push, call->r);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_INFO("DCE/RPC fault in call %s:%02X - %s\n",
+ call->context->iface->name,
+ call->pkt.u.request.opnum,
+ dcerpc_errstr(call, call->fault_code));
+ return dcerpc_fault_to_nt_status(call->fault_code);
+ }
+
+ rep = talloc_zero(call, struct data_blob_list_item);
+ if (rep == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ rep->blob = ndr_push_blob(push);
+ DLIST_ADD_END(call->replies, rep);
+
+ return NT_STATUS_OK;
+}
diff --git a/librpc/rpc/dcesrv_core.h b/librpc/rpc/dcesrv_core.h
new file mode 100644
index 0000000..3758c8d
--- /dev/null
+++ b/librpc/rpc/dcesrv_core.h
@@ -0,0 +1,715 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ server side dcerpc defines
+
+ Copyright (C) Andrew Tridgell 2003-2005
+ Copyright (C) Stefan (metze) Metzmacher 2004-2005
+ Copyright (C) Samuel Cabrero <scabrero@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 _LIBRPC_RPC_DCESRV_CORE_H_
+#define _LIBRPC_RPC_DCESRV_CORE_H_
+
+#include "librpc/rpc/rpc_common.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/security.h"
+
+/* modules can use the following to determine if the interface has changed
+ * please increment the version number after each interface change
+ * with a comment and maybe update struct dcesrv_critical_sizes.
+ */
+/* version 1 - initial version - metze */
+#define DCERPC_MODULE_VERSION 1
+
+struct dcesrv_connection;
+struct dcesrv_call_state;
+struct dcesrv_auth;
+struct dcesrv_connection_context;
+struct dcesrv_iface_state;
+struct cli_credentials;
+
+struct dcesrv_interface {
+ const char *name;
+ struct ndr_syntax_id syntax_id;
+
+ /* this function is called when the client binds to this interface */
+ NTSTATUS (*bind)(struct dcesrv_connection_context *, const struct dcesrv_interface *);
+
+ /* this function is called when the client disconnects the endpoint */
+ void (*unbind)(struct dcesrv_connection_context *, const struct dcesrv_interface *);
+
+ /* the ndr_pull function for the chosen interface.
+ */
+ NTSTATUS (*ndr_pull)(struct dcesrv_call_state *, TALLOC_CTX *, struct ndr_pull *, void **);
+
+ /* the dispatch function for the chosen interface.
+ */
+ NTSTATUS (*dispatch)(struct dcesrv_call_state *, TALLOC_CTX *, void *);
+
+ /* the reply function for the chosen interface.
+ */
+ NTSTATUS (*reply)(struct dcesrv_call_state *, TALLOC_CTX *, void *);
+
+ /* the ndr_push function for the chosen interface.
+ */
+ NTSTATUS (*ndr_push)(struct dcesrv_call_state *, TALLOC_CTX *, struct ndr_push *, const void *);
+
+ /* the local dispatch function for the chosen interface.
+ */
+ NTSTATUS (*local)(struct dcesrv_call_state *, TALLOC_CTX *, void *);
+
+ /* for any private use by the interface code */
+ const void *private_data;
+
+ uint64_t flags;
+};
+
+#define DCESRV_INTERFACE_FLAGS_HANDLES_NOT_USED 0x00000001
+
+enum dcesrv_call_list {
+ DCESRV_LIST_NONE,
+ DCESRV_LIST_CALL_LIST,
+ DCESRV_LIST_FRAGMENTED_CALL_LIST,
+ DCESRV_LIST_PENDING_CALL_LIST
+};
+
+struct data_blob_list_item {
+ struct data_blob_list_item *prev,*next;
+ DATA_BLOB blob;
+};
+
+/* the state of an ongoing dcerpc call */
+struct dcesrv_call_state {
+ struct dcesrv_call_state *next, *prev;
+ struct dcesrv_auth *auth_state;
+ struct dcesrv_connection *conn;
+ struct dcesrv_connection_context *context;
+ struct ncacn_packet pkt;
+
+ /*
+ * Used during async bind/alter_context.
+ */
+ struct ncacn_packet ack_pkt;
+
+ /*
+ which list this request is in, if any
+ */
+ enum dcesrv_call_list list;
+
+ /* the backend can mark the call
+ * with DCESRV_CALL_STATE_FLAG_ASYNC
+ * that will cause the frontend to not touch r->out
+ * and skip the reply
+ *
+ * this is only allowed to the backend when DCESRV_CALL_STATE_FLAG_MAY_ASYNC
+ * is already set by the frontend
+ *
+ * the backend then needs to call dcesrv_reply() when it's
+ * ready to send the reply
+ */
+#define DCESRV_CALL_STATE_FLAG_ASYNC (1<<0)
+#define DCESRV_CALL_STATE_FLAG_MAY_ASYNC (1<<1)
+#define DCESRV_CALL_STATE_FLAG_MULTIPLEXED (1<<3)
+#define DCESRV_CALL_STATE_FLAG_PROCESS_PENDING_CALL (1<<4)
+#define DCESRV_CALL_STATE_FLAG_WINBIND_OFF (1 << 5)
+ uint32_t state_flags;
+
+ /* the time the request arrived in the server */
+ struct timeval time;
+
+ /* the backend can use this event context for async replies */
+ struct tevent_context *event_ctx;
+
+ /* this is the pointer to the allocated function struct */
+ void *r;
+
+ /*
+ * that's the ndr pull context used in dcesrv_request()
+ * needed by dcesrv_reply() to carry over information
+ * for full pointer support.
+ */
+ struct ndr_pull *ndr_pull;
+
+ DATA_BLOB input;
+
+ struct data_blob_list_item *replies;
+
+ /* this is used by the boilerplate code to generate DCERPC faults */
+ uint32_t fault_code;
+
+ /* the reason why we terminate the connection after sending a response */
+ const char *terminate_reason;
+
+ /* temporary auth_info fields */
+ struct dcerpc_auth in_auth_info;
+ struct dcerpc_auth _out_auth_info;
+ struct dcerpc_auth *out_auth_info;
+
+ /*
+ * Optional subreq for pending calls,
+ * will be used to call tevent_req_cancel()
+ * if the connection terminates,
+ * we got an ORPHANED PDU
+ * or got a CO_CANCEL PDU
+ */
+ bool got_disconnect;
+ bool got_orphaned;
+ bool got_co_cancel;
+ struct tevent_req *subreq;
+};
+
+/*
+* DCERPC Handles
+* --------------
+* The various handles that are used in the RPC servers should be
+* created and fetch using the dcesrv_handle_* functions.
+*
+* Use
+* dcesrv_handle_create(struct dcesrv_call_state \*, uint8 handle_type)
+* to obtain a new handle of the specified type. Handle types are
+* unique within each pipe.
+*
+* The handle can later be fetched again using:
+*
+* struct dcesrv_handle *dcesrv_handle_lookup(
+* struct dcesrv_call_state *dce_call,
+* struct policy_handle *p,
+* uint8 handle_type)
+*
+* and destroyed by:
+*
+* TALLOC_FREE(struct dcesrv_handle *).
+*
+* User data should be stored in the 'data' member of the dcesrv_handle
+* struct.
+*/
+
+#define DCESRV_HANDLE_ANY 255
+
+/* a dcerpc handle in internal format */
+struct dcesrv_handle {
+ struct dcesrv_handle *next, *prev;
+ struct dcesrv_assoc_group *assoc_group;
+ struct policy_handle wire_handle;
+ struct dom_sid sid;
+ enum dcerpc_AuthLevel min_auth_level;
+ const struct dcesrv_interface *iface;
+ void *data;
+};
+
+/* hold the authentication state information */
+struct dcesrv_auth {
+ struct dcesrv_auth *prev, *next;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+ uint32_t auth_context_id;
+ struct gensec_security *gensec_security;
+ struct auth_session_info *session_info;
+ NTSTATUS (*session_key_fn)(struct dcesrv_auth *, DATA_BLOB *session_key);
+ bool auth_started;
+ bool auth_finished;
+ bool auth_audited;
+ bool auth_invalid;
+};
+
+struct dcesrv_connection_context {
+ struct dcesrv_connection_context *next, *prev;
+ uint16_t context_id;
+
+ /* the connection this is on */
+ struct dcesrv_connection *conn;
+
+ /* the ndr function table for the chosen interface */
+ const struct dcesrv_interface *iface;
+
+ /*
+ * the minimum required auth level for this interface
+ */
+ enum dcerpc_AuthLevel min_auth_level;
+ bool allow_connect;
+
+ /* the negotiated transfer syntax */
+ struct ndr_syntax_id transfer_syntax;
+ bool ndr64;
+};
+
+
+/* the state associated with a dcerpc server connection */
+struct dcesrv_connection {
+ /* for the broken_connections DLIST */
+ struct dcesrv_connection *prev, *next;
+
+ /* the top level context for this server */
+ struct dcesrv_context *dce_ctx;
+
+ /* the endpoint that was opened */
+ const struct dcesrv_endpoint *endpoint;
+
+ /* a list of established context_ids */
+ struct dcesrv_connection_context *contexts;
+
+ /* the state of the current incoming call fragments */
+ struct dcesrv_call_state *incoming_fragmented_call_list;
+
+ /* the state of the async pending calls */
+ struct dcesrv_call_state *pending_call_list;
+
+ /* the state of the current outgoing calls */
+ struct dcesrv_call_state *call_list;
+
+ /* the maximum size the client wants to receive */
+ uint16_t max_recv_frag;
+ uint16_t max_xmit_frag;
+
+ DATA_BLOB partial_input;
+
+ /* the event_context that will be used for this connection */
+ struct tevent_context *event_ctx;
+
+ /* is this connection pending termination? If so, why? */
+ const char *terminate;
+
+ const char *packet_log_dir;
+
+ /* this is the default state_flags for dcesrv_call_state structs */
+ uint32_t state_flags;
+
+ struct {
+ void *private_data;
+ void (*report_output_data)(struct dcesrv_connection *);
+ void (*terminate_connection)(struct dcesrv_connection *,
+ const char *);
+ } transport;
+
+ struct tstream_context *stream;
+ struct tevent_queue *send_queue;
+
+ const struct tsocket_address *local_address;
+ const struct tsocket_address *remote_address;
+
+ /* the current authentication state */
+ struct dcesrv_auth *default_auth_state;
+ size_t max_auth_states;
+ struct dcesrv_auth *auth_states;
+ bool got_explicit_auth_level_connect;
+ struct dcesrv_auth *default_auth_level_connect;
+ bool client_hdr_signing;
+ bool support_hdr_signing;
+ bool negotiated_hdr_signing;
+
+ /*
+ * remember which pdu types are allowed
+ */
+ bool allow_bind;
+ bool allow_alter;
+
+ /* the association group the connection belongs to */
+ struct dcesrv_assoc_group *assoc_group;
+
+ /* The maximum total payload of reassembled request pdus */
+ size_t max_total_request_size;
+
+ /*
+ * Our preferred transfer syntax.
+ */
+ const struct ndr_syntax_id *preferred_transfer;
+
+ /*
+ * This is used to block the connection during
+ * pending authentication.
+ */
+ struct tevent_req *(*wait_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ void *private_data);
+ NTSTATUS (*wait_recv)(struct tevent_req *req);
+ void *wait_private;
+};
+
+
+struct dcesrv_endpoint_server {
+ /* this is the name of the endpoint server */
+ const char *name;
+
+ /* true if the endpoint server has been initialized */
+ bool initialized;
+
+ /* this function should register endpoints and some other setup stuff,
+ * it is called when the dcesrv_context gets initialized.
+ */
+ NTSTATUS (*init_server)(struct dcesrv_context *, const struct dcesrv_endpoint_server *);
+
+ /* this function should cleanup endpoint server state and unregister
+ * the endpoint server from dcesrv_context */
+ NTSTATUS (*shutdown_server)(struct dcesrv_context *, const struct dcesrv_endpoint_server *);
+
+ /* this function can be used by other endpoint servers to
+ * ask for a dcesrv_interface implementation
+ * - iface must be reference to an already existing struct !
+ */
+ bool (*interface_by_uuid)(struct dcesrv_interface *iface, const struct GUID *, uint32_t);
+
+ /* this function can be used by other endpoint servers to
+ * ask for a dcesrv_interface implementation
+ * - iface must be reference to an already existing struct !
+ */
+ bool (*interface_by_name)(struct dcesrv_interface *iface, const char *);
+};
+
+
+/* one association groups */
+struct dcesrv_assoc_group {
+ /* the wire id */
+ uint32_t id;
+
+ /* The transport this is valid on */
+ enum dcerpc_transport_t transport;
+
+ /* list of handles in this association group */
+ struct dcesrv_handle *handles;
+
+ /*
+ * list of iface states per assoc/conn
+ */
+ struct dcesrv_iface_state *iface_states;
+
+ /* parent context */
+ struct dcesrv_context *dce_ctx;
+
+ /* the negotiated bind time features */
+ uint16_t bind_time_features;
+};
+
+struct dcesrv_context_callbacks {
+ struct {
+ void (*successful_authz)(
+ struct dcesrv_call_state *call, void *private_data);
+ void *private_data;
+ } log;
+ struct {
+ NTSTATUS (*gensec_prepare)(
+ TALLOC_CTX *mem_ctx,
+ struct dcesrv_call_state *call,
+ struct gensec_security **out,
+ void *private_data);
+ void *private_data;
+ void (*become_root)(void);
+ void (*unbecome_root)(void);
+ } auth;
+ struct {
+ NTSTATUS (*find)(
+ struct dcesrv_call_state *call, void *private_data);
+ void *private_data;
+ } assoc_group;
+};
+
+/* server-wide context information for the dcerpc server */
+struct dcesrv_context {
+ /*
+ * The euid at startup time.
+ *
+ * This is required for DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM
+ */
+ uid_t initial_euid;
+
+ /* the list of endpoints that have registered
+ * by the configured endpoint servers
+ */
+ struct dcesrv_endpoint {
+ struct dcesrv_endpoint *next, *prev;
+ /* the type and location of the endpoint */
+ struct dcerpc_binding *ep_description;
+ /* the secondary endpoint description for the BIND_ACK */
+ struct dcerpc_binding *ep_2nd_description;
+ /* the security descriptor for smb named pipes */
+ struct security_descriptor *sd;
+ /* the list of interfaces available on this endpoint */
+ struct dcesrv_if_list {
+ struct dcesrv_if_list *next, *prev;
+ struct dcesrv_interface *iface;
+ } *interface_list;
+
+ /*
+ * Should this service be run in a single process (so far only
+ * NETLOGON is not run in a single process)
+ */
+ bool use_single_process;
+ } *endpoint_list;
+
+ /*
+ * registered auth_type/principals
+ * for dcesrv_mgmt_inq_princ_name()
+ */
+ struct dcesrv_ctx_principal {
+ struct dcesrv_ctx_principal *next, *prev;
+ enum dcerpc_AuthType auth_type;
+ const char *principal_name;
+ } *principal_list;
+
+ /* loadparm context to use for this connection */
+ struct loadparm_context *lp_ctx;
+
+ struct idr_context *assoc_groups_idr;
+ uint32_t assoc_groups_num;
+
+ struct dcesrv_connection *broken_connections;
+
+ /*
+ * Our preferred transfer syntax.
+ */
+ const struct ndr_syntax_id *preferred_transfer;
+
+ struct dcesrv_context_callbacks *callbacks;
+};
+
+/* this structure is used by modules to determine the size of some critical types */
+struct dcesrv_critical_sizes {
+ int interface_version;
+ int sizeof_dcesrv_context;
+ int sizeof_dcesrv_endpoint;
+ int sizeof_dcesrv_endpoint_server;
+ int sizeof_dcesrv_interface;
+ int sizeof_dcesrv_if_list;
+ int sizeof_dcesrv_connection;
+ int sizeof_dcesrv_call_state;
+ int sizeof_dcesrv_auth;
+ int sizeof_dcesrv_handle;
+};
+
+NTSTATUS dcesrv_auth_type_principal_register(struct dcesrv_context *dce_ctx,
+ enum dcerpc_AuthType auth_type,
+ const char *principal_name);
+const char *dcesrv_auth_type_principal_find(struct dcesrv_context *dce_ctx,
+ enum dcerpc_AuthType auth_type);
+NTSTATUS dcesrv_register_default_auth_types(struct dcesrv_context *dce_ctx,
+ const char *principal);
+NTSTATUS dcesrv_register_default_auth_types_machine_principal(struct dcesrv_context *dce_ctx);
+NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
+ const char *ep_name,
+ const char *ncacn_np_secondary_endpoint,
+ const struct dcesrv_interface *iface,
+ const struct security_descriptor *sd);
+NTSTATUS dcesrv_interface_register_b(struct dcesrv_context *dce_ctx,
+ struct dcerpc_binding *binding,
+ struct dcerpc_binding *binding2,
+ const struct dcesrv_interface *iface,
+ const struct security_descriptor *sd);
+NTSTATUS dcerpc_register_ep_server(const struct dcesrv_endpoint_server *ep_server);
+NTSTATUS dcesrv_init_ep_servers(struct dcesrv_context *dce_ctx,
+ const char **ep_servers);
+NTSTATUS dcesrv_init_registered_ep_servers(struct dcesrv_context *dce_ctx);
+NTSTATUS dcesrv_shutdown_registered_ep_servers(struct dcesrv_context *dce_ctx);
+NTSTATUS dcesrv_init_ep_server(struct dcesrv_context *dce_ctx,
+ const char *ep_server_name);
+NTSTATUS dcesrv_shutdown_ep_server(struct dcesrv_context *dce_ctx,
+ const char *name);
+const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name);
+
+NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct dcesrv_context_callbacks *cb,
+ struct dcesrv_context **_dce_ctx);
+void dcesrv_context_set_callbacks(
+ struct dcesrv_context *dce_ctx,
+ struct dcesrv_context_callbacks *cb);
+
+/*
+ * Use dcesrv_async_reply() in async code
+ */
+NTSTATUS dcesrv_reply(struct dcesrv_call_state *call);
+void _dcesrv_async_reply(struct dcesrv_call_state *call,
+ const char *func,
+ const char *location);
+#define dcesrv_async_reply(__call) \
+ _dcesrv_async_reply(__call, __func__, __location__)
+
+struct dcesrv_handle *dcesrv_handle_create(struct dcesrv_call_state *call,
+ uint8_t handle_type);
+
+struct dcesrv_handle *dcesrv_handle_lookup(struct dcesrv_call_state *call,
+ const struct policy_handle *p,
+ uint8_t handle_type);
+
+const struct tsocket_address *dcesrv_connection_get_local_address(struct dcesrv_connection *conn);
+const struct tsocket_address *dcesrv_connection_get_remote_address(struct dcesrv_connection *conn);
+
+/*
+ * Fetch the authentication session key if available.
+ *
+ * This is the key generated by a gensec authentication.
+ */
+NTSTATUS dcesrv_auth_session_key(struct dcesrv_call_state *call,
+ DATA_BLOB *session_key);
+
+/*
+ * Fetch the transport session key if available.
+ * Typically this is the SMB session key
+ * or a fixed key for local transports.
+ *
+ * The key is always truncated to 16 bytes.
+*/
+NTSTATUS dcesrv_transport_session_key(struct dcesrv_call_state *call,
+ DATA_BLOB *session_key);
+
+/* a useful macro for generating a RPC fault in the backend code */
+#define DCESRV_FAULT(code) do { \
+ dce_call->fault_code = code; \
+ return r->out.result; \
+} while(0)
+
+/* a useful macro for generating a RPC fault in the backend code */
+#define DCESRV_FAULT_VOID(code) do { \
+ dce_call->fault_code = code; \
+ return; \
+} while(0)
+
+/* a useful macro for checking the validity of a dcerpc policy handle
+ and giving the right fault code if invalid */
+#define DCESRV_CHECK_HANDLE(h) do {if (!(h)) DCESRV_FAULT(DCERPC_FAULT_CONTEXT_MISMATCH); } while (0)
+
+/* this checks for a valid policy handle, and gives a fault if an
+ invalid handle or retval if the handle is of the
+ wrong type */
+#define DCESRV_PULL_HANDLE_RETVAL(h, inhandle, t, retval) do { \
+ (h) = dcesrv_handle_lookup(dce_call, (inhandle), DCESRV_HANDLE_ANY); \
+ DCESRV_CHECK_HANDLE(h); \
+ if ((t) != DCESRV_HANDLE_ANY && (h)->wire_handle.handle_type != (t)) { \
+ return retval; \
+ } \
+} while (0)
+
+/* this checks for a valid policy handle and gives a dcerpc fault
+ if its the wrong type of handle */
+#define DCESRV_PULL_HANDLE_FAULT(h, inhandle, t) do { \
+ (h) = dcesrv_handle_lookup(dce_call, (inhandle), t); \
+ DCESRV_CHECK_HANDLE(h); \
+} while (0)
+
+#define DCESRV_PULL_HANDLE(h, inhandle, t) DCESRV_PULL_HANDLE_RETVAL(h, inhandle, t, NT_STATUS_INVALID_HANDLE)
+#define DCESRV_PULL_HANDLE_WERR(h, inhandle, t) DCESRV_PULL_HANDLE_RETVAL(h, inhandle, t, WERR_INVALID_HANDLE)
+
+/**
+ * retrieve credentials from a dce_call
+ */
+_PUBLIC_ struct cli_credentials *dcesrv_call_credentials(struct dcesrv_call_state *dce_call);
+
+/**
+ * returns true if this is an authenticated call
+ */
+_PUBLIC_ bool dcesrv_call_authenticated(struct dcesrv_call_state *dce_call);
+
+/**
+ * retrieve account_name for a dce_call
+ */
+_PUBLIC_ const char *dcesrv_call_account_name(struct dcesrv_call_state *dce_call);
+
+/**
+ * retrieve session_info from a dce_call
+ */
+_PUBLIC_ struct auth_session_info *dcesrv_call_session_info(struct dcesrv_call_state *dce_call);
+
+/**
+ * retrieve auth type/level from a dce_call
+ */
+_PUBLIC_ void dcesrv_call_auth_info(struct dcesrv_call_state *dce_call,
+ enum dcerpc_AuthType *auth_type,
+ enum dcerpc_AuthLevel *auth_level);
+
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_require_integrity(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface);
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_require_privacy(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface);
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_reject_connect(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface);
+_PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface);
+
+_PUBLIC_ NTSTATUS _dcesrv_iface_state_store_assoc(
+ struct dcesrv_call_state *call,
+ uint64_t magic,
+ void *ptr,
+ const char *location);
+#define dcesrv_iface_state_store_assoc(call, magic, ptr) \
+ _dcesrv_iface_state_store_assoc((call), (magic), (ptr), \
+ __location__)
+_PUBLIC_ void *_dcesrv_iface_state_find_assoc(
+ struct dcesrv_call_state *call,
+ uint64_t magic);
+#define dcesrv_iface_state_find_assoc(call, magic, _type) \
+ talloc_get_type( \
+ _dcesrv_iface_state_find_assoc((call), (magic)), \
+ _type)
+
+_PUBLIC_ NTSTATUS _dcesrv_iface_state_store_conn(
+ struct dcesrv_call_state *call,
+ uint64_t magic,
+ void *_pptr,
+ const char *location);
+#define dcesrv_iface_state_store_conn(call, magic, ptr) \
+ _dcesrv_iface_state_store_conn((call), (magic), (ptr), \
+ __location__)
+_PUBLIC_ void *_dcesrv_iface_state_find_conn(
+ struct dcesrv_call_state *call,
+ uint64_t magic);
+#define dcesrv_iface_state_find_conn(call, magic, _type) \
+ talloc_get_type( \
+ _dcesrv_iface_state_find_conn((call), (magic)), \
+ _type)
+
+_PUBLIC_ void dcesrv_cleanup_broken_connections(struct dcesrv_context *dce_ctx);
+
+_PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
+ TALLOC_CTX *mem_ctx,
+ const struct dcesrv_endpoint *ep,
+ struct auth_session_info *session_info,
+ struct tevent_context *event_ctx,
+ uint32_t state_flags,
+ struct dcesrv_connection **_p);
+_PUBLIC_ NTSTATUS dcesrv_find_endpoint(struct dcesrv_context *dce_ctx,
+ const struct dcerpc_binding *ep_description,
+ struct dcesrv_endpoint **_out);
+
+_PUBLIC_ void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn,
+ const char *reason);
+_PUBLIC_ void dcesrv_sock_report_output_data(struct dcesrv_connection *dce_conn);
+
+_PUBLIC_ NTSTATUS dcesrv_connection_loop_start(struct dcesrv_connection *conn);
+
+_PUBLIC_ void dcesrv_loop_next_packet(
+ struct dcesrv_connection *dce_conn,
+ struct ncacn_packet *pkt,
+ DATA_BLOB buffer);
+
+_PUBLIC_ NTSTATUS dcesrv_call_dispatch_local(struct dcesrv_call_state *call);
+
+_PUBLIC_ const struct dcesrv_interface *find_interface_by_syntax_id(
+ const struct dcesrv_endpoint *endpoint,
+ const struct ndr_syntax_id *interface);
+
+void _dcesrv_save_ndr_fuzz_seed(DATA_BLOB call_blob,
+ struct dcesrv_call_state *call,
+ ndr_flags_type flags);
+
+#if DEVELOPER
+#define dcesrv_save_ndr_fuzz_seed(stub, call, flags) \
+ _dcesrv_save_ndr_fuzz_seed(stub, call, flags)
+#else
+#define dcesrv_save_ndr_fuzz_seed(stub, call, flags) \
+ /* */
+#endif
+
+
+#endif /* _LIBRPC_RPC_DCESRV_CORE_H_ */
diff --git a/librpc/rpc/dcesrv_handles.c b/librpc/rpc/dcesrv_handles.c
new file mode 100644
index 0000000..b8719d8
--- /dev/null
+++ b/librpc/rpc/dcesrv_handles.c
@@ -0,0 +1,372 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ server side dcerpc handle code
+
+ 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 "lib/util/dlinklist.h"
+#include "rpc_server/dcerpc_server.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/auth.h"
+
+/*
+ destroy a rpc handle
+*/
+static int dcesrv_handle_destructor(struct dcesrv_handle *h)
+{
+ DLIST_REMOVE(h->assoc_group->handles, h);
+ return 0;
+}
+
+
+/*
+ allocate a new rpc handle
+*/
+_PUBLIC_
+struct dcesrv_handle *dcesrv_handle_create(struct dcesrv_call_state *call,
+ uint8_t handle_type)
+{
+ struct dcesrv_connection_context *context = call->context;
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(call);
+ struct dcesrv_handle *h;
+ struct dom_sid *sid;
+
+ /*
+ * For simplicity, ensure we abort here for an interface that
+ * has no handles (programmer error)
+ */
+ SMB_ASSERT((context->iface->flags & DCESRV_INTERFACE_FLAGS_HANDLES_NOT_USED) == 0);
+
+ sid = &session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+
+ h = talloc_zero(context->conn->assoc_group, struct dcesrv_handle);
+ if (!h) {
+ return NULL;
+ }
+ h->data = NULL;
+ sid_copy(&h->sid, sid);
+ h->min_auth_level = call->auth_state->auth_level;
+ h->assoc_group = context->conn->assoc_group;
+ h->iface = context->iface;
+ h->wire_handle.handle_type = handle_type;
+ h->wire_handle.uuid = GUID_random();
+
+ DLIST_ADD(context->conn->assoc_group->handles, h);
+
+ talloc_set_destructor(h, dcesrv_handle_destructor);
+
+ return h;
+}
+
+/**
+ find an internal handle given a wire handle. If the wire handle is NULL then
+ allocate a new handle
+*/
+
+_PUBLIC_
+struct dcesrv_handle *dcesrv_handle_lookup(struct dcesrv_call_state *call,
+ const struct policy_handle *p,
+ uint8_t handle_type)
+{
+ struct dcesrv_connection_context *context = call->context;
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(call);
+ struct dcesrv_handle *h;
+ struct dom_sid *sid;
+
+ /*
+ * For simplicity, ensure we abort here for an interface that
+ * has no handles (programmer error)
+ */
+ SMB_ASSERT((context->iface->flags & DCESRV_INTERFACE_FLAGS_HANDLES_NOT_USED) == 0);
+
+ sid = &session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+
+ if (ndr_policy_handle_empty(p)) {
+ /* TODO: we should probably return a NULL handle here */
+ return dcesrv_handle_create(call, handle_type);
+ }
+
+ if (handle_type != DCESRV_HANDLE_ANY &&
+ p->handle_type != handle_type) {
+ DBG_WARNING("client gave us the wrong handle type "
+ "(%"PRIu32" should be %"PRIu8")\n",
+ p->handle_type,
+ handle_type);
+ return NULL;
+ }
+
+ for (h=context->conn->assoc_group->handles; h; h=h->next) {
+ if (h->wire_handle.handle_type == p->handle_type &&
+ GUID_equal(&p->uuid, &h->wire_handle.uuid)) {
+ break;
+ }
+ }
+
+ if (h == NULL) {
+ /* not found */
+ return NULL;
+ }
+
+ if (!dom_sid_equal(&h->sid, sid)) {
+ struct dom_sid_buf buf1, buf2;
+ DBG_ERR("Attempt to use invalid sid %s - %s\n",
+ dom_sid_str_buf(&h->sid, &buf1),
+ dom_sid_str_buf(sid, &buf2));
+ return NULL;
+ }
+
+ if (call->auth_state->auth_level < h->min_auth_level) {
+ DBG_ERR("Attempt to use invalid auth_level %u < %u\n",
+ call->auth_state->auth_level,
+ h->min_auth_level);
+ return NULL;
+ }
+
+ if (h->iface != context->iface) {
+ DBG_ERR("Attempt to use invalid iface\n");
+ return NULL;
+ }
+
+ return h;
+}
+
+struct dcesrv_iface_state {
+ struct dcesrv_iface_state *prev, *next;
+ struct dcesrv_assoc_group *assoc;
+ const struct dcesrv_interface *iface;
+ struct dom_sid owner;
+ const struct dcesrv_connection *conn;
+ const struct dcesrv_auth *auth;
+ const struct dcesrv_connection_context *pres;
+ uint64_t magic;
+ void *ptr;
+ const char *location;
+};
+
+static int dcesrv_iface_state_destructor(struct dcesrv_iface_state *istate)
+{
+ DLIST_REMOVE(istate->assoc->iface_states, istate);
+ return 0;
+}
+
+static void *dcesrv_iface_state_find(struct dcesrv_assoc_group *assoc,
+ const struct dcesrv_interface *iface,
+ const struct dom_sid *owner,
+ const struct dcesrv_connection *conn,
+ const struct dcesrv_auth *auth,
+ const struct dcesrv_connection_context *pres,
+ uint64_t magic,
+ const void *ptr)
+{
+ struct dcesrv_iface_state *cur = NULL;
+
+ for (cur = assoc->iface_states; cur != NULL; cur = cur->next) {
+ bool match;
+
+ SMB_ASSERT(cur->assoc == assoc);
+
+ if (cur->ptr == ptr) {
+ return cur->ptr;
+ }
+
+ if (cur->iface != iface) {
+ continue;
+ }
+
+ match = dom_sid_equal(&cur->owner, owner);
+ if (!match) {
+ continue;
+ }
+
+ if (cur->conn != conn) {
+ continue;
+ }
+
+ if (cur->auth != auth) {
+ continue;
+ }
+
+ if (cur->pres != pres) {
+ continue;
+ }
+
+ if (cur->magic != magic) {
+ continue;
+ }
+
+ return cur->ptr;
+ }
+
+ return NULL;
+}
+
+static NTSTATUS dcesrv_iface_state_store(struct dcesrv_assoc_group *assoc,
+ const struct dcesrv_interface *iface,
+ const struct dom_sid *owner,
+ const struct dcesrv_connection *conn,
+ const struct dcesrv_auth *auth,
+ const struct dcesrv_connection_context *pres,
+ uint64_t magic,
+ TALLOC_CTX *mem_ctx,
+ void *ptr,
+ const char *location)
+{
+ struct dcesrv_iface_state *istate = NULL;
+ void *optr = NULL;
+
+ optr = dcesrv_iface_state_find(assoc,
+ iface,
+ owner,
+ conn,
+ auth,
+ pres,
+ magic,
+ ptr);
+ if (optr != NULL) {
+ return NT_STATUS_OBJECTID_EXISTS;
+ }
+
+ istate = talloc_zero(ptr, struct dcesrv_iface_state);
+ if (istate == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *istate = (struct dcesrv_iface_state) {
+ .assoc = assoc,
+ .iface = iface,
+ .owner = *owner,
+ .conn = conn,
+ .auth = auth,
+ .pres = pres,
+ .magic = magic,
+ .location = location,
+ };
+
+ istate->ptr = talloc_steal(mem_ctx, ptr);
+
+ talloc_set_destructor(istate, dcesrv_iface_state_destructor);
+
+ DLIST_ADD_END(assoc->iface_states, istate);
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS _dcesrv_iface_state_store_assoc(struct dcesrv_call_state *call,
+ uint64_t magic,
+ void *ptr,
+ const char *location)
+{
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(call);
+ const struct dom_sid *owner =
+ &session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+ NTSTATUS status;
+
+ status = dcesrv_iface_state_store(call->conn->assoc_group,
+ call->context->iface,
+ owner,
+ NULL, /* conn */
+ NULL, /* auth */
+ NULL, /* pres */
+ magic,
+ call->conn->assoc_group, /* mem_ctx */
+ ptr,
+ location);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+void *_dcesrv_iface_state_find_assoc(struct dcesrv_call_state *call, uint64_t magic)
+{
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(call);
+ const struct dom_sid *owner =
+ &session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+ void *ptr = NULL;
+
+ ptr = dcesrv_iface_state_find(call->conn->assoc_group,
+ call->context->iface,
+ owner,
+ NULL, /* conn */
+ NULL, /* auth */
+ NULL, /* pres */
+ magic,
+ NULL); /* ptr */
+ if (ptr == NULL) {
+ return NULL;
+ }
+
+ return ptr;
+}
+
+NTSTATUS _dcesrv_iface_state_store_conn(struct dcesrv_call_state *call,
+ uint64_t magic,
+ void *ptr,
+ const char *location)
+{
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(call);
+ const struct dom_sid *owner =
+ &session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+ NTSTATUS status;
+
+ status = dcesrv_iface_state_store(call->conn->assoc_group,
+ call->context->iface,
+ owner,
+ call->conn,
+ call->auth_state,
+ call->context,
+ magic,
+ call->conn, /* mem_ctx */
+ ptr,
+ location);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+void *_dcesrv_iface_state_find_conn(struct dcesrv_call_state *call, uint64_t magic)
+{
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(call);
+ const struct dom_sid *owner =
+ &session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
+ void *ptr = NULL;
+
+ ptr = dcesrv_iface_state_find(call->conn->assoc_group,
+ call->context->iface,
+ owner,
+ call->conn,
+ call->auth_state,
+ call->context,
+ magic,
+ NULL); /* ptr */
+ if (ptr == NULL) {
+ return NULL;
+ }
+
+ return ptr;
+}
diff --git a/librpc/rpc/dcesrv_mgmt.c b/librpc/rpc/dcesrv_mgmt.c
new file mode 100644
index 0000000..8f00e91
--- /dev/null
+++ b/librpc/rpc/dcesrv_mgmt.c
@@ -0,0 +1,169 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ endpoint server for the mgmt pipe
+
+ 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/>.
+*/
+
+#include "includes.h"
+#include "librpc/rpc/dcesrv_core.h"
+#include "librpc/rpc/dcesrv_core_proto.h"
+#include "librpc/gen_ndr/ndr_mgmt.h"
+
+#define DCESRV_INTERFACE_MGMT_BIND(context, iface) \
+ dcesrv_interface_mgmt_bind(context, iface)
+/*
+ * This #define allows the mgmt interface to accept invalid
+ * association groups, because association groups are to coordinate
+ * handles, and handles are not used in mgmt. This in turn avoids
+ * the need to coordinate these across multiple possible NETLOGON
+ * processes, as an mgmt interface is added to each
+ */
+
+#define DCESRV_INTERFACE_MGMT_FLAGS DCESRV_INTERFACE_FLAGS_HANDLES_NOT_USED
+
+static NTSTATUS dcesrv_interface_mgmt_bind(struct dcesrv_connection_context *context,
+ const struct dcesrv_interface *iface)
+{
+ return dcesrv_interface_bind_allow_connect(context, iface);
+}
+
+/*
+ mgmt_inq_if_ids
+*/
+static WERROR dcesrv_mgmt_inq_if_ids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct mgmt_inq_if_ids *r)
+{
+ const struct dcesrv_endpoint *ep = dce_call->conn->endpoint;
+ struct dcesrv_if_list *l = NULL;
+ struct rpc_if_id_vector_t *vector = NULL;
+
+ vector = talloc(mem_ctx, struct rpc_if_id_vector_t);
+ if (vector == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ vector->count = 0;
+ vector->if_id = NULL;
+
+ for (l = ep->interface_list; l; l = l->next) {
+ bool filter;
+
+ filter = ndr_syntax_id_equal(&l->iface->syntax_id, &ndr_table_mgmt.syntax_id);
+ if (filter) {
+ /*
+ * We should not return the mgmt syntax itself here
+ */
+ continue;
+ }
+
+ vector->count++;
+ vector->if_id = talloc_realloc(vector, vector->if_id, struct ndr_syntax_id_p, vector->count);
+ if (vector->if_id == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ vector->if_id[vector->count-1].id = &l->iface->syntax_id;
+ }
+
+ *r->out.if_id_vector = vector;
+ return WERR_OK;
+}
+
+
+/*
+ mgmt_inq_stats
+*/
+static WERROR dcesrv_mgmt_inq_stats(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct mgmt_inq_stats *r)
+{
+ if (r->in.max_count != MGMT_STATS_ARRAY_MAX_SIZE)
+ return WERR_NOT_SUPPORTED;
+
+ r->out.statistics->statistics = talloc_zero_array(mem_ctx,
+ uint32_t,
+ r->in.max_count);
+ if (r->out.statistics->statistics == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ r->out.statistics->count = r->in.max_count;
+ /* FIXME */
+ r->out.statistics->statistics[MGMT_STATS_CALLS_IN] = 0;
+ r->out.statistics->statistics[MGMT_STATS_CALLS_OUT] = 0;
+ r->out.statistics->statistics[MGMT_STATS_PKTS_IN] = 0;
+ r->out.statistics->statistics[MGMT_STATS_PKTS_OUT] = 0;
+
+ return WERR_OK;
+}
+
+
+/*
+ mgmt_is_server_listening
+*/
+static uint32_t dcesrv_mgmt_is_server_listening(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct mgmt_is_server_listening *r)
+{
+ *r->out.status = 0;
+ return 1;
+}
+
+
+/*
+ mgmt_stop_server_listening
+*/
+static WERROR dcesrv_mgmt_stop_server_listening(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct mgmt_stop_server_listening *r)
+{
+ return WERR_ACCESS_DENIED;
+}
+
+
+/*
+ mgmt_inq_princ_name
+*/
+static WERROR dcesrv_mgmt_inq_princ_name(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+ struct mgmt_inq_princ_name *r)
+{
+ const char *principal = NULL;
+
+ if (r->in.princ_name_size < 1) {
+ DCESRV_FAULT(DCERPC_FAULT_BAD_STUB_DATA);
+ }
+
+ r->out.princ_name = "";
+
+ principal = dcesrv_auth_type_principal_find(dce_call->conn->dce_ctx,
+ r->in.authn_proto);
+ if (principal == NULL) {
+ return WERR_RPC_S_UNKNOWN_AUTHN_SERVICE;
+ }
+
+ if (strlen(principal) + 1 > r->in.princ_name_size) {
+ return WERR_INSUFFICIENT_BUFFER;
+ }
+
+ r->out.princ_name = principal;
+ return WERR_OK;
+}
+
+
+/* include the generated boilerplate */
+#include "librpc/gen_ndr/ndr_mgmt_s.c"
+
+const struct dcesrv_interface *dcesrv_get_mgmt_interface(void)
+{
+ return &dcesrv_mgmt_interface;
+}
diff --git a/librpc/rpc/dcesrv_reply.c b/librpc/rpc/dcesrv_reply.c
new file mode 100644
index 0000000..6d60516
--- /dev/null
+++ b/librpc/rpc/dcesrv_reply.c
@@ -0,0 +1,309 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ server side dcerpc common code
+
+ Copyright (C) Andrew Tridgell 2003-2010
+ Copyright (C) Stefan (metze) Metzmacher 2004-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 "librpc/rpc/dcesrv_core.h"
+#include "librpc/rpc/dcesrv_core_proto.h"
+#include "librpc/rpc/dcerpc_util.h"
+#include "auth/gensec/gensec.h"
+#include "lib/util/dlinklist.h"
+#include "param/param.h"
+
+/*
+ move a call from an existing linked list to the specified list. This
+ prevents bugs where we forget to remove the call from a previous
+ list when moving it.
+ */
+static void dcesrv_call_set_list(struct dcesrv_call_state *call,
+ enum dcesrv_call_list list)
+{
+ switch (call->list) {
+ case DCESRV_LIST_NONE:
+ break;
+ case DCESRV_LIST_CALL_LIST:
+ DLIST_REMOVE(call->conn->call_list, call);
+ break;
+ case DCESRV_LIST_FRAGMENTED_CALL_LIST:
+ DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
+ break;
+ case DCESRV_LIST_PENDING_CALL_LIST:
+ DLIST_REMOVE(call->conn->pending_call_list, call);
+ break;
+ }
+ call->list = list;
+ switch (list) {
+ case DCESRV_LIST_NONE:
+ break;
+ case DCESRV_LIST_CALL_LIST:
+ DLIST_ADD_END(call->conn->call_list, call);
+ break;
+ case DCESRV_LIST_FRAGMENTED_CALL_LIST:
+ DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call);
+ break;
+ case DCESRV_LIST_PENDING_CALL_LIST:
+ DLIST_ADD_END(call->conn->pending_call_list, call);
+ break;
+ }
+}
+
+
+void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
+{
+ pkt->rpc_vers = 5;
+ pkt->rpc_vers_minor = 0;
+ if (bigendian) {
+ pkt->drep[0] = 0;
+ } else {
+ pkt->drep[0] = DCERPC_DREP_LE;
+ }
+ pkt->drep[1] = 0;
+ pkt->drep[2] = 0;
+ pkt->drep[3] = 0;
+}
+
+
+/*
+ return a dcerpc fault
+*/
+NTSTATUS dcesrv_fault_with_flags(struct dcesrv_call_state *call,
+ uint32_t fault_code,
+ uint8_t extra_flags)
+{
+ struct ncacn_packet pkt;
+ struct data_blob_list_item *rep;
+ NTSTATUS status;
+
+ if (call->conn->terminate != NULL) {
+ /*
+ * If we're already disconnecting
+ * we should just drop a possible
+ * response
+ */
+ talloc_free(call);
+ return NT_STATUS_OK;
+ }
+
+ /* setup a fault */
+ dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
+ pkt.auth_length = 0;
+ pkt.call_id = call->pkt.call_id;
+ pkt.ptype = DCERPC_PKT_FAULT;
+ pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
+ pkt.u.fault.alloc_hint = 24;
+ if (call->context != NULL) {
+ pkt.u.fault.context_id = call->context->context_id;
+ } else {
+ pkt.u.fault.context_id = 0;
+ }
+ pkt.u.fault.cancel_count = 0;
+ pkt.u.fault.flags = 0;
+ pkt.u.fault.status = fault_code;
+ pkt.u.fault.reserved = 0;
+ pkt.u.fault.error_and_verifier = data_blob_null;
+
+ rep = talloc_zero(call, struct data_blob_list_item);
+ if (!rep) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = dcerpc_ncacn_push_auth(&rep->blob, call, &pkt, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ dcerpc_set_frag_length(&rep->blob, rep->blob.length);
+
+ DLIST_ADD_END(call->replies, rep);
+ dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
+
+ if (call->conn->call_list && call->conn->call_list->replies) {
+ if (call->conn->transport.report_output_data) {
+ call->conn->transport.report_output_data(call->conn);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
+{
+ return dcesrv_fault_with_flags(call, fault_code, 0);
+}
+
+_PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
+{
+ struct ndr_push *push;
+ NTSTATUS status;
+ DATA_BLOB stub;
+ uint32_t total_length, chunk_size;
+ struct dcesrv_connection_context *context = call->context;
+ struct dcesrv_auth *auth = call->auth_state;
+ size_t sig_size = 0;
+
+ /*
+ * call the reply function,
+ * it's mostly for debug messages
+ * and dcesrv_fault() also checks for
+ * (call->conn->terminate != NULL) internally.
+ */
+ status = context->iface->reply(call, call, call->r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_fault(call, call->fault_code);
+ }
+
+ if (call->conn->terminate != NULL) {
+ /*
+ * If we're already disconnecting
+ * we should just drop a possible
+ * response
+ */
+ talloc_free(call);
+ return NT_STATUS_OK;
+ }
+
+ /* form the reply NDR */
+ push = ndr_push_init_ctx(call);
+ NT_STATUS_HAVE_NO_MEMORY(push);
+
+ /* carry over the pointer count to the reply in case we are
+ using full pointer. See NDR specification for full
+ pointers */
+ push->ptr_count = call->ndr_pull->ptr_count;
+
+ if (lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
+ push->flags |= LIBNDR_FLAG_BIGENDIAN;
+ }
+
+ if (context->ndr64) {
+ push->flags |= LIBNDR_FLAG_NDR64;
+ }
+
+ status = context->iface->ndr_push(call, call, push, call->r);
+ if (!NT_STATUS_IS_OK(status)) {
+ return dcesrv_fault(call, call->fault_code);
+ }
+
+ stub = ndr_push_blob(push);
+
+ dcesrv_save_ndr_fuzz_seed(stub,
+ call,
+ NDR_OUT);
+
+ total_length = stub.length;
+
+ /* we can write a full max_recv_frag size, minus the dcerpc
+ request header size */
+ chunk_size = call->conn->max_xmit_frag;
+ chunk_size -= DCERPC_REQUEST_LENGTH;
+ if (auth->auth_finished && auth->gensec_security != NULL) {
+ size_t max_payload = chunk_size;
+
+ max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
+ max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
+
+ sig_size = gensec_sig_size(auth->gensec_security,
+ max_payload);
+ if (sig_size) {
+ chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
+ chunk_size -= sig_size;
+ }
+ }
+ chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
+
+ do {
+ uint32_t length;
+ struct data_blob_list_item *rep;
+ struct ncacn_packet pkt;
+ bool ok;
+
+ rep = talloc_zero(call, struct data_blob_list_item);
+ NT_STATUS_HAVE_NO_MEMORY(rep);
+
+ length = MIN(chunk_size, stub.length);
+
+ /* form the dcerpc response packet */
+ dcesrv_init_hdr(&pkt,
+ lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
+ pkt.auth_length = 0;
+ pkt.call_id = call->pkt.call_id;
+ pkt.ptype = DCERPC_PKT_RESPONSE;
+ pkt.pfc_flags = 0;
+ if (stub.length == total_length) {
+ pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
+ }
+ if (length == stub.length) {
+ pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
+ }
+ pkt.u.response.alloc_hint = stub.length;
+ /*
+ * bug for bug, feature for feature...
+ *
+ * Windows truncates the context_id with & 0xFF,
+ * so we do.
+ */
+ pkt.u.response.context_id = context->context_id & 0xFF;
+ pkt.u.response.cancel_count = 0;
+ pkt.u.response.stub_and_verifier.data = stub.data;
+ pkt.u.response.stub_and_verifier.length = length;
+
+ ok = dcesrv_auth_pkt_push(call, &rep->blob, sig_size,
+ DCERPC_RESPONSE_LENGTH,
+ &pkt.u.response.stub_and_verifier,
+ &pkt);
+ if (!ok) {
+ return dcesrv_fault(call, DCERPC_FAULT_OTHER);
+ }
+
+ dcerpc_set_frag_length(&rep->blob, rep->blob.length);
+
+ DLIST_ADD_END(call->replies, rep);
+
+ stub.data += length;
+ stub.length -= length;
+ } while (stub.length != 0);
+
+ /* move the call from the pending to the finished calls list */
+ dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
+
+ if (call->conn->call_list && call->conn->call_list->replies) {
+ if (call->conn->transport.report_output_data) {
+ call->conn->transport.report_output_data(call->conn);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+_PUBLIC_ void _dcesrv_async_reply(struct dcesrv_call_state *call,
+ const char *func,
+ const char *location)
+{
+ struct dcesrv_connection *conn = call->conn;
+ NTSTATUS status;
+
+ status = dcesrv_reply(call);
+ if (!NT_STATUS_IS_OK(status)) {
+ D_ERR("%s: %s: dcesrv_async_reply() failed - %s\n",
+ func, location, nt_errstr(status));
+ dcesrv_terminate_connection(conn, nt_errstr(status));
+ }
+}
diff --git a/librpc/rpc/rpc_common.h b/librpc/rpc/rpc_common.h
new file mode 100644
index 0000000..7655710
--- /dev/null
+++ b/librpc/rpc/rpc_common.h
@@ -0,0 +1,412 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Stefan Metzmacher 2010-2011
+ Copyright (C) Andrew Tridgell 2010-2011
+ Copyright (C) Simo Sorce 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 __DEFAULT_LIBRPC_RPCCOMMON_H__
+#define __DEFAULT_LIBRPC_RPCCOMMON_H__
+
+#include "lib/util/data_blob.h"
+
+#include "gen_ndr/dcerpc.h"
+#include "lib/util/attr.h"
+
+#include "librpc/ndr/libndr.h"
+
+struct dcerpc_binding_handle;
+struct GUID;
+struct ndr_interface_table;
+struct ndr_interface_call;
+struct ndr_push;
+struct ndr_pull;
+struct ncacn_packet;
+struct epm_floor;
+struct epm_tower;
+struct tevent_context;
+struct tstream_context;
+struct gensec_security;
+
+enum dcerpc_transport_t {
+ NCA_UNKNOWN, NCACN_NP, NCACN_IP_TCP, NCACN_IP_UDP, NCACN_VNS_IPC,
+ NCACN_VNS_SPP, NCACN_AT_DSP, NCADG_AT_DDP, NCALRPC, NCACN_UNIX_STREAM,
+ NCADG_UNIX_DGRAM, NCACN_HTTP, NCADG_IPX, NCACN_SPX, NCACN_INTERNAL };
+
+/** this describes a binding to a particular transport/pipe */
+struct dcerpc_binding;
+
+/* dcerpc pipe flags */
+#define DCERPC_DEBUG_PRINT_IN (1<<0)
+#define DCERPC_DEBUG_PRINT_OUT (1<<1)
+#define DCERPC_DEBUG_PRINT_BOTH (DCERPC_DEBUG_PRINT_IN | DCERPC_DEBUG_PRINT_OUT)
+
+#define DCERPC_DEBUG_VALIDATE_IN (1<<2)
+#define DCERPC_DEBUG_VALIDATE_OUT (1<<3)
+#define DCERPC_DEBUG_VALIDATE_BOTH (DCERPC_DEBUG_VALIDATE_IN | DCERPC_DEBUG_VALIDATE_OUT)
+
+#define DCERPC_CONNECT (1<<4)
+#define DCERPC_SIGN (1<<5)
+#define DCERPC_SEAL (1<<6)
+
+#define DCERPC_PUSH_BIGENDIAN (1<<7)
+#define DCERPC_PULL_BIGENDIAN (1<<8)
+
+#define DCERPC_SCHANNEL (1<<9)
+
+#define DCERPC_ANON_FALLBACK (1<<10)
+
+/* use a 128 bit session key */
+#define DCERPC_SCHANNEL_128 (1<<12)
+
+/* check incoming pad bytes */
+#define DCERPC_DEBUG_PAD_CHECK (1<<13)
+
+/* set LIBNDR_FLAG_REF_ALLOC flag when decoding NDR */
+#define DCERPC_NDR_REF_ALLOC (1<<14)
+
+#define DCERPC_AUTH_OPTIONS (DCERPC_SEAL|DCERPC_SIGN|DCERPC_SCHANNEL|DCERPC_AUTH_SPNEGO|DCERPC_AUTH_KRB5|DCERPC_AUTH_NTLM)
+
+/* select spnego auth */
+#define DCERPC_AUTH_SPNEGO (1<<15)
+
+/* select krb5 auth */
+#define DCERPC_AUTH_KRB5 (1<<16)
+
+#define DCERPC_SMB2 (1<<17)
+
+/* select NTLM auth */
+#define DCERPC_AUTH_NTLM (1<<18)
+
+/* this triggers the DCERPC_PFC_FLAG_CONC_MPX flag in the bind request */
+#define DCERPC_CONCURRENT_MULTIPLEX (1<<19)
+
+/* this indicates DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN flag was negotiated */
+#define DCERPC_HEADER_SIGNING (1<<20)
+
+/* use NDR64 transport */
+#define DCERPC_NDR64 (1<<21)
+
+/* handle upgrades or downgrades automatically */
+#define DCERPC_SCHANNEL_AUTO (1<<23)
+
+/* use aes schannel with hmac-sh256 session key */
+#define DCERPC_SCHANNEL_AES (1<<24)
+
+/* this triggers the DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN flag in the bind request */
+#define DCERPC_PROPOSE_HEADER_SIGNING (1<<25)
+
+#define DCERPC_PACKET (1<<26)
+
+#define DCERPC_SMB1 (1<<27)
+
+/* The following definitions come from ../librpc/rpc/dcerpc_error.c */
+
+const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code);
+NTSTATUS dcerpc_fault_to_nt_status(uint32_t fault_code);
+uint32_t dcerpc_fault_from_nt_status(NTSTATUS nt_status);
+
+/* The following definitions come from ../librpc/rpc/binding.c */
+
+const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor);
+char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor);
+enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot);
+struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
+ const struct dcerpc_binding *b);
+NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
+ const struct dcerpc_binding *binding,
+ struct epm_tower *tower);
+NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
+ struct epm_tower *tower,
+ struct dcerpc_binding **b_out);
+NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_binding **b_out);
+char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b);
+struct GUID dcerpc_binding_get_object(const struct dcerpc_binding *b);
+NTSTATUS dcerpc_binding_set_object(struct dcerpc_binding *b,
+ struct GUID object);
+enum dcerpc_transport_t dcerpc_binding_get_transport(const struct dcerpc_binding *b);
+NTSTATUS dcerpc_binding_set_transport(struct dcerpc_binding *b,
+ enum dcerpc_transport_t transport);
+void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
+ enum dcerpc_AuthType *_auth_type,
+ enum dcerpc_AuthLevel *_auth_level);
+uint32_t dcerpc_binding_get_assoc_group_id(const struct dcerpc_binding *b);
+NTSTATUS dcerpc_binding_set_assoc_group_id(struct dcerpc_binding *b,
+ uint32_t assoc_group_id);
+struct ndr_syntax_id dcerpc_binding_get_abstract_syntax(const struct dcerpc_binding *b);
+NTSTATUS dcerpc_binding_set_abstract_syntax(struct dcerpc_binding *b,
+ const struct ndr_syntax_id *syntax);
+const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
+ const char *name);
+char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
+ const struct dcerpc_binding *b,
+ const char *name);
+NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
+ const char *name,
+ const char *value);
+uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b);
+NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
+ uint32_t additional,
+ uint32_t clear);
+NTSTATUS dcerpc_floor_get_uuid_full(const struct epm_floor *epm_floor, struct ndr_syntax_id *syntax);
+const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t);
+enum dcerpc_transport_t dcerpc_transport_by_name(const char *name);
+enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower);
+
+/* The following definitions come from ../librpc/rpc/binding_handle.c */
+
+struct dcerpc_binding_handle_ops {
+ const char *name;
+
+ bool (*is_connected)(struct dcerpc_binding_handle *h);
+ uint32_t (*set_timeout)(struct dcerpc_binding_handle *h,
+ uint32_t timeout);
+
+ void (*auth_info)(struct dcerpc_binding_handle *h,
+ enum dcerpc_AuthType *auth_type,
+ enum dcerpc_AuthLevel *auth_level);
+
+ struct tevent_req *(*raw_call_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ uint32_t opnum,
+ uint32_t in_flags,
+ const uint8_t *in_data,
+ size_t in_length);
+ NTSTATUS (*raw_call_recv)(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **out_data,
+ size_t *out_length,
+ uint32_t *out_flags);
+
+ struct tevent_req *(*disconnect_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h);
+ NTSTATUS (*disconnect_recv)(struct tevent_req *req);
+
+ /* TODO: remove the following functions */
+ bool (*push_bigendian)(struct dcerpc_binding_handle *h);
+ bool (*ref_alloc)(struct dcerpc_binding_handle *h);
+ bool (*use_ndr64)(struct dcerpc_binding_handle *h);
+ void (*do_ndr_print)(struct dcerpc_binding_handle *h,
+ ndr_flags_type ndr_flags,
+ const void *struct_ptr,
+ const struct ndr_interface_call *call);
+ void (*ndr_push_failed)(struct dcerpc_binding_handle *h,
+ NTSTATUS error,
+ const void *struct_ptr,
+ const struct ndr_interface_call *call);
+ void (*ndr_pull_failed)(struct dcerpc_binding_handle *h,
+ NTSTATUS error,
+ const DATA_BLOB *blob,
+ const struct ndr_interface_call *call);
+ NTSTATUS (*ndr_validate_in)(struct dcerpc_binding_handle *h,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob,
+ const struct ndr_interface_call *call);
+ NTSTATUS (*ndr_validate_out)(struct dcerpc_binding_handle *h,
+ struct ndr_pull *pull_in,
+ const void *struct_ptr,
+ const struct ndr_interface_call *call);
+};
+
+struct dcerpc_binding_handle *_dcerpc_binding_handle_create(TALLOC_CTX *mem_ctx,
+ const struct dcerpc_binding_handle_ops *ops,
+ const struct GUID *object,
+ const struct ndr_interface_table *table,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location);
+#define dcerpc_binding_handle_create(mem_ctx, ops, object, table, \
+ state, type, location) \
+ _dcerpc_binding_handle_create(mem_ctx, ops, object, table, \
+ state, sizeof(type), #type, location)
+
+void *_dcerpc_binding_handle_data(struct dcerpc_binding_handle *h);
+#define dcerpc_binding_handle_data(_h, _type) \
+ talloc_get_type_abort(_dcerpc_binding_handle_data(_h), _type)
+
+_DEPRECATED_ void dcerpc_binding_handle_set_sync_ev(struct dcerpc_binding_handle *h,
+ struct tevent_context *ev);
+
+bool dcerpc_binding_handle_is_connected(struct dcerpc_binding_handle *h);
+
+uint32_t dcerpc_binding_handle_set_timeout(struct dcerpc_binding_handle *h,
+ uint32_t timeout);
+
+void dcerpc_binding_handle_auth_info(struct dcerpc_binding_handle *h,
+ enum dcerpc_AuthType *auth_type,
+ enum dcerpc_AuthLevel *auth_level);
+
+struct tevent_req *dcerpc_binding_handle_raw_call_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ uint32_t opnum,
+ uint32_t in_flags,
+ const uint8_t *in_data,
+ size_t in_length);
+NTSTATUS dcerpc_binding_handle_raw_call_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **out_data,
+ size_t *out_length,
+ uint32_t *out_flags);
+NTSTATUS dcerpc_binding_handle_raw_call(struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ uint32_t opnum,
+ uint32_t in_flags,
+ const uint8_t *in_data,
+ size_t in_length,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **out_data,
+ size_t *out_length,
+ uint32_t *out_flags);
+
+struct tevent_req *dcerpc_binding_handle_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h);
+NTSTATUS dcerpc_binding_handle_disconnect_recv(struct tevent_req *req);
+
+struct tevent_req *dcerpc_binding_handle_call_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ const struct ndr_interface_table *table,
+ uint32_t opnum,
+ TALLOC_CTX *r_mem,
+ void *r_ptr);
+NTSTATUS dcerpc_binding_handle_call_recv(struct tevent_req *req);
+NTSTATUS dcerpc_binding_handle_call(struct dcerpc_binding_handle *h,
+ const struct GUID *object,
+ const struct ndr_interface_table *table,
+ uint32_t opnum,
+ TALLOC_CTX *r_mem,
+ void *r_ptr);
+
+/**
+ * Extract header information from a ncacn_packet
+ * as a dcerpc_sec_vt_header2 as used by the security verification trailer.
+ *
+ * @param[in] pkt a packet
+ *
+ * @return a dcerpc_sec_vt_header2
+ */
+struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struct ncacn_packet *pkt);
+
+
+/**
+ * Test if two dcerpc_sec_vt_header2 structures are equal
+ * without consideration of reserved fields.
+ *
+ * @param v1 a pointer to a dcerpc_sec_vt_header2 structure
+ * @param v2 a pointer to a dcerpc_sec_vt_header2 structure
+ *
+ * @retval true if *v1 equals *v2
+ */
+bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
+ const struct dcerpc_sec_vt_header2 *v2);
+
+/**
+ * Check for consistency of the security verification trailer with the PDU header.
+ * See <a href="http://msdn.microsoft.com/en-us/library/cc243559.aspx">MS-RPCE 2.2.2.13</a>.
+ * A check with an empty trailer succeeds.
+ *
+ * @param[in] vt a pointer to the security verification trailer.
+ * @param[in] bitmask1 which flags were negotiated on the connection.
+ * @param[in] pcontext the syntaxes negotiated for the presentation context.
+ * @param[in] header2 some fields from the PDU header.
+ *
+ * @retval true on success.
+ */
+bool dcerpc_sec_verification_trailer_check(
+ const struct dcerpc_sec_verification_trailer *vt,
+ const uint32_t *bitmask1,
+ const struct dcerpc_sec_vt_pcontext *pcontext,
+ const struct dcerpc_sec_vt_header2 *header2);
+
+/**
+ * @brief check and optionally extract the Bind Time Features from
+ * the given ndr_syntax_id.
+ *
+ * <a href="http://msdn.microsoft.com/en-us/library/cc243715.aspx">MS-RPCE 3.3.1.5.3 Bind Time Feature Negotiation</a>.
+ *
+ * @param[in] s the syntax that should be checked.
+ *
+ * @param[out] features This is optional, it will be filled with the extracted
+ * features the on success, otherwise it's filled with 0.
+ *
+ * @return true if the syntax matches the 6CB71C2C-9812-4540 prefix with version 1, false otherwise.
+ *
+ * @see dcerpc_construct_bind_time_features
+ */
+bool dcerpc_extract_bind_time_features(struct ndr_syntax_id syntax, uint64_t *features);
+
+/**
+ * @brief Construct a ndr_syntax_id used for Bind Time Features Negotiation.
+ *
+ * <a href="http://msdn.microsoft.com/en-us/library/cc243715.aspx">MS-RPCE 3.3.1.5.3 Bind Time Feature Negotiation</a>.
+ *
+ * @param[in] features The supported features.
+ *
+ * @return The ndr_syntax_id with the given features.
+ *
+ * @see dcerpc_extract_bind_time_features
+ */
+struct ndr_syntax_id dcerpc_construct_bind_time_features(uint64_t features);
+
+#define DCERPC_AUTH_PAD_LENGTH(stub_length) (\
+ (((stub_length) % DCERPC_AUTH_PAD_ALIGNMENT) > 0)?\
+ (DCERPC_AUTH_PAD_ALIGNMENT - (stub_length) % DCERPC_AUTH_PAD_ALIGNMENT):\
+ 0)
+
+NTSTATUS dcerpc_generic_session_key(DATA_BLOB *session_key);
+
+NTSTATUS dcerpc_ncacn_push_auth(DATA_BLOB *blob,
+ TALLOC_CTX *mem_ctx,
+ struct ncacn_packet *pkt,
+ struct dcerpc_auth *auth_info);
+
+void dcerpc_log_packet(const char *packet_log_dir,
+ const char *interface_name,
+ uint32_t opnum, ndr_flags_type flags,
+ const DATA_BLOB *pkt,
+ const char *why);
+
+#ifdef DEVELOPER
+void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx,
+ DATA_BLOB raw_blob,
+ const char *dump_dir,
+ const char *iface_name,
+ ndr_flags_type flags,
+ int opnum,
+ bool ndr64);
+#else
+static inline void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx,
+ DATA_BLOB raw_blob,
+ const char *dump_dir,
+ const char *iface_name,
+ ndr_flags_type flags,
+ int opnum,
+ bool ndr64)
+{
+ return;
+}
+#endif
+
+#endif /* __DEFAULT_LIBRPC_RPCCOMMON_H__ */
diff --git a/librpc/rpc/server/netlogon/schannel_util.c b/librpc/rpc/server/netlogon/schannel_util.c
new file mode 100644
index 0000000..b14497b
--- /dev/null
+++ b/librpc/rpc/server/netlogon/schannel_util.c
@@ -0,0 +1,570 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ netlogon schannel utility functions
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2008
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
+ Copyright (C) Matthias Dieter Wallnöfer 2009-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 "schannel_util.h"
+#include "param/param.h"
+#include "libcli/security/dom_sid.h"
+#include "libcli/auth/schannel.h"
+#include "librpc/rpc/dcesrv_core.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "lib/util/util_str_escape.h"
+
+struct dcesrv_netr_check_schannel_state {
+ struct dom_sid account_sid;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ bool schannel_global_required;
+ bool schannel_required;
+ bool schannel_explicitly_set;
+
+ bool seal_global_required;
+ bool seal_required;
+ bool seal_explicitly_set;
+
+ NTSTATUS result;
+};
+
+static NTSTATUS dcesrv_netr_check_schannel_get_state(struct dcesrv_call_state *dce_call,
+ const struct netlogon_creds_CredentialState *creds,
+ enum dcerpc_AuthType auth_type,
+ enum dcerpc_AuthLevel auth_level,
+ struct dcesrv_netr_check_schannel_state **_s)
+{
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ int schannel = lpcfg_server_schannel(lp_ctx);
+ bool schannel_global_required = (schannel == true);
+ bool schannel_required = schannel_global_required;
+ const char *explicit_opt = NULL;
+ bool global_require_seal = lpcfg_server_schannel_require_seal(lp_ctx);
+ bool require_seal = global_require_seal;
+ const char *explicit_seal_opt = NULL;
+#define DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC (NETLOGON_SERVER_PIPE_STATE_MAGIC+1)
+ struct dcesrv_netr_check_schannel_state *s = NULL;
+ NTSTATUS status;
+
+ *_s = NULL;
+
+ s = dcesrv_iface_state_find_conn(dce_call,
+ DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC,
+ struct dcesrv_netr_check_schannel_state);
+ if (s != NULL) {
+ if (!dom_sid_equal(&s->account_sid, creds->sid)) {
+ goto new_state;
+ }
+ if (s->auth_type != auth_type) {
+ goto new_state;
+ }
+ if (s->auth_level != auth_level) {
+ goto new_state;
+ }
+
+ *_s = s;
+ return NT_STATUS_OK;
+ }
+
+new_state:
+ TALLOC_FREE(s);
+ s = talloc_zero(dce_call,
+ struct dcesrv_netr_check_schannel_state);
+ if (s == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ s->account_sid = *creds->sid;
+ s->auth_type = auth_type;
+ s->auth_level = auth_level;
+ s->result = NT_STATUS_MORE_PROCESSING_REQUIRED;
+
+ /*
+ * We don't use lpcfg_parm_bool(), as we
+ * need the explicit_opt pointer in order to
+ * adjust the debug messages.
+ */
+ explicit_seal_opt = lpcfg_get_parametric(lp_ctx,
+ NULL,
+ "server schannel require seal",
+ creds->account_name);
+ if (explicit_seal_opt != NULL) {
+ require_seal = lp_bool(explicit_seal_opt);
+ }
+
+ /*
+ * We don't use lpcfg_parm_bool(), as we
+ * need the explicit_opt pointer in order to
+ * adjust the debug messages.
+ */
+ explicit_opt = lpcfg_get_parametric(lp_ctx,
+ NULL,
+ "server require schannel",
+ creds->account_name);
+ if (explicit_opt != NULL) {
+ schannel_required = lp_bool(explicit_opt);
+ }
+
+ s->schannel_global_required = schannel_global_required;
+ s->schannel_required = schannel_required;
+ s->schannel_explicitly_set = explicit_opt != NULL;
+
+ s->seal_global_required = global_require_seal;
+ s->seal_required = require_seal;
+ s->seal_explicitly_set = explicit_seal_opt != NULL;
+
+ status = dcesrv_iface_state_store_conn(dce_call,
+ DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC,
+ s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *_s = s;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_call,
+ struct dcesrv_netr_check_schannel_state *s,
+ const struct netlogon_creds_CredentialState *creds,
+ uint16_t opnum)
+{
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+ int CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL,
+ "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR);
+ int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL,
+ "CVE_2020_1472", "error_debug_level", DBGLVL_ERR);
+ int CVE_2022_38023_warn_level = lpcfg_parm_int(lp_ctx, NULL,
+ "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR);
+ int CVE_2022_38023_error_level = lpcfg_parm_int(lp_ctx, NULL,
+ "CVE_2022_38023", "error_debug_level", DBGLVL_ERR);
+ TALLOC_CTX *frame = talloc_stackframe();
+ unsigned int dbg_lvl = DBGLVL_DEBUG;
+ const char *opname = "<unknown>";
+ const char *reason = "<unknown>";
+
+ if (opnum < ndr_table_netlogon.num_calls) {
+ opname = ndr_table_netlogon.calls[opnum].name;
+ }
+
+ if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ if (s->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ reason = "WITH SEALED";
+ } else if (s->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
+ reason = "WITH SIGNED";
+ } else {
+ reason = "WITH INVALID";
+ dbg_lvl = DBGLVL_ERR;
+ s->result = NT_STATUS_INTERNAL_ERROR;
+ }
+ } else {
+ reason = "WITHOUT";
+ }
+
+ if (!NT_STATUS_EQUAL(s->result, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ if (!NT_STATUS_IS_OK(s->result)) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
+ }
+
+ DEBUG(dbg_lvl, (
+ "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
+ "%s request (opnum[%u]) %s schannel from "
+ "client_account[%s] client_computer_name[%s] %s\n",
+ opname, opnum, reason,
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name),
+ nt_errstr(s->result)));
+ TALLOC_FREE(frame);
+ return s->result;
+ }
+
+ if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL &&
+ s->auth_level == DCERPC_AUTH_LEVEL_PRIVACY)
+ {
+ s->result = NT_STATUS_OK;
+
+ if (s->schannel_explicitly_set && !s->schannel_required) {
+ dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level);
+ } else if (!s->schannel_required) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
+ }
+ if (s->seal_explicitly_set && !s->seal_required) {
+ dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level);
+ } else if (!s->seal_required) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
+ }
+
+ DEBUG(dbg_lvl, (
+ "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
+ "%s request (opnum[%u]) %s schannel from "
+ "client_account[%s] client_computer_name[%s] %s\n",
+ opname, opnum, reason,
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name),
+ nt_errstr(s->result)));
+
+ if (s->schannel_explicitly_set && !s->schannel_required) {
+ DEBUG(CVE_2020_1472_warn_level, (
+ "CVE-2020-1472(ZeroLogon): "
+ "Option 'server require schannel:%s = no' not needed for '%s'!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name)));
+ }
+
+ if (s->seal_explicitly_set && !s->seal_required) {
+ DEBUG(CVE_2022_38023_warn_level, (
+ "CVE-2022-38023: "
+ "Option 'server schannel require seal:%s = no' not needed for '%s'!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name)));
+ }
+
+ TALLOC_FREE(frame);
+ return s->result;
+ }
+
+ if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ if (s->seal_required) {
+ s->result = NT_STATUS_ACCESS_DENIED;
+
+ if (s->seal_explicitly_set) {
+ dbg_lvl = DBGLVL_NOTICE;
+ } else {
+ dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
+ }
+ if (s->schannel_explicitly_set && !s->schannel_required) {
+ dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level);
+ }
+
+ DEBUG(dbg_lvl, (
+ "CVE-2022-38023: "
+ "%s request (opnum[%u]) %s schannel from "
+ "from client_account[%s] client_computer_name[%s] %s\n",
+ opname, opnum, reason,
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name),
+ nt_errstr(s->result)));
+ if (s->seal_explicitly_set) {
+ D_NOTICE("CVE-2022-38023: Option "
+ "'server schannel require seal:%s = yes' "
+ "rejects access for client.\n",
+ log_escape(frame, creds->account_name));
+ } else {
+ DEBUG(CVE_2020_1472_error_level, (
+ "CVE-2022-38023: Check if option "
+ "'server schannel require seal:%s = no' "
+ "might be needed for a legacy client.\n",
+ log_escape(frame, creds->account_name)));
+ }
+ if (s->schannel_explicitly_set && !s->schannel_required) {
+ DEBUG(CVE_2020_1472_warn_level, (
+ "CVE-2020-1472(ZeroLogon): Option "
+ "'server require schannel:%s = no' "
+ "not needed for '%s'!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name)));
+ }
+ TALLOC_FREE(frame);
+ return s->result;
+ }
+
+ s->result = NT_STATUS_OK;
+
+ if (s->schannel_explicitly_set && !s->schannel_required) {
+ dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level);
+ } else if (!s->schannel_required) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
+ }
+ if (s->seal_explicitly_set && !s->seal_required) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
+ } else if (!s->seal_required) {
+ dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
+ }
+
+ DEBUG(dbg_lvl, (
+ "CVE-2020-1472(ZeroLogon): "
+ "%s request (opnum[%u]) %s schannel from "
+ "client_account[%s] client_computer_name[%s] %s\n",
+ opname, opnum, reason,
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name),
+ nt_errstr(s->result)));
+ if (s->schannel_explicitly_set && !s->schannel_required) {
+ DEBUG(CVE_2020_1472_warn_level, (
+ "CVE-2020-1472(ZeroLogon): "
+ "Option 'server require schannel:%s = no' not needed for '%s'!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name)));
+ }
+ if (s->seal_explicitly_set && !s->seal_required) {
+ D_INFO("CVE-2022-38023: "
+ "Option 'server schannel require seal:%s = no' still needed for '%s'!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name));
+ } else if (!s->seal_required) {
+ /*
+ * admins should set
+ * server schannel require seal:COMPUTER$ = no
+ * in order to avoid the level 0 messages.
+ * Over time they can switch the global value
+ * to be strict.
+ */
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: "
+ "Please use 'server schannel require seal:%s = no' "
+ "for '%s' to avoid this warning!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name)));
+ }
+
+ TALLOC_FREE(frame);
+ return s->result;
+ }
+
+ if (s->seal_required) {
+ s->result = NT_STATUS_ACCESS_DENIED;
+
+ if (s->seal_explicitly_set) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE);
+ } else {
+ dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
+ }
+ if (!s->schannel_explicitly_set) {
+ dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
+ } else if (s->schannel_required) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE);
+ }
+
+ DEBUG(dbg_lvl, (
+ "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
+ "%s request (opnum[%u]) %s schannel from "
+ "from client_account[%s] client_computer_name[%s] %s\n",
+ opname, opnum, reason,
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name),
+ nt_errstr(s->result)));
+ if (s->seal_explicitly_set) {
+ D_NOTICE("CVE-2022-38023: Option "
+ "'server schannel require seal:%s = yes' "
+ "rejects access for client.\n",
+ log_escape(frame, creds->account_name));
+ } else {
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: Check if option "
+ "'server schannel require seal:%s = no' "
+ "might be needed for a legacy client.\n",
+ log_escape(frame, creds->account_name)));
+ }
+ if (!s->schannel_explicitly_set) {
+ DEBUG(CVE_2020_1472_error_level, (
+ "CVE-2020-1472(ZeroLogon): Check if option "
+ "'server require schannel:%s = no' "
+ "might be needed for a legacy client.\n",
+ log_escape(frame, creds->account_name)));
+ } else if (s->schannel_required) {
+ D_NOTICE("CVE-2022-38023: Option "
+ "'server require schannel:%s = yes' "
+ "also rejects access for client.\n",
+ log_escape(frame, creds->account_name));
+ }
+ TALLOC_FREE(frame);
+ return s->result;
+ }
+
+ if (s->schannel_required) {
+ s->result = NT_STATUS_ACCESS_DENIED;
+
+ if (s->schannel_explicitly_set) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE);
+ } else {
+ dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
+ }
+ if (!s->seal_explicitly_set) {
+ dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
+ }
+
+ DEBUG(dbg_lvl, (
+ "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
+ "%s request (opnum[%u]) %s schannel from "
+ "client_account[%s] client_computer_name[%s] %s\n",
+ opname, opnum, reason,
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name),
+ nt_errstr(s->result)));
+ if (s->schannel_explicitly_set) {
+ D_NOTICE("CVE-2020-1472(ZeroLogon): Option "
+ "'server require schannel:%s = yes' "
+ "rejects access for client.\n",
+ log_escape(frame, creds->account_name));
+ } else {
+ DEBUG(CVE_2020_1472_error_level, (
+ "CVE-2020-1472(ZeroLogon): Check if option "
+ "'server require schannel:%s = no' "
+ "might be needed for a legacy client.\n",
+ log_escape(frame, creds->account_name)));
+ }
+ if (!s->seal_explicitly_set) {
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: Check if option "
+ "'server schannel require seal:%s = no' "
+ "might be needed for a legacy client.\n",
+ log_escape(frame, creds->account_name)));
+ }
+ TALLOC_FREE(frame);
+ return s->result;
+ }
+
+ s->result = NT_STATUS_OK;
+
+ if (s->seal_explicitly_set) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
+ } else {
+ dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
+ }
+
+ if (s->schannel_explicitly_set) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
+ } else {
+ dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
+ }
+
+ DEBUG(dbg_lvl, (
+ "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
+ "%s request (opnum[%u]) %s schannel from "
+ "client_account[%s] client_computer_name[%s] %s\n",
+ opname, opnum, reason,
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name),
+ nt_errstr(s->result)));
+
+ if (s->seal_explicitly_set) {
+ D_INFO("CVE-2022-38023: Option "
+ "'server schannel require seal:%s = no' "
+ "still needed for '%s'!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name));
+ } else {
+ /*
+ * admins should set
+ * server schannel require seal:COMPUTER$ = no
+ * in order to avoid the level 0 messages.
+ * Over time they can switch the global value
+ * to be strict.
+ */
+ DEBUG(CVE_2022_38023_error_level, (
+ "CVE-2022-38023: Please use "
+ "'server schannel require seal:%s = no' "
+ "for '%s' to avoid this warning!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name)));
+ }
+
+ if (s->schannel_explicitly_set) {
+ D_INFO("CVE-2020-1472(ZeroLogon): Option "
+ "'server require schannel:%s = no' "
+ "still needed for '%s'!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name));
+ } else {
+ /*
+ * admins should set
+ * server require schannel:COMPUTER$ = no
+ * in order to avoid the level 0 messages.
+ * Over time they can switch the global value
+ * to be strict.
+ */
+ DEBUG(CVE_2020_1472_error_level, (
+ "CVE-2020-1472(ZeroLogon): "
+ "Please use 'server require schannel:%s = no' "
+ "for '%s' to avoid this warning!\n",
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name)));
+ }
+
+ TALLOC_FREE(frame);
+ return s->result;
+}
+
+NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
+ const struct netlogon_creds_CredentialState *creds,
+ enum dcerpc_AuthType auth_type,
+ enum dcerpc_AuthLevel auth_level,
+ uint16_t opnum)
+{
+ struct dcesrv_netr_check_schannel_state *s = NULL;
+ NTSTATUS status;
+
+ status = dcesrv_netr_check_schannel_get_state(dce_call,
+ creds,
+ auth_type,
+ auth_level,
+ &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcesrv_netr_check_schannel_once(dce_call, s, creds, opnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ const char *computer_name,
+ struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator,
+ struct netlogon_creds_CredentialState **creds_out)
+{
+ NTSTATUS nt_status;
+ struct netlogon_creds_CredentialState *creds = NULL;
+ enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
+ enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
+
+ dcesrv_call_auth_info(dce_call, &auth_type, &auth_level);
+
+ nt_status = schannel_check_creds_state(mem_ctx,
+ dce_call->conn->dce_ctx->lp_ctx,
+ computer_name,
+ received_authenticator,
+ return_authenticator,
+ &creds);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ ZERO_STRUCTP(return_authenticator);
+ return nt_status;
+ }
+
+ nt_status = dcesrv_netr_check_schannel(dce_call,
+ creds,
+ auth_type,
+ auth_level,
+ dce_call->pkt.u.request.opnum);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ TALLOC_FREE(creds);
+ ZERO_STRUCTP(return_authenticator);
+ return nt_status;
+ }
+
+ *creds_out = creds;
+ return NT_STATUS_OK;
+}
diff --git a/librpc/rpc/server/netlogon/schannel_util.h b/librpc/rpc/server/netlogon/schannel_util.h
new file mode 100644
index 0000000..561e256
--- /dev/null
+++ b/librpc/rpc/server/netlogon/schannel_util.h
@@ -0,0 +1,54 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ netlogon schannel utility functions
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2008
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
+ Copyright (C) Matthias Dieter Wallnöfer 2009-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 __LIBRPC_RPC_SERVER_NETLOGON_SCHANNEL_UTIL_H__
+#define __LIBRPC_RPC_SERVER_NETLOGON_SCHANNEL_UTIL_H__
+
+#include "replace.h"
+#include <talloc.h>
+#include "libcli/util/ntstatus.h"
+
+#define NETLOGON_SERVER_PIPE_STATE_MAGIC 0x4f555358
+
+struct dcesrv_call_state;
+struct netlogon_creds_CredentialState;
+struct netr_Authenticator;
+enum dcerpc_AuthType;
+enum dcerpc_AuthLevel;
+
+NTSTATUS dcesrv_netr_check_schannel(
+ struct dcesrv_call_state *dce_call,
+ const struct netlogon_creds_CredentialState *creds,
+ enum dcerpc_AuthType auth_type,
+ enum dcerpc_AuthLevel auth_level,
+ uint16_t opnum);
+
+NTSTATUS dcesrv_netr_creds_server_step_check(
+ struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ const char *computer_name,
+ struct netr_Authenticator *received_authenticator,
+ struct netr_Authenticator *return_authenticator,
+ struct netlogon_creds_CredentialState **creds_out);
+
+#endif /* __LIBRPC_RPC_SERVER_NETLOGON_SCHANNEL_UTIL_H__ */
diff --git a/librpc/tables.pl b/librpc/tables.pl
new file mode 100755
index 0000000..b7ac6e0
--- /dev/null
+++ b/librpc/tables.pl
@@ -0,0 +1,87 @@
+#!/usr/bin/perl -w
+
+###################################################
+# package to produce a table of all idl parsers
+# Copyright tridge@samba.org 2003
+# Copyright jelmer@samba.org 2005
+# released under the GNU GPL
+
+use strict;
+
+use Getopt::Long;
+use File::Basename;
+
+my $opt_help = 0;
+
+
+#########################################
+# display help text
+sub ShowHelp()
+{
+ print "
+ perl NDR interface table generator
+ Copyright (C) tridge\@samba.org
+
+ Usage: tables.pl [options] <idlfile>
+
+ \n";
+ exit(0);
+}
+
+# main program
+GetOptions (
+ 'help|h|?' => \$opt_help,
+ );
+
+if ($opt_help) {
+ ShowHelp();
+ exit(0);
+}
+
+my $init_fns = "";
+
+###################################
+# extract table entries from 1 file
+sub process_file($)
+{
+ my $filename = shift;
+ open(FILE, $filename) || die "unable to open $filename\n";
+ my $found = 0;
+
+ while (my $line = <FILE>) {
+ if ($line =~ /extern const struct ndr_interface_table (\w+);/) {
+ $found = 1;
+ $init_fns.="\tstatus = ndr_table_register(&$1);\n";
+ $init_fns.="\tif (NT_STATUS_IS_ERR(status)) return status;\n\n";
+ }
+ }
+
+ if ($found) {
+ print "#include \"$filename\"\n";
+ }
+
+ close(FILE);
+}
+
+print <<EOF;
+
+/* Automatically generated by tables.pl. DO NOT EDIT */
+
+#include "includes.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/ndr/ndr_table.h"
+EOF
+
+process_file($_) foreach (@ARGV);
+
+print <<EOF;
+
+NTSTATUS ndr_table_register_builtin_tables(void)
+{
+ NTSTATUS status;
+
+$init_fns
+
+ return NT_STATUS_OK;
+}
+EOF
diff --git a/librpc/tests/test_ndr.c b/librpc/tests/test_ndr.c
new file mode 100644
index 0000000..a26c75a
--- /dev/null
+++ b/librpc/tests/test_ndr.c
@@ -0,0 +1,142 @@
+/*
+ * Tests for librpc ndr functions
+ *
+ * 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/>.
+ *
+ */
+
+/*
+ * 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 "replace.h"
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "librpc/ndr/libndr.h"
+
+/*
+ * Test NDR_PULL_NEED_BYTES integer overflow handling.
+ */
+static enum ndr_err_code wrap_NDR_PULL_NEED_BYTES(
+ struct ndr_pull *ndr,
+ uint32_t bytes) {
+
+ NDR_PULL_NEED_BYTES(ndr, bytes);
+ return NDR_ERR_SUCCESS;
+}
+
+static void test_NDR_PULL_NEED_BYTES(void **state)
+{
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+
+ ndr.data_size = UINT32_MAX;
+ ndr.offset = UINT32_MAX -1;
+
+ /*
+ * This will not cause an overflow
+ */
+ err = wrap_NDR_PULL_NEED_BYTES(&ndr, 1);
+ assert_int_equal(NDR_ERR_SUCCESS, err);
+
+ /*
+ * This will cause an overflow
+ * and (offset + n) will be less than data_size
+ */
+ err = wrap_NDR_PULL_NEED_BYTES(&ndr, 2);
+ assert_int_equal(NDR_ERR_BUFSIZE, err);
+}
+
+/*
+ * Test NDR_PULL_ALIGN integer overflow handling.
+ */
+static enum ndr_err_code wrap_NDR_PULL_ALIGN(
+ struct ndr_pull *ndr,
+ uint32_t bytes) {
+
+ NDR_PULL_ALIGN(ndr, bytes);
+ return NDR_ERR_SUCCESS;
+}
+
+static void test_NDR_PULL_ALIGN(void **state)
+{
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+
+ ndr.data_size = UINT32_MAX;
+ ndr.offset = UINT32_MAX -1;
+
+ /*
+ * This will not cause an overflow
+ */
+ err = wrap_NDR_PULL_ALIGN(&ndr, 2);
+ assert_int_equal(NDR_ERR_SUCCESS, err);
+
+ /*
+ * This will cause an overflow
+ * and (offset + n) will be less than data_size
+ */
+ err = wrap_NDR_PULL_ALIGN(&ndr, 4);
+ assert_int_equal(NDR_ERR_BUFSIZE, err);
+}
+
+/*
+ * Test ndr_pull_advance integer overflow handling.
+ */
+static void test_ndr_pull_advance(void **state)
+{
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+
+ ndr.data_size = UINT32_MAX;
+ ndr.offset = UINT32_MAX -1;
+
+ /*
+ * This will not cause an overflow
+ */
+ err = ndr_pull_advance(&ndr, 1);
+ assert_int_equal(NDR_ERR_SUCCESS, err);
+
+ /*
+ * This will cause an overflow
+ * and (offset + n) will be less than data_size
+ */
+ err = ndr_pull_advance(&ndr, 2);
+ assert_int_equal(NDR_ERR_BUFSIZE, err);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_NDR_PULL_NEED_BYTES),
+ cmocka_unit_test(test_NDR_PULL_ALIGN),
+ cmocka_unit_test(test_ndr_pull_advance),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/librpc/tests/test_ndr_dns_nbt.c b/librpc/tests/test_ndr_dns_nbt.c
new file mode 100644
index 0000000..1e2ef45
--- /dev/null
+++ b/librpc/tests/test_ndr_dns_nbt.c
@@ -0,0 +1,236 @@
+/*
+ * Tests for librpc ndr functions
+ *
+ * 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/>.
+ *
+ */
+
+#include "replace.h"
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "includes.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dns.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "lib/util/time.h"
+
+#define NBT_NAME "EOGFGLGPCACACACACACACACACACACACA" /* "neko" */
+
+
+static DATA_BLOB generate_obnoxious_dns_name(TALLOC_CTX *mem_ctx,
+ size_t n_labels,
+ size_t dot_every,
+ bool is_nbt)
+{
+ size_t i, j;
+ char *s;
+ DATA_BLOB name = data_blob_talloc(mem_ctx, NULL, 64 * n_labels + 1);
+ assert_non_null(name.data);
+
+ s = (char*)name.data;
+ if (is_nbt) {
+ size_t len = strlen(NBT_NAME);
+ *s = len;
+ s++;
+ memcpy(s, NBT_NAME, len);
+ s += len;
+ n_labels--;
+ }
+
+ for (i = 0; i < n_labels; i++) {
+ *s = 63;
+ s++;
+ for (j = 0; j < 63; j++) {
+ if (j % dot_every == (dot_every - 1)) {
+ *s = '.';
+ } else {
+ *s = 'x';
+ }
+ s++;
+ }
+ }
+ *s = 0;
+ s++;
+ name.length = s - (char*)name.data;
+ return name;
+}
+
+
+static char *_test_ndr_pull_dns_string_list(TALLOC_CTX *mem_ctx,
+ size_t n_labels,
+ size_t dot_every,
+ bool is_nbt)
+{
+ enum ndr_err_code ndr_err;
+ DATA_BLOB blob = generate_obnoxious_dns_name(mem_ctx,
+ n_labels,
+ dot_every,
+ is_nbt);
+
+ char *name;
+ ndr_pull_flags_fn_t fn;
+
+ if (is_nbt) {
+ fn = (ndr_pull_flags_fn_t)ndr_pull_nbt_string;
+ } else {
+ fn = (ndr_pull_flags_fn_t)ndr_pull_dns_string;
+ }
+
+ ndr_err = ndr_pull_struct_blob(&blob,
+ mem_ctx,
+ &name,
+ fn);
+ /* Success here is not expected, but we let it go to measure timing. */
+ if (ndr_err == NDR_ERR_SUCCESS) {
+ printf("pull succeed\n");
+ } else {
+ assert_int_equal(ndr_err, NDR_ERR_STRING);
+ }
+
+ TALLOC_FREE(blob.data);
+ return name;
+}
+
+
+static void _test_ndr_push_dns_string_list(TALLOC_CTX *mem_ctx,
+ char *name,
+ bool is_nbt)
+{
+ DATA_BLOB blob;
+ enum ndr_err_code ndr_err;
+ ndr_push_flags_fn_t fn;
+
+ if (is_nbt) {
+ fn = (ndr_push_flags_fn_t)ndr_push_nbt_string;
+ } else {
+ fn = (ndr_push_flags_fn_t)ndr_push_dns_string;
+ }
+
+ ndr_err = ndr_push_struct_blob(&blob,
+ mem_ctx,
+ name,
+ fn);
+
+ /* Success here is not expected, but we let it go to measure timing. */
+ if (ndr_err == NDR_ERR_SUCCESS) {
+ printf("push succeed\n");
+ } else {
+ assert_int_equal(ndr_err, NDR_ERR_STRING);
+ }
+}
+
+
+static uint64_t elapsed_time(struct timespec start, const char *print)
+{
+ struct timespec end;
+ unsigned long long microsecs;
+ clock_gettime_mono(&end);
+ end.tv_sec -= start.tv_sec;
+ if (end.tv_nsec < start.tv_nsec) {
+ /* we need to borrow */
+ end.tv_nsec += 1000 * 1000 * 1000;
+ end.tv_sec -= 1;
+ }
+ end.tv_nsec -= start.tv_nsec;
+ microsecs = end.tv_sec * 1000000;
+ microsecs += end.tv_nsec / 1000;
+
+ if (print != NULL) {
+ printf(" %s: %llu microseconds\n", print, microsecs);
+ }
+ return microsecs;
+}
+
+
+static void test_ndr_dns_string_half_dots(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ char *name;
+ struct timespec start;
+ uint64_t elapsed;
+
+ clock_gettime_mono(&start);
+ name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 2, false);
+ elapsed_time(start, "pull");
+ _test_ndr_push_dns_string_list(mem_ctx, name, false);
+ elapsed = elapsed_time(start, "total");
+ assert_in_range(elapsed, 0, 200000);
+ talloc_free(mem_ctx);
+}
+
+static void test_ndr_nbt_string_half_dots(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ char *name;
+ struct timespec start;
+ uint64_t elapsed;
+
+ clock_gettime_mono(&start);
+ name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 2, true);
+ elapsed_time(start, "pull");
+ _test_ndr_push_dns_string_list(mem_ctx, name, true);
+ elapsed = elapsed_time(start, "total");
+ assert_in_range(elapsed, 0, 200000);
+ talloc_free(mem_ctx);
+}
+
+static void test_ndr_dns_string_all_dots(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ char *name;
+ struct timespec start;
+ uint64_t elapsed;
+
+ clock_gettime_mono(&start);
+ name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 1, false);
+ elapsed_time(start, "pull");
+ _test_ndr_push_dns_string_list(mem_ctx, name, false);
+ elapsed = elapsed_time(start, "total");
+ assert_in_range(elapsed, 0, 200000);
+ talloc_free(mem_ctx);
+}
+
+static void test_ndr_nbt_string_all_dots(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ char *name;
+ struct timespec start;
+ uint64_t elapsed;
+
+ clock_gettime_mono(&start);
+ name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 1, true);
+ elapsed_time(start, "pull");
+ _test_ndr_push_dns_string_list(mem_ctx, name, true);
+ elapsed = elapsed_time(start, "total");
+ assert_in_range(elapsed, 0, 200000);
+ talloc_free(mem_ctx);
+}
+
+
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_ndr_nbt_string_half_dots),
+ cmocka_unit_test(test_ndr_dns_string_half_dots),
+ cmocka_unit_test(test_ndr_nbt_string_all_dots),
+ cmocka_unit_test(test_ndr_dns_string_all_dots),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/librpc/tests/test_ndr_gmsa.c b/librpc/tests/test_ndr_gmsa.c
new file mode 100644
index 0000000..67aa7c2
--- /dev/null
+++ b/librpc/tests/test_ndr_gmsa.c
@@ -0,0 +1,166 @@
+/*
+ * Unit tests for GMSA NDR structures.
+ *
+ * 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 <setjmp.h>
+#include <stdint.h>
+#include "cmocka.h"
+
+#include "lib/replace/replace.h"
+
+#include "lib/util/attr.h"
+#include "lib/util/bytearray.h"
+#include "librpc/gen_ndr/ndr_gmsa.h"
+#include "librpc/gen_ndr/gmsa.h"
+
+static void assert_utf16_equal(const unsigned char *s1, const unsigned char *s2)
+{
+ uint16_t c1;
+ uint16_t c2;
+ size_t n = 0;
+
+ assert_non_null(s1);
+ assert_non_null(s2);
+
+ do {
+ c1 = PULL_LE_U16(s1, n);
+ c2 = PULL_LE_U16(s2, n);
+ assert_int_equal(c1, c2);
+ n += 2;
+ } while (c1);
+}
+
+static void test_managed_password_blob(void **state)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+
+ enum ndr_err_code err;
+ struct MANAGEDPASSWORD_BLOB managed_password = {};
+
+ /* A sample blob produced by Windows. */
+ uint8_t data[] = {
+ 1, 0, 0, 0, 34, 1, 0, 0, 16, 0, 0, 0, 18,
+ 1, 26, 1, 141, 65, 237, 151, 152, 15, 173, 200, 51, 62,
+ 252, 30, 45, 180, 254, 9, 148, 134, 82, 118, 93, 131, 207,
+ 203, 229, 43, 238, 154, 85, 94, 21, 146, 124, 43, 133, 75,
+ 168, 15, 221, 241, 54, 38, 127, 134, 4, 232, 180, 54, 112,
+ 224, 35, 18, 178, 140, 241, 53, 177, 75, 47, 178, 148, 17,
+ 178, 163, 78, 51, 82, 15, 197, 117, 2, 57, 115, 243, 251,
+ 146, 75, 249, 21, 55, 226, 125, 85, 112, 156, 85, 42, 39,
+ 131, 17, 41, 198, 233, 163, 44, 171, 134, 145, 93, 134, 90,
+ 95, 244, 70, 252, 137, 76, 200, 15, 20, 5, 86, 125, 235,
+ 2, 3, 161, 249, 4, 26, 245, 205, 138, 17, 249, 33, 139,
+ 150, 129, 142, 35, 23, 123, 190, 217, 88, 83, 128, 187, 24,
+ 3, 69, 250, 56, 137, 86, 158, 197, 158, 122, 138, 101, 20,
+ 252, 105, 105, 118, 28, 235, 24, 220, 251, 58, 44, 52, 231,
+ 66, 74, 250, 215, 207, 96, 217, 57, 153, 25, 11, 5, 10,
+ 81, 198, 198, 242, 245, 83, 91, 122, 175, 74, 30, 254, 26,
+ 218, 113, 193, 249, 189, 95, 125, 151, 249, 235, 132, 66, 69,
+ 170, 235, 143, 107, 155, 26, 34, 160, 27, 166, 79, 32, 104,
+ 246, 100, 58, 76, 146, 102, 241, 105, 8, 151, 163, 20, 26,
+ 232, 33, 138, 159, 184, 129, 187, 30, 123, 181, 17, 149, 84,
+ 183, 248, 210, 254, 46, 98, 225, 12, 49, 196, 192, 149, 0,
+ 0, 169, 191, 68, 132, 110, 23, 0, 0, 169, 97, 116, 209,
+ 109, 23, 0, 0,
+ };
+
+ const DATA_BLOB blob = {data, sizeof data};
+
+ /* The UTF‐16 password contained in the blob. */
+ const unsigned char current_password[] = {
+ 141, 65, 237, 151, 152, 15, 173, 200, 51, 62, 252, 30, 45,
+ 180, 254, 9, 148, 134, 82, 118, 93, 131, 207, 203, 229, 43,
+ 238, 154, 85, 94, 21, 146, 124, 43, 133, 75, 168, 15, 221,
+ 241, 54, 38, 127, 134, 4, 232, 180, 54, 112, 224, 35, 18,
+ 178, 140, 241, 53, 177, 75, 47, 178, 148, 17, 178, 163, 78,
+ 51, 82, 15, 197, 117, 2, 57, 115, 243, 251, 146, 75, 249,
+ 21, 55, 226, 125, 85, 112, 156, 85, 42, 39, 131, 17, 41,
+ 198, 233, 163, 44, 171, 134, 145, 93, 134, 90, 95, 244, 70,
+ 252, 137, 76, 200, 15, 20, 5, 86, 125, 235, 2, 3, 161,
+ 249, 4, 26, 245, 205, 138, 17, 249, 33, 139, 150, 129, 142,
+ 35, 23, 123, 190, 217, 88, 83, 128, 187, 24, 3, 69, 250,
+ 56, 137, 86, 158, 197, 158, 122, 138, 101, 20, 252, 105, 105,
+ 118, 28, 235, 24, 220, 251, 58, 44, 52, 231, 66, 74, 250,
+ 215, 207, 96, 217, 57, 153, 25, 11, 5, 10, 81, 198, 198,
+ 242, 245, 83, 91, 122, 175, 74, 30, 254, 26, 218, 113, 193,
+ 249, 189, 95, 125, 151, 249, 235, 132, 66, 69, 170, 235, 143,
+ 107, 155, 26, 34, 160, 27, 166, 79, 32, 104, 246, 100, 58,
+ 76, 146, 102, 241, 105, 8, 151, 163, 20, 26, 232, 33, 138,
+ 159, 184, 129, 187, 30, 123, 181, 17, 149, 84, 183, 248, 210,
+ 254, 46, 98, 225, 12, 49, 196, 192, 149, 0, 0};
+
+ DATA_BLOB packed_blob = data_blob_null;
+
+ mem_ctx = talloc_new(NULL);
+ assert_non_null(mem_ctx);
+
+ /* Pull the Managed Password structure. */
+ err = ndr_pull_struct_blob(&blob,
+ mem_ctx,
+ &managed_password,
+ (ndr_pull_flags_fn_t)
+ ndr_pull_MANAGEDPASSWORD_BLOB);
+ assert_int_equal(NDR_ERR_SUCCESS, err);
+
+ /* Check the header. */
+ assert_int_equal(1, managed_password.version);
+ assert_int_equal(0, managed_password.reserved);
+ assert_int_equal(sizeof data, managed_password.length);
+
+ /* Check the password fields. */
+ assert_utf16_equal(managed_password.passwords.current,
+ current_password);
+ assert_null(managed_password.passwords.previous);
+
+ /* Check the password query intervals.*/
+ assert_int_equal(0x176e8444bfa9,
+ *managed_password.passwords.query_interval);
+ assert_int_equal(0x176dd17461a9,
+ *managed_password.passwords.unchanged_interval);
+
+ /* Repack the Managed Password structure. */
+ managed_password.length = 0;
+ err = ndr_push_struct_blob(&packed_blob,
+ mem_ctx,
+ &managed_password,
+ (ndr_push_flags_fn_t)
+ ndr_push_MANAGEDPASSWORD_BLOB);
+ assert_int_equal(NDR_ERR_SUCCESS, err);
+
+ /*
+ * Check that the result is identical to the blob produced by Windows.
+ */
+ assert_int_equal(blob.length, packed_blob.length);
+ assert_memory_equal(blob.data, packed_blob.data, blob.length);
+
+ talloc_free(mem_ctx);
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_managed_password_blob),
+ };
+ if (!isatty(1)) {
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ }
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/librpc/tests/test_ndr_macros.c b/librpc/tests/test_ndr_macros.c
new file mode 100644
index 0000000..337bc95
--- /dev/null
+++ b/librpc/tests/test_ndr_macros.c
@@ -0,0 +1,136 @@
+/*
+ * Tests for librpc ndr functions
+ *
+ * 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/>.
+ *
+ */
+
+/*
+ * 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 "replace.h"
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "librpc/ndr/libndr.h"
+
+/*
+ * Test NDR_RECURSION_CHECK.
+ */
+static enum ndr_err_code wrap_NDR_RECURSION_CHECK(
+ struct ndr_pull *ndr,
+ uint32_t bytes) {
+
+ NDR_RECURSION_CHECK(ndr, bytes);
+ return NDR_ERR_SUCCESS;
+}
+
+static void test_NDR_RECURSION_CHECK(void **state)
+{
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+
+
+ ndr.global_max_recursion = 0;
+ ndr.recursion_depth = 42;
+ err = wrap_NDR_RECURSION_CHECK(&ndr, 43);
+ assert_int_equal(NDR_ERR_SUCCESS, err);
+ assert_int_equal(43, ndr.recursion_depth);
+
+ ndr.global_max_recursion = 0;
+ ndr.recursion_depth = 43;
+ err = wrap_NDR_RECURSION_CHECK(&ndr, 43);
+ assert_int_equal(NDR_ERR_MAX_RECURSION_EXCEEDED, err);
+ assert_int_equal(44, ndr.recursion_depth);
+
+ ndr.global_max_recursion = 0;
+ ndr.recursion_depth = 44;
+ err = wrap_NDR_RECURSION_CHECK(&ndr, 43);
+ assert_int_equal(NDR_ERR_MAX_RECURSION_EXCEEDED, err);
+ assert_int_equal(45, ndr.recursion_depth);
+
+ ndr.global_max_recursion = 5;
+ ndr.recursion_depth = 5;
+ err = wrap_NDR_RECURSION_CHECK(&ndr, 20);
+ assert_int_equal(NDR_ERR_MAX_RECURSION_EXCEEDED, err);
+ assert_int_equal(6, ndr.recursion_depth);
+
+ ndr.global_max_recursion = 5;
+ ndr.recursion_depth = 4;
+ err = wrap_NDR_RECURSION_CHECK(&ndr, 20);
+ assert_int_equal(NDR_ERR_SUCCESS, err);
+ assert_int_equal(5, ndr.recursion_depth);
+
+ ndr.global_max_recursion = 20;
+ ndr.recursion_depth = 5;
+ err = wrap_NDR_RECURSION_CHECK(&ndr, 5);
+ assert_int_equal(NDR_ERR_MAX_RECURSION_EXCEEDED, err);
+ assert_int_equal(6, ndr.recursion_depth);
+
+ ndr.global_max_recursion = 20;
+ ndr.recursion_depth = 4;
+ err = wrap_NDR_RECURSION_CHECK(&ndr, 5);
+ assert_int_equal(NDR_ERR_SUCCESS, err);
+ assert_int_equal(5, ndr.recursion_depth);
+}
+
+/*
+ * Test NDR_RECURSION_RETURN.
+ */
+static enum ndr_err_code wrap_NDR_RECURSION_UNWIND(
+ struct ndr_pull *ndr) {
+
+ NDR_RECURSION_UNWIND(ndr);
+ return NDR_ERR_SUCCESS;
+}
+
+static void test_NDR_RECURSION_UNWIND(void **state)
+{
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+
+ ndr.recursion_depth = 5;
+ err = wrap_NDR_RECURSION_UNWIND(&ndr);
+ assert_int_equal(NDR_ERR_SUCCESS, err);
+ assert_int_equal(4, ndr.recursion_depth);
+
+ ndr.recursion_depth = 0;
+ err = wrap_NDR_RECURSION_UNWIND(&ndr);
+ assert_int_equal(NDR_ERR_UNDERFLOW, err);
+ assert_int_equal(0, ndr.recursion_depth);
+
+}
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_NDR_RECURSION_CHECK),
+ cmocka_unit_test(test_NDR_RECURSION_UNWIND),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/librpc/tests/test_ndr_string.c b/librpc/tests/test_ndr_string.c
new file mode 100644
index 0000000..3250f39
--- /dev/null
+++ b/librpc/tests/test_ndr_string.c
@@ -0,0 +1,542 @@
+/*
+ * Tests for librpc ndr_string.c
+ *
+ * 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/>.
+ *
+ */
+
+/*
+ * 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 "replace.h"
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include "librpc/ndr/ndr_string.c"
+
+/*
+ * Try and pull a null terminated string from a zero length buffer
+ * Should fail for both 1 byte, and 2 byte character strings.
+ */
+static void test_pull_string_zero_len_nul_term(void **state)
+{
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ uint8_t data[] = {0x0, 0x0};
+ const char *s = NULL;
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_NULLTERM;
+ ndr.data = data;
+ ndr.data_size = 0;
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_BUFSIZE);
+ assert_null(s);
+ assert_int_equal(0, ndr.offset);
+
+ ndr.flags = LIBNDR_FLAG_STR_NULLTERM;
+ ndr.offset = 0;
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_BUFSIZE);
+ assert_null(s);
+ assert_int_equal(0, ndr.offset);
+
+}
+
+/*
+ * Try and pull a null terminated string from a 1 byte buffer
+ * Should succeed for 1 byte character and
+ * fail for 2 byte character strings.
+ */
+static void test_pull_string_len_1_nul_term(void **state)
+{
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = {0x0, 0x0};
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_NULLTERM;
+ ndr.data = data;
+ ndr.data_size = 1;
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_int_equal(1, ndr.offset);
+
+ ndr.offset = 0;
+ ndr.flags = LIBNDR_FLAG_STR_NULLTERM;
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_BUFSIZE);
+ assert_int_equal(0, ndr.offset);
+}
+
+/*
+ * Try and pull a null terminated string from a 2 byte buffer
+ * Should succeed for both 1 byte, and 2 byte character strings.
+ */
+static void test_pull_string_len_2_nul_term(void **state)
+{
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s;
+ uint8_t data[] = {0x0, 0x0};
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_NULLTERM;
+ ndr.data = data;
+ ndr.data_size = 2;
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_int_equal(1, ndr.offset);
+
+ ndr.offset = 0;
+ ndr.flags = LIBNDR_FLAG_STR_NULLTERM;
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_int_equal(2, ndr.offset);
+
+
+}
+
+static void test_ndr_string_n_length(void **state)
+{
+ char test_str1[5] = "Test";
+ char test_str2[5] = {0};
+ char test_str3[32] = "This is a test too";
+ uint8_t test_str_u16[64] = {
+ 0x5C, 0x00, 0x5C, 0x00, 0x4C, 0x00, 0x6F, 0x00,
+ 0x67, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x2D, 0x00,
+ 0x6D, 0x00, 0x75, 0x00, 0x63, 0x00, 0x5C, 0x00,
+ 0x6B, 0x00, 0x79, 0x00, 0x6F, 0x00, 0x63, 0x00,
+ 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x2D, 0x00,
+ 0x6D, 0x00, 0x75, 0x00, 0x63, 0x00, 0x2D, 0x00,
+ 0x6E, 0x00, 0x00, 0x00 };
+ size_t len;
+
+ len = ndr_string_n_length(test_str1, sizeof(test_str1), 1);
+ assert_int_equal(len, 5);
+
+ len = ndr_string_n_length(test_str1, sizeof(test_str1) - 1, 1);
+ assert_int_equal(len, 4);
+
+ len = ndr_string_n_length(test_str2, sizeof(test_str2), 1);
+ assert_int_equal(len, 1);
+
+ len = ndr_string_n_length(test_str3, sizeof(test_str3), 1);
+ assert_int_equal(len, 19);
+
+ len = ndr_string_n_length(test_str3, 0, 1);
+ assert_int_equal(len, 0);
+
+ len = ndr_string_n_length(test_str_u16, 32, 2);
+ assert_int_equal(len, 26);
+}
+
+static void test_pull_string_array(void **state)
+{
+ /* We try pulling long string arrays without long strings */
+ const char **r = NULL;
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ size_t len = 1 * 1024 * 1024;
+ uint8_t *data = talloc_array(mem_ctx, uint8_t, len);
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ data[i] = (i & 1) ? '\0' : 'X';
+ }
+
+ ndr.current_mem_ctx = mem_ctx;
+
+ ndr.flags = (LIBNDR_FLAG_REF_ALLOC |
+ LIBNDR_FLAG_REMAINING |
+ LIBNDR_FLAG_STR_NULLTERM |
+ LIBNDR_FLAG_STR_RAW8);
+ ndr.data = data;
+ ndr.data_size = len;
+
+ err = ndr_pull_string_array(&ndr, NDR_SCALARS, &r);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_string_equal(r[0], "X");
+ assert_string_equal(r[len / 3], "X");
+ assert_string_equal(r[len / 2 - 1], "X");
+ assert_ptr_equal(r[len / 2], NULL);
+ TALLOC_FREE(mem_ctx);
+}
+
+static void test_pull_string_zero_len_utf8_NOTERM_STR_NO_EMBEDDED_NUL(void **state)
+{
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x0, 0x0 };
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NOTERM | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_string_equal(s, "");
+ assert_int_equal(sizeof(data), ndr.offset);
+
+}
+
+static void test_pull_string_utf8_nul_term_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x2, 0x0, 'a', 0x0 };
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_string_equal(s, "a");
+ assert_int_equal(sizeof(data), ndr.offset);
+
+}
+
+static void test_pull_string_utf8_nul_term_NOTERM_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x2, 0x0, 'a', 0x0 };
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NOTERM | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_CHARCNV);
+ assert_int_equal(2, ndr.offset);
+
+}
+
+static void test_pull_string_utf8_nullterm_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x4, 0x0, 'a', 'b', 'c', 0x0};
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_string_equal(s, "abc");
+ assert_int_equal(sizeof(data), ndr.offset);
+
+}
+
+static void test_pull_string_utf8_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x3, 0x0, 'a', 'b', 'c'};
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_CHARCNV);
+ assert_int_equal(2, ndr.offset);
+
+}
+
+static void test_pull_string_utf8_NOTERM_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x3, 0x0, 'a', 'b', 'c'};
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NOTERM | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_string_equal(s, "abc");
+ assert_int_equal(sizeof(data), ndr.offset);
+
+}
+
+static void test_pull_string_utf8_nullterm_NOTERM_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x4, 0x0, 'a', 'b', 'c', 0x0};
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NOTERM | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_CHARCNV);
+ assert_int_equal(2, ndr.offset);
+
+}
+
+static void test_pull_string_utf8_LIBNDR_FLAG_STR_NOTERM_STR_NO_EMBEDDED_NUL_fail(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x3, 0x0, 'a', 0x0, 'a'};
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NOTERM | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_CHARCNV);
+ assert_int_equal(2, ndr.offset);
+
+}
+
+static void test_pull_string_utf16_LIBNDR_FLAG_STR_NOTERM_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x3, 0x0, 'a', 0x0, 'b', 0x0, 'c', 0x0};
+
+ ndr.flags = LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NOTERM | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_string_equal(s, "abc");
+ assert_int_equal(sizeof(data), ndr.offset);
+
+}
+
+static void test_pull_string_utf16_LIBNDR_FLAG_STR_NOTERM_STR_NO_EMBEDDED_NUL_fail(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x3, 0x0, 'a', 0x0, 0x0, 0x0, 'c', 0x0};
+
+ ndr.flags = LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NOTERM | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_CHARCNV);
+ assert_int_equal(2, ndr.offset);
+
+}
+
+static void test_pull_string_zero_len_utf8_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x0, 0x0 };
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_string_equal(s, "");
+ assert_int_equal(sizeof(data), ndr.offset);
+
+}
+
+static void test_pull_string_nul_only_utf8_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = { 0x2, 0x0, 0x0, 0x0 };
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_SIZE2 | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_CHARCNV);
+ assert_int_equal(2, ndr.offset);
+
+}
+
+static void test_pull_string_nul_term_utf8_NOTERM_NDR_REMAINING_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = {'a', 'b', 'c', 0x0 };
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_NOTERM | LIBNDR_FLAG_REMAINING | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_CHARCNV);
+ assert_int_equal(0, ndr.offset);
+
+}
+
+static void test_pull_string_utf8_NOTERM_NDR_REMAINING_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = {'a', 'b', 'c' };
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_NOTERM | LIBNDR_FLAG_REMAINING | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_string_equal(s, "abc");
+ assert_int_equal(sizeof(data), ndr.offset);
+
+}
+
+static void test_pull_string_nul_term_utf8_STR_NULLTERM_NDR_REMAINING_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = {'a', 'b', 'c', 0x0 };
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_NULLTERM | LIBNDR_FLAG_REMAINING | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_SUCCESS);
+ assert_non_null(s);
+ assert_string_equal(s, "abc");
+ assert_int_equal(sizeof(data), ndr.offset);
+
+}
+
+static void test_pull_string_utf8_NDR_REMAINING_STR_NULLTERM_STR_NO_EMBEDDED_NUL(void **state)
+{
+
+ struct ndr_pull ndr = {0};
+ enum ndr_err_code err;
+ ndr_flags_type flags = NDR_SCALARS;
+ const char *s = NULL;
+ uint8_t data[] = {'a', 'b', 'c' };
+
+ ndr.flags = LIBNDR_FLAG_STR_UTF8 | LIBNDR_FLAG_STR_NULLTERM | LIBNDR_FLAG_REMAINING | LIBNDR_FLAG_STR_NO_EMBEDDED_NUL;
+
+ ndr.data = data;
+ ndr.data_size = sizeof(data);
+ err = ndr_pull_string(&ndr, flags, &s);
+ assert_int_equal(err, NDR_ERR_CHARCNV);
+ assert_int_equal(0, ndr.offset);
+
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_pull_string_zero_len_nul_term),
+ cmocka_unit_test(test_pull_string_len_1_nul_term),
+ cmocka_unit_test(test_pull_string_len_2_nul_term),
+ cmocka_unit_test(test_ndr_string_n_length),
+ cmocka_unit_test(test_pull_string_array),
+ cmocka_unit_test(test_pull_string_zero_len_utf8_NOTERM_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf8_nul_term_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf8_nul_term_NOTERM_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf8_nullterm_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf8_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf8_NOTERM_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf8_nullterm_NOTERM_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf8_LIBNDR_FLAG_STR_NOTERM_STR_NO_EMBEDDED_NUL_fail),
+ cmocka_unit_test(test_pull_string_utf16_LIBNDR_FLAG_STR_NOTERM_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf16_LIBNDR_FLAG_STR_NOTERM_STR_NO_EMBEDDED_NUL_fail),
+ cmocka_unit_test(test_pull_string_zero_len_utf8_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_nul_only_utf8_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_nul_term_utf8_NOTERM_NDR_REMAINING_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf8_NOTERM_NDR_REMAINING_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_nul_term_utf8_STR_NULLTERM_NDR_REMAINING_STR_NO_EMBEDDED_NUL),
+ cmocka_unit_test(test_pull_string_utf8_NDR_REMAINING_STR_NULLTERM_STR_NO_EMBEDDED_NUL)
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/librpc/tools/ndrdump.1.xml b/librpc/tools/ndrdump.1.xml
new file mode 100644
index 0000000..fa6d763
--- /dev/null
+++ b/librpc/tools/ndrdump.1.xml
@@ -0,0 +1,89 @@
+<?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="ndrdump.1">
+
+<refmeta>
+ <refentrytitle>ndrdump</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+ <refmiscinfo class="version">4.0</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>ndrdump</refname>
+ <refpurpose>DCE/RPC Packet Parser and Dumper</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>ndrdump</command>
+ <arg choice="opt">-c context</arg>
+ <arg choice="req">pipe</arg>
+ <arg choice="req">format</arg>
+ <arg choice="req">in|out|struct</arg>
+ <arg choice="req">filename</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>ndrdump</command>
+ <arg choice="opt">pipe</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>ndrdump</command>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>ndrdump tries to parse the specified <replaceable>filename</replaceable>
+ using Samba's parser for the specified pipe and format. The
+ third argument should be
+ either <emphasis>in</emphasis>, <emphasis>out</emphasis>
+ or <emphasis>struct</emphasis>depending
+ on whether the data should be parsed as a request, reply or a
+ public structure.</para>
+
+ <para>Running ndrdump without arguments will list the pipes for which
+ parsers are available.</para>
+
+ <para>Running ndrdump with one argument will list the functions and
+ public structures that
+ Samba can parse for the specified pipe.</para>
+
+ <para>The primary function of ndrdump is debugging Samba's internal
+ DCE/RPC parsing functions. The file being parsed is usually
+ one exported by wiresharks <quote>Export selected packet bytes</quote>
+ function.</para>
+
+ <para>The context argument can be used to load context data from the request
+ packet when parsing reply packets (such as array lengths).</para>
+
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 4.0 of the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+
+ <para>wireshark, pidl</para>
+
+</refsect1>
+
+<refsect1>
+ <title>AUTHOR</title>
+
+ <para>This utility is part of the <ulink url="http://www.samba.org/">Samba</ulink> suite, which is developed by the global <ulink url="http://www.samba.org/samba/team/">Samba Team</ulink>.</para>
+
+ <para>ndrdump was written by Andrew Tridgell. </para>
+
+ <para>This manpage was written by Jelmer Vernooij. </para>
+
+</refsect1>
+
+</refentry>
diff --git a/librpc/tools/ndrdump.c b/librpc/tools/ndrdump.c
new file mode 100644
index 0000000..528e1fa
--- /dev/null
+++ b/librpc/tools/ndrdump.c
@@ -0,0 +1,795 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Andrew Tridgell 2003
+ 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/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "system/locale.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/ndr/ndr_table.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "lib/cmdline/cmdline.h"
+#include "param/param.h"
+#include "lib/util/base64.h"
+
+static const struct ndr_interface_call *find_function(
+ const struct ndr_interface_table *p,
+ const char *function)
+{
+ unsigned int i;
+ if (isdigit(function[0])) {
+ char *eptr = NULL;
+ i = strtoul(function, &eptr, 0);
+ if (i >= p->num_calls
+ || eptr == NULL
+ || eptr[0] != '\0') {
+ printf("Function number '%s' not found\n",
+ function);
+ exit(1);
+ }
+ return &p->calls[i];
+ }
+ for (i=0;i<p->num_calls;i++) {
+ if (strcmp(p->calls[i].name, function) == 0) {
+ break;
+ }
+ }
+ if (i == p->num_calls) {
+ printf("Function '%s' not found\n", function);
+ exit(1);
+ }
+ return &p->calls[i];
+}
+
+/*
+ * Find a public structure on the pipe and return it as if it were
+ * a function (as the rest of ndrdump is based around functions)
+ */
+static const struct ndr_interface_call *find_struct(
+ const struct ndr_interface_table *p,
+ const char *struct_name,
+ struct ndr_interface_call *out_buffer)
+{
+ unsigned int i;
+ const struct ndr_interface_public_struct *public_struct = NULL;
+ if (isdigit(struct_name[0])) {
+ char *eptr = NULL;
+ i = strtoul(struct_name, &eptr, 0);
+ if (i >= p->num_public_structs
+ || eptr == NULL
+ || eptr[0] != '\0') {
+ printf("Public structure number '%s' not found\n",
+ struct_name);
+ exit(1);
+ }
+ public_struct = &p->public_structs[i];
+ } else {
+ for (i=0;i<p->num_public_structs;i++) {
+ if (strcmp(p->public_structs[i].name, struct_name) == 0) {
+ break;
+ }
+ }
+ if (i == p->num_public_structs) {
+ printf("Public structure '%s' not found\n", struct_name);
+ exit(1);
+ }
+ public_struct = &p->public_structs[i];
+ }
+ *out_buffer = (struct ndr_interface_call) {
+ .name = public_struct->name,
+ .struct_size = public_struct->struct_size,
+ .ndr_pull = public_struct->ndr_pull,
+ .ndr_push = public_struct->ndr_push,
+ .ndr_print = public_struct->ndr_print
+ };
+ return out_buffer;
+}
+
+_NORETURN_ static void show_pipes(void)
+{
+ const struct ndr_interface_list *l;
+ printf("\nYou must specify a pipe\n");
+ printf("known pipes are:\n");
+ for (l=ndr_table_list();l;l=l->next) {
+ if(l->table->helpstring) {
+ printf("\t%s - %s\n", l->table->name, l->table->helpstring);
+ } else {
+ printf("\t%s\n", l->table->name);
+ }
+ }
+ exit(1);
+}
+
+_NORETURN_ static void show_functions(const struct ndr_interface_table *p)
+{
+ int i;
+ printf("\nYou must specify a function\n");
+ printf("known functions on '%s' are:\n", p->name);
+ for (i=0;i<p->num_calls;i++) {
+ printf("\t0x%02x (%2d) %s\n", i, i, p->calls[i].name);
+ }
+ printf("known public structures on '%s' are:\n", p->name);
+ for (i=0;i<p->num_public_structs;i++) {
+ printf("\t%s\n", p->public_structs[i].name);
+ }
+ exit(1);
+}
+
+static char *stdin_load(TALLOC_CTX *mem_ctx, size_t *size)
+{
+ int num_read, total_len = 0;
+ char buf[255];
+ char *result = NULL;
+
+ while((num_read = read(STDIN_FILENO, buf, 255)) > 0) {
+
+ if (result) {
+ result = talloc_realloc(
+ mem_ctx, result, char, total_len + num_read);
+ } else {
+ result = talloc_array(mem_ctx, char, num_read);
+ }
+
+ memcpy(result + total_len, buf, num_read);
+
+ total_len += num_read;
+ }
+
+ if (size)
+ *size = total_len;
+
+ return result;
+}
+
+static const struct ndr_interface_table *load_iface_from_plugin(const char *plugin, const char *pipe_name)
+{
+ const struct ndr_interface_table *p;
+ void *handle;
+ char *symbol;
+
+ handle = dlopen(plugin, RTLD_NOW);
+ if (handle == NULL) {
+ printf("%s: Unable to open: %s\n", plugin, dlerror());
+ return NULL;
+ }
+
+ symbol = talloc_asprintf(NULL, "ndr_table_%s", pipe_name);
+ p = (const struct ndr_interface_table *)dlsym(handle, symbol);
+
+ if (!p) {
+ printf("%s: Unable to find DCE/RPC interface table for '%s': %s\n", plugin, pipe_name, dlerror());
+ talloc_free(symbol);
+ dlclose(handle);
+ return NULL;
+ }
+
+ talloc_free(symbol);
+
+ return p;
+}
+
+static void ndrdump_data(uint8_t *d, uint32_t l, bool force)
+{
+ dump_data_file(d, l, !force, stdout);
+}
+
+static void ndrdump_data_diff(const uint8_t *d1, size_t l1,
+ const uint8_t *d2, size_t l2,
+ bool force)
+{
+ dump_data_file_diff(stdout, !force, d1, l1, d2, l2);
+}
+
+static NTSTATUS ndrdump_pull_and_print_pipes(const char *function,
+ struct ndr_pull *ndr_pull,
+ struct ndr_print *ndr_print,
+ const struct ndr_interface_call_pipes *pipes)
+{
+ enum ndr_err_code ndr_err;
+ uint32_t i;
+
+ for (i=0; i < pipes->num_pipes; i++) {
+ uint64_t idx = 0;
+ while (true) {
+ void *saved_mem_ctx;
+ uint32_t *count;
+ void *c;
+ char *n;
+
+ c = talloc_zero_size(ndr_pull, pipes->pipes[i].chunk_struct_size);
+ talloc_set_name(c, "struct %s", pipes->pipes[i].name);
+ /*
+ * Note: the first struct member is always
+ * 'uint32_t count;'
+ */
+ count = (uint32_t *)c;
+
+ n = talloc_asprintf(c, "%s: %s[%"PRIu64"]",
+ function, pipes->pipes[i].name,
+ idx);
+
+ 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;
+
+ printf("pull returned %s\n",
+ ndr_map_error2string(ndr_err));
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(c);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ pipes->pipes[i].ndr_print(ndr_print, n, c);
+ if (*count == 0) {
+ talloc_free(c);
+ break;
+ }
+ talloc_free(c);
+ idx++;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
+{
+ /* This is here so that you can turn ndr printing off for the purposes
+ of benchmarking ndr parsing. */
+}
+
+ int main(int argc, const char *argv[])
+{
+ const struct ndr_interface_table *p = NULL;
+ const struct ndr_interface_call *f;
+ struct ndr_interface_call f_buffer;
+ const char *pipe_name = NULL;
+ const char *filename = NULL;
+ /*
+ * The format type:
+ * in: a request
+ * out: a response
+ * struct: a public structure
+ */
+ const char *type = NULL;
+ /*
+ * Format is either the name of the decoding function or the
+ * name of a public structure
+ */
+ const char *format = NULL;
+ const char *cmdline_input = NULL;
+ const uint8_t *data;
+ size_t size;
+ DATA_BLOB blob;
+ struct ndr_pull *ndr_pull;
+ struct ndr_print *ndr_print;
+ TALLOC_CTX *mem_ctx;
+ ndr_flags_type flags = 0;
+ poptContext pc;
+ NTSTATUS status;
+ enum ndr_err_code ndr_err;
+ void *st;
+ void *v_st;
+ const char *ctx_filename = NULL;
+ const char *plugin = NULL;
+ bool validate = false;
+ bool dumpdata = false;
+ bool assume_ndr64 = false;
+ bool quiet = false;
+ bool hex_input = false;
+ bool base64_input = false;
+ bool print_after_parse_failure = false;
+ int opt;
+ enum {
+ OPT_CONTEXT_FILE=1000,
+ OPT_VALIDATE,
+ OPT_DUMP_DATA,
+ OPT_LOAD_DSO,
+ OPT_NDR64,
+ OPT_QUIET,
+ OPT_BASE64_INPUT,
+ OPT_HEX_INPUT,
+ OPT_CMDLINE_INPUT,
+ OPT_PRINT_AFTER_PARSE_FAILURE,
+ };
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"context-file", 'c', POPT_ARG_STRING, NULL, OPT_CONTEXT_FILE, "In-filename to parse first", "CTX-FILE" },
+ {"validate", 0, POPT_ARG_NONE, NULL, OPT_VALIDATE, "try to validate the data", NULL },
+ {"dump-data", 0, POPT_ARG_NONE, NULL, OPT_DUMP_DATA, "dump the hex data", NULL },
+ {"load-dso", 0, POPT_ARG_STRING, NULL, OPT_LOAD_DSO, "load from shared object file", NULL },
+ {"ndr64", 0, POPT_ARG_NONE, NULL, OPT_NDR64, "Assume NDR64 data", NULL },
+ {"quiet", 0, POPT_ARG_NONE, NULL, OPT_QUIET, "Don't actually dump anything", NULL },
+ {"base64-input", 0, POPT_ARG_NONE, NULL, OPT_BASE64_INPUT, "Read the input file in as a base64 string", NULL },
+ {"hex-input", 0, POPT_ARG_NONE, NULL, OPT_HEX_INPUT, "Read the input file in as a hex dump", NULL },
+ {"input", 0, POPT_ARG_STRING, NULL, OPT_CMDLINE_INPUT, "Provide the input on the command line (use with --base64-input)", "INPUT" },
+ {"print-after-parse-failure", 0, POPT_ARG_NONE, NULL, OPT_PRINT_AFTER_PARSE_FAILURE,
+ "Try to print structures that fail to parse (used to develop parsers, segfaults are likely).", NULL },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_VERSION
+ POPT_TABLEEND
+ };
+ uint32_t highest_ofs;
+ struct dcerpc_sec_verification_trailer *sec_vt = NULL;
+ bool ok;
+
+ ndr_table_init();
+
+ /* Initialise samba stuff */
+ smb_init_locale();
+
+ setlinebuf(stdout);
+
+ mem_ctx = talloc_init("ndrdump.c/main");
+ if (mem_ctx == NULL) {
+ exit(ENOMEM);
+ }
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv,
+ long_options,
+ 0);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ poptSetOtherOptionHelp(
+ pc, "<pipe|uuid> <format> <in|out|struct> [<filename>]");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case OPT_CONTEXT_FILE:
+ ctx_filename = poptGetOptArg(pc);
+ break;
+ case OPT_VALIDATE:
+ validate = true;
+ break;
+ case OPT_DUMP_DATA:
+ dumpdata = true;
+ break;
+ case OPT_LOAD_DSO:
+ plugin = poptGetOptArg(pc);
+ break;
+ case OPT_NDR64:
+ assume_ndr64 = true;
+ break;
+ case OPT_QUIET:
+ quiet = true;
+ break;
+ case OPT_BASE64_INPUT:
+ base64_input = true;
+ break;
+ case OPT_HEX_INPUT:
+ hex_input = true;
+ break;
+ case OPT_CMDLINE_INPUT:
+ cmdline_input = poptGetOptArg(pc);
+ break;
+ case OPT_PRINT_AFTER_PARSE_FAILURE:
+ print_after_parse_failure = true;
+ break;
+ }
+ }
+
+ pipe_name = poptGetArg(pc);
+
+ if (!pipe_name) {
+ poptPrintUsage(pc, stderr, 0);
+ show_pipes();
+ exit(1);
+ }
+
+ if (plugin != NULL) {
+ p = load_iface_from_plugin(plugin, pipe_name);
+ }
+ if (!p) {
+ p = ndr_table_by_name(pipe_name);
+ }
+
+ if (!p) {
+ struct GUID uuid;
+
+ status = GUID_from_string(pipe_name, &uuid);
+
+ if (NT_STATUS_IS_OK(status)) {
+ p = ndr_table_by_uuid(&uuid);
+ }
+ }
+
+ if (!p) {
+ printf("Unknown pipe or UUID '%s'\n", pipe_name);
+ exit(1);
+ }
+
+ format = poptGetArg(pc);
+ type = poptGetArg(pc);
+ filename = poptGetArg(pc);
+
+ if (!format || !type) {
+ poptPrintUsage(pc, stderr, 0);
+ show_functions(p);
+ exit(1);
+ }
+
+ if (strcmp(type, "struct") == 0) {
+ flags = NDR_SCALARS|NDR_BUFFERS; /* neither NDR_IN nor NDR_OUT */
+ f = find_struct(p, format, &f_buffer);
+ } else {
+ f = find_function(p, format);
+ if (strcmp(type, "in") == 0 ||
+ strcmp(type, "request") == 0) {
+ flags |= NDR_IN;
+ } else if (strcmp(type, "out") == 0 ||
+ strcmp(type, "response") == 0) {
+ flags |= NDR_OUT;
+ } else {
+ printf("Bad type value '%s'\n", type);
+ exit(1);
+ }
+ }
+
+ st = talloc_zero_size(mem_ctx, f->struct_size);
+ if (!st) {
+ printf("Unable to allocate %zu bytes for %s structure\n",
+ f->struct_size,
+ f->name);
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ v_st = talloc_zero_size(mem_ctx, f->struct_size);
+ if (!v_st) {
+ printf("Unable to allocate %zu bytes for %s validation "
+ "structure\n",
+ f->struct_size,
+ f->name);
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ if (ctx_filename) {
+ if (flags & NDR_IN) {
+ printf("Context file can only be used for \"out\" packages\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ data = (uint8_t *)file_load(ctx_filename, &size, 0, mem_ctx);
+ if (!data) {
+ perror(ctx_filename);
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ blob = data_blob_const(data, size);
+
+ ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
+ if (ndr_pull == NULL) {
+ perror("ndr_pull_init_blob");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+ ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ if (assume_ndr64) {
+ ndr_pull->flags |= LIBNDR_FLAG_NDR64;
+ }
+
+ ndr_err = f->ndr_pull(ndr_pull, NDR_IN, st);
+
+ if (ndr_pull->offset > ndr_pull->relative_highest_offset) {
+ highest_ofs = ndr_pull->offset;
+ } else {
+ highest_ofs = ndr_pull->relative_highest_offset;
+ }
+
+ if (highest_ofs != ndr_pull->data_size) {
+ printf("WARNING! %"PRIu32" unread bytes while parsing context file\n", ndr_pull->data_size - highest_ofs);
+ }
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ printf("pull for context file returned %s\n",
+ ndr_map_error2string(ndr_err));
+ TALLOC_FREE(mem_ctx);
+ exit(2);
+ }
+ memcpy(v_st, st, f->struct_size);
+ }
+
+ if (filename && cmdline_input) {
+ printf("cannot combine --input with a filename\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ } else if (cmdline_input) {
+ data = (const uint8_t *)cmdline_input;
+ size = strlen(cmdline_input);
+ } else if (filename) {
+ data = (uint8_t *)file_load(filename, &size, 0, mem_ctx);
+ } else {
+ data = (uint8_t *)stdin_load(mem_ctx, &size);
+ }
+
+ if (!data) {
+ if (filename)
+ perror(filename);
+ else
+ perror("stdin");
+ exit(1);
+ }
+
+ if (hex_input && base64_input) {
+ printf("cannot combine --hex-input with --base64-input\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+
+ } else if (hex_input && size >= 1 && data[0] != '[') {
+ blob = strhex_to_data_blob(mem_ctx, (const char *)data);
+ } else if (hex_input) {
+ blob = hexdump_to_data_blob(mem_ctx, (const char *)data, size);
+ } else if (base64_input) {
+ /* Use talloc_strndup() to ensure null termination */
+ blob = base64_decode_data_blob_talloc(
+ mem_ctx,
+ talloc_strndup(mem_ctx, (const char *)data, size));
+ } else {
+ blob = data_blob_const(data, size);
+ }
+
+ if (data != NULL && blob.data == NULL) {
+ printf("failed to decode input data\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
+ if (ndr_pull == NULL) {
+ perror("ndr_pull_init_blob");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+ ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ if (assume_ndr64) {
+ ndr_pull->flags |= LIBNDR_FLAG_NDR64;
+ }
+
+ ndr_print = talloc_zero(mem_ctx, struct ndr_print);
+ if (quiet) {
+ ndr_print->print = ndr_print_dummy;
+ } else {
+ ndr_print->print = ndr_print_printf_helper;
+ }
+ ndr_print->depth = 1;
+
+ ndr_err = ndr_pop_dcerpc_sec_verification_trailer(ndr_pull, mem_ctx, &sec_vt);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ printf("ndr_pop_dcerpc_sec_verification_trailer returned %s\n",
+ ndr_map_error2string(ndr_err));
+ }
+
+ if (sec_vt != NULL && sec_vt->count.count > 0) {
+ printf("SEC_VT: consumed %zu bytes\n",
+ blob.length - ndr_pull->data_size);
+ if (dumpdata) {
+ ndrdump_data(blob.data + ndr_pull->data_size,
+ blob.length - ndr_pull->data_size,
+ dumpdata);
+ }
+ ndr_print_dcerpc_sec_verification_trailer(ndr_print, "SEC_VT", sec_vt);
+ }
+ TALLOC_FREE(sec_vt);
+
+ if (flags & NDR_OUT) {
+ status = ndrdump_pull_and_print_pipes(format,
+ ndr_pull,
+ ndr_print,
+ &f->out_pipes);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("pull and dump of OUT pipes FAILED: %s\n",
+ nt_errstr(status));
+ TALLOC_FREE(mem_ctx);
+ exit(2);
+ }
+ }
+
+ ndr_err = f->ndr_pull(ndr_pull, flags, st);
+ printf("pull returned %s\n",
+ ndr_map_error2string(ndr_err));
+
+ if (ndr_pull->offset > ndr_pull->relative_highest_offset) {
+ highest_ofs = ndr_pull->offset;
+ } else {
+ highest_ofs = ndr_pull->relative_highest_offset;
+ }
+
+ if (dumpdata) {
+ printf("%"PRIu32" bytes consumed\n", highest_ofs);
+ ndrdump_data(blob.data, blob.length, dumpdata);
+ }
+
+ if (!print_after_parse_failure && !NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(mem_ctx);
+ exit(2);
+ }
+
+ if (highest_ofs != ndr_pull->data_size) {
+ printf("WARNING! %"PRIu32" unread bytes\n", ndr_pull->data_size - highest_ofs);
+ ndrdump_data(ndr_pull->data+highest_ofs,
+ ndr_pull->data_size - highest_ofs,
+ dumpdata);
+ }
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ printf("WARNING: pull of %s was incomplete, "
+ "therefore the parse below may SEGFAULT\n",
+ f->name);
+ }
+
+ f->ndr_print(ndr_print, f->name, flags, st);
+
+ if (flags & NDR_IN) {
+ status = ndrdump_pull_and_print_pipes(format,
+ ndr_pull,
+ ndr_print,
+ &f->in_pipes);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("pull and dump of IN pipes FAILED: %s\n",
+ nt_errstr(status));
+ exit(1);
+ }
+ }
+
+ /* Do not proceed to validate if we got an error */
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ printf("dump of failed-to-parse %s complete\n",
+ f->name);
+ TALLOC_FREE(mem_ctx);
+ exit(2);
+ }
+
+ if (validate) {
+ DATA_BLOB v_blob;
+ struct ndr_push *ndr_v_push;
+ struct ndr_pull *ndr_v_pull;
+ struct ndr_print *ndr_v_print;
+ uint32_t highest_v_ofs;
+ uint32_t i;
+ uint8_t byte_a, byte_b;
+ bool differ;
+
+ ndr_v_push = ndr_push_init_ctx(mem_ctx);
+ if (ndr_v_push == NULL) {
+ printf("No memory\n");
+ exit(1);
+ }
+
+ if (assume_ndr64) {
+ ndr_v_push->flags |= LIBNDR_FLAG_NDR64;
+ }
+
+ ndr_err = f->ndr_push(ndr_v_push, flags, st);
+ printf("push returned %s\n",
+ ndr_map_error2string(ndr_err));
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ printf("validate push FAILED\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ v_blob = ndr_push_blob(ndr_v_push);
+
+ if (dumpdata) {
+ printf("%zu bytes generated (validate)\n", v_blob.length);
+ ndrdump_data(v_blob.data, v_blob.length, dumpdata);
+ }
+
+ ndr_v_pull = ndr_pull_init_blob(&v_blob, mem_ctx);
+ if (ndr_v_pull == NULL) {
+ perror("ndr_pull_init_blob");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+ ndr_v_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ ndr_err = f->ndr_pull(ndr_v_pull, flags, v_st);
+ printf("pull returned %s\n",
+ ndr_map_error2string(ndr_err));
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ printf("validate pull FAILED\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ if (ndr_v_pull->offset > ndr_v_pull->relative_highest_offset) {
+ highest_v_ofs = ndr_v_pull->offset;
+ } else {
+ highest_v_ofs = ndr_v_pull->relative_highest_offset;
+ }
+
+ if (highest_v_ofs != ndr_v_pull->data_size) {
+ printf("WARNING! %"PRIu32" unread bytes in validation\n",
+ ndr_v_pull->data_size - highest_v_ofs);
+ ndrdump_data(ndr_v_pull->data + highest_v_ofs,
+ ndr_v_pull->data_size - highest_v_ofs,
+ dumpdata);
+ }
+
+ ndr_v_print = talloc_zero(mem_ctx, struct ndr_print);
+ ndr_v_print->print = ndr_print_debug_helper;
+ ndr_v_print->depth = 1;
+ f->ndr_print(ndr_v_print,
+ format,
+ flags, v_st);
+
+ if (blob.length != v_blob.length) {
+ printf("WARNING! orig bytes:%zu validated pushed bytes:%zu\n",
+ blob.length, v_blob.length);
+ }
+
+ if (highest_ofs != highest_v_ofs) {
+ printf("WARNING! orig pulled bytes:%"PRIu32" validated pulled bytes:%"PRIu32"\n",
+ highest_ofs, highest_v_ofs);
+ }
+
+ differ = false;
+ byte_a = 0x00;
+ byte_b = 0x00;
+ for (i=0; i < blob.length; i++) {
+ byte_a = blob.data[i];
+
+ if (i == v_blob.length) {
+ byte_b = 0x00;
+ differ = true;
+ break;
+ }
+
+ byte_b = v_blob.data[i];
+
+ if (byte_a != byte_b) {
+ differ = true;
+ break;
+ }
+ }
+ if (differ) {
+ printf("WARNING! orig and validated differ at byte 0x%02"PRIX32" (%"PRIu32")\n", i, i);
+ printf("WARNING! orig byte[0x%02"PRIX32"] = 0x%02"PRIX8" validated byte[0x%02"PRIX32"] = 0x%02"PRIX8"\n",
+ i, byte_a, i, byte_b);
+ ndrdump_data_diff(blob.data, blob.length,
+ v_blob.data, v_blob.length,
+ dumpdata);
+ }
+ }
+
+ printf("dump OK\n");
+ TALLOC_FREE(mem_ctx);
+
+ poptFreeContext(pc);
+
+ return 0;
+}
diff --git a/librpc/tools/wscript_build b/librpc/tools/wscript_build
new file mode 100644
index 0000000..3f2f950
--- /dev/null
+++ b/librpc/tools/wscript_build
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+bld.SAMBA_BINARY('ndrdump',
+ source='ndrdump.c',
+ manpages='ndrdump.1',
+ deps='samba-hostconfig samba-util popt CMDLINE_S4 ndr-table samba-errors NDR_DCERPC'
+ )
diff --git a/librpc/wscript_build b/librpc/wscript_build
new file mode 100644
index 0000000..ee2ad70
--- /dev/null
+++ b/librpc/wscript_build
@@ -0,0 +1,804 @@
+#!/usr/bin/env python
+
+bld.RECURSE('idl')
+bld.RECURSE('../lib/compression')
+
+bld.SAMBA_SUBSYSTEM('NDR_AUDIOSRV',
+ source='gen_ndr/ndr_audiosrv.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_AUTH',
+ source='gen_ndr/ndr_auth.c ndr/ndr_auth.c',
+ public_headers='gen_ndr/auth.h',
+ header_path='gen_ndr',
+ public_deps='ndr NDR_SECURITY ndr-krb5pac'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_ATSVC',
+ source='gen_ndr/ndr_atsvc.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_NAMED_PIPE_AUTH',
+ source='gen_ndr/ndr_named_pipe_auth.c',
+ public_deps='ndr NDR_AUTH'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DNSSERVER',
+ source='gen_ndr/ndr_dnsserver.c ndr/ndr_dnsserver.c',
+ public_deps='ndr NDR_DNSP'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DNS',
+ source='gen_ndr/ndr_dns.c ndr/ndr_dns.c ndr/ndr_dns_utils.c',
+ public_deps='ndr NDR_DNSP'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DSBACKUP',
+ source='gen_ndr/ndr_dsbackup.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DFS',
+ source='gen_ndr/ndr_dfs.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_WINREG',
+ source='gen_ndr/ndr_winreg.c',
+ public_deps='ndr NDR_SECURITY NDR_LSA'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_EFS',
+ source='gen_ndr/ndr_efs.c',
+ public_deps='ndr NDR_SECURITY'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_ROT',
+ source='gen_ndr/ndr_rot.c',
+ public_deps='ndr NDR_ORPC'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_FRSRPC',
+ source='ndr/ndr_frsrpc.c gen_ndr/ndr_frsrpc.c',
+ public_deps='ndr NDR_FSCC'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_FRSAPI',
+ source='gen_ndr/ndr_frsapi.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_FRSTRANS',
+ source='gen_ndr/ndr_frstrans.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DFSBLOBS',
+ source='gen_ndr/ndr_dfsblobs.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_BKUPBLOBS',
+ source='ndr/ndr_bkupblobs.c gen_ndr/ndr_bkupblobs.c',
+ public_deps='ndr NDR_SECURITY NDR_FSCC'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_FSCC',
+ source='gen_ndr/ndr_fscc.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_POLICYAGENT',
+ source='gen_ndr/ndr_policyagent.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_UNIXINFO',
+ source='gen_ndr/ndr_unixinfo.c',
+ public_deps='ndr NDR_SECURITY'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SPOOLSS',
+ source='gen_ndr/ndr_spoolss.c',
+ public_deps='ndr NDR_SPOOLSS_BUF NDR_SECURITY'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SPOOLSS_BUF',
+ source='ndr/ndr_spoolss_buf.c',
+ deps='talloc'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_WINSPOOL',
+ source='gen_ndr/ndr_winspool.c',
+ public_deps='ndr NDR_SPOOLSS'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_PRINTCAP',
+ source='gen_ndr/ndr_printcap.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_EPMAPPER',
+ source='gen_ndr/ndr_epmapper.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DBGIDL',
+ source='gen_ndr/ndr_dbgidl.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DSSETUP',
+ source='gen_ndr/ndr_dssetup.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_MSGSVC',
+ source='gen_ndr/ndr_msgsvc.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_MGMT',
+ source='gen_ndr/ndr_mgmt.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_ORPC',
+ source='ndr/ndr_orpc.c gen_ndr/ndr_orpc.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_WZCSVC',
+ source='gen_ndr/ndr_wzcsvc.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_BROWSER',
+ source='gen_ndr/ndr_browser.c',
+ public_deps='ndr NDR_SRVSVC'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_W32TIME',
+ source='gen_ndr/ndr_w32time.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SCERPC',
+ source='gen_ndr/ndr_scerpc.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SERVER_ID',
+ source='gen_ndr/ndr_server_id.c',
+ deps='ndr',
+ public_headers='gen_ndr/server_id.h',
+ header_path='gen_ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_TRKWKS',
+ source='gen_ndr/ndr_trkwks.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_KEYSVC',
+ source='gen_ndr/ndr_keysvc.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_RAP',
+ source='gen_ndr/ndr_rap.c ndr/ndr_rap.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_IDMAP',
+ source='gen_ndr/ndr_idmap.c',
+ public_deps='ndr ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_NOTIFY',
+ source='gen_ndr/ndr_notify.c',
+ public_deps='ndr ndr-standard NDR_SERVER_ID NDR_FILE_ID'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_NTLMSSP',
+ source='ndr/ndr_ntlmssp.c gen_ndr/ndr_ntlmssp.c',
+ public_deps='ndr ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_NEGOEX',
+ source='ndr/ndr_negoex.c gen_ndr/ndr_negoex.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DNSP',
+ source='gen_ndr/ndr_dnsp.c ndr/ndr_dnsp.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_NFS4ACL',
+ source='gen_ndr/ndr_nfs4acl.c',
+ public_deps='ndr NDR_SECURITY'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_NTPRINTING',
+ source='gen_ndr/ndr_ntprinting.c ndr/ndr_ntprinting.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SAMR',
+ source='gen_ndr/ndr_samr.c',
+ public_deps='ndr NDR_SECURITY NDR_LSA'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_LSA',
+ source='gen_ndr/ndr_lsa.c',
+ public_deps='ndr NDR_SECURITY'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SECURITY',
+ source='gen_ndr/ndr_security.c ndr/ndr_sec_helper.c',
+ deps='ndr samba-security',
+ public_headers='gen_ndr/security.h',
+ header_path='gen_ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SMB_ACL',
+ source='gen_ndr/ndr_smb_acl.c',
+ deps='ndr',
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SVCCTL',
+ source='gen_ndr/ndr_svcctl.c ndr/ndr_svcctl.c',
+ public_deps='ndr NDR_SECURITY'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SRVSVC',
+ source='gen_ndr/ndr_srvsvc.c',
+ public_deps='ndr NDR_SECURITY NDR_SVCCTL'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_NETLOGON',
+ source='gen_ndr/ndr_netlogon.c ndr/ndr_netlogon.c',
+ public_deps='ndr NDR_SECURITY NDR_LSA NDR_SAMR ndr_nbt'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_EVENTLOG',
+ source='gen_ndr/ndr_eventlog.c',
+ public_deps='ndr NDR_SECURITY NDR_LSA'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_EVENTLOG6',
+ source='gen_ndr/ndr_eventlog6.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_NTSVCS',
+ source='gen_ndr/ndr_ntsvcs.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_WKSSVC',
+ source='gen_ndr/ndr_wkssvc.c',
+ public_deps='ndr NDR_SECURITY NDR_SRVSVC NDR_LSA'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_ECHO',
+ source='gen_ndr/ndr_echo.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_INITSHUTDOWN',
+ source='gen_ndr/ndr_initshutdown.c',
+ public_deps='ndr NDR_LSA'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_COMPRESSION',
+ source='ndr/ndr_compression.c',
+ public_deps='samba-errors ndr',
+ deps='z LZXPRESS'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_FSRVP',
+ source='gen_ndr/ndr_fsrvp.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_GENERATOR('gen_wsp_props',
+ source='../source4/scripting/bin/gen_wsp_props.py wsp/allprops-from-ms-wsp-spec.csv wsp/extra-props.csv',
+target='wsp/wsp_props_gen.c',
+ group='build_source',
+ rule='${PYTHON} ${SRC[0].abspath(env)} ${SRC[1].abspath(env)} ${TGT[0].abspath(env)} ${SRC[2].abspath(env)}'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_WSP',
+ source='gen_ndr/ndr_wsp.c wsp/wsp_helper.c wsp/wsp_props_gen.c',
+ public_deps='ndr gen_wsp_props'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_WSP_DATA',
+ source='gen_ndr/ndr_wsp_data.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('WSP_UTIL',
+ source='wsp/wsp_util.c wsp/wsp_props_gen.c',
+ public_deps='ndr gen_wsp_props'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_WITNESS',
+ source='gen_ndr/ndr_witness.c ndr/ndr_witness.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_CLUSAPI',
+ source='gen_ndr/ndr_clusapi.c',
+ public_deps='ndr NDR_WINREG'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_MDSSVC',
+ source='gen_ndr/ndr_mdssvc.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DCERPC',
+ source='gen_ndr/ndr_dcerpc.c ndr/ndr_dcerpc.c',
+ public_deps='ndr',
+ public_headers='gen_ndr/ndr_dcerpc.h gen_ndr/dcerpc.h ndr/ndr_dcerpc.h',
+ header_path=[ ('gen_ndr*', 'gen_ndr'), ('ndr*', 'ndr')]
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DRSUAPI',
+ source='ndr/ndr_drsuapi.c gen_ndr/ndr_drsuapi.c',
+ public_deps='ndr NDR_COMPRESSION NDR_SECURITY ndr-standard asn1util',
+ public_headers='gen_ndr/ndr_drsuapi.h gen_ndr/drsuapi.h ndr/ndr_drsuapi.h',
+ header_path=[ ('gen_ndr*', 'gen_ndr'), ('ndr*', 'ndr')]
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_DRSBLOBS',
+ source='ndr/ndr_drsblobs.c gen_ndr/ndr_drsblobs.c',
+ public_deps='ndr NDR_DRSUAPI',
+ public_headers='gen_ndr/ndr_drsblobs.h gen_ndr/drsblobs.h ndr/ndr_drsblobs.h',
+ header_path=[ ('gen_ndr*', 'gen_ndr'), ('ndr*', 'ndr')]
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_ODJ',
+ source='gen_ndr/ndr_ODJ.c ndr/ndr_ODJ.c',
+ public_deps='NDR_LSA NDR_NETLOGON NDR_SECURITY',
+ deps='ndr')
+
+bld.SAMBA_SUBSYSTEM('NDR_KRB5PAC',
+ source='',
+ deps='ndr-krb5pac')
+
+bld.SAMBA_LIBRARY('ndr-krb5pac',
+ source='ndr/ndr_krb5pac.c gen_ndr/ndr_krb5pac.c',
+ public_deps='ndr ndr-standard NDR_SECURITY NDR_CLAIMS',
+ public_headers='gen_ndr/krb5pac.h gen_ndr/ndr_krb5pac.h ndr/ndr_krb5pac.h',
+ header_path=[ ('gen_ndr*', 'gen_ndr'), ('ndr*', 'ndr')],
+ pc_files='ndr_krb5pac.pc',
+ vnum='0.0.1'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_KRB5CCACHE',
+ source='gen_ndr/ndr_krb5ccache.c',
+ deps='ndr NDR_SECURITY ndr-standard asn1util'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_CLAIMS',
+ source='gen_ndr/ndr_claims.c ndr/ndr_claims.c',
+ deps='ndr NDR_COMPRESSION LZXPRESS')
+
+bld.SAMBA_SUBSYSTEM('NDR_GKDI',
+ source='gen_ndr/ndr_gkdi.c',
+ deps='ndr')
+
+bld.SAMBA_SUBSYSTEM('NDR_GMSA',
+ source='gen_ndr/ndr_gmsa.c',
+ deps='ndr')
+
+bld.SAMBA_LIBRARY('ndr-standard',
+ source='',
+ vnum='0.0.1',
+ pc_files='ndr_standard.pc',
+ deps='''NDR_SECURITY NDR_LSA NDR_SAMR NDR_NETLOGON
+ NDR_EVENTLOG NDR_EVENTLOG6 NDR_DFS
+ NDR_NTSVCS NDR_SVCCTL NDR_INITSHUTDOWN NDR_WKSSVC NDR_SRVSVC NDR_WINREG
+ NDR_ECHO security NDR_DNS NDR_DNSP NDR_ATSVC NDR_SPOOLSS NDR_DSSETUP
+ NDR_SERVER_ID NDR_NOTIFY''',
+ public_deps='ndr',
+ public_headers='gen_ndr/samr.h gen_ndr/ndr_samr.h gen_ndr/lsa.h gen_ndr/netlogon.h gen_ndr/atsvc.h gen_ndr/ndr_atsvc.h gen_ndr/ndr_svcctl.h gen_ndr/svcctl.h gen_ndr/claims.h',
+ header_path='gen_ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_XATTR',
+ source='ndr/ndr_xattr.c gen_ndr/ndr_xattr.c',
+ public_deps='ndr NDR_SECURITY'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SMB3POSIX',
+ source='gen_ndr/ndr_smb3posix.c',
+ public_deps='ndr',
+ public_headers='gen_ndr/smb3posix.h')
+
+bld.SAMBA_SUBSYSTEM('NDR_SMB2_LEASE_STRUCT',
+ source='gen_ndr/ndr_smb2_lease_struct.c',
+ public_deps='ndr',
+ public_headers='gen_ndr/smb2_lease_struct.h'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_QUOTA',
+ source='gen_ndr/ndr_quota.c',
+ public_deps='ndr',
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_SCHANNEL',
+ source='ndr/ndr_schannel.c gen_ndr/ndr_schannel.c',
+ public_deps='ndr ndr_nbt'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_NBT',
+ source='',
+ deps='ndr_nbt')
+
+bld.SAMBA_LIBRARY('ndr_nbt',
+ source='gen_ndr/ndr_nbt.c ndr/ndr_nbt.c',
+ public_deps='ndr NDR_NBT_BUF NDR_SECURITY NDR_DNS',
+ public_headers='gen_ndr/nbt.h gen_ndr/ndr_nbt.h ndr/ndr_nbt.h',
+ header_path=[ ('gen_ndr*', 'gen_ndr'), ('ndr*', 'ndr')],
+ pc_files='ndr_nbt.pc',
+ vnum='0.0.1'
+)
+
+bld.SAMBA_SUBSYSTEM('NDR_BACKUPKEY',
+ source='ndr/ndr_backupkey.c gen_ndr/ndr_backupkey.c',
+ public_deps='ndr NDR_SECURITY'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_PREG',
+ source='gen_ndr/ndr_preg.c ndr/ndr_preg.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_CAB',
+ source='''
+ gen_ndr/ndr_cab.c
+ ndr/ndr_cab.c
+ ''',
+ public_deps='ndr NDR_COMPRESSION')
+
+bld.SAMBA_SUBSYSTEM('NDR_FILE_ID',
+ source='gen_ndr/ndr_file_id.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_MESSAGING',
+ source='gen_ndr/ndr_messaging.c',
+ public_deps='ndr NDR_SERVER_ID'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_WINSTATION',
+ source='gen_ndr/ndr_winstation.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_CONDITIONAL_ACE',
+ source='gen_ndr/ndr_conditional_ace.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_ATSVC',
+ source='gen_ndr/ndr_atsvc_c.c',
+ public_deps='dcerpc-binding NDR_ATSVC'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_ECHO',
+ source='gen_ndr/ndr_echo_c.c',
+ public_deps='dcerpc-binding NDR_ECHO'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_LSA',
+ source='gen_ndr/ndr_lsa_c.c',
+ public_deps='dcerpc-binding ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_SAMR',
+ source='gen_ndr/ndr_samr_c.c',
+ public_deps='dcerpc-binding NDR_SAMR'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_DFS',
+ source='gen_ndr/ndr_dfs_c.c',
+ public_deps='dcerpc-binding ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_FRSAPI',
+ source='gen_ndr/ndr_frsapi_c.c',
+ public_deps='dcerpc-binding NDR_FRSAPI'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_DRSUAPI',
+ source='gen_ndr/ndr_drsuapi_c.c',
+ public_deps='dcerpc-binding NDR_DRSUAPI'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_UNIXINFO',
+ source='gen_ndr/ndr_unixinfo_c.c',
+ public_deps='dcerpc-binding NDR_UNIXINFO'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_BROWSER',
+ source='gen_ndr/ndr_browser_c.c',
+ public_deps='dcerpc-binding NDR_BROWSER'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_SPOOLSS',
+ source='gen_ndr/ndr_spoolss_c.c',
+ public_deps='dcerpc-binding NDR_SPOOLSS'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_WINSPOOL',
+ source='gen_ndr/ndr_winspool_c.c',
+ public_deps='dcerpc-binding NDR_WINSPOOL'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_WKSSVC',
+ source='gen_ndr/ndr_wkssvc_c.c',
+ public_deps='dcerpc-binding ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_SRVSVC',
+ source='gen_ndr/ndr_srvsvc_c.c',
+ public_deps='dcerpc-binding NDR_SRVSVC'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_SVCCTL',
+ source='gen_ndr/ndr_svcctl_c.c',
+ public_deps='dcerpc-binding ndr-standard',
+ public_headers='gen_ndr/ndr_svcctl_c.h ndr/ndr_svcctl.h',
+ header_path=[ ('gen_ndr*', 'gen_ndr'), ('ndr*', 'ndr')]
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_EVENTLOG',
+ source='gen_ndr/ndr_eventlog_c.c',
+ public_deps='dcerpc-binding ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_EPMAPPER',
+ source='gen_ndr/ndr_epmapper_c.c',
+ public_deps='tevent NDR_EPMAPPER'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_DSSETUP',
+ source='gen_ndr/ndr_dssetup_c.c',
+ public_deps='dcerpc-binding NDR_DSSETUP'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_WINREG',
+ source='gen_ndr/ndr_winreg_c.c',
+ public_deps='dcerpc-binding ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_INITSHUTDOWN',
+ source='gen_ndr/ndr_initshutdown_c.c',
+ public_deps='dcerpc-binding ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_MGMT',
+ source='gen_ndr/ndr_mgmt_c.c',
+ deps='tevent NDR_MGMT'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_NTSVCS',
+ source='gen_ndr/ndr_ntsvcs_c.c',
+ public_deps='dcerpc-binding ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_NETLOGON',
+ source='gen_ndr/ndr_netlogon_c.c',
+ public_deps='ndr-standard tevent'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_BACKUPKEY',
+ source='gen_ndr/ndr_backupkey_c.c',
+ public_deps='dcerpc-binding NDR_BACKUPKEY'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_DNSSERVER',
+ source='gen_ndr/ndr_dnsserver_c.c',
+ public_deps='dcerpc-binding ndr-standard'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_IOCTL',
+ source='gen_ndr/ndr_ioctl.c ndr/ndr_ioctl.c',
+ public_deps='ndr'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_FSRVP',
+ source='gen_ndr/ndr_fsrvp_c.c',
+ public_deps='dcerpc-binding NDR_FSRVP'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_WITNESS',
+ source='gen_ndr/ndr_witness_c.c',
+ public_deps='dcerpc-binding NDR_WITNESS'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_CLUSAPI',
+ source='gen_ndr/ndr_clusapi_c.c',
+ public_deps='dcerpc-binding NDR_CLUSAPI'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_MDSSVC',
+ source='gen_ndr/ndr_mdssvc_c.c',
+ public_deps='dcerpc-binding NDR_MDSSVC'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_GKDI',
+ source='gen_ndr/ndr_gkdi_c.c',
+ public_deps='dcerpc-binding NDR_GKDI'
+ )
+
+# a grouping library for NDR subsystems that may be used by more than one target
+bld.SAMBA_LIBRARY('ndr-samba',
+ source=[],
+ deps='''NDR_DRSBLOBS NDR_DRSUAPI NDR_IDMAP NDR_NTLMSSP NDR_NEGOEX NDR_SCHANNEL NDR_MGMT
+ NDR_DNSSERVER NDR_EPMAPPER NDR_XATTR NDR_UNIXINFO NDR_NAMED_PIPE_AUTH
+ NDR_NTPRINTING NDR_FSRVP NDR_WITNESS NDR_MDSSVC NDR_OPEN_FILES NDR_SMBXSRV
+ NDR_SMB3POSIX NDR_RPCD_WITNESS
+ NDR_KRB5CCACHE NDR_WSP NDR_GKDI NDR_GMSA''',
+ private_library=True,
+ grouping_library=True
+ )
+
+# a grouping library for RPC_NDR subsystems that may be used by more than one target
+bld.SAMBA_LIBRARY('dcerpc-samba',
+ source='',
+ deps='''RPC_NDR_LSA RPC_NDR_SAMR RPC_NDR_NETLOGON RPC_NDR_EVENTLOG
+ RPC_NDR_DFS RPC_NDR_NTSVCS RPC_NDR_SVCCTL RPC_NDR_INITSHUTDOWN
+ RPC_NDR_WKSSVC RPC_NDR_SRVSVC RPC_NDR_WINREG RPC_NDR_ECHO RPC_NDR_EPMAPPER
+ RPC_NDR_ATSVC RPC_NDR_SPOOLSS RPC_NDR_DNSSERVER RPC_NDR_GKDI''',
+ public_deps='ndr-standard',
+ private_library=True,
+ grouping_library=True
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_MISC',
+ source='',
+ deps='ndr')
+
+bld.SAMBA_LIBRARY('ndr',
+ source='ndr/ndr_string.c ndr/ndr_basic.c ndr/uuid.c ndr/ndr.c ndr/ndr_misc.c gen_ndr/ndr_misc.c ndr/util.c',
+ pc_files='ndr.pc',
+ public_deps='samba-errors talloc samba-util util_str_hex',
+ public_headers='gen_ndr/misc.h gen_ndr/ndr_misc.h ndr/libndr.h:ndr.h',
+ header_path= [('*gen_ndr*', 'gen_ndr')],
+ vnum='4.0.0',
+ abi_directory='ABI',
+ abi_match='!ndr_table_* ndr_* GUID_* _ndr_pull_error* _ndr_push_error*',
+ )
+
+bld.SAMBA_LIBRARY('dcerpc-binding',
+ source='''
+ rpc/dcerpc_error.c
+ rpc/binding.c
+ rpc/dcerpc_util.c
+ rpc/binding_handle.c
+ ''',
+ deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util',
+ pc_files=[],
+ public_headers='rpc/rpc_common.h',
+ vnum='0.0.1')
+
+bld.SAMBA_LIBRARY('dcerpc-pkt-auth',
+ private_library=True,
+ source='''
+ rpc/dcerpc_pkt_auth.c
+ ''',
+ deps='dcerpc-binding gensec')
+
+bld.SAMBA_SUBSYSTEM('DCERPC_SERVER_NETLOGON',
+ source='''
+ rpc/server/netlogon/schannel_util.c
+ ''',
+ deps='''
+ talloc
+ util_str_escape
+ samba-hostconfig
+ NDR_NETLOGON
+ dcerpc-server-core
+ ''')
+
+bld.SAMBA_LIBRARY('dcerpc-server-core',
+ source='''
+ rpc/dcesrv_core.c
+ rpc/dcesrv_auth.c
+ rpc/dcesrv_mgmt.c
+ rpc/dcesrv_reply.c
+ rpc/dcesrv_handles.c
+ ''',
+ deps='''
+ ndr
+ dcerpc-binding
+ samba-util-core
+ gnutls
+ GNUTLS_HELPERS
+ dcerpc-pkt-auth
+ ''',
+ pc_files=[],
+ public_headers='rpc/dcesrv_core.h',
+ autoproto='rpc/dcesrv_core_proto.h',
+ vnum='0.0.1')
+
+bld.SAMBA_SUBSYSTEM('DCERPC_HELPER',
+ source='rpc/dcerpc_helper.c',
+ public_deps='''
+ samba-hostconfig
+ samba-security
+ gnutls
+ GNUTLS_HELPERS
+ ''')
+
+bld.SAMBA_SUBSYSTEM('NDR_WINBIND',
+ source='gen_ndr/ndr_winbind.c',
+ public_deps='ndr NDR_LSA'
+ )
+
+bld.SAMBA_SUBSYSTEM('RPC_NDR_WINBIND',
+ source='gen_ndr/ndr_winbind_c.c',
+ public_deps='dcerpc NDR_WINBIND'
+ )
+
+bld.SAMBA_SUBSYSTEM('NDR_FSRVP_STATE',
+ source='gen_ndr/ndr_fsrvp_state.c',
+ public_deps='ndr'
+ )
+#
+# Cmocka tests
+#
+
+bld.SAMBA_BINARY('test_ndr_macros',
+ source='tests/test_ndr_macros.c',
+ deps='''
+ cmocka
+ ndr
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_ndr_string',
+ source='tests/test_ndr_string.c',
+ deps='''
+ cmocka
+ talloc
+ ndr
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_ndr',
+ source='tests/test_ndr.c',
+ deps='''
+ cmocka
+ ndr
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY('test_ndr_dns_nbt',
+ source='tests/test_ndr_dns_nbt.c',
+ deps='''
+ cmocka
+ ndr
+ ndr_nbt
+ ''',
+ for_selftest=True)
+
+bld.SAMBA_BINARY(
+ 'test_ndr_gmsa',
+ source='tests/test_ndr_gmsa.c',
+ deps='''
+ cmocka
+ talloc
+ NDR_GMSA
+ ''',
+ for_selftest=True,
+)
diff --git a/librpc/wsp/README b/librpc/wsp/README
new file mode 100644
index 0000000..45a544e
--- /dev/null
+++ b/librpc/wsp/README
@@ -0,0 +1,50 @@
+WSP properties are described in a number of sections in the MS-WSP protocol
+document. The document says that all properties are categorised as follows
+
+"GUID and PropId: Together, these parameters establish the unique identifier
+ for documents.
+isColumn: A boolean value set to TRUE if, and only if, the property can be
+ returned as a requested property as specified in the
+ ProjectionColumnsOffsets argument to a RunNewQuery Generic Search
+ Service (GSS) abstract interface call.
+inInvertedIndex: A boolean value set to TRUE if, and only if, the property can
+ be an argument to CContentRestriction within the
+ RestrictionSet argument to a RunNewQuery GSS abstract
+ interface call.
+columnIndexType: This parameter defines whether sorting, grouping, and
+ filtering are allowed for this property, as defined in the
+ SortOrders, Groupings, and Restrictions parameters of the
+ RunNewQuery GSS abstract interface call.
+ The columnIndexType parameter is a string set to one of the
+ following"
+
+additionally the property type 'VT_XXXX' and max size are known
+
+However, not all properties described match this, only properties mentioned in
+the "full property table" are fully described, others mentioned e.g. in
+"Standard" & "Open" property sections (and associated tables) have just the
+GUID, propid & property data type described, still other properties are only
+mentioned in the Example section and one needs to manually extract the info.
+
+We need the property descriptions and some scripting helps here, in this
+directory there is
+
+librpc/wsp/allprops-from-ms-wsp-spec.csv:
+ a csv file made from the "full property table" exported from the html
+ oneline version online version of MS-WSP open specification document.
+extra-props.csv:
+ a csv file of the same format containing the other properties mentioned
+ above and additionally a few more from the wireshark repo)
+
+and in directory source4/scripting/bin
+
+gen_wsp_props.py:
+ a simple python script to generate code from the csv files above,
+
+extra-props.csv was generated by basically grabbing the property definititions
+from the wireshark repo
+ https://github.com/wireshark/wireshark.git(epan/dissectors/packet-mswsp.c
+and comparing against the properties we already have
+
+The build generates code from the csv file mentioned above which is built into
+the NDR_WSP subsystem.
diff --git a/librpc/wsp/allprops-from-ms-wsp-spec.csv b/librpc/wsp/allprops-from-ms-wsp-spec.csv
new file mode 100644
index 0000000..b822304
--- /dev/null
+++ b/librpc/wsp/allprops-from-ms-wsp-spec.csv
@@ -0,0 +1,423 @@
+#Intellectual Property Rights Notice for Open Specifications Documentation
+#Technical Documentation. Microsoft publishes Open Specifications documentation (“this
+#documentation”) for protocols, file formats, data portability, computer languages, and standards
+#support. Additionally, overview documents cover inter-protocol relationships and interactions.
+#Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other
+#terms that are contained in the terms of use for the Microsoft website that hosts this
+#documentation, you can make copies of it in order to develop implementations of the technologies
+#that are described in this documentation and can distribute portions of it in your implementations
+#that use these technologies or in your documentation as necessary to properly document the
+#implementation. You can also distribute in your implementation, with or without modification, any
+#schemas, IDLs, or code samples that are included in the documentation. This permission also
+#applies to any documents that are referenced in the Open Specifications documentation.
+#No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation.
+#Patents. Microsoft has patents that might cover your implementations of the technologies
+#described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of
+#this documentation grants any licenses under those patents or any other Microsoft patents.
+#However, a given Open Specifications document might be covered by the Microsoft Open
+#Specifications Promise or the Microsoft Community Promise. If you would prefer a written license,
+#or if the technologies described in this documentation are not covered by the Open Specifications
+#Promise or Community Promise, as applicable, patent licenses are available by contacting
+#iplg@microsoft.com.
+#License Programs. To see all of the protocols in scope under a specific license program and the
+#associated patents, visit the Patent Map.
+#Trademarks. The names of companies and products contained in this documentation might be
+#covered by trademarks or similar intellectual property rights. This notice does not grant any
+#licenses under those rights. For a list of Microsoft trademarks, visit
+#www.microsoft.com/trademarks.
+#Fictitious Names. The example companies, organizations, products, domain names, email
+#addresses, logos, people, places, and events that are depicted in this documentation are fictitious.
+#No association with any real company, organization, product, domain name, email address, logo,
+#person, place, or event is intended or should be inferred.
+#Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other
+#than as specifically described above, whether by implication, estoppel, or otherwise.
+#Tools. The Open Specifications documentation does not require the use of Microsoft programming
+#tools or programming environments in order for you to develop an implementation. If you have access
+#to Microsoft programming tools and environments, you are free to take advantage of them. Certain
+#Open Specifications documents are intended for use in conjunction with publicly available standards
+#specifications and network programming art and, as such, assume that the reader either is familiar
+#with the aforementioned material or has immediate access to it.
+#Support. For questions and support, please contact dochelp@microsoft.com.
+#
+# content below has been extracted from the open specification MS-WSP
+#
+#Property Name,GUID,propID,inInvertedIndex,isColumn,columnIndexType,type,MaxSize,Vector Property,Description
+#
+System.AcquisitionID,{65A98875-3C80-40AB-ABBC-EFDAF77DBEE2},100,FALSE,TRUE, ,Int32,4, ,Hash to determine acquisition session.
+System.ApplicationName,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},18,TRUE,TRUE, ,String,512, , 
+System.Audio.ChannelCount,{64440490-4C8B-11D1-8B70-080036B11A03},7,FALSE,TRUE, ,UInt32,4, ,"Indicates the channel count for the audio file. Values: 1 (mono), 2 (stereo)."
+System.Audio.EncodingBitrate,{64440490-4C8B-11D1-8B70-080036B11A03},4,FALSE,TRUE, ,UInt32,4, ,"Indicates the average data rate in Hz for the audio file in ""bits per second""."
+System.Audio.PeakValue,{2579E5D0-1116-4084-BD9A-9B4F7CB4DF5E},100,FALSE,TRUE, ,UInt32,4, , 
+System.Audio.SampleRate,{64440490-4C8B-11D1-8B70-080036B11A03},5,FALSE,TRUE, ,UInt32,4, ,"Indicates the audio sample rate for the audio file in ""samples per second""."
+System.Audio.SampleSize,{64440490-4C8B-11D1-8B70-080036B11A03},6,FALSE,TRUE, ,UInt32,4, ,"Indicates the audio sample size for the audio file in ""bits per sample""."
+System.Author,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},4,TRUE,TRUE, ,String,256,TRUE, 
+System.Calendar.Duration,{293CA35A-09AA-4DD2-B180-1FE245728A52},100,TRUE,TRUE, ,String,512, ,The duration as specified in a string.
+System.Calendar.IsOnline,{BFEE9149-E3E2-49A7-A862-C05988145CEC},100,FALSE,TRUE, ,Boolean,2, ,Indicates whether the event is an online event.
+System.Calendar.IsRecurring,{315B9C8D-80A9-4EF9-AE16-8E746DA51D70},100,FALSE,TRUE, ,Boolean,2, , 
+System.Calendar.Location,{F6272D18-CECC-40B1-B26A-3911717AA7BD},100,TRUE,TRUE, ,String,512, , 
+System.Calendar.OptionalAttendeeAddresses,{D55BAE5A-3892-417A-A649-C6AC5AAAEAB3},100,TRUE,TRUE, ,String,256,TRUE, 
+System.Calendar.OptionalAttendeeNames,{09429607-582D-437F-84C3-DE93A2B24C3C},100,TRUE,TRUE, ,String,256,TRUE, 
+System.Calendar.OrganizerAddress,{744C8242-4DF5-456C-AB9E-014EFB9021E3},100,TRUE,TRUE, ,String,256, ,Address of the organizer organizing the event.
+System.Calendar.OrganizerName,{AAA660F9-9865-458E-B484-01BC7FE3973E},100,TRUE,TRUE, ,String,256, ,Name of the organizer organizing the event.
+System.Calendar.ReminderTime,{72FC5BA4-24F9-4011-9F3F-ADD27AFAD818},100,FALSE,TRUE, ,DateTime,8, , 
+System.Calendar.RequiredAttendeeAddresses,{0BA7D6C3-568D-4159-AB91-781A91FB71E5},100,TRUE,TRUE, ,String,256,TRUE, 
+System.Calendar.RequiredAttendeeNames,{B33AF30B-F552-4584-936C-CB93E5CDA29F},100,TRUE,TRUE, ,String,256,TRUE, 
+System.Calendar.Resources,{00F58A38-C54B-4C40-8696-97235980EAE1},100,TRUE,TRUE, ,String,512,TRUE, 
+System.Calendar.ResponseStatus,{188C1F91-3C40-4132-9EC5-D8B03B72A8A2},100,FALSE,TRUE, ,UInt16,2, ,This property stores the status of the user responses to meetings in the user's calendar.
+System.Calendar.ShowTimeAs,{5BF396D4-5EB2-466F-BDE9-2FB3F2361D6E},100,FALSE,TRUE, ,UInt16,2, , 
+System.Calendar.ShowTimeAsText,{53DA57CF-62C0-45C4-81DE-7610BCEFD7F5},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Calendar.ShowTimeAs. Not intended to be parsed programmatically.
+System.Category,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},2,TRUE,TRUE, ,String,512,TRUE, 
+System.Comment,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},6,TRUE,TRUE, ,String,2048, ,Comments.
+System.Communication.AccountName,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},9,TRUE,TRUE, ,String,512, ,Account Name
+System.Communication.DateItemExpires,{428040AC-A177-4C8A-9760-F6F761227F9A},100,FALSE,TRUE, ,DateTime,8, ,Date the item expires due to the retention policy.
+System.Communication.FollowupIconIndex,{83A6347E-6FE4-4F40-BA9C-C4865240D1F4},100,FALSE,TRUE, ,Int32,4, ,This is the icon index used on messages marked for follow up.
+System.Communication.HeaderItem,{C9C34F84-2241-4401-B607-BD20ED75AE7F},100,FALSE,TRUE, ,Boolean,2, ,This property will be true if the item is a header item which means the item hasn't been fully downloaded.
+System.Communication.PolicyTag,{EC0B4191-AB0B-4C66-90B6-C6637CDEBBAB},100,TRUE,TRUE, ,String,512, ,This a string used to identify the retention policy applied to the item.
+System.Communication.SecurityFlags,{8619A4B6-9F4D-4429-8C0F-B996CA59E335},100,FALSE,TRUE, ,Int32,4, ,"Security flags associated with the item to know if the item is encrypted, signed or DRM enabled."
+System.Communication.TaskStatus,{BE1A72C6-9A1D-46B7-AFE7-AFAF8CEF4999},100,FALSE,TRUE, ,UInt16,2, , 
+System.Communication.TaskStatusText,{A6744477-C237-475B-A075-54F34498292A},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Communication.TaskStatus. Not intended to be parsed programmatically.
+System.Company,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},15,TRUE,TRUE, ,String,512, ,The company or publisher.
+System.ComputerName,{28636AA6-953D-11D2-B5D6-00C04FD918D0},5,FALSE,TRUE, ,String,512, , 
+System.Contact.Anniversary,{9AD5BADB-CEA7-4470-A03D-B84E51B9949E},100,FALSE,TRUE, ,DateTime,8, , 
+System.Contact.AssistantName,{CD102C9C-5540-4A88-A6F6-64E4981C8CD1},100,TRUE,TRUE, ,String,256, , 
+System.Contact.AssistantTelephone,{9A93244D-A7AD-4FF8-9B99-45EE4CC09AF6},100,TRUE,TRUE, ,String,512, , 
+System.Contact.Birthday,{176DC63C-2688-4E89-8143-A347800F25E9},47,FALSE,TRUE, ,DateTime,8, , 
+System.Contact.BusinessAddress,{730FB6DD-CF7C-426B-A03F-BD166CC9EE24},100,TRUE,TRUE, ,String,512, , 
+System.Contact.BusinessAddressCity,{402B5934-EC5A-48C3-93E6-85E86A2D934E},100,TRUE,TRUE, ,String,512, , 
+System.Contact.BusinessAddressCountry,{B0B87314-FCF6-4FEB-8DFF-A50DA6AF561C},100,TRUE,TRUE, ,String,512, , 
+System.Contact.BusinessAddressPostalCode,{E1D4A09E-D758-4CD1-B6EC-34A8B5A73F80},100,TRUE,TRUE, ,String,512, , 
+System.Contact.BusinessAddressPostOfficeBox,{BC4E71CE-17F9-48D5-BEE9-021DF0EA5409},100,TRUE,TRUE, ,String,512, , 
+System.Contact.BusinessAddressState,{446F787F-10C4-41CB-A6C4-4D0343551597},100,TRUE,TRUE, ,String,512, , 
+System.Contact.BusinessAddressStreet,{DDD1460F-C0BF-4553-8CE4-10433C908FB0},100,TRUE,TRUE, ,String,512, , 
+System.Contact.BusinessFaxNumber,{91EFF6F3-2E27-42CA-933E-7C999FBE310B},100,TRUE,TRUE, ,String,512, ,Business fax number of the contact.
+System.Contact.BusinessHomePage,{56310920-2491-4919-99CE-EADB06FAFDB2},100,TRUE,TRUE, ,String,512, , 
+System.Contact.BusinessTelephone,{6A15E5A0-0A1E-4CD7-BB8C-D2F1B0C929BC},100,TRUE,TRUE, ,String,512, , 
+System.Contact.CallbackTelephone,{BF53D1C3-49E0-4F7F-8567-5A821D8AC542},100,TRUE,TRUE, ,String,512, , 
+System.Contact.CarTelephone,{8FDC6DEA-B929-412B-BA90-397A257465FE},100,TRUE,TRUE, ,String,512, , 
+System.Contact.Children,{D4729704-8EF1-43EF-9024-2BD381187FD5},100,TRUE,TRUE, ,String,512,TRUE, 
+System.Contact.CompanyMainTelephone,{8589E481-6040-473D-B171-7FA89C2708ED},100,TRUE,TRUE, ,String,512, , 
+System.Contact.Department,{FC9F7306-FF8F-4D49-9FB6-3FFE5C0951EC},100,TRUE,TRUE, ,String,512, , 
+System.Contact.EmailAddress,{F8FA7FA3-D12B-4785-8A4E-691A94F7A3E7},100,TRUE,TRUE, ,String,256, , 
+System.Contact.EmailAddress2,{38965063-EDC8-4268-8491-B7723172CF29},100,TRUE,TRUE, ,String,256, , 
+System.Contact.EmailAddress3,{644D37B4-E1B3-4BAD-B099-7E7C04966ACA},100,TRUE,TRUE, ,String,256, , 
+System.Contact.EmailAddresses,{84D8F337-981D-44B3-9615-C7596DBA17E3},100,TRUE,TRUE, ,String,256,TRUE, 
+System.Contact.EmailName,{CC6F4F24-6083-4BD4-8754-674D0DE87AB8},100,TRUE,TRUE, ,String,256, , 
+System.Contact.FileAsName,{F1A24AA7-9CA7-40F6-89EC-97DEF9FFE8DB},100,TRUE,TRUE, ,String,256, , 
+System.Contact.FirstName,{14977844-6B49-4AAD-A714-A4513BF60460},100,TRUE,TRUE, ,String,256, , 
+System.Contact.FullName,{635E9051-50A5-4BA2-B9DB-4ED056C77296},100,TRUE,TRUE, ,String,256, , 
+System.Contact.Gender,{3C8CEE58-D4F0-4CF9-B756-4E5D24447BCD},100,TRUE,TRUE, ,String,512, , 
+System.Contact.GenderValue,{3C8CEE58-D4F0-4CF9-B756-4E5D24447BCD},101,FALSE,TRUE, ,UInt16,2, , 
+System.Contact.Hobbies,{5DC2253F-5E11-4ADF-9CFE-910DD01E3E70},100,TRUE,TRUE, ,String,512,TRUE, 
+System.Contact.HomeAddress,{98F98354-617A-46B8-8560-5B1B64BF1F89},100,TRUE,TRUE, ,String,512, , 
+System.Contact.HomeAddressCity,{176DC63C-2688-4E89-8143-A347800F25E9},65,TRUE,TRUE, ,String,512, , 
+System.Contact.HomeAddressCountry,{08A65AA1-F4C9-43DD-9DDF-A33D8E7EAD85},100,TRUE,TRUE, ,String,512, , 
+System.Contact.HomeAddressPostalCode,{8AFCC170-8A46-4B53-9EEE-90BAE7151E62},100,TRUE,TRUE, ,String,512, , 
+System.Contact.HomeAddressPostOfficeBox,{7B9F6399-0A3F-4B12-89BD-4ADC51C918AF},100,TRUE,TRUE, ,String,512, , 
+System.Contact.HomeAddressState,{C89A23D0-7D6D-4EB8-87D4-776A82D493E5},100,TRUE,TRUE, ,String,512, , 
+System.Contact.HomeAddressStreet,{0ADEF160-DB3F-4308-9A21-06237B16FA2A},100,TRUE,TRUE, ,String,512, , 
+System.Contact.HomeFaxNumber,{660E04D6-81AB-4977-A09F-82313113AB26},100,TRUE,TRUE, ,String,512, , 
+System.Contact.HomeTelephone,{176DC63C-2688-4E89-8143-A347800F25E9},20,TRUE,TRUE, ,String,512, , 
+System.Contact.IMAddress,{D68DBD8A-3374-4B81-9972-3EC30682DB3D},100,TRUE,TRUE, ,String,256,TRUE, 
+System.Contact.JA.CompanyNamePhonetic,{897B3694-FE9E-43E6-8066-260F590C0100},2,TRUE,TRUE, ,String,256, , 
+System.Contact.JA.FirstNamePhonetic,{897B3694-FE9E-43E6-8066-260F590C0100},3,TRUE,TRUE, ,String,512, , 
+System.Contact.JA.LastNamePhonetic,{897B3694-FE9E-43E6-8066-260F590C0100},4,TRUE,TRUE, ,String,256, , 
+System.Contact.JobTitle,{176DC63C-2688-4E89-8143-A347800F25E9},6,TRUE,TRUE, ,String,512, , 
+System.Contact.Label,{97B0AD89-DF49-49CC-834E-660974FD755B},100,TRUE,TRUE, ,String,512, , 
+System.Contact.LastName,{8F367200-C270-457C-B1D4-E07C5BCD90C7},100,TRUE,TRUE, ,String,256, , 
+System.Contact.MailingAddress,{C0AC206A-827E-4650-95AE-77E2BB74FCC9},100,TRUE,TRUE, ,String,512, , 
+System.Contact.MiddleName,{176DC63C-2688-4E89-8143-A347800F25E9},71,TRUE,TRUE, ,String,256, , 
+System.Contact.MobileTelephone,{176DC63C-2688-4E89-8143-A347800F25E9},35,TRUE,TRUE, ,String,512, , 
+System.Contact.NickName,{176DC63C-2688-4E89-8143-A347800F25E9},74,TRUE,TRUE, ,String,256, , 
+System.Contact.OfficeLocation,{176DC63C-2688-4E89-8143-A347800F25E9},7,TRUE,TRUE, ,String,512, , 
+System.Contact.OtherAddress,{508161FA-313B-43D5-83A1-C1ACCF68622C},100,TRUE,TRUE, ,String,512, , 
+System.Contact.OtherAddressCity,{6E682923-7F7B-4F0C-A337-CFCA296687BF},100,TRUE,TRUE, ,String,512, , 
+System.Contact.OtherAddressCountry,{8F167568-0AAE-4322-8ED9-6055B7B0E398},100,TRUE,TRUE, ,String,512, , 
+System.Contact.OtherAddressPostalCode,{95C656C1-2ABF-4148-9ED3-9EC602E3B7CD},100,TRUE,TRUE, ,String,512, , 
+System.Contact.OtherAddressPostOfficeBox,{8B26EA41-058F-43F6-AECC-4035681CE977},100,TRUE,TRUE, ,String,512, , 
+System.Contact.OtherAddressState,{71B377D6-E570-425F-A170-809FAE73E54E},100,TRUE,TRUE, ,String,512, , 
+System.Contact.OtherAddressStreet,{FF962609-B7D6-4999-862D-95180D529AEA},100,TRUE,TRUE, ,String,512, , 
+System.Contact.PagerTelephone,{D6304E01-F8F5-4F45-8B15-D024A6296789},100,TRUE,TRUE, ,String,512, , 
+System.Contact.PersonalTitle,{176DC63C-2688-4E89-8143-A347800F25E9},69,TRUE,TRUE, ,String,512, , 
+System.Contact.PrimaryAddressCity,{C8EA94F0-A9E3-4969-A94B-9C62A95324E0},100,TRUE,TRUE, ,String,512, , 
+System.Contact.PrimaryAddressCountry,{E53D799D-0F3F-466E-B2FF-74634A3CB7A4},100,TRUE,TRUE, ,String,512, , 
+System.Contact.PrimaryAddressPostalCode,{18BBD425-ECFD-46EF-B612-7B4A6034EDA0},100,TRUE,TRUE, ,String,512, , 
+System.Contact.PrimaryAddressPostOfficeBox,{DE5EF3C7-46E1-484E-9999-62C5308394C1},100,TRUE,TRUE, ,String,512, , 
+System.Contact.PrimaryAddressState,{F1176DFE-7138-4640-8B4C-AE375DC70A6D},100,TRUE,TRUE, ,String,512, , 
+System.Contact.PrimaryAddressStreet,{63C25B20-96BE-488F-8788-C09C407AD812},100,TRUE,TRUE, ,String,512, , 
+System.Contact.PrimaryEmailAddress,{176DC63C-2688-4E89-8143-A347800F25E9},48,TRUE,TRUE, ,String,256, , 
+System.Contact.PrimaryTelephone,{176DC63C-2688-4E89-8143-A347800F25E9},25,TRUE,TRUE, ,String,512, , 
+System.Contact.Profession,{7268AF55-1CE4-4F6E-A41F-B6E4EF10E4A9},100,TRUE,TRUE, ,String,512, , 
+System.Contact.SpouseName,{9D2408B6-3167-422B-82B0-F583B7A7CFE3},100,TRUE,TRUE, ,String,256, , 
+System.Contact.Suffix,{176DC63C-2688-4E89-8143-A347800F25E9},73,TRUE,TRUE, ,String,512, , 
+System.Contact.TelexNumber,{C554493C-C1F7-40C1-A76C-EF8C0614003E},100,TRUE,TRUE, ,String,512, , 
+System.Contact.TTYTDDTelephone,{AAF16BAC-2B55-45E6-9F6D-415EB94910DF},100,TRUE,TRUE, ,String,512, , 
+System.Contact.WebPage,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},18,TRUE,TRUE, ,String,4168, , 
+System.ContentStatus,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},27,TRUE,TRUE, ,String,512, , 
+System.ContentType,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},26,TRUE,TRUE, ,String,512, , 
+System.ContentUrl,{49691C90-7E17-101A-A91C-08002B2ECDA9},10,TRUE,TRUE, ,String,4168, ,"In the Open Search Provider, an item is usually made up of a link and some content. This represents the URL to the content."
+System.Copyright,{64440492-4C8B-11D1-8B70-080036B11A03},11,TRUE,TRUE, ,String,512, , 
+System.DateAccessed,{B725F130-47EF-101A-A5F1-02608C9EEBAC},16,FALSE,TRUE, ,DateTime,8, , 
+System.DateAcquired,{2CBAA8F5-D81F-47CA-B17A-F8D822300131},100,FALSE,TRUE, ,DateTime,8, ,"The date the file entered the system via acquisition. This is not the same as System.DateImported. This would apply, for example, to transfer an image from a camera or to music purchase from an online site."
+System.DateArchived,{43F8D7B7-A444-4F87-9383-52271C9B915C},100,FALSE,TRUE, ,DateTime,8, , 
+System.DateCompleted,{72FAB781-ACDA-43E5-B155-B2434F85E678},100,FALSE,TRUE, ,DateTime,8, , 
+System.DateCreated,{B725F130-47EF-101A-A5F1-02608C9EEBAC},15,FALSE,TRUE, ,DateTime,8, ,The date and time the item was created. The WSS friendly name is 'create'.
+System.DateImported,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},18258,FALSE,TRUE, ,DateTime,8, ,"The date the file is imported into a separate database. This is not the same as System.DateAcquired. (For example, 2003:05:22 13:55:04)"
+System.DateModified,{B725F130-47EF-101A-A5F1-02608C9EEBAC},14,FALSE,TRUE, ,DateTime,8, ,The date and time of the last write to the item. The WSS friendly name is 'write'.
+System.Document.ByteCount,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},4,FALSE,TRUE, ,Int32,4, , 
+System.Document.CharacterCount,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},16,FALSE,TRUE, ,Int32,4, , 
+System.Document.ClientID,{276D7BB0-5B34-4FB0-AA4B-158ED12A1809},100,TRUE,TRUE, ,String,512, , 
+System.Document.Contributor,{F334115E-DA1B-4509-9B3D-119504DC7ABB},100,TRUE,TRUE, ,String,512,TRUE, 
+System.Document.DateCreated,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},12,FALSE,TRUE, ,DateTime,8, ,"This property is stored in the document, not obtained from the file system."
+System.Document.DatePrinted,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},11,FALSE,TRUE, ,DateTime,8, , 
+System.Document.DateSaved,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},13,FALSE,TRUE, ,DateTime,8, , 
+System.Document.Division,{1E005EE6-BF27-428B-B01C-79676ACD2870},100,TRUE,TRUE, ,String,512, , 
+System.Document.DocumentID,{E08805C8-E395-40DF-80D2-54F0D6C43154},100,TRUE,TRUE, ,String,512, , 
+System.Document.HiddenSlideCount,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},9,FALSE,TRUE, ,Int32,4, , 
+System.Document.LastAuthor,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},8,TRUE,TRUE, ,String,256, , 
+System.Document.LineCount,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},5,FALSE,TRUE, ,Int32,4, , 
+System.Document.Manager,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},14,TRUE,TRUE, ,String,512, , 
+System.Document.PageCount,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},14,FALSE,TRUE, ,Int32,4, , 
+System.Document.ParagraphCount,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},6,FALSE,TRUE, ,Int32,4, , 
+System.Document.PresentationFormat,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},3,TRUE,TRUE, ,String,512, , 
+System.Document.RevisionNumber,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},9,TRUE,TRUE, ,String,512, , 
+System.Document.SlideCount,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},7,FALSE,TRUE, ,Int32,4, , 
+System.Document.TotalEditingTime,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},10,FALSE,TRUE, ,UInt64,8, ,"100ns units, not milliseconds. VT_FILETIME for IPropertySetStorage handlers (legacy)"
+System.Document.Version,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},29,FALSE,TRUE, ,String,512, , 
+System.Document.WordCount,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},15,FALSE,TRUE, ,Int32,4, , 
+System.DRM.IsProtected,{AEAC19E4-89AE-4508-B9B7-BB867ABEE2ED},2,FALSE,TRUE, ,Boolean,2, , 
+System.DueDate,{3F8472B5-E0AF-4DB2-8071-C53FE76AE7CE},100,FALSE,TRUE, ,DateTime,8, , 
+System.EndDate,{C75FAA05-96FD-49E7-9CB4-9F601082D553},100,FALSE,TRUE, ,DateTime,8, , 
+System.FileAttributes,{B725F130-47EF-101A-A5F1-02608C9EEBAC},13,FALSE,TRUE, ,UInt32,4, ,This is the WIN32_FIND_DATA dwFileAttributes for the file-based item.
+System.FileDescription,{0CEF7D53-FA64-11D1-A203-0000F81FEDEE},3,TRUE,FALSE, ,String,512, ,This is a user-friendly description of the file.
+System.FileExtension,{E4F10A3C-49E6-405D-8288-A23BD4EEAA6C},100,TRUE,TRUE, ,String,512, ,"This is the file extension of the file-based item, including the leading period. If System.FileName is VT_EMPTY, then this property should be too. Otherwise, it should be derived appropriately by the data source from System.FileName. If System.FileName does not have a file extension, this value should be VT_EMPTY. To obtain the type of any item (including an item that is not a file), use System.ItemType.Example values: If the path is... The property value is... ----------------- ------------------------ ""c:\foo\bar\hello.txt"" "".txt"" ""\\server\share\mydir\goodnews.doc"" "".doc"" ""\\server\share\numbers.xls"" "".xls"" ""\\server\share\folder"" VT_EMPTY ""c:\foo\MyFolder"" VT_EMPTY [desktop] VT_EMPTY"
+System.FileFRN,{B725F130-47EF-101A-A5F1-02608C9EEBAC},21,FALSE,TRUE, ,UInt64,8, ,"This is the unique file ID, also known as the File Reference Number. For a given file, this is the same value as is found in the structure variable FILE_ID_BOTH_DIR_INFO.FileId, via GetFileInformationByHandleEx()."
+System.FileName,{41CF5AE0-F75A-4806-BD87-59C7D9248EB9},100,TRUE,TRUE, ,String,520, ,"This is the file name (including extension) of the file. It is possible that the item might not exist on a filesystem (that is, it may not be opened using CreateFile). Nonetheless, if the item is represented as a file from the logical sense (and its name follows standard Win32 file-naming syntax), then the data source should emit this property. If an item is not a file, then the value for this property is VT_EMPTY. SeeSystem.ItemNameDisplay. This has the same value as System.ParsingName for items that are provided by the Shell's file folder. Example values: if the path is... The property value is...----------------- ------------------------""c:\foo\bar\hello.txt"" ""hello.txt""""\\server\share\mydir\goodnews.doc"" ""goodnews.doc""""\\server\share\numbers.xls"" ""numbers.xls""""c:\foo\MyFolder"" ""MyFolder""(email message) VT_EMPTY(song on portable device) ""song.wma"""
+System.FileOwner,{9B174B34-40FF-11D2-A27E-00C04FC30871},4,TRUE,TRUE, ,String,256, ,"This is the owner of the file, according to the file system."
+System.FlagColor,{67DF94DE-0CA7-4D6F-B792-053A3E4F03CF},100,FALSE,TRUE, ,UInt16,2, ,"name=""Purple"" value=""1"" text=""Purple""name=""Orange"" value=""2"" text=""Orange""name=""Green"" value=""3"" text=""Green"" name=""Yellow"" value=""4"" text=""Yellow""name=""Blue"" value=""5"" text=""Blue"" name=""Red"" value=""6"" text=""Red"" "
+System.FlagColorText,{45EAE747-8E2A-40AE-8CBF-CA52ABA6152A},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.FlagColor. Not intended to be parsed programmatically.
+System.FlagStatus,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},12,FALSE,TRUE, ,Int32,4, ,Status of Flag. Values: (0=none 1=white 2=Red).
+System.FlagStatusText,{DC54FD2E-189D-4871-AA01-08C2F57A4ABC},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.FlagStatus. Not intended to be parsed programmatically.
+System.GPS.Date,{3602C812-0F3B-45F0-85AD-603468D69423},100,FALSE,TRUE, ,DateTime,8, ,Date and time of the GPS record.
+System.IconIndex,{5CBF2787-48CF-4208-B90E-EE5E5D420294},26,FALSE,TRUE, ,Int32,4, , 
+System.Identity,{A26F4AFC-7346-4299-BE47-EB1AE613139F},100,TRUE,TRUE, ,String,512, , 
+System.Image.BitDepth,{6444048F-4C8B-11D1-8B70-080036B11A03},7,FALSE,TRUE, ,UInt32,4, , 
+System.Image.Compression,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},259,FALSE,TRUE, ,UInt16,2, ,Indicates the image compression level. PropertyTagCompression.
+System.Image.CompressionText,{3F08E66F-2F44-4BB9-A682-AC35D2562322},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Image.Compression. Not intended to be parsed programmatically.
+System.Image.Dimensions,{6444048F-4C8B-11D1-8B70-080036B11A03},13,TRUE,TRUE, ,String,512, ,Indicates the dimensions of the image.
+System.Image.HorizontalResolution,{6444048F-4C8B-11D1-8B70-080036B11A03},5,FALSE,TRUE, ,Double,8, , 
+System.Image.HorizontalSize,{6444048F-4C8B-11D1-8B70-080036B11A03},3,FALSE,TRUE, ,UInt32,4, , 
+System.Image.VerticalResolution,{6444048F-4C8B-11D1-8B70-080036B11A03},6,FALSE,TRUE, ,Double,8, , 
+System.Image.VerticalSize,{6444048F-4C8B-11D1-8B70-080036B11A03},4,FALSE,TRUE, ,UInt32,4, , 
+System.Importance,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},11,FALSE,TRUE, ,Int32,4, , 
+System.ImportanceText,{A3B29791-7713-4E1D-BB40-17DB85F01831},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Importance. Not intended to be parsed programmatically.
+System.IsAttachment,{F23F425C-71A1-4FA8-922F-678EA4A60408},100,FALSE,TRUE, ,Boolean,2, ,Identifies this item as an attachment.
+System.IsDeleted,{5CDA5FC8-33EE-4FF3-9094-AE7BD8868C4D},100,FALSE,TRUE, ,Boolean,2, , 
+System.IsEncrypted,{90E5E14E-648B-4826-B2AA-ACAF790E3513},10,FALSE,TRUE, ,Boolean,2, ,Holds a value indicating whether the item encrypted?
+System.IsFlagged,{5DA84765-E3FF-4278-86B0-A27967FBDD03},100,FALSE,TRUE, ,Boolean,2, , 
+System.IsFlaggedComplete,{A6F360D2-55F9-48DE-B909-620E090A647C},100,FALSE,TRUE, ,Boolean,2, , 
+System.IsFolder,{09329B74-40A3-4C68-BF07-AF9A572F607C},100,FALSE,TRUE, ,Boolean,2, ,Set this to true if the item is a folder.
+System.IsIncomplete,{346C8BD1-2E6A-4C45-89A4-61B78E8E700F},100,FALSE,TRUE, ,Boolean,2, ,Indicates whether the message was not completely received for some error condition.
+System.IsRead,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},10,FALSE,TRUE, ,Boolean,2, ,Has the item been read?
+System.ItemAuthors,{D0A04F0A-462A-48A4-BB2F-3706E88DBD7D},100,TRUE,TRUE, ,String,256,TRUE,"This is the generic list of authors associated with an item. For example, the artist name for a track is the item author."
+System.ItemDate,{F7DB74B4-4287-4103-AFBA-F1B13DCD75CF},100,FALSE,TRUE, ,DateTime,8, ,"This is the main date for an item. The date of interest. For example, for photos this maps to System.Photo.DateTaken."
+System.ItemFolderNameDisplay,{B725F130-47EF-101A-A5F1-02608C9EEBAC},2,TRUE,TRUE, ,String,512, ,"This is the user-friendly display name of the parent folder of an item. If System.ItemFolderPathDisplay is VT_EMPTY, then this property should be too. Otherwise, it should be derived appropriately by the data source from System.ItemFolderPathDisplay. If the folder is a file folder, the value will be localized if a localized name is available .Example values: If the path is... The property value is...----------------- ------------------------""c:\foo\bar\hello.txt"" ""bar""""\\server\share\mydir\goodnews.doc"" ""mydir""""\\server\share\numbers.xls"" ""share""""c:\foo\MyFolder"" ""foo""""/Mailbox Account/Inbox/'Re: Hello!'"" ""Inbox"""
+System.ItemFolderPathDisplay,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},6,TRUE,TRUE, ,String,520, ,"This is the user-friendly display path of the parent folder of an item.If System.ItemPathDisplay is VT_EMPTY, then this property should be too. Otherwise, it should be derived appropriately by the data source from System.ItemPathDisplay.Example values:If the path is... The property value is...----------------- ------------------------""c:\foo\bar\hello.txt"" ""c:\foo\bar""""\\server\share\mydir\goodnews.doc"" ""\\server\share\mydir""""\\server\share\numbers.xls"" ""\\server\share""""c:\foo\MyFolder"" ""c:\foo""""/Mailbox Account/Inbox/'Re: Hello!'"" ""/Mailbox Account/Inbox"""
+System.ItemFolderPathDisplayNarrow,{DABD30ED-0043-4789-A7F8-D013A4736622},100,TRUE,TRUE, ,String,520, ,"This is the user-friendly display path of the parent folder of an item. The format of the string should be tailored such that the folder name comes first, to optimize for a narrow viewing column. If the folder is a file folder, the value includes localized names if they are present. If System.ItemFolderPathDisplay is VT_EMPTY, then this property should be too. Otherwise, it should be derived appropriately by the data source from System.ItemFolderPathDisplay.Example values: ----------------""c:\foo\bar\hello.txt"" ""bar (c:\foo)""""\\server\share\mydir\goodnews.doc"" ""mydir (\\server\share)""""\\server\share\numbers.xls"" ""share (\\server)""""c:\foo\MyFolder"" ""foo (c:\)""""/Mailbox Account/Inbox/'Re: Hello!'"" ""Inbox (/Mailbox Account)"""
+System.ItemName,{6B8DA074-3B5C-43BC-886F-0A2CDCE00B6F},100,FALSE,TRUE, ,String,520, ,"This is the base-name of the System.ItemNameDisplay. If the item is a file this property includes the extension in all cases, and will be localized if a localized name is available. If the item is a message, then the value of this property does not include the forwarding or reply prefixes (see System.ItemNamePrefix)."
+System.ItemNameDisplay,{B725F130-47EF-101A-A5F1-02608C9EEBAC},10,TRUE,TRUE, ,String,520, ,"This is the display name in ""most complete"" form. This is the best effort unique representation of the name of an item that makes sense for end users to read. It is the concatenation of System.ItemNamePrefix and System.ItemName. If the item is a file this property includes the extension in all cases, and will be localized if a localized name is available. There are acceptable cases when System.FileName is not VT_EMPTY, yet the value of this property is completely different. Email messages are a key example. If the item is an email message, the item name is likely the subject. In that case, the value must be the concatenation of the System.ItemNamePrefix and System.ItemName. Since the value of System.ItemNamePrefix excludes any trailing whitespace, the concatenation must include whitespace when generating System.ItemNameDisplay. Note that this property is not guaranteed to be unique, but the idea is to promote the most likely candidate that can be unique and also makes sense for end users. For example, for documents, you might think about using System.Title as the System.ItemNameDisplay, but in practice the title of the documents may not be useful or unique enough to be of value as the sole System.ItemNameDisplay. Instead, providing the value of System.FileName as the value of System.ItemNameDisplay is a better candidate. In Windows Mail, the emails are stored in the file system as .eml files and the System.FileName for those files are not human-friendly as they contain GUIDs. In this example, promoting System.Subject as System.ItemNameDisplay makes more sense. Compatibility notes: Shell folder implementations on Vista: use PKEY_ItemNameDisplay for the name column when you want Explorer to call ISF::GetDisplayNameOf(SHGDN_NORMAL) to get the value of the name. Use another PKEY (like PKEY_ItemName) when you want Explorer to call either the folder's property store orISF2::GetDetailsEx in order to get the value of the name. Shell folder implementations on XP: the first column needs to be the name column, and Explorer will call ISF::GetDisplayNameOf to get the value of the name. The PKEY/SCID does not matter. Example values:File: ""hello.txt""Message: ""Re: Let's talk about Tom's argyle socks!""Device folder: ""song.wma""Folder: ""Documents"""
+System.ItemNamePrefix,{D7313FF1-A77A-401C-8C99-3DBDD68ADD36},100,FALSE,TRUE, ,String,520, ,"This is the prefix of an item, used for email messages where the subject begins with ""Re:"" which is the prefix. If the item is a file, then the value of this property is VT_EMPTY. If the item is a message, then the value of this property is the forwarding or reply prefixes (including delimiting colon, but no whitespace), or VT_EMPTY if there is no prefix. Example values: System.ItemNamePrefix System.ItemName System.ItemNameDisplay--------------------- ------------------- ----------------------VT_EMPTY ""Great day"" ""Great day""""Re:"" ""Great day"" ""Re: Great day""""Fwd: "" ""Monthly budget"" ""Fwd: Monthly budget""VT_EMPTY ""accounts.xls"" ""accounts.xls"""
+System.ItemParticipants,{D4D0AA16-9948-41A4-AA85-D97FF9646993},100,TRUE,TRUE, ,String,256,TRUE,"This is the generic list of people associated with an item and who contributed to the item. For example, this is the combination of people in the To list, Cc list and Sender of an email message."
+System.ItemPathDisplay,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},7,TRUE,TRUE, ,String,520, ,"This is the user-friendly display path to the item. If the item is a file or folder this property includes the extension in all cases, and will be localized if a localized name is available. For other items, this is the user-friendly equivalent, assuming the item exists in hierarchical storage. Unlike System.ItemUrl, this property value does not include the URL scheme. To parse an item path, use System.ItemUrl or System.ParsingPath. To reference shell namespace items using shell APIs, use System.ParsingPath. Example values: If the path is... The property value is...----------------- ------------------------""c:\foo\bar\hello.txt"" ""c:\foo\bar\hello.txt""""\\server\share\mydir\goodnews.doc"" ""\\server\share\mydir\goodnews.doc""""\\server\share\numbers.xls"" ""\\server\share\numbers.xls""""c:\foo\MyFolder"" ""c:\foo\MyFolder""""/Mailbox Account/Inbox/'Re: Hello!'"" ""/Mailbox Account/Inbox/'Re: Hello!'"""
+System.ItemPathDisplayNarrow,{28636AA6-953D-11D2-B5D6-00C04FD918D0},8,FALSE,TRUE, ,String,520, ,"This is the user-friendly display path to the item. The format of the string should be tailored such that the name comes first, to optimize for a narrow viewing column. If the item is a file, the value excludes the file extension, and includes localized names if they are present. If the item is a message, the value includes the System.ItemNamePrefix. To parse an item path, use System.ItemUrl or System.ParsingPath. Example values: If the path is... The property value is...----------------- ------------------------""c:\foo\bar\hello.txt"" ""hello (c:\foo\bar)""""\\server\share\mydir\goodnews.doc"" ""goodnews (\\server\share\mydir)""""\\server\share\folder"" ""folder (\\server\share)""""c:\foo\MyFolder"" ""MyFolder (c:\foo)""""/Mailbox Account/Inbox/'Re: Hello!'"" ""Re: Hello! (/Mailbox Account/Inbox)"""
+System.ItemType,{28636AA6-953D-11D2-B5D6-00C04FD918D0},11,TRUE,TRUE, ,String,512, ,"This is the canonical type of the item and is intended to be programmatically parsed. If there is no canonical type, the value is VT_EMPTY. If the item is a file (that is, System.FileName is not VT_EMPTY), the value is the same as System.FileExtension. Use System.ItemTypeText when you want to display the type to end users in a view. (If the item is a file, passing the System.ItemType value to PSFormatForDisplay will result in the same value as System.ItemTypeText.) Example values: If the path is... The property value is...----------------- ------------------------""c:\foo\bar\hello.txt"" "".txt""""\\server\share\mydir\goodnews.doc"" "".doc""""\\server\share\folder"" ""Directory""""c:\foo\MyFolder"" ""Directory""[desktop] ""Folder""""/Mailbox Account/Inbox/'Re: Hello!'"" ""MAPI/IPM.Message"""
+System.ItemTypeText,{B725F130-47EF-101A-A5F1-02608C9EEBAC},4,TRUE,TRUE, ,String,512, ,"This is the user friendly type name of the item. This is not intended to be programmatically parsed. If System.ItemType is VT_EMPTY, the value of this property is also VT_EMPTY. If the item is a file, the value of this property is the same as if you passed thefile's System.ItemType value to PSFormatForDisplay.This property should not be confused with System.Kind, where System.Kind is a high-level user friendly kind name. For example, for a document, System.Kind = ""Document"" andSystem.Item.Type = "".doc"" and System.Item.TypeText = ""Microsoft Word Document"" Example values: If the path is... The property value is...----------------- ------------------------""c:\foo\bar\hello.txt"" ""Text File""""\\server\share\mydir\goodnews.doc"" ""Microsoft Word Document""""\\server\share\folder"" ""File Folder""""c:\foo\MyFolder"" ""File Folder""""/Mailbox Account/Inbox/'Re: Hello!'"" ""Outlook E-mail Message"""
+System.ItemUrl,{49691C90-7E17-101A-A91C-08002B2ECDA9},9,TRUE,TRUE, ,String,4168, ,"This always represents a well formed URL that points to the item. To reference shell namespace items using shell APIs, use System.ParsingPath. Example values:Files: ""file:///c:/foo/bar/hello.txt""""csc://{GUID}/...""Messages: ""mapi://..."""
+System.Journal.Contacts,{DEA7C82C-1D89-4A66-9427-A4E3DEBABCB1},100,TRUE,TRUE, ,String,512,TRUE, 
+System.Journal.EntryType,{95BEB1FC-326D-4644-B396-CD3ED90E6DDF},100,TRUE,TRUE, ,String,512, , 
+System.Keywords,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},5,TRUE,TRUE, ,String,512,TRUE,The keywords for the item. Also referred to as tags.
+System.Kind,{1E3EE840-BC2B-476C-8237-2ACD1A839B22},3,TRUE,TRUE, ,String,512,TRUE,"System.Kind is used to map extensions to various .Search folders. Extensions are mapped to Kinds at HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\KindMapThe list of kinds is not extensible. ""Calendar"" ""Communication"" ""Contact"" ""Document"" ""Email"" ""Feed"" ""Folder"" ""Game"" ""InstantMessage"" ""Journal"" ""Link"" ""Movie"" ""Music"" ""Note"" ""Picture"" ""Program"" ""RecordedTV"" ""SearchFolder"" ""Task"" ""Video"" ""WebHistory"" "
+System.KindText,{F04BEF95-C585-4197-A2B7-DF46FDC9EE6D},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Kind. Not intended to be parsed programmatically.
+System.Language,{D5CDD502-2E9C-101B-9397-08002B2CF9AE},28,TRUE,TRUE, ,String,512, , 
+System.Link.TargetExtension,{7A7D76F4-B630-4BD7-95FF-37CC51A975C9},2,TRUE,FALSE, ,String,512,TRUE,The file extension of the link target. See System.File.Extension
+System.Link.TargetParsingPath,{B9B4B3FC-2B51-4A42-B5D8-324146AFCF25},2,FALSE,TRUE, ,String,520, ,"This is the shell namespace path to the target of the link item. This path may be passed toSHParseDisplayName to parse the path to the correct shell folder. If the target item is a file, the value is identical to System.ItemPathDisplay. If the target item cannot be accessed through the shell namespace, this value is VT_EMPTY."
+System.Link.TargetSFGAOFlags,{B9B4B3FC-2B51-4A42-B5D8-324146AFCF25},8,FALSE,TRUE, ,UInt32,4, ,"IShellFolder::GetAttributesOf flags for the target of a link, with SFGAO_PKEYSFGAOMASK attributes masked out."
+System.Link.TargetSFGAOFlagsStrings,{D6942081-D53B-443D-AD47-5E059D9CD27A},3,TRUE,FALSE, ,String,512,TRUE,Expresses the SFGAO flags of a link as string values and is used as a query optimization. See PKEY_Shell_SFGAOFlagsStrings for possible values of this.
+System.Link.TargetUrl,{5CBF2787-48CF-4208-B90E-EE5E5D420294},2,TRUE,TRUE, ,String,4168, , 
+System.Media.AverageLevel,{09EDD5B6-B301-43C5-9990-D00302EFFD46},100,FALSE,TRUE, ,UInt32,4, , 
+System.Media.ClassPrimaryID,{64440492-4C8B-11D1-8B70-080036B11A03},13,FALSE,TRUE, ,String,512, , 
+System.Media.ClassSecondaryID,{64440492-4C8B-11D1-8B70-080036B11A03},14,FALSE,TRUE, ,String,512, , 
+System.Media.CollectionGroupID,{64440492-4C8B-11D1-8B70-080036B11A03},24,FALSE,TRUE, ,String,512, , 
+System.Media.CollectionID,{64440492-4C8B-11D1-8B70-080036B11A03},25,FALSE,TRUE, ,String,512, , 
+System.Media.ContentDistributor,{64440492-4C8B-11D1-8B70-080036B11A03},18,FALSE,TRUE, ,String,512, , 
+System.Media.ContentID,{64440492-4C8B-11D1-8B70-080036B11A03},26,FALSE,TRUE, ,String,512, , 
+System.Media.CreatorApplication,{64440492-4C8B-11D1-8B70-080036B11A03},27,TRUE,TRUE, ,String,512, , 
+System.Media.CreatorApplicationVersion,{64440492-4C8B-11D1-8B70-080036B11A03},28,TRUE,TRUE, ,String,512, , 
+System.Media.DateEncoded,{2E4B640D-5019-46D8-8881-55414CC5CAA0},100,FALSE,TRUE, ,DateTime,8, ,"DateTime is in UTC (in the doc, not file system)."
+System.Media.DateReleased,{DE41CC29-6971-4290-B472-F59F2E2F31E2},100,TRUE,TRUE, ,String,512, , 
+System.Media.Duration,{64440490-4C8B-11D1-8B70-080036B11A03},3,FALSE,TRUE, ,UInt64,8, ,"100ns units, not milliseconds"
+System.Media.DVDID,{64440492-4C8B-11D1-8B70-080036B11A03},15,FALSE,TRUE, ,String,512, , 
+System.Media.EncodedBy,{64440492-4C8B-11D1-8B70-080036B11A03},36,TRUE,TRUE, ,String,512, , 
+System.Media.FrameCount,{6444048F-4C8B-11D1-8B70-080036B11A03},12,FALSE,TRUE, ,UInt32,4, ,Indicates the frame count for the image.
+System.Media.MCDI,{64440492-4C8B-11D1-8B70-080036B11A03},16,FALSE,TRUE, ,String,512, , 
+System.Media.MetadataContentProvider,{64440492-4C8B-11D1-8B70-080036B11A03},17,FALSE,TRUE, ,String,512, , 
+System.Media.Producer,{64440492-4C8B-11D1-8B70-080036B11A03},22,TRUE,TRUE, ,String,256,TRUE, 
+System.Media.ProtectionType,{64440492-4C8B-11D1-8B70-080036B11A03},38,FALSE,TRUE, ,String,512, ,"If media is protected, how is it protected?"
+System.Media.ProviderRating,{64440492-4C8B-11D1-8B70-080036B11A03},39,FALSE,TRUE, ,String,512, ,Rating (0 - 99) supplied by metadata provider
+System.Media.ProviderStyle,{64440492-4C8B-11D1-8B70-080036B11A03},40,FALSE,TRUE, ,String,512, ,"Style of music or video, supplied by metadata provider"
+System.Media.Publisher,{64440492-4C8B-11D1-8B70-080036B11A03},30,TRUE,TRUE, ,String,512, , 
+System.Media.SubscriptionContentId,{9AEBAE7A-9644-487D-A92C-657585ED751A},100,FALSE,TRUE, ,String,512, , 
+System.Media.SubTitle,{56A3372E-CE9C-11D2-9F0E-006097C686F6},38,TRUE,TRUE, ,String,512, , 
+System.Media.UniqueFileIdentifier,{64440492-4C8B-11D1-8B70-080036B11A03},35,FALSE,TRUE, ,String,512, , 
+System.Media.UserNoAutoInfo,{64440492-4C8B-11D1-8B70-080036B11A03},41,FALSE,TRUE, ,String,512, ,"If true, do NOT alter this file's metadata. Set by user."
+System.Media.UserWebUrl,{64440492-4C8B-11D1-8B70-080036B11A03},34,FALSE,TRUE, ,String,4168, , 
+System.Media.Writer,{64440492-4C8B-11D1-8B70-080036B11A03},23,TRUE,TRUE, ,String,256,TRUE, 
+System.Media.Year,{56A3372E-CE9C-11D2-9F0E-006097C686F6},5,FALSE,TRUE, ,UInt32,4, , 
+System.Message.AttachmentContents,{3143BF7C-80A8-4854-8880-E2E40189BDD0},100,TRUE,FALSE, ,String,512, , 
+System.Message.AttachmentNames,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},21,TRUE,TRUE, ,String,512,TRUE,The names of the attachments in a message
+System.Message.BccAddress,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},2,TRUE,TRUE, ,String,256,TRUE,Lists the addresses in the Bcc: field
+System.Message.BccName,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},3,TRUE,TRUE, ,String,256,TRUE,Lists the names in the Bcc: field
+System.Message.CcAddress,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},4,TRUE,TRUE, ,String,256,TRUE,Lists the addresses in the Cc: field
+System.Message.CcName,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},5,TRUE,TRUE, ,String,256,TRUE,Indicates the names listed in the Cc: field
+System.Message.ConversationID,{DC8F80BD-AF1E-4289-85B6-3DFC1B493992},100,TRUE,TRUE, ,String,512, , 
+System.Message.ConversationIndex,{DC8F80BD-AF1E-4289-85B6-3DFC1B493992},101,FALSE,TRUE, ,Buffer,1024, , 
+System.Message.DateReceived,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},20,FALSE,TRUE, ,DateTime,8, ,Date and Time communication was received.
+System.Message.DateSent,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},19,FALSE,TRUE, ,DateTime,8, ,Date and Time communication was sent.
+System.Message.Flags,{A82D9EE7-CA67-4312-965E-226BCEA85023},100,FALSE,TRUE, ,Int32,4, ,"These are flags associated with email messages to know if a read receipt is pending, etc. The values stored here by Outlook are defined for PR_MESSAGE_FLAGS on MSDN."
+System.Message.FromAddress,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},13,TRUE,TRUE, ,String,256,TRUE, 
+System.Message.FromName,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},14,TRUE,TRUE, ,String,256,TRUE,Specifies the address in the from field as a person's name.
+System.Message.HasAttachments,{9C1FCF74-2D97-41BA-B4AE-CB2E3661A6E4},8,FALSE,TRUE, ,Boolean,2, , 
+System.Message.IsFwdOrReply,{9A9BC088-4F6D-469E-9919-E705412040F9},100,FALSE,TRUE, ,Int32,4, , 
+System.Message.MessageClass,{CD9ED458-08CE-418F-A70E-F912C7BB9C5C},103,TRUE,TRUE, ,String,512, ,"Describes what type of Outlook message this is (meeting, task, mail, etc.)"
+System.Message.ProofInProgress,{9098F33C-9A7D-48A8-8DE5-2E1227A64E91},100,FALSE,TRUE, ,Boolean,2, ,This property will be true if the message junk email proofing is still in progress.
+System.Message.SenderAddress,{0BE1C8E7-1981-4676-AE14-FDD78F05A6E7},100,TRUE,TRUE, ,String,256, , 
+System.Message.SenderName,{0DA41CFA-D224-4A18-AE2F-596158DB4B3A},100,TRUE,TRUE, ,String,256, , 
+System.Message.Store,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},15,FALSE,TRUE, ,String,512, ,"The store (aka protocol handler) FILE, MAIL, OUTLOOKEXPRESS"
+System.Message.ToAddress,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},16,TRUE,TRUE, ,String,256,TRUE,Addresses in To: field
+System.Message.ToDoFlags,{1F856A9F-6900-4ABA-9505-2D5F1B4D66CB},100,FALSE,TRUE, ,Int32,4, ,"Flags associated with a message flagged to know if it's still active, if it was custom flagged, etc."
+System.Message.ToDoTitle,{BCCC8A3C-8CEF-42E5-9B1C-C69079398BC7},100,TRUE,TRUE, ,String,512, , 
+System.Message.ToName,{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD},17,TRUE,TRUE, ,String,256,TRUE,Person names in To: field
+System.MileageInformation,{FDF84370-031A-4ADD-9E91-0D775F1C6605},100,TRUE,TRUE, ,String,512, , 
+System.MIMEType,{0B63E350-9CCC-11D0-BCDB-00805FCCCE04},5,TRUE,TRUE, ,String,512, ,"The MIME type. Eg, for EML files: 'message/rfc822'."
+System.Music.AlbumArtist,{56A3372E-CE9C-11D2-9F0E-006097C686F6},13,TRUE,TRUE, ,String,256, , 
+System.Music.AlbumID,{56A3372E-CE9C-11D2-9F0E-006097C686F6},100,TRUE,TRUE, ,String,2048, ,"Concatenation of System.Music.AlbumArtist and System.Music.AlbumTitle, suitable for indexing and display. Used to differentiate albums with the same title from different artists."
+System.Music.AlbumTitle,{56A3372E-CE9C-11D2-9F0E-006097C686F6},4,TRUE,TRUE, ,String,512, , 
+System.Music.Artist,{56A3372E-CE9C-11D2-9F0E-006097C686F6},2,TRUE,TRUE, ,String,256,TRUE, 
+System.Music.BeatsPerMinute,{56A3372E-CE9C-11D2-9F0E-006097C686F6},35,TRUE,TRUE, ,String,512, , 
+System.Music.Composer,{64440492-4C8B-11D1-8B70-080036B11A03},19,TRUE,TRUE, ,String,256,TRUE, 
+System.Music.Conductor,{56A3372E-CE9C-11D2-9F0E-006097C686F6},36,TRUE,TRUE, ,String,256,TRUE, 
+System.Music.ContentGroupDescription,{56A3372E-CE9C-11D2-9F0E-006097C686F6},33,FALSE,TRUE, ,String,512, , 
+System.Music.DisplayArtist,{FD122953-FA93-4EF7-92C3-04C946B2F7C8},100,TRUE,TRUE, ,String,256, ,"This property returns the best representation of Album Artist for a given music file based upon AlbumArtist, ContributingArtist and compilation info."
+System.Music.Genre,{56A3372E-CE9C-11D2-9F0E-006097C686F6},11,TRUE,TRUE, ,String,512,TRUE, 
+System.Music.InitialKey,{56A3372E-CE9C-11D2-9F0E-006097C686F6},34,TRUE,TRUE, ,String,512, , 
+System.Music.IsCompilation,{C449D5CB-9EA4-4809-82E8-AF9D59DED6D1},100,FALSE,TRUE, ,Boolean,2, ,Indicates whether the file is part of a compilation.
+System.Music.Lyrics,{56A3372E-CE9C-11D2-9F0E-006097C686F6},12,TRUE,FALSE, ,String,512, , 
+System.Music.Mood,{56A3372E-CE9C-11D2-9F0E-006097C686F6},39,TRUE,TRUE, ,String,512, , 
+System.Music.PartOfSet,{56A3372E-CE9C-11D2-9F0E-006097C686F6},37,FALSE,TRUE, ,String,512, , 
+System.Music.Period,{64440492-4C8B-11D1-8B70-080036B11A03},31,TRUE,TRUE, ,String,512, , 
+System.Music.TrackNumber,{56A3372E-CE9C-11D2-9F0E-006097C686F6},7,FALSE,TRUE, ,UInt32,4, , 
+System.Note.Color,{4776CAFA-BCE4-4CB1-A23E-265E76D8EB11},100,FALSE,TRUE, ,UInt16,2, ,"name=""Blue"" value=""0""name=""Green"" value=""1""name=""Pink"" value=""2""name=""Yellow"" value=""3""name=""White"" value=""4""name=""LightGreen"" value=""5"""
+System.Note.ColorText,{46B4E8DE-CDB2-440D-885C-1658EB65B914},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Note.Color. Not intended to be parsed programmatically.
+System.OriginalFileName,{0CEF7D53-FA64-11D1-A203-0000F81FEDEE},6,TRUE,TRUE, ,String,520, , 
+System.ParentalRating,{64440492-4C8B-11D1-8B70-080036B11A03},21,TRUE,TRUE, ,String,512, , 
+System.ParentalRatingReason,{10984E0A-F9F2-4321-B7EF-BAF195AF4319},100,TRUE,TRUE, ,String,512, , 
+System.ParsingName,{28636AA6-953D-11D2-B5D6-00C04FD918D0},24,TRUE,TRUE, ,String,520, ,The shell namespace name of an item relative to a parent folder. This name may be passed to IShellFolder::ParseDisplayName() of the parent shell folder.
+System.Photo.Aperture,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},37378,FALSE,TRUE, ,Double,8, ,PropertyTagExifAperture. Calculated from PKEY_Photo_ApertureNumerator and PKEY_Photo_ApertureDenominator
+System.Photo.CameraManufacturer,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},271,TRUE,TRUE, ,String,512, , 
+System.Photo.CameraModel,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},272,TRUE,TRUE, ,String,512, , 
+System.Photo.ContrastText,{59DDE9F2-5253-40EA-9A8B-479E96C6249A},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Photo.Contrast. Not intended to be parsed programmatically.
+System.Photo.DateTaken,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},36867,FALSE,TRUE, ,DateTime,8, , 
+System.Photo.DigitalZoom,{F85BF840-A925-4BC2-B0C4-8E36B598679E},100,FALSE,TRUE, ,Double,8, ,Calculated from PKEY_Photo_DigitalZoomNumerator and PKEY_Photo_DigitalZoomDenominator
+System.Photo.Event,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},18248,TRUE,TRUE, ,String,512,TRUE,The event at which the photo was taken.
+System.Photo.ExposureBias,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},37380,FALSE,TRUE, ,Double,8, ,Calculated from PKEY_Photo_ExposureBiasNumerator and PKEY_Photo_ExposureBiasDenominator
+System.Photo.ExposureProgram,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},34850,FALSE,TRUE, ,UInt32,4, ,"name=""Unknown"" value=""0"" text=""Unknown"" name=""Manual"" value=""1"" text=""Manual"" name=""Normal"" value=""2"" text=""Normal"" name=""Aperture"" value=""3"" text=""Aperture Priority"" name=""Shutter"" value=""4"" text=""Shutter Priority"" name=""Creative"" value=""5"" text=""Creative Program (biased toward depth of field)"" name=""Action"" value=""6"" text=""Action Program (biased toward shutter speed)"" name=""Portrait"" value=""7"" text=""Portrait Mode"" name=""Landscape"" value=""8"" text=""Landscape Mode"" "
+System.Photo.ExposureProgramText,{FEC690B7-5F30-4646-AE47-4CAAFBA884A3},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Photo.ExposureProgram. Not intended to be parsed programmatically.
+System.Photo.ExposureTime,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},33434,FALSE,TRUE, ,Double,8, ,Calculated from PKEY_Photo_ExposureTimeNumerator and PKEY_Photo_ExposureTimeDenominator
+System.Photo.Flash,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},37385,FALSE,TRUE, ,Byte,1, ,"name=""NoFlash"" value=""0"" text=""No flash"" name=""Flash"" value=""1"" text=""Flash"" name=""FlashNoReturnLight"" value=""5"" text=""Flash, no strobe return"" name=""FlashReturnLight"" value=""7"" text=""Flash, strobe return"" name=""FlashCompulsory"" value=""9"" text=""Flash, compulsory"" name=""FlashCompulsoryNoReturnLight"" value=""13"" text=""Flash, compulsory, no strobe return"" name=""FlashCompulsoryReturnLight"" value=""15"" text=""Flash, compulsory, strobe return"" name=""NoFlashCompulsory"" value=""16"" text=""No flash, compulsory"" name=""NoFlashAuto"" value=""24"" text=""No flash, auto"" name=""FlashAuto"" value=""25"" text=""Flash, auto"" name=""FlashAutoNoReturnLight"" value=""29"" text=""Flash, auto, no strobe return"" name=""FlashAutoReturnLight"" value=""31"" text=""Flash, auto, strobe return"" name=""NoFlashFunction"" value=""32"" text=""No flash function"" name=""FlashRedEye"" value=""65"" text=""Flash, red-eye"" name=""FlashRedEyeNoReturnLight"" value=""69"" text=""Flash, red-eye, no strobe return"" name=""FlashRedEyeReturnLight"" value=""71"" text=""Flash, red-eye, strobe return"" name=""FlashCompulsoryRedEye"" value=""73"" text=""Flash, compulsory, red-eye"" name=""FlashCompulsoryRedEyeNoReturnLight"" value=""77"" text=""Flash, compulsory, red-eye, no strobe return""name=""FlashCompulsoryRedEyeReturnLight"" value=""79"" text=""Flash, compulsory, red-eye, strobe return"" name=""FlashAutoRedEye"" value=""89"" text=""Flash, auto, red-eye"" name=""FlashAutoRedEyeNoReturnLight"" value=""93"" text=""Flash, auto, no strobe return, red-eye"" name=""FlashAutoRedEyeReturnLight"" value=""95"" text=""Flash, auto, strobe return, red-eye"" "
+System.Photo.FlashFired,{2D152B40-CA39-40DB-B2CC-573725B2FEC5},100,FALSE,TRUE, ,Boolean,2, , 
+System.Photo.FlashText,{6B8B68F6-200B-47EA-8D25-D8050F57339F},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Photo.Flash. Not intended to be parsed programmatically.
+System.Photo.FNumber,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},33437,FALSE,TRUE, ,Double,8, ,Calculated from PKEY_Photo_FNumberNumerator and PKEY_Photo_FNumberDenominator
+System.Photo.FocalLength,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},37386,FALSE,TRUE, ,Double,8, ,Calculated from PKEY_Photo_FocalLengthNumerator and PKEY_Photo_FocalLengthDenominator
+System.Photo.FocalLengthInFilm,{A0E74609-B84D-4F49-B860-462BD9971F98},100,FALSE,TRUE, ,UInt16,2, , 
+System.Photo.GainControlText,{C06238B2-0BF9-4279-A723-25856715CB9D},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Photo.GainControl. Not intended to be parsed programmatically.
+System.Photo.ISOSpeed,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},34855,FALSE,TRUE, ,UInt16,2, , 
+System.Photo.LightSource,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},37384,FALSE,TRUE, ,UInt32,4, ,"name=""Unknown"" value=""0"" text=""Unknown"" name=""Daylight"" value=""1"" text=""Daylight"" name=""Fluorescent"" value=""2"" text=""Fluorescent"" name=""Tungsten"" value=""3"" text=""Tungsten"" name=""StandardA"" value=""17"" text=""Standard Illuminant A""name=""StandardB"" value=""18"" text=""Standard Illuminant B""name=""StandardC"" value=""19"" text=""Standard Illuminant C""name=""D55"" value=""20"" text=""D55"" name=""D65"" value=""21"" text=""D65"" name=""D75"" value=""22"" text=""D75"" "
+System.Photo.MaxAperture,{08F6D7C2-E3F2-44FC-AF1E-5AA5C81A2D3E},100,FALSE,TRUE, ,Double,8, ,Calculated from PKEY_Photo_MaxApertureNumerator and PKEY_Photo_MaxApertureDenominator
+System.Photo.MeteringMode,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},37383,FALSE,TRUE, ,UInt16,2, ,"name=""Unknown"" value=""0"" text=""Unknown"" name=""Average"" value=""1"" text=""Average"" name=""Center"" value=""2"" text=""Center Weighted Average"" name=""Spot"" value=""3"" text=""Spot"" name=""MultiSpot"" value=""4"" text=""Multi Spot"" name=""Pattern"" value=""5"" text=""Pattern"" name=""Partial"" value=""6"" text=""Partial"" "
+System.Photo.MeteringModeText,{F628FD8C-7BA8-465A-A65B-C5AA79263A9E},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Photo.MeteringMode. Not intended to be parsed programmatically.
+System.Photo.Orientation,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},274,FALSE,TRUE, ,UInt16,2, ,"This is the image orientation viewed in terms of rows and columns.name=""Normal"" value=""1"" text=""Normal"" name=""FlipHorizontal"" value=""2"" text=""Flip horizontal"" name=""Rotate180"" value=""3"" text=""Rotate 180 degrees""name=""FlipVertical"" value=""4"" text=""Flip vertical"" name=""Transpose"" value=""5"" text=""Transpose"" name=""Rotate270"" value=""6"" text=""Rotate 270 degrees""name=""Transverse"" value=""7"" text=""Transverse"" name=""Rotate90"" value=""8"" text=""Rotate 90 degrees"" "
+System.Photo.OrientationText,{A9EA193C-C511-498A-A06B-58E2776DCC28},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Photo.Orientation. Not intended to be parsed programmatically.
+System.Photo.PeopleNames,{E8309B6E-084C-49B4-B1FC-90A80331B638},100,TRUE,TRUE, ,String,512,TRUE,The people tags on an image.
+System.Photo.PhotometricInterpretationText,{821437D6-9EAB-4765-A589-3B1CBBD22A61},100,TRUE,TRUE, ,String,512, ,"This is the user-friendly form of System.Photo.PhotometricInterpretation. Not intended to be parsed programmatically. name=""RGB"" value=""2"" text=""RGB"" name=""YCbCr"" value=""6"" text=""YCbCr"" "
+System.Photo.ProgramModeText,{7FE3AA27-2648-42F3-89B0-454E5CB150C3},100,TRUE,TRUE, ,String,512, ,"This is the user-friendly form of System.Photo.ProgramMode. Not intended to be parsed programmatically. name=""NotDefined"" value=""0"" text=""Not defined"" name=""Manual"" value=""1"" text=""Manual"" name=""Normal"" value=""2"" text=""Normal program"" name=""Aperture"" value=""3"" text=""Aperture priorityname=""Shutter"" value=""4"" text=""Shutter priority""name=""Creative"" value=""5"" text=""Creative program""name=""Action"" value=""6"" text=""Action program"" name=""Portrait"" value=""7"" text=""Portrait"" name=""Landscape"" value=""8"" text=""Landscape"" "
+System.Photo.SaturationText,{61478C08-B600-4A84-BBE4-E99C45F0A072},100,TRUE,TRUE, ,String,512, ,"This is the user-friendly form of System.Photo.Saturation. Not intended to be parsed programmatically. name=""Normal"" value=""0"" text=""Normal"" name=""Low"" value=""1"" text=""Low saturation"" name=""High"" value=""2"" text=""High saturation"" "
+System.Photo.SharpnessText,{51EC3F47-DD50-421D-8769-334F50424B1E},100,TRUE,TRUE, ,String,512, ,"This is the user-friendly form of System.Photo.Sharpness. Not intended to be parsed programmatically. name=""Normal"" value=""0"" text=""Normal""name=""Soft"" value=""1"" text=""Soft"" name=""Hard"" value=""2"" text=""Hard"" "
+System.Photo.ShutterSpeed,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},37377,FALSE,TRUE, ,Double,8, ,Calculated from PKEY_Photo_ShutterSpeedNumerator and PKEY_Photo_ShutterSpeedDenominator
+System.Photo.SubjectDistance,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},37382,FALSE,TRUE, ,Double,8, ,Calculated from PKEY_Photo_SubjectDistanceNumerator and PKEY_Photo_SubjectDistanceDenominator
+System.Photo.TagViewAggregate,{B812F15D-C2D8-4BBF-BACD-79744346113F},100,TRUE,TRUE,l,String,512,TRUE,A read-only aggregation of tag-like properties for use in building views.
+System.Photo.WhiteBalance,{EE3D3D8A-5381-4CFA-B13B-AAF66B5F4EC9},100,FALSE,TRUE, ,UInt32,4, ,"Indicates the white balance mode set when the image was shot. name=""Auto"" value=""0"" text=""Auto"" name=""Manual"" value=""1"" text=""Manual"" "
+System.Photo.WhiteBalanceText,{6336B95E-C7A7-426D-86FD-7AE3D39C84B4},100,TRUE,TRUE, ,String,512, ,"This is the user-friendly form of System.Photo.WhiteBalance. Not intended to be parsed programmatically. name=""Low"" value=""0"" text=""Low"" name=""Normal"" value=""1"" text=""Normal""name=""High"" value=""2"" text=""High"" "
+System.Priority,{9C1FCF74-2D97-41BA-B4AE-CB2E3661A6E4},5,FALSE,TRUE, ,UInt16,2, ,"name=""Low"" value=""0"" text=""Low"" name=""Normal"" value=""1"" text=""Normal""name=""High"" value=""2"" text=""High"" "
+System.PriorityText,{D98BE98B-B86B-4095-BF52-9D23B2E0A752},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Priority. Not intended to be parsed programmatically.
+System.Project,{39A7F922-477C-48DE-8BC8-B28441E342E3},100,TRUE,TRUE, ,String,512, , 
+System.ProviderItemID,{F21D9941-81F0-471A-ADEE-4E74B49217ED},100,TRUE,TRUE, ,String,512, , 
+System.Rating,{64440492-4C8B-11D1-8B70-080036B11A03},9,FALSE,TRUE, ,UInt32,4, ,"Indicates the users preference rating of an item on a scale of 1-99 (1-12 = One Star, 13-37 = Two Stars, 38-62 = Three Stars, 63-87 = Four Stars, 88-99 = Five Stars)."
+System.RatingText,{90197CA7-FD8F-4E8C-9DA3-B57E1E609295},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Rating. Not intended to be parsed programmatically.
+System.RecordedTV.ChannelNumber,{6D748DE2-8D38-4CC3-AC60-F009B057C557},7,FALSE,TRUE, ,UInt32,4, ,Example: 42
+System.RecordedTV.DateContentExpires,{6D748DE2-8D38-4CC3-AC60-F009B057C557},15,FALSE,TRUE, ,DateTime,8, , 
+System.RecordedTV.EpisodeName,{6D748DE2-8D38-4CC3-AC60-F009B057C557},2,TRUE,TRUE, ,String,512, ,"Example: ""Nowhere to Hyde"""
+System.RecordedTV.IsATSCContent,{6D748DE2-8D38-4CC3-AC60-F009B057C557},16,FALSE,TRUE, ,Boolean,2, , 
+System.RecordedTV.IsClosedCaptioningAvailable,{6D748DE2-8D38-4CC3-AC60-F009B057C557},12,FALSE,TRUE, ,Boolean,2, , 
+System.RecordedTV.IsDTVContent,{6D748DE2-8D38-4CC3-AC60-F009B057C557},17,FALSE,TRUE, ,Boolean,2, , 
+System.RecordedTV.IsHDContent,{6D748DE2-8D38-4CC3-AC60-F009B057C557},18,FALSE,TRUE, ,Boolean,2, , 
+System.RecordedTV.IsRepeatBroadcast,{6D748DE2-8D38-4CC3-AC60-F009B057C557},13,FALSE,TRUE, ,Boolean,2, , 
+System.RecordedTV.IsSAP,{6D748DE2-8D38-4CC3-AC60-F009B057C557},14,FALSE,TRUE, ,Boolean,2, , 
+System.RecordedTV.NetworkAffiliation,{2C53C813-FB63-4E22-A1AB-0B331CA1E273},100,FALSE,TRUE, ,String,512, , 
+System.RecordedTV.OriginalBroadcastDate,{4684FE97-8765-4842-9C13-F006447B178C},100,FALSE,TRUE, ,DateTime,8, , 
+System.RecordedTV.ProgramDescription,{6D748DE2-8D38-4CC3-AC60-F009B057C557},3,TRUE,TRUE, ,String,2048, , 
+System.RecordedTV.RecordingTime,{A5477F61-7A82-4ECA-9DDE-98B69B2479B3},100,FALSE,TRUE, ,DateTime,8, , 
+System.RecordedTV.StationCallSign,{6D748DE2-8D38-4CC3-AC60-F009B057C557},5,TRUE,TRUE, ,String,512, ,"Example: ""TOONP"""
+System.RecordedTV.StationName,{1B5439E7-EBA1-4AF8-BDD7-7AF1D4549493},100,TRUE,TRUE, ,String,512, , 
+# LEGACY ??? as a propid, I suppose it means something but what???
+#System.SDID,{B725F130-47EF-101A-A5F1-02608C9EEBAC},LEGACY,FALSE,TRUE, ,UInt32,4, ,Internal MSSearch Security Descriptor ID
+System.Search.AccessCount,{0B63E350-9CCC-11D0-BCDB-00805FCCCE04},9,FALSE,TRUE, ,UInt32,4, ,The number of times that the Windows Search Gatherer process pushed properties of this document to the Windows Search Gatherer Plugins.
+System.Search.AutoSummary,{560C36C0-503A-11CF-BAA1-00004C752A9A},2,FALSE,TRUE,NotIndexed,String,2048, ,General Summary of the document.
+System.Search.ContainerHash,{BCEEE283-35DF-4D53-826A-F36A3EEFC6BE},100,TRUE,FALSE, ,String,512, ,Hash code used to identify attachments to be deleted based on a common container URL.
+System.Search.Contents,{B725F130-47EF-101A-A5F1-02608C9EEBAC},19,TRUE,FALSE, ,String,512, ,The contents of the item. This property is for query restrictions only; it cannot be retrieved in a query result. The WSS friendly name is 'contents'.
+System.Search.EntryID,{49691C90-7E17-101A-A91C-08002B2ECDA9},5,FALSE,TRUE,NotIndexed,Int32,4, ,"The entry ID for an item within a given catalog in the Windows Search Index. This value may be recycled, and therefore is not considered unique over time."
+System.Search.GatherTime,{0B63E350-9CCC-11D0-BCDB-00805FCCCE04},8,FALSE,TRUE, ,DateTime,8, ,The Datetime that the Windows Search Gatherer process last pushed properties of this document to the Windows Search Gatherer Plugins.
+System.Search.HitCount,{49691C90-7E17-101A-A91C-08002B2ECDA9},4,FALSE,TRUE,NotIndexed,Int32,4, ,"When using CONTAINS over the Windows Search Index, this is the number of matches of the term. If there are multiple CONTAINS, an AND computes the min number of hits and an OR the max number of hits."
+System.Search.LastIndexedTotalTime,{0B63E350-9CCC-11D0-BCDB-00805FCCCE04},11,FALSE,TRUE, ,Double,8, ,The total time in seconds taken to index this document the last time it was indexed.
+System.Search.Rank,{49691C90-7E17-101A-A91C-08002B2ECDA9},3,FALSE,TRUE,NotIndexed,Int32,4, ,Relevance rank of row. Ranges from 0-1000. Larger numbers = better matches. Query-time only.
+System.Search.ReverseFileName,{49691C90-7E17-101A-A91C-08002B2ECDA9},8,TRUE,TRUE, ,String,520, ,Reverse of the FileName from Query propset.
+System.Search.Store,{A06992B3-8CAF-4ED7-A547-B259E32AC9FC},100,TRUE,TRUE, ,String,512, ,"The identifier for the protocol handler that produced this item. (E.g. MAPI, CSC, FILE etc.)"
+System.Sensitivity,{F8D3F6AC-4874-42CB-BE59-AB454B30716A},100,FALSE,TRUE, ,UInt16,2, ,"name=""Normal"" value=""0"" text=""Normal"" name=""Personal"" value=""1"" text=""Personal"" name=""Private"" value=""2"" text=""Private"" name=""Confidential"" value=""3"" text=""Confidential"""
+System.SensitivityText,{D0C7F054-3F72-4725-8527-129A577CB269},100,TRUE,TRUE, ,String,512, ,This is the user-friendly form of System.Sensitivity. Not intended to be parsed programmatically.
+System.SFGAOFlags,{28636AA6-953D-11D2-B5D6-00C04FD918D0},25,FALSE,TRUE, ,UInt32,4, ,"IShellFolder::GetAttributesOf flags, with SFGAO_PKEYSFGAOMASK attributes masked out."
+System.Shell.OmitFromView,{DE35258C-C695-4CBC-B982-38B0AD24CED0},2,TRUE,TRUE, ,String,512, ,Set this to a string value of 'True' to omit this item from shell views
+System.Shell.SFGAOFlagsStrings,{D6942081-D53B-443D-AD47-5E059D9CD27A},2,TRUE,FALSE, ,String,512,TRUE,"Expresses the SFGAO flags as string values and is used as a query optimization.name=""FileSys"" value=""filesys"" name=""FileSysAncestor"" value=""fileanc"" name=""StorageAncestor"" value=""storageanc""name=""Stream"" value=""stream"" name=""Link"" value=""link"" name=""Hidden"" value=""hidden"" name=""Superhidden"" value=""superhiddenname=""Folder"" value=""folder"" name=""NonEnumerated"" value=""nonenum"" name=""Browsable"" value=""browsable"" "
+System.Size,{B725F130-47EF-101A-A5F1-02608C9EEBAC},12,FALSE,TRUE, ,UInt64,8, ,"name=""Empty"" minValue=""0"" setValue=""0"" text=""Empty (0 KB)"" name=""Tiny"" minValue=""1"" setValue=""1"" text=""Tiny (0 - 10 KB)"" dname=""Small"" minValue=""10241"" setValue=""10241"" text=""Small (10 - 100 KB)"" name=""Medium"" minValue=""102401"" setValue=""102401"" text=""Medium (100 KB - 1 MB)""name=""Large"" minValue=""1048577"" setValue=""1048577"" text=""Large (1 - 16 MB)"" name=""Huge"" minValue=""16777217"" setValue=""16777217"" text=""Huge (16 - 128 MB)"" name=""Gigantic"" minValue=""134217729"" setValue=""134217729"" text=""Gigantic (>128 MB)"" "
+System.Software.DateLastUsed,{841E4F90-FF59-4D16-8947-E81BBFFAB36D},16,TRUE,TRUE, ,DateTime,8, , 
+System.Software.ProductName,{0CEF7D53-FA64-11D1-A203-0000F81FEDEE},7,TRUE,FALSE, ,String,512, , 
+System.Software.ProductVersion,{0CEF7D53-FA64-11D1-A203-0000F81FEDEE},8,TRUE,FALSE, ,String,512, , 
+System.SoftwareUsed,{14B81DA1-0135-4D31-96D9-6CBFC9671A99},305,TRUE,TRUE, ,String,512, , 
+System.SourceItem,{668CDFA5-7A1B-4323-AE4B-E527393A1D81},100,TRUE,TRUE, ,String,512, , 
+System.StartDate,{48FD6EC8-8A12-4CDF-A03E-4EC5A511EDDE},100,FALSE,TRUE, ,DateTime,8, , 
+System.Status,{000214A1-0000-0000-C000-000000000046},9,TRUE,TRUE, ,String,512, , 
+System.Subject,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},3,TRUE,TRUE, ,String,520, , 
+System.Task.BillingInformation,{D37D52C6-261C-4303-82B3-08B926AC6F12},100,TRUE,FALSE, ,String,512, , 
+System.Task.CompletionStatus,{084D8A0A-E6D5-40DE-BF1F-C8820E7C877C},100,TRUE,TRUE, ,String,512, , 
+System.Task.Owner,{08C7CC5F-60F2-4494-AD75-55E3E0B5ADD0},100,TRUE,TRUE, ,String,256, , 
+System.ThumbnailCacheId,{446D16B1-8DAD-4870-A748-402EA43D788C},100,FALSE,TRUE, ,UInt64,8, ,"Unique value that can be used as a key to cache thumbnails. The value changes when the name, volume, or data modified of an item changes."
+System.Title,{F29F85E0-4FF9-1068-AB91-08002B27B3D9},2,TRUE,TRUE, ,String,520, , 
+System.Video.Compression,{64440491-4C8B-11D1-8B70-080036B11A03},10,TRUE,TRUE, ,String,512, ,"Indicates the level of compression for the video stream. ""Compression""."
+System.Video.Director,{64440492-4C8B-11D1-8B70-080036B11A03},20,TRUE,TRUE, ,String,256,TRUE, 
+System.Video.EncodingBitrate,{64440491-4C8B-11D1-8B70-080036B11A03},8,FALSE,TRUE, ,UInt32,4, ,"Indicates the data rate in ""bits per second"" for the video stream. ""DataRate""."
+System.Video.FourCC,{64440491-4C8B-11D1-8B70-080036B11A03},44,FALSE,TRUE, ,UInt32,4, ,Indicates the 4CC for the video stream.
+System.Video.FrameHeight,{64440491-4C8B-11D1-8B70-080036B11A03},4,FALSE,TRUE, ,UInt32,4, ,Indicates the frame height for the video stream.
+System.Video.FrameRate,{64440491-4C8B-11D1-8B70-080036B11A03},6,FALSE,TRUE, ,UInt32,4, ,"Indicates the frame rate in ""frames per millisecond"" for the video stream."
+System.Video.FrameWidth,{64440491-4C8B-11D1-8B70-080036B11A03},3,FALSE,TRUE, ,UInt32,4, ,Indicates the frame width for the video stream.
+System.Video.HorizontalAspectRatio,{64440491-4C8B-11D1-8B70-080036B11A03},42,FALSE,TRUE, ,UInt32,4, ,"Indicates the horizontal portion of the aspect ratio. The X portion of XX:YY, like 16:9."
+System.Video.SampleSize,{64440491-4C8B-11D1-8B70-080036B11A03},9,FALSE,TRUE, ,UInt32,4, ,"Indicates the sample size in bits for the video stream. ""SampleSize""."
+System.Video.StreamName,{64440491-4C8B-11D1-8B70-080036B11A03},2,TRUE,TRUE, ,String,512, ,Indicates the name for the video stream.
+System.Video.TotalBitrate,{64440491-4C8B-11D1-8B70-080036B11A03},43,FALSE,TRUE, ,UInt32,4, ,"Indicates the total data rate in ""bits per second"" for all video and audio streams."
+System.Video.VerticalAspectRatio,{64440491-4C8B-11D1-8B70-080036B11A03},45,FALSE,TRUE, ,UInt32,4, ,Indicates the vertical portion of the aspect ratio. The Y portion of XX:YY.
diff --git a/librpc/wsp/extra-props.csv b/librpc/wsp/extra-props.csv
new file mode 100644
index 0000000..d26238b
--- /dev/null
+++ b/librpc/wsp/extra-props.csv
@@ -0,0 +1,63 @@
+# Unix SMB/CIFS implementation.
+#
+# WSP property definitions
+#
+# Copyright (C) Noel Power
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+DBPROP_CI_CATALOG_NAME,{a9bd1526-6a80-11d0-8c9d-0020af1d740e},2,FALSE,FALSE,,String,,,
+DBPROP_CI_INCLUDE_SCOPES,{a9bd1526-6a80-11d0-8c9d-0020af1d740e},3,FALSE,FALSE,,String,,TRUE,
+DBPROP_CI_SCOPE_FLAGS,{a9bd1526-6a80-11d0-8c9d-0020af1d740e},4,FALSE,FALSE,,Int32,,TRUE,
+DBPROP_CI_QUERY_TYPE,{a9bd1526-6a80-11d0-8c9d-0020af1d740e},7,FALSE,FALSE,,Int32,,,
+DBPROP_USECONTENTINDEX,{a7ac77ed-f8d7-11ce-a798-0020f8008025},2,FALSE,FALSE,,Boolean,,,
+DBPROP_DEFERNONINDEXEDTRIMMING,{a7ac77ed-f8d7-11ce-a798-0020f8008025},3,FALSE,FALSE,,Boolean,,,
+DBPROP_USEEXTENDEDDBTYPES,{a7ac77ed-f8d7-11ce-a798-0020f8008025},4,FALSE,FALSE,,Boolean,,,
+DBPROP_IGNORENOISEONLYCLAUSES,{a7ac77ed-f8d7-11ce-a798-0020f8008025},5,FALSE,FALSE,,Boolean,,,
+DBPROP_GENERICOPTIONS_STRING,{a7ac77ed-f8d7-11ce-a798-0020f8008025},6,FALSE,FALSE,,BString,,,
+DBPROP_FIRSTROWS,{a7ac77ed-f8d7-11ce-a798-0020f8008025},7,FALSE,FALSE,,Boolean,,,
+DBPROP_DEFERCATALOGVERIFICATION,{a7ac77ed-f8d7-11ce-a798-0020f8008025},8,FALSE,FALSE,,Boolean,,,
+DBPROP_GENERATEPARSETREE,{a7ac77ed-f8d7-11ce-a798-0020f8008025},10,FALSE,FALSE,,Boolean,,,
+DBPROP_FREETEXTANYTERM,{a7ac77ed-f8d7-11ce-a798-0020f8008025},12,FALSE,FALSE,,Boolean,,,
+DBPROP_FREETEXTUSESTEMMING,{a7ac77ed-f8d7-11ce-a798-0020f8008025},13,FALSE,FALSE,,Boolean,,,
+DBPROP_IGNORESBRI,{a7ac77ed-f8d7-11ce-a798-0020f8008025},14,FALSE,FALSE,,Boolean,,,
+DBPROP_ENABLEROWSETEVENTS,{a7ac77ed-f8d7-11ce-a798-0020f8008025},16,FALSE,FALSE,,Boolean,,,
+DBPROP_MACHINE,{afafaca5-b5d1-11d0-8c62-00c04fc2db8d},2,FALSE,FALSE,,BString,,,
+DBPROP_CLIENT_CLSID,{afafaca5-b5d1-11d0-8c62-00c04fc2db8d},3,FALSE,FALSE,,GUID,,,
+MSIDXSPROP_ROWSETQUERYSTATUS,{aa6ee6b0-e828-11d0-b23e-00aa0047fc01},2,FALSE,FALSE,,Int32,,,
+MSIDXSPROP_COMMAND_LOCALE_STRING,{aa6ee6b0-e828-11d0-b23e-00aa0047fc01},3,FALSE,FALSE,,BString,,,
+MSIDXSPROP_QUERY_RESTRICTION,{aa6ee6b0-e828-11d0-b23e-00aa0047fc01},4,FALSE,FALSE,,BString,,,
+MSIDXSPROP_PARSE_TREE,{aa6ee6b0-e828-11d0-b23e-00aa0047fc01},5,FALSE,FALSE,,BString,,,
+MSIDXSPROP_MAX_RANK,{aa6ee6b0-e828-11d0-b23e-00aa0047fc01},6,FALSE,FALSE,,Int32,,,
+MSIDXSPROP_RESULTS_FOUND,{aa6ee6b0-e828-11d0-b23e-00aa0047fc01},7,FALSE,FALSE,,Int32,,,
+ClassId,{b725f130-47ef-101a-a5f1-02608c9eebac},3,FALSE,FALSE,,GUID,,,
+FileIndex,{b725f130-47ef-101a-a5f1-02608c9eebac},8,FALSE,FALSE,,UInt64,,,
+USN,{b725f130-47ef-101a-a5f1-02608c9eebac},9,FALSE,FALSE,,Int64,,,
+Path,{b725f130-47ef-101a-a5f1-02608c9eebac},11,FALSE,FALSE,,String,,,
+AllocSize,{b725f130-47ef-101a-a5f1-02608c9eebac},18,FALSE,FALSE,,Int64,,,
+ShortFilename,{b725f130-47ef-101a-a5f1-02608c9eebac},20,FALSE,FALSE,,String,,,
+Scope,{b725f130-47ef-101a-a5f1-02608c9eebac},22,FALSE,FALSE,,String,,,
+DocTemplate,{f29f85e0-4ff9-1068-ab91-08002b27b3d9},7,FALSE,FALSE,,String,,,
+#NOTE!! DocThumbnail is reported as VT_CF (we know nothing about this type???)
+# so for the moment just say its a blob (so we at least generate a name for the property)
+DocThumbnail,{f29f85e0-4ff9-1068-ab91-08002b27b3d9},17,FALSE,FALSE,,Buffer,,,
+RankVector,{49691c90-7e17-101a-a91c-08002b2ecda9},2,FALSE,FALSE,,UInt32,,TRUE,
+All,{49691c90-7e17-101a-a91c-08002b2ecda9},6,FALSE,FALSE,,String,,,
+System.Search.RowID,{49691c90-7e17-101a-a91c-08002b2ecda9},15,FALSE,FALSE,,Int32,,,
+#PercivedType, FileCount & TotalFileSize are defined by gregors wireshark wip
+PercivedType,{28636aa6-953d-11d2-b5d6-00c04fd918d0},9,FALSE,FALSE,,Int32,,,
+FileCount,{28636aa6-953d-11d2-b5d6-00c04fd918d0},12,FALSE,FALSE,,UInt64,,,
+TotalFileSize,{28636aa6-953d-11d2-b5d6-00c04fd918d0},14,FALSE,FALSE,,UInt64,,,
+DocNoteCount,{d5cdd502-2e9c-101b-9397-08002b2cf9ae},8,FALSE,FALSE,,Int32,,,
+DocPartTitles,{d5cdd502-2e9c-101b-9397-08002b2cf9ae},13,FALSE,FALSE,,String,,TRUE,
diff --git a/librpc/wsp/wsp_helper.c b/librpc/wsp/wsp_helper.c
new file mode 100644
index 0000000..5e95c40
--- /dev/null
+++ b/librpc/wsp/wsp_helper.c
@@ -0,0 +1,40 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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/wsp/wsp_helper.h"
+#include "librpc/gen_ndr/ndr_wsp.h"
+
+uint32_t calc_array_size(struct safearraybound *bounds, uint32_t ndims)
+{
+ uint32_t i;
+ uint32_t result = 0;
+
+ for(i = 0; i < ndims; i++) {
+ uint32_t celements = bounds[i].celements;
+ if (i) {
+ SMB_ASSERT((result > UINT32_MAX / celements) == false);
+ result = result * celements;
+ } else {
+ result = celements;
+ }
+ }
+ return result;
+}
diff --git a/librpc/wsp/wsp_helper.h b/librpc/wsp/wsp_helper.h
new file mode 100644
index 0000000..7d1fc3e
--- /dev/null
+++ b/librpc/wsp/wsp_helper.h
@@ -0,0 +1,28 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 __LIBRPC_WSP_HELPER_H__
+#define __LIBRPC_WSP_HELPER_H__
+
+struct safearraybound;
+
+uint32_t calc_array_size(struct safearraybound *bounds, uint32_t ndims);
+
+#endif /* __LIBRPC_WSP_HELPER_H__ */
diff --git a/librpc/wsp/wsp_util.c b/librpc/wsp/wsp_util.c
new file mode 100644
index 0000000..fae6e0b
--- /dev/null
+++ b/librpc/wsp/wsp_util.c
@@ -0,0 +1,919 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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/wsp/wsp_util.h"
+#include "librpc/gen_ndr/wsp.h"
+#include "librpc/gen_ndr/ndr_wsp.h"
+#include "lib/util/strv_util.h"
+#include "lib/util/strv.h"
+#include "lib/util/util_str_hex.h"
+#include "source3/param/param_proto.h"
+#include "lib/util/dlinklist.h"
+
+#define BUFFER_SIZE 1024000
+struct guidtopropmap_holder
+{
+ struct guidtopropmap *guidtopropmaploc;
+};
+
+struct full_propset_info_list {
+ struct full_propset_info_list *prev, *next;
+ struct full_propset_info info;
+};
+
+struct guidtopropmap {
+ struct guidtopropmap *prev, *next;
+ struct GUID guid;
+ struct full_propset_info_list *propset;
+};
+
+static struct guidtopropmap *find_guid_props(
+ struct guidtopropmap_holder *holder,
+ const struct GUID *guid)
+{
+ struct guidtopropmap *mapitem;
+ for (mapitem = holder->guidtopropmaploc; mapitem; mapitem = mapitem->next) {
+ if (GUID_equal(guid, &mapitem->guid)) {
+ return mapitem;
+ }
+ }
+ return NULL;
+}
+
+static bool getbool(char *str)
+{
+ char *cpy = talloc_strdup(NULL, str);
+ bool result;
+
+ trim_string(cpy, " ", " ");
+ if (strequal("TRUE", cpy)) {
+ result = true;
+ } else {
+ result = false;
+ }
+ TALLOC_FREE(cpy);
+ return result;
+}
+
+struct {
+ const char* typename;
+ uint16_t type;
+} vtype_map[] = {
+ {"GUID", VT_CLSID},
+ {"String", VT_LPWSTR},
+ {"BString", VT_BSTR},
+ {"Double", VT_R8},
+ {"Buffer", VT_BLOB_OBJECT},
+ {"Byte", VT_UI1},
+ {"UInt64", VT_UI8},
+ {"Int64", VT_I8},
+ {"UInt32", VT_UI4},
+ {"Int32", VT_I4},
+ {"UInt16", VT_UI2},
+ {"Int16", VT_I2},
+ {"DateTime", VT_FILETIME},
+ {"Boolean", VT_BOOL}
+};
+
+static uint16_t getvtype(char *str, bool isvec)
+{
+ uint16_t result = UINT16_MAX;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(vtype_map); i++) {
+ if (strequal(vtype_map[i].typename, str)) {
+ result = vtype_map[i].type;
+ if (isvec) {
+ result |= VT_VECTOR;
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+static bool parse_csv_line(TALLOC_CTX *ctx,
+ char **csvs, size_t num_values,
+ struct guidtopropmap_holder *propmap_holder)
+{
+ struct guidtopropmap *mapitem = NULL;
+ struct full_propset_info_list *item = NULL;
+
+ char *guid_str = NULL;
+ struct GUID guid;
+ bool ok;
+
+ item = talloc_zero(ctx,
+ struct full_propset_info_list);
+ if (!item) {
+ return false;
+ }
+
+ item->info.in_inverted_index = false;
+ item->info.is_column = true;
+ item->info.can_col_be_indexed = true;
+
+ if (strlen(csvs[1])) {
+ guid_str = talloc_strdup(ctx, csvs[1]);
+ }
+
+ if (!guid_str) {
+ DBG_ERR("out of memory\n");
+ return false;
+ }
+
+ if (!trim_string(guid_str, "{", "}")) {
+ return false;
+ }
+
+ if (strlen(csvs[0])) {
+ char *tmp = talloc_strdup(item, csvs[0]);
+ trim_string(tmp, " ", " ");
+ item->info.name = tmp;
+ }
+
+ if (strlen(csvs[2])) {
+ item->info.id = atoi(csvs[2]);
+ }
+
+ if (strlen(csvs[3])) {
+ item->info.in_inverted_index = getbool(csvs[3]);
+ }
+
+ if (strlen(csvs[4])) {
+ item->info.is_column = getbool(csvs[4]);
+ }
+
+ if (strlen(csvs[5])) {
+ item->info.can_col_be_indexed = getbool(csvs[5]);
+ }
+
+ if (strlen(csvs[6])) {
+ bool isvec = false;
+ uint16_t type;
+ if (strlen(csvs[0])) {
+ isvec = getbool(csvs[8]);
+ }
+ type = getvtype(csvs[6], isvec);
+ if (type == UINT16_MAX) {
+ DBG_ERR("failed to parse type\n");
+ return false;
+ }
+ item->info.vtype = type;
+ }
+
+ ok = parse_guid_string(guid_str, &guid);
+ if (!ok) {
+ return false;
+ }
+
+ mapitem = find_guid_props(propmap_holder, &guid);
+ if (!mapitem) {
+ mapitem = talloc_zero(propmap_holder,
+ struct guidtopropmap);
+ if (!mapitem) {
+ return false;
+ }
+ mapitem->guid = guid;
+ DLIST_ADD_END(propmap_holder->guidtopropmaploc, mapitem);
+ }
+
+ talloc_steal(mapitem, item);
+ DLIST_ADD_END(mapitem->propset, item);
+ return true;
+}
+
+static bool parse_properties_line(TALLOC_CTX *ctx,
+ const char* line,
+ struct guidtopropmap_holder *propmap_holder)
+{
+ int ret;
+ int pos;
+ char* strv = NULL;
+ char** csv_line = NULL;
+ char* t = NULL;
+ size_t len;
+
+ ret = strv_split(ctx,
+ &strv,
+ line,
+ ",");
+
+ if (ret != 0) {
+ DBG_ERR("failed to split line\n");
+ return false;
+ }
+
+ len = strv_count(strv);
+
+ if (len < 9) {
+ DBG_WARNING("skipping line as it doesn't have "
+ "enough fields\n");
+ return true;
+ }
+
+ csv_line = talloc_zero_array(ctx,
+ char *,
+ len);
+
+ if (!csv_line) {
+ DBG_ERR("out of memory\n");
+ return false;
+ }
+ for (pos = 0; pos < talloc_array_length(csv_line); pos++) {
+ t = strv_next(strv, t);
+ /* the scraped property file can have a non ascii char */
+ if (strlen(t) == 1 && *t == 0xa0) {
+ csv_line[pos] = talloc_strdup(csv_line,
+ "");
+ } else {
+ csv_line[pos] = talloc_strdup(csv_line,
+ t);
+ }
+ trim_string(csv_line[pos], " ", " ");
+ }
+
+ if (!parse_csv_line(csv_line, csv_line, len, propmap_holder)) {
+ DBG_ERR("failed to parse line\n");
+ TALLOC_FREE(csv_line);
+ return false;
+ }
+ TALLOC_FREE(csv_line);
+ return true;
+}
+
+static bool parse_properties_csvfile(TALLOC_CTX *ctx,
+ struct guidtopropmap_holder *propmap_holder,
+ const char* filename)
+{
+ char **lines = NULL;
+ int numlines;
+ int i;
+
+ if (filename == NULL || strlen(filename) == 0) {
+ return false;
+ }
+
+ lines = file_lines_load(filename,
+ &numlines,
+ BUFFER_SIZE,
+ ctx);
+ if (!lines) {
+ DBG_ERR("Failed to load %s\n", filename);
+ return false;
+ }
+ DBG_ERR("parsed %d lines\n", numlines);
+
+ for (i = 0; i < numlines; i++) {
+ TALLOC_CTX *line_ctx = talloc_init("line context");
+ if (!line_ctx) {
+ DBG_ERR("out of memory\n");
+ return false;
+ }
+
+ trim_string(lines[i], " ", " ");
+ if (lines[i][0] == '#') {
+ DBG_WARNING("skipping comment at line %d.\n)", i);
+ TALLOC_FREE(line_ctx);
+ continue;
+ }
+
+ if (!parse_properties_line(line_ctx,
+ lines[i],
+ propmap_holder)) {
+ DBG_ERR("Failed to parse line %d\n", i);
+ }
+ TALLOC_FREE(line_ctx);
+ }
+ return true;
+}
+
+static bool populate_map(struct guidtopropmap_holder *propmap_holder)
+{
+ const char * path = NULL;
+ path = lp_wsp_property_file();
+
+ /* first populate the map from property file */
+ if (path) {
+ parse_properties_csvfile(propmap_holder, propmap_holder, path);
+ }
+
+ return true;
+}
+
+static struct guidtopropmap_holder *propmap(void)
+{
+ static struct guidtopropmap_holder *holder = NULL;
+
+ if (!holder) {
+ holder = talloc_zero(NULL, struct guidtopropmap_holder);
+ if (holder) {
+ populate_map(holder);
+ }
+ }
+
+ return holder;
+}
+
+const struct full_propset_info *get_propset_info_with_guid(
+ const char *prop_name,
+ struct GUID *propset_guid)
+{
+ const struct full_propset_info *result = NULL;
+ struct guidtopropmap_holder *holder = NULL;
+ struct guidtopropmap *mapitem = NULL;
+
+ size_t i;
+ const struct full_guid_propset *guid_propset = NULL;
+
+ /* search builtin props first */
+ for (i = 0; full_propertyset[i].prop_info != NULL; i++) {
+ const struct full_propset_info *item = NULL;
+ guid_propset = &full_propertyset[i];
+ item = guid_propset->prop_info;
+ while (item->id) {
+ if (strequal(prop_name, item->name)) {
+ *propset_guid = guid_propset->guid;
+ result = item;
+ break;
+ }
+ item++;
+ }
+ if (result) {
+ break;
+ }
+ }
+
+ if (result) {
+ return result;
+ }
+
+ /* if we didn't find a match in builtin props try the extra props */
+ holder = propmap();
+ for (mapitem = holder->guidtopropmaploc; mapitem;
+ mapitem = mapitem->next) {
+ struct full_propset_info_list *propitem;
+ for (propitem = mapitem->propset; propitem;
+ propitem = propitem->next) {
+ if (strequal(prop_name, propitem->info.name)) {
+ *propset_guid = mapitem->guid;
+ result = &propitem->info;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+const struct full_propset_info *get_prop_info(const char *prop_name)
+{
+ const struct full_propset_info *result = NULL;
+ struct GUID guid;
+ result = get_propset_info_with_guid(prop_name, &guid);
+ return result;
+}
+
+char *prop_from_fullprop(TALLOC_CTX *ctx, struct wsp_cfullpropspec *fullprop)
+{
+ size_t i;
+ char *result = NULL;
+ const struct full_propset_info *item = NULL;
+ const struct full_propset_info_list *prop_item = NULL;
+ bool search_by_id = (fullprop->ulkind == PRSPEC_PROPID);
+ struct guidtopropmap_holder *holder = NULL;
+ struct guidtopropmap *mapitem = NULL;
+
+ /* check builtin properties */
+ for (i = 0; full_propertyset[i].prop_info != NULL; i++) {
+ /* find propset */
+ if (GUID_equal(&fullprop->guidpropset,
+ &full_propertyset[i].guid)) {
+ item = full_propertyset[i].prop_info;
+ break;
+ }
+ }
+ if (item) {
+ while (item->id) {
+ if (search_by_id) {
+ if( fullprop->name_or_id.prspec == item->id) {
+ result = talloc_strdup(ctx, item->name);
+ break;
+ }
+ } else if (strcmp(item->name,
+ fullprop->name_or_id.propname.vstring)
+ == 0) {
+ result = talloc_strdup(ctx, item->name);
+ break;
+ }
+ item++;
+ }
+ }
+
+ /* not found, search the extra props */
+ if (!result) {
+ holder = propmap();
+
+ for (mapitem = holder->guidtopropmaploc; mapitem;
+ mapitem = mapitem->next) {
+ if (GUID_equal(&fullprop->guidpropset,
+ &mapitem->guid)) {
+ prop_item = mapitem->propset;
+ break;
+ }
+ }
+
+ for (;prop_item; prop_item = prop_item->next) {
+ if (search_by_id) {
+ if(fullprop->name_or_id.prspec ==
+ prop_item->info.id) {
+ result = talloc_strdup(ctx,
+ prop_item->info.name);
+ break;
+ }
+ } else if (strcmp(prop_item->info.name,
+ fullprop->name_or_id.propname.vstring) == 0) {
+ result = talloc_strdup(ctx,
+ prop_item->info.name);
+ break;
+ }
+ }
+ }
+
+ if (!result) {
+ result = GUID_string(ctx, &fullprop->guidpropset);
+
+ if (search_by_id) {
+ result = talloc_asprintf(result, "%s/%d", result,
+ fullprop->name_or_id.prspec);
+ } else {
+ result = talloc_asprintf(result, "%s/%s", result,
+ fullprop->name_or_id.propname.vstring);
+ }
+ }
+ return result;
+}
+
+const char *genmeth_to_string(uint32_t genmethod)
+{
+ const char *result = NULL;
+ switch (genmethod) {
+ case 0:
+ result = "equals";
+ break;
+ case 1:
+ result = "starts with";
+ break;
+ case 2:
+ result = "matches inflection";
+ break;
+ default:
+ result = NULL;
+ break;
+ }
+ return result;
+}
+
+bool is_operator(struct wsp_crestriction *restriction) {
+ bool result;
+ switch(restriction->ultype) {
+ case RTAND:
+ case RTOR:
+ case RTNOT:
+ result = true;
+ break;
+ default:
+ result = false;
+ break;
+ }
+ return result;
+}
+
+const char *op_as_string(struct wsp_crestriction *restriction)
+{
+ const char *op = NULL;
+ if (is_operator(restriction)) {
+ switch(restriction->ultype) {
+ case RTAND:
+ op = " && ";
+ break;
+ case RTOR:
+ op = " || ";
+ break;
+ case RTNOT:
+ op = "!";
+ break;
+ }
+ } else if (restriction->ultype == RTPROPERTY) {
+ struct wsp_cpropertyrestriction *prop_restr =
+ &restriction->restriction.cpropertyrestriction;
+ switch (prop_restr->relop & 0XF) {
+ case PREQ:
+ op = "=";
+ break;
+ case PRNE:
+ op = "!=";
+ break;
+ case PRGE:
+ op = ">=";
+ break;
+ case PRLE:
+ op = "<=";
+ break;
+ case PRLT:
+ op = "<";
+ break;
+ case PRGT:
+ op = ">";
+ break;
+ default:
+ break;
+ }
+ } else if (restriction->ultype == RTCONTENT) {
+ struct wsp_ccontentrestriction *content = NULL;
+ content = &restriction->restriction.ccontentrestriction;
+ op = genmeth_to_string(content->ulgeneratemethod);
+ } else if (restriction->ultype == RTNATLANGUAGE) {
+ op = "=";
+ }
+ return op;
+}
+
+struct wsp_cfullpropspec *get_full_prop(struct wsp_crestriction *restriction)
+{
+ struct wsp_cfullpropspec *result;
+ switch (restriction->ultype) {
+ case RTPROPERTY:
+ result = &restriction->restriction.cpropertyrestriction.property;
+ break;
+ case RTCONTENT:
+ result = &restriction->restriction.ccontentrestriction.property;
+ break;
+ case RTNATLANGUAGE:
+ result = &restriction->restriction.cnatlanguagerestriction.property;
+ break;
+ default:
+ result = NULL;
+ break;
+ }
+ return result;
+}
+
+const char *variant_as_string(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *value, bool quote)
+{
+ const char* result = NULL;
+ switch(value->vtype) {
+ case VT_UI1:
+ result = talloc_asprintf(ctx, "%u",
+ value->vvalue.vt_ui1);
+ break;
+ case VT_INT:
+ case VT_I4:
+ result = talloc_asprintf(ctx, "%d",
+ value->vvalue.vt_i4);
+ break;
+ case VT_ERROR:
+ case VT_UINT:
+ case VT_UI4:
+ result = talloc_asprintf(ctx, "%u",
+ value->vvalue.vt_ui4);
+ break;
+ case VT_UI2:
+ case VT_I2:
+ result = talloc_asprintf(ctx, "%u",
+ value->vvalue.vt_ui2);
+ break;
+ case VT_BOOL:
+ result = talloc_asprintf(ctx, "%s",
+ value->vvalue.vt_ui2 == 0xFFFF ?
+ "true" : "false");
+ break;
+ case VT_DATE:
+ case VT_FILETIME: {
+ NTTIME filetime = value->vvalue.vt_ui8;
+ time_t unixtime;
+ struct tm *tm = NULL;
+ char datestring[256];
+ unixtime = nt_time_to_unix(filetime);
+ tm = gmtime(&unixtime);
+ strftime(datestring, sizeof(datestring), "%FT%TZ", tm);
+ result = talloc_strdup(ctx, datestring);
+ break;
+ }
+ case VT_R4: {
+ float f;
+ if (sizeof(f) != sizeof(value->vvalue.vt_ui4)) {
+ DBG_ERR("can't convert float\n");
+ break;
+ }
+ memcpy((void*)&f,
+ (void*)&value->vvalue.vt_ui4,
+ sizeof(value->vvalue.vt_ui4));
+ result = talloc_asprintf(ctx, "%f",
+ f);
+ break;
+ }
+ case VT_R8: {
+ /* should this really be unsigned ? */
+ double dval;
+ if (sizeof(dval) != sizeof(value->vvalue.vt_i8)) {
+ DBG_ERR("can't convert double\n");
+ break;
+ }
+ memcpy((void*)&dval,
+ (void*)&value->vvalue.vt_i8,
+ sizeof(dval));
+ result = talloc_asprintf(ctx, "%f",
+ dval);
+ break;
+ }
+ case VT_I8: {
+ result = talloc_asprintf(ctx, "%" PRIi64,
+ value->vvalue.vt_i8);
+ break;
+ }
+ case VT_UI8: {
+ result = talloc_asprintf(ctx, "%" PRIu64,
+ value->vvalue.vt_ui8);
+ break;
+ }
+ case VT_LPWSTR:
+ result = talloc_asprintf(ctx, "%s%s%s",
+ quote ? "\'" : "",
+ value->vvalue.vt_lpwstr.value,
+ quote ? "\'" : "");
+ break;
+ case VT_LPWSTR | VT_VECTOR: {
+ int num_elems =
+ value->vvalue.vt_lpwstr_v.vvector_elements;
+ int i;
+ for(i = 0; i < num_elems; i++) {
+ struct vt_lpwstr_vec *vec;
+ const char *val;
+ vec = &value->vvalue.vt_lpwstr_v;
+ val = vec->vvector_data[i].value;
+ result =
+ talloc_asprintf(ctx,
+ "%s%s%s%s%s",
+ result ? result : "",
+ i ? "," : "",
+ quote ? "\'" : "",
+ val,
+ quote ? "\'" : "");
+ }
+ break;
+ }
+ default:
+ DBG_INFO("can't represent unsupported vtype 0x%x as string\n",
+ value->vtype);
+ break;
+ }
+ return result;
+}
+
+static const struct {
+ uint32_t id;
+ const char *name;
+} typename_map[] = {
+ {VT_EMPTY, "Empty"},
+ {VT_NULL, "Null"},
+ {VT_I2, "VT_I2"},
+ {VT_I4, "VT_I4"},
+ {VT_I4, "VT_I4"},
+ {VT_R4, "VT_R4"},
+ {VT_R8, "VT_R8"},
+ {VT_CY, "VT_CY"},
+ {VT_DATE, "VT_DATE"},
+ {VT_BSTR, "VT_BSTR"},
+ {VT_I1, "VT_I1"},
+ {VT_UI1, "VT_UI1"},
+ {VT_UI2, "VT_UI2"},
+ {VT_UI4, "VT_UI4"},
+ {VT_I8, "VT_I8"},
+ {VT_UI8, "VT_UI8"},
+ {VT_INT, "VT_INT"},
+ {VT_UINT, "VT_UINT"},
+ {VT_ERROR, "VT_ERROR"},
+ {VT_BOOL, "VT_BOOL"},
+ {VT_VARIANT, "VT_VARIANT"},
+ {VT_DECIMAL, "VT_DECIMAL"},
+ {VT_FILETIME, "VT_FILETIME"},
+ {VT_BLOB, "VT_BLOB"},
+ {VT_BLOB_OBJECT, "VT_BLOB_OBJECT"},
+ {VT_CLSID, "VT_CLSID"},
+ {VT_LPSTR, "VT_LPSTR"},
+ {VT_LPWSTR, "VT_LPWSTR"},
+ {VT_COMPRESSED_LPWSTR, "VT_COMPRESSED_LPWSTR"},
+};
+
+const char *get_vtype_name(uint32_t type)
+{
+ const char *type_name = NULL;
+ static char result_buf[255];
+ int i;
+ uint32_t temp = type & ~(VT_VECTOR | VT_ARRAY);
+ for (i = 0; i < ARRAY_SIZE(typename_map); i++) {
+ if (temp == typename_map[i].id) {
+ type_name = typename_map[i].name;
+ break;
+ }
+ }
+ if (type & VT_VECTOR) {
+ snprintf(result_buf, sizeof(result_buf), "Vector | %s", type_name);
+ } else if (type & VT_ARRAY) {
+ snprintf(result_buf, sizeof(result_buf), "Array | %s", type_name);
+ } else {
+ snprintf(result_buf, sizeof(result_buf), "%s", type_name);
+ }
+ return result_buf;
+}
+
+bool is_variable_size(uint16_t vtype)
+{
+ bool result;
+ switch(vtype) {
+ case VT_LPWSTR:
+ case VT_COMPRESSED_LPWSTR:
+ case VT_BSTR:
+ case VT_BLOB:
+ case VT_BLOB_OBJECT:
+ case VT_VARIANT:
+ result = true;
+ break;
+ default:
+ result = false;
+ break;
+ }
+ return result;
+}
+
+const char *get_store_status(uint8_t status_byte)
+{
+ const char *result;
+ switch(status_byte) {
+ case 0:
+ result = "StoreStatusOk";
+ break;
+ case 1:
+ result = "StoreStatusDeferred";
+ break;
+ case 2:
+ result = "StoreStatusNull";
+ break;
+ default:
+ result = "Unknown Status";
+ break;
+ }
+ return result;
+}
+
+void set_variant_lpwstr(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *vvalue,
+ const char *string_val)
+{
+ vvalue->vtype = VT_LPWSTR;
+ vvalue->vvalue.vt_lpwstr.value = talloc_strdup(ctx, string_val);
+}
+
+void set_variant_i4(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *vvalue,
+ uint32_t val)
+{
+ vvalue->vtype = VT_I4;
+ vvalue->vvalue.vt_i4 = val;
+}
+
+void set_variant_vt_bool(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ bool bval)
+{
+ variant->vtype = VT_BOOL;
+ variant->vvalue.vt_bool = bval;
+}
+
+static void fill_int32_vec(TALLOC_CTX* ctx,
+ int32_t **pdest,
+ int32_t* ivector, uint32_t elems)
+{
+ int i;
+ int32_t *dest = talloc_zero_array(ctx, int32_t, elems);
+ for ( i = 0; i < elems; i++ ) {
+ dest[ i ] = ivector[ i ];
+ }
+ *pdest = dest;
+}
+
+void set_variant_i4_vector(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ int32_t* ivector, uint32_t elems)
+{
+ variant->vtype = VT_VECTOR | VT_I4;
+ variant->vvalue.vt_i4_vec.vvector_elements = elems;
+ fill_int32_vec(ctx, &variant->vvalue.vt_i4_vec.vvector_data, ivector, elems);
+}
+
+static void fill_string_vec(TALLOC_CTX* ctx,
+ struct wsp_cbasestoragevariant *variant,
+ const char **strings, uint16_t elems)
+{
+ int i;
+ variant->vvalue.vt_lpwstr_v.vvector_elements = elems;
+ variant->vvalue.vt_lpwstr_v.vvector_data = talloc_zero_array(ctx,
+ struct vt_lpwstr,
+ elems);
+
+ for( i = 0; i < elems; i++ ) {
+ variant->vvalue.vt_lpwstr_v.vvector_data[ i ].value = talloc_strdup(ctx, strings[ i ]);
+ }
+}
+
+static void fill_bstr_vec(TALLOC_CTX *ctx,
+ struct vt_bstr **pvector,
+ const char **strings, uint16_t elems)
+{
+ int i;
+ struct vt_bstr *vdata = talloc_zero_array(ctx, struct vt_bstr, elems);
+
+ for( i = 0; i < elems; i++ ) {
+ vdata [ i ].value = talloc_strdup(ctx, strings[ i ]);
+ }
+ *pvector = vdata;
+}
+
+void set_variant_bstr(TALLOC_CTX *ctx, struct wsp_cbasestoragevariant *variant,
+ const char *string_val)
+{
+ variant->vtype = VT_BSTR;
+ variant->vvalue.vt_bstr.value = talloc_strdup(ctx, string_val);
+}
+
+void set_variant_lpwstr_vector(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ const char **string_vals, uint32_t elems)
+{
+ variant->vtype = VT_LPWSTR | VT_VECTOR;
+ fill_string_vec(ctx, variant, string_vals, elems);
+}
+
+void set_variant_array_bstr(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ const char **string_vals, uint16_t elems)
+{
+ variant->vtype = VT_BSTR | VT_ARRAY;
+ variant->vvalue.vt_bstr_array.cdims = 1;
+ variant->vvalue.vt_bstr_array.ffeatures = 0;
+
+ variant->vvalue.vt_bstr_array.rgsabound =
+ talloc_zero_array(ctx, struct safearraybound, 1);
+
+ variant->vvalue.vt_bstr_array.rgsabound[0].celements = elems;
+ variant->vvalue.vt_bstr_array.rgsabound[0].ilbound = 0;
+ variant->vvalue.vt_bstr_array.cbelements = 0;
+ fill_bstr_vec(ctx, &variant->vvalue.vt_bstr_array.vdata,
+ string_vals, elems);
+ /*
+ * if cbelements is the num bytes per elem it kindof means each
+ * string in the array must be the same size ?
+ */
+
+ if (elems >0) {
+ variant->vvalue.vt_bstr_array.cbelements =
+ strlen_m_term(variant->vvalue.vt_bstr_array.vdata[0].value)*2;
+ }
+}
+
+/* create single dim array of vt_i4 */
+void set_variant_array_i4(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ int32_t *vals, uint16_t elems)
+{
+ /* #TODO see if we can combine with other set_variant_array methods */
+ variant->vtype = VT_I4 | VT_ARRAY;
+ variant->vvalue.vt_i4_array.cdims = 1;
+ variant->vvalue.vt_i4_array.ffeatures = 0;
+
+ variant->vvalue.vt_i4_array.rgsabound =
+ talloc_zero_array(ctx, struct safearraybound, 1);
+
+ variant->vvalue.vt_i4_array.rgsabound[0].celements = elems;
+ variant->vvalue.vt_i4_array.rgsabound[0].ilbound = 0;
+ variant->vvalue.vt_i4_array.cbelements = sizeof(uint32_t);
+ fill_int32_vec(ctx, &variant->vvalue.vt_i4_array.vdata, vals, elems);
+}
diff --git a/librpc/wsp/wsp_util.h b/librpc/wsp/wsp_util.h
new file mode 100644
index 0000000..ccda53b
--- /dev/null
+++ b/librpc/wsp/wsp_util.h
@@ -0,0 +1,89 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Window Search Service
+ *
+ * Copyright (c) Noel Power
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 __LIBRPC_WSP_UTIL_H__
+#define __LIBRPC_WSP_UTIL_H__
+
+#include "librpc/gen_ndr/misc.h"
+
+struct safearraybound;
+struct wsp_cfullpropspec;
+struct wsp_cbasestoragevariant;
+struct wsp_crestriction;
+
+struct full_propset_info {
+ uint32_t id;
+ const char *name;
+ uint16_t vtype;
+ bool extra_info;
+ bool in_inverted_index;
+ bool is_column;
+ bool can_col_be_indexed;
+ uint16_t max_size;
+};
+
+struct full_guid_propset {
+ struct GUID guid;
+ const struct full_propset_info *prop_info;
+};
+
+extern const struct full_guid_propset full_propertyset[];
+
+char *prop_from_fullprop(TALLOC_CTX *ctx, struct wsp_cfullpropspec *fullprop);
+const struct full_propset_info *get_prop_info(const char *prop_name);
+const struct full_propset_info *get_propset_info_with_guid(
+ const char *prop_name,
+ struct GUID *guid);
+const char * get_vtype_name(uint32_t type);
+bool is_variable_size(uint16_t vtype);
+const char *get_store_status(uint8_t status_byte);
+
+bool is_operator(struct wsp_crestriction *restriction);
+const char *op_as_string(struct wsp_crestriction *restriction);
+const char *genmeth_to_string(uint32_t genmethod);
+const char *variant_as_string(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *value,
+ bool quote);
+void set_variant_lpwstr(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *vvalue,
+ const char *string_val);
+void set_variant_i4(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *vvalue,
+ uint32_t val);
+void set_variant_vt_bool(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ bool bval);
+void set_variant_bstr(TALLOC_CTX *ctx, struct wsp_cbasestoragevariant *variant,
+ const char *string_val);
+void set_variant_lpwstr_vector(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ const char **string_vals, uint32_t elems);
+void set_variant_array_bstr(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ const char **string_vals, uint16_t elems);
+void set_variant_i4_vector(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ int32_t* ivector, uint32_t elems);
+void set_variant_array_i4(TALLOC_CTX *ctx,
+ struct wsp_cbasestoragevariant *variant,
+ int32_t *vals, uint16_t elems);
+
+struct wsp_cfullpropspec *get_full_prop(struct wsp_crestriction *restriction);
+#endif /* __LIBRPC_WSP_UTIL_H__ */